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); \
})
|