code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(252 lines)
1 // This file defines some of the helper functions used for printing values
3 #include <ctype.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <unistd.h>
8 #include "fpconv.h"
9 #include "print.h"
10 #include "util.h"
12 public
13 int _print_int(FILE *f, int64_t n) {
14 char buf[21] = {[20] = 0}; // Big enough for INT64_MIN + '\0'
15 char *p = &buf[19];
16 bool negative = n < 0;
17 if (negative) n = -n;
19 do {
20 *(p--) = '0' + (n % 10);
21 n /= 10;
22 } while (n > 0);
24 if (negative) *(p--) = '-';
26 return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f);
29 public
30 int _print_uint(FILE *f, uint64_t n) {
31 char buf[21] = {[20] = 0}; // Big enough for UINT64_MAX + '\0'
32 char *p = &buf[19];
34 do {
35 *(p--) = '0' + (n % 10);
36 n /= 10;
37 } while (n > 0);
39 return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f);
42 public
43 int _print_hex(FILE *f, hex_format_t hex) {
44 int printed = 0;
45 if (!hex.no_prefix) printed += fputs("0x", f);
46 if (hex.digits > 0) {
47 hex.digits -= (hex.n == 0); // Don't need a leading zero for a zero
48 for (uint64_t n = hex.n; n > 0 && hex.digits > 0; n /= 16) {
49 hex.digits -= 1;
51 for (; hex.digits > 0; hex.digits -= 1) {
52 printed += fputc('0', f);
55 char buf[9] = {[8] = '\0'}; // Enough space for FFFFFFFF + '\0'
56 char *p = &buf[7];
57 do {
58 uint8_t digit = hex.n % 16;
59 if (digit <= 9) *(p--) = '0' + digit;
60 else if (hex.uppercase) *(p--) = 'A' + digit - 10;
61 else *(p--) = 'a' + digit - 10;
62 hex.n /= 16;
63 } while (hex.n > 0);
64 printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[7] - p), f);
65 return printed;
68 public
69 int _print_oct(FILE *f, oct_format_t oct) {
70 int printed = 0;
71 if (!oct.no_prefix) printed += fputs("0o", f);
72 if (oct.digits > 0) {
73 oct.digits -= (oct.n == 0); // Don't need a leading zero for a zero
74 for (uint64_t n = oct.n; n > 0 && oct.digits > 0; n /= 8)
75 oct.digits -= 1;
76 for (; oct.digits > 0; oct.digits -= 1)
77 printed += fputc('0', f);
79 char buf[12] = {[11] = '\0'}; // Enough space for octal UINT64_MAX + '\0'
80 char *p = &buf[10];
81 do {
82 *(p--) = '0' + (oct.n % 8);
83 oct.n /= 8;
84 } while (oct.n > 0);
85 printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[10] - p), f);
86 return printed;
89 public
90 int _print_double(FILE *f, double n) {
91 static char buf[24];
92 int len = fpconv_dtoa(n, buf);
93 return (int)fwrite(buf, sizeof(char), (size_t)len, f);
96 public
97 int _print_hex_double(FILE *f, hex_double_t hex) {
98 if (hex.d != hex.d) return fputs("NAN", f);
99 else if (hex.d == 1.0 / 0.0) return fputs("INF", f);
100 else if (hex.d == -1.0 / 0.0) return fputs("-INF", f);
101 else if (hex.d == 0.0) return fputs("0.0", f);
103 union {
104 double d;
105 uint64_t u;
106 } bits = {.d = hex.d};
108 int sign = (bits.u >> 63) & 1ull;
109 int exp = (int)((bits.u >> 52) & 0x7FF) - 1023ull;
110 uint64_t frac = bits.u & 0xFFFFFFFFFFFFFull;
112 char buf[25];
113 char *p = buf;
115 if (sign) *p++ = '-';
116 *p++ = '0';
117 *p++ = 'x';
119 uint64_t mantissa = (1ull << 52) | frac; // implicit 1
120 int mantissa_shift = 52;
122 while ((mantissa & 0xF) == 0 && mantissa_shift > 0) {
123 mantissa >>= 4;
124 mantissa_shift -= 4;
127 uint64_t int_part = mantissa >> mantissa_shift;
128 *p++ = "0123456789abcdef"[int_part];
130 *p++ = '.';
132 while (mantissa_shift > 0) {
133 mantissa_shift -= 4;
134 uint64_t digit = (mantissa >> mantissa_shift) & 0xF;
135 *p++ = "0123456789abcdef"[digit];
138 *p++ = 'p';
140 if (exp >= 0) {
141 *p++ = '+';
142 } else {
143 *p++ = '-';
144 exp = -exp;
147 char expbuf[6];
148 int ei = 5;
149 expbuf[ei--] = '\0';
150 do {
151 expbuf[ei--] = '0' + (exp % 10);
152 exp /= 10;
153 } while (exp && ei >= 0);
155 ei++;
156 while (expbuf[ei])
157 *p++ = expbuf[ei++];
159 *p = '\0';
160 return fwrite(buf, sizeof(char), (size_t)(p - buf), f);
163 public
164 int _print_char(FILE *f, char c) {
165 #define ESC(e) "'\\" e "'"
166 const char *named[256] = {
167 ['\''] = ESC("'"), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"),
168 ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")};
169 const char *name = named[(uint8_t)c];
170 if (name != NULL) return fputs(name, f);
171 else if (isprint(c)) return fputc('\'', f) + fputc(c, f) + fputc('\'', f);
172 else
173 return (fputs("'\\x", f) + _print_hex(f, hex((uint64_t)c, .digits = 2, .no_prefix = true, .uppercase = true))
174 + fputs("'", f));
175 #undef ESC
178 public
179 int _print_quoted(FILE *f, quoted_t quoted) {
180 #define ESC(e) "\\" e
181 const char *named[256] = {
182 ['"'] = ESC("\""), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"),
183 ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")};
184 int printed = fputc('"', f);
185 for (const char *p = quoted.str; *p; p++) {
186 const char *name = named[(uint8_t)*p];
187 if (name != NULL) {
188 printed += fputs(name, f);
189 } else if (isprint(*p) || (uint8_t)*p > 0x7F) {
190 printed += fputc(*p, f);
191 } else {
192 printed +=
193 fputs("\\x", f) + _print_hex(f, hex((uint64_t)*p, .digits = 2, .no_prefix = true, .uppercase = true));
196 printed += fputc('"', f);
197 #undef ESC
198 return printed;
201 #if defined(__GLIBC__) && defined(_GNU_SOURCE)
202 // GLIBC has fopencookie()
203 static ssize_t _gc_stream_write(void *cookie, const char *buf, size_t size) {
204 gc_stream_t *stream = (gc_stream_t *)cookie;
205 if (stream->position + size + 1 > *stream->size)
206 *stream->buffer =
207 GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL)));
208 memcpy(&(*stream->buffer)[stream->position], buf, size);
209 stream->position += size;
210 (*stream->buffer)[stream->position] = '\0';
211 return (ssize_t)size;
214 public
215 FILE *gc_memory_stream(char **buf, size_t *size) {
216 gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t));
217 stream->size = size;
218 stream->buffer = buf;
219 *stream->size = 16;
220 *stream->buffer = GC_MALLOC_ATOMIC(*stream->size);
221 (*stream->buffer)[0] = '\0';
222 stream->position = 0;
223 cookie_io_functions_t functions = {.write = _gc_stream_write};
224 return fopencookie(stream, "w", functions);
226 #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
227 // BSDs have funopen() and fwopen()
228 static int _gc_stream_write(void *cookie, const char *buf, int size) {
229 gc_stream_t *stream = (gc_stream_t *)cookie;
230 if (stream->position + size + 1 > *stream->size)
231 *stream->buffer =
232 GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL)));
233 memcpy(&(*stream->buffer)[stream->position], buf, size);
234 stream->position += size;
235 (*stream->buffer)[stream->position] = '\0';
236 return size;
239 public
240 FILE *gc_memory_stream(char **buf, size_t *size) {
241 gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t));
242 stream->size = size;
243 stream->buffer = buf;
244 *stream->size = 16;
245 *stream->buffer = GC_MALLOC_ATOMIC(*stream->size);
246 (*stream->buffer)[0] = '\0';
247 stream->position = 0;
248 return fwopen(stream, _gc_stream_write);
250 #else
251 #error "This platform doesn't support fopencookie() or funopen()!"
252 #endif