MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 124 lines 3.2 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <stdarg.h> 4#include <stdio.h> 5#include <stdlib.h> 6#include <string.h> 7 8#include "output.h" 9 10#define ANT_OUTPUT_INITIAL_CAP 65536 11 12static ant_output_stream_t g_stdout_writer = { .stream = NULL }; 13static ant_output_stream_t g_stderr_writer = { .stream = NULL }; 14 15ant_output_stream_t *ant_output_stream(FILE *stream) { 16 ant_output_stream_t *out = (stream == stderr) ? &g_stderr_writer : &g_stdout_writer; 17 out->stream = stream; 18 return out; 19} 20 21void ant_output_stream_begin(ant_output_stream_t *out) { 22 if (!out) return; 23 out->buffer.len = 0; 24 out->buffer.failed = false; 25} 26 27bool ant_output_stream_reserve(ant_output_stream_t *out, size_t extra) { 28 size_t needed = 0; 29 size_t next_cap = 0; 30 char *next = NULL; 31 32 if (!out || out->buffer.failed) return false; 33 34 needed = out->buffer.len + extra; 35 if (needed <= out->buffer.cap) return true; 36 37 next_cap = out->buffer.cap ? out->buffer.cap * 2 : ANT_OUTPUT_INITIAL_CAP; 38 while (next_cap < needed) next_cap *= 2; 39 40 next = realloc(out->buffer.data, next_cap); 41 if (!next) { 42 out->buffer.failed = true; 43 return false; 44 } 45 46 out->buffer.data = next; 47 out->buffer.cap = next_cap; 48 return true; 49} 50 51bool ant_output_stream_append(ant_output_stream_t *out, const void *data, size_t len) { 52 if (!ant_output_stream_reserve(out, len)) return false; 53 if (len > 0) memcpy(out->buffer.data + out->buffer.len, data, len); 54 out->buffer.len += len; 55 return true; 56} 57 58bool ant_output_stream_append_cstr(ant_output_stream_t *out, const char *str) { 59 return ant_output_stream_append(out, str, strlen(str)); 60} 61 62bool ant_output_stream_putc(ant_output_stream_t *out, char ch) { 63 return ant_output_stream_append(out, &ch, 1); 64} 65 66#pragma GCC diagnostic push 67#pragma GCC diagnostic ignored "-Wformat-nonliteral" 68 69bool ant_output_stream_appendfv(ant_output_stream_t *out, const char *fmt, va_list ap) { 70 char stack[256]; 71 va_list ap_copy; 72 int written = 0; 73 74 if (!out || out->buffer.failed) return false; 75 76 va_copy(ap_copy, ap); 77 written = vsnprintf(stack, sizeof(stack), fmt, ap_copy); 78 va_end(ap_copy); 79 80 if (written < 0) { 81 out->buffer.failed = true; 82 return false; 83 } 84 85 if ((size_t)written < sizeof(stack)) 86 return ant_output_stream_append(out, stack, (size_t)written); 87 88 if (!ant_output_stream_reserve(out, (size_t)written + 1)) return false; 89 vsnprintf(out->buffer.data + out->buffer.len, out->buffer.cap - out->buffer.len, fmt, ap); 90 out->buffer.len += (size_t)written; 91 92 return true; 93} 94 95bool ant_output_stream_appendf(ant_output_stream_t *out, const char *fmt, ...) { 96 va_list ap; 97 bool ok = false; 98 99 va_start(ap, fmt); 100 ok = ant_output_stream_appendfv(out, fmt, ap); 101 va_end(ap); 102 return ok; 103} 104 105#pragma GCC diagnostic pop 106 107bool ant_output_stream_flush(ant_output_stream_t *out) { 108 size_t len = 0; 109 size_t wrote = 0; 110 111 if (!out || !out->stream) return false; 112 if (out->buffer.failed) { 113 out->buffer.len = 0; 114 out->buffer.failed = false; 115 return false; 116 } 117 if (out->buffer.len == 0) return fflush(out->stream) == 0; 118 119 len = out->buffer.len; 120 wrote = fwrite(out->buffer.data, 1, len, out->stream); 121 out->buffer.len = 0; 122 123 return wrote == len && fflush(out->stream) == 0; 124}