/*
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * Copyright © 2025 Keith Packard
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "ubsan.h"
#include <stdio.h>

void
__ubsan_val_to_string(char str[static VAL_STR_LEN], struct type_descriptor *type, void *value)
{
    int width;

    switch (type->type_kind) {
    case type_kind_int:
        width = type_int_width(type);
        if (type_is_signed(type)) {
            snprintf(str, VAL_STR_LEN, "%" PRIdMAX "(s%d)", __ubsan_val_to_imax(type, value, 0),
                     width);
        } else {
            snprintf(str, VAL_STR_LEN, "%" PRIuMAX "(u%d)", __ubsan_val_to_umax(type, value, 0),
                     width);
        }
        break;
    case type_kind_float:
        width = type_float_width(type);
        if (width == sizeof(float) * 8) {
            snprintf(str, VAL_STR_LEN, "%af", (double)*(float *)value);
        } else if (width == sizeof(double) * 8) {
            snprintf(str, VAL_STR_LEN, "%a", *(double *)value);
#ifdef __SIZEOF_LONG_DOUBLE__
        } else if (width == sizeof(long double) * 8) {
            snprintf(str, VAL_STR_LEN, "%Lal", *(long double *)value);
#endif
        } else {
            snprintf(str, VAL_STR_LEN, "float %d bits", width);
        }
        break;
    default:
        snprintf(str, VAL_STR_LEN, "kind %d\n", type->type_kind);
        break;
    }
}
