code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(171 lines)
1 // This file defines some functions to make it easy to do formatted text
2 // without using printf style specifiers:
3 //
4 // print(...) - print text
5 // fprint(file, ...) - print text to file
6 // print_err(...) - print an error message and exit with EXIT_FAILURE
7 // String(...) - return an allocated string
9 #pragma once
11 #include <assert.h>
12 #include <gc.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/param.h>
19 #include <unistd.h>
21 #include "datatypes.h"
22 #include "mapmacro.h"
24 // GCC lets you define macro-like functions which are always inlined and never
25 // compiled using this combination of flags. See: https://gcc.gnu.org/onlinedocs/gcc/Inline.html
26 #ifndef PRINT_FN
27 #ifdef __TINYC__
28 #define PRINT_FN static inline __attribute__((gnu_inline, always_inline)) int
29 #else
30 #define PRINT_FN extern inline __attribute__((gnu_inline, always_inline)) int
31 #endif
32 #endif
34 typedef struct {
35 uint64_t n;
36 bool no_prefix;
37 bool uppercase;
38 int digits;
39 } hex_format_t;
40 #define hex(x, ...) ((hex_format_t){.n = x, __VA_ARGS__})
42 typedef struct {
43 double d;
44 } hex_double_t;
45 #define hex_double(x, ...) ((hex_double_t){.d = x, __VA_ARGS__})
47 typedef struct {
48 uint64_t n;
49 bool no_prefix;
50 int digits;
51 } oct_format_t;
52 #define oct(x, ...) ((oct_format_t){.n = x, __VA_ARGS__})
54 typedef struct {
55 const char *str;
56 } quoted_t;
57 #define quoted(s) ((quoted_t){s})
59 typedef struct {
60 const char *str;
61 size_t length;
62 } string_slice_t;
63 #define string_slice(...) ((string_slice_t){__VA_ARGS__})
65 typedef struct {
66 char c;
67 int length;
68 } repeated_char_t;
69 #define repeated_char(ch, len) ((repeated_char_t){.c = ch, .length = len})
71 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
72 #define FMT64 "ll"
73 #else
74 #define FMT64 "l"
75 #endif
77 int _print_int(FILE *f, int64_t x);
78 int _print_uint(FILE *f, uint64_t x);
79 int _print_double(FILE *f, double x);
80 int _print_hex(FILE *f, hex_format_t hex);
81 int _print_hex_double(FILE *f, hex_double_t hex);
82 int _print_oct(FILE *f, oct_format_t oct);
83 PRINT_FN _print_float(FILE *f, float x) {
84 return _print_double(f, (double)x);
86 PRINT_FN _print_pointer(FILE *f, void *p) {
87 return _print_hex(f, hex((uint64_t)p));
89 PRINT_FN _print_bool(FILE *f, bool b) {
90 return fputs(b ? "yes" : "no", f);
92 PRINT_FN _print_str(FILE *f, const char *s) {
93 return fputs(s ? s : "(null)", f);
95 int _print_char(FILE *f, char c);
96 int _print_quoted(FILE *f, quoted_t quoted);
97 PRINT_FN _print_string_slice(FILE *f, string_slice_t slice) {
98 return slice.str ? fwrite(slice.str, 1, slice.length, f) : (size_t)fputs("(null)", f);
100 PRINT_FN _print_repeated_char(FILE *f, repeated_char_t repeated) {
101 int len = 0;
102 for (int n = 0; n < repeated.length; n++)
103 len += fputc(repeated.c, f);
104 return len;
107 extern int Text$print(FILE *stream, Text_t text);
108 extern int Int$print(FILE *f, Int_t i);
109 #ifndef _fprint1
110 #define _fprint1(f, x) \
111 _Generic((x), \
112 char *: _print_str, \
113 const char *: _print_str, \
114 char: _print_char, \
115 bool: _print_bool, \
116 int64_t: _print_int, \
117 int32_t: _print_int, \
118 int16_t: _print_int, \
119 int8_t: _print_int, \
120 uint64_t: _print_uint, \
121 uint32_t: _print_uint, \
122 uint16_t: _print_uint, \
123 uint8_t: _print_uint, \
124 float: _print_float, \
125 double: _print_double, \
126 hex_format_t: _print_hex, \
127 hex_double_t: _print_hex_double, \
128 oct_format_t: _print_oct, \
129 quoted_t: _print_quoted, \
130 string_slice_t: _print_string_slice, \
131 repeated_char_t: _print_repeated_char, \
132 Text_t: Text$print, \
133 Int_t: Int$print, \
134 void *: _print_pointer)(f, x)
135 #endif
137 typedef struct {
138 char **buffer;
139 size_t *size;
140 size_t position;
141 } gc_stream_t;
143 FILE *gc_memory_stream(char **buf, size_t *size);
145 #define _print(x) _n += _fprint1(_printing, x)
146 #define _fprint(f, ...) \
147 ({ \
148 FILE *_printing = f; \
149 int _n = 0; \
150 MAP_LIST(_print, __VA_ARGS__); \
151 _n; \
153 #define fprint(f, ...) _fprint(f, __VA_ARGS__, "\n")
154 #define print(...) fprint(stdout, __VA_ARGS__)
155 #define fprint_inline(f, ...) _fprint(f, __VA_ARGS__)
156 #define print_inline(...) fprint_inline(stdout, __VA_ARGS__)
157 #define String(...) \
158 ({ \
159 char *_buf = NULL; \
160 size_t _size = 0; \
161 FILE *_stream = gc_memory_stream(&_buf, &_size); \
162 assert(_stream); \
163 _fprint(_stream, __VA_ARGS__); \
164 fflush(_stream); \
165 _buf; \
167 #define print_err(...) \
168 ({ \
169 fprint(stderr, "\033[31;1m", __VA_ARGS__, "\033[m"); \
170 exit(EXIT_FAILURE); \