llm
Download
169 lines 8.5 KiBCModified 2026-08-31 raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
// This file defines some functions to make it easy to do formatted text
// without using printf style specifiers:
//
//     print(...) - print text
//     fprint(file, ...) - print text to file
//     print_err(...) - print an error message and exit with EXIT_FAILURE
//     String(...) - return an allocated string

#pragma once

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "bigint.h" // IWYU pragma: export
#include "datatypes.h" // IWYU pragma: export
#include "integers.h" // IWYU pragma: export
#include "mapmacro.h"
#include "path.h" // IWYU pragma: export
#include "stdlib.h" // IWYU pragma: export (USE_COLOR)
#include "text.h" // IWYU pragma: export

// This combination of attributes defines macro-like functions which are always
// inlined and never emitted as standalone compiled functions:
#ifndef PRINT_FN
#define PRINT_FN extern inline __attribute__((gnu_inline, always_inline)) int
#endif

typedef struct {
    uint64_t n;
    bool no_prefix;
    bool uppercase;
    int digits;
} hex_format_t;
#define hex(x, ...) ((hex_format_t){.n = x, __VA_ARGS__})

typedef struct {
    double d;
} hex_double_t;
#define hex_double(x, ...) ((hex_double_t){.d = x, __VA_ARGS__})

typedef struct {
    uint64_t n;
    bool no_prefix;
    int digits;
} oct_format_t;
#define oct(x, ...) ((oct_format_t){.n = x, __VA_ARGS__})

typedef struct {
    const char *str;
} quoted_t;
#define quoted(s) ((quoted_t){s})

typedef struct {
    const char *str;
    size_t length;
} string_slice_t;
#define string_slice(...) ((string_slice_t){__VA_ARGS__})

typedef struct {
    char c;
    int length;
} repeated_char_t;
#define repeated_char(ch, len) ((repeated_char_t){.c = ch, .length = len})

#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define FMT64 "ll"
#else
#define FMT64 "l"
#endif

int _print_uint(FILE *f, uint64_t x);
int _print_double(FILE *f, double x);
int _print_hex(FILE *f, hex_format_t hex);
int _print_hex_double(FILE *f, hex_double_t hex);
int _print_oct(FILE *f, oct_format_t oct);
PRINT_FN _print_float(FILE *f, float x) {
    return _print_double(f, (double)x);
}
PRINT_FN _print_pointer(FILE *f, void *p) {
    return _print_hex(f, hex((uint64_t)p));
}
PRINT_FN _print_bool(FILE *f, bool b) {
    return fputs(b ? "yes" : "no", f);
}
PRINT_FN _print_str(FILE *f, const char *s) {
    return fputs(s ? s : "(null)", f);
}
int _print_char(FILE *f, char c);
int _print_quoted(FILE *f, quoted_t quoted);
PRINT_FN _print_string_slice(FILE *f, string_slice_t slice) {
    return slice.str ? fwrite(slice.str, 1, slice.length, f) : (size_t)fputs("(null)", f);
}
PRINT_FN _print_repeated_char(FILE *f, repeated_char_t repeated) {
    int len = 0;
    for (int n = 0; n < repeated.length; n++)
        len += fputc(repeated.c, f);
    return len;
}

#ifndef _fprint1
#define _fprint1(f, x)                                                                                                 \
    _Generic((x),                                                                                                      \
        char *: _print_str,                                                                                            \
        const char *: _print_str,                                                                                      \
        char: _print_char,                                                                                             \
        bool: _print_bool,                                                                                             \
        int64_t: Int64$print,                                                                                          \
        int32_t: Int64$print,                                                                                          \
        int16_t: Int64$print,                                                                                          \
        int8_t: Int64$print,                                                                                           \
        uint64_t: _print_uint,                                                                                         \
        uint32_t: _print_uint,                                                                                         \
        uint16_t: _print_uint,                                                                                         \
        uint8_t: _print_uint,                                                                                          \
        float: _print_float,                                                                                           \
        double: _print_double,                                                                                         \
        hex_format_t: _print_hex,                                                                                      \
        hex_double_t: _print_hex_double,                                                                               \
        oct_format_t: _print_oct,                                                                                      \
        quoted_t: _print_quoted,                                                                                       \
        string_slice_t: _print_string_slice,                                                                           \
        repeated_char_t: _print_repeated_char,                                                                         \
        Text_t: Text$print,                                                                                            \
        Int_t: Int$print,                                                                                              \
        void *: _print_pointer)(f, x)
#endif

typedef struct {
    char **buffer;
    size_t *size;
    size_t position;
} gc_stream_t;

FILE *gc_memory_stream(char **buf, size_t *size);
char *gc_stream_finalize(FILE *stream, char **buf, size_t *size);

#define _print(x) _n += _fprint1(_printing, x)
#define _fprint(f, ...)                                                                                                \
    ({                                                                                                                 \
        FILE *_printing = f;                                                                                           \
        int _n = 0;                                                                                                    \
        MAP_LIST(_print, __VA_ARGS__);                                                                                 \
        _n;                                                                                                            \
    })
#define fprint(f, ...) _fprint(f, __VA_ARGS__, "\n")
#define print(...) fprint(stdout, __VA_ARGS__)
#define fprint_inline(f, ...) _fprint(f, __VA_ARGS__)
#define print_inline(...) fprint_inline(stdout, __VA_ARGS__)
#define String(...)                                                                                                    \
    ({                                                                                                                 \
        char *_buf = NULL;                                                                                             \
        size_t _size = 0;                                                                                              \
        FILE *_stream = gc_memory_stream(&_buf, &_size);                                                               \
        assert(_stream);                                                                                               \
        _fprint(_stream, __VA_ARGS__);                                                                                 \
        gc_stream_finalize(_stream, &_buf, &_size);                                                                    \
    })
// The highlighting is left out when output isn't colored (NO_COLOR, COLOR=0,
// or not a terminal; see tomo_init()):
#define print_err(...)                                                                                                 \
    ({                                                                                                                 \
        fprint(stderr, USE_COLOR ? "\033[91;1m" : "", __VA_ARGS__, USE_COLOR ? "\033[m" : "");                         \
        exit(EXIT_FAILURE);                                                                                            \
    })