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.

migrate to themackabu/crprintf instead of embedded

+14 -1339
-47
include/cli/crprintf.h
··· 1 - #ifndef CRPRINTF_H 2 - #define CRPRINTF_H 3 - 4 - #include <stdio.h> 5 - #include <stddef.h> 6 - #include <stdbool.h> 7 - 8 - extern bool io_no_color; 9 - extern bool crprintf_debug; 10 - extern bool crprintf_debug_hex; 11 - 12 - typedef struct program_t program_t; 13 - program_t *crprintf_compile(const char *fmt); 14 - 15 - void crprintf_var(const char *name, const char *value); 16 - void crprintf_hexdump(program_t *prog, FILE *out); 17 - void crprintf_disasm(program_t *prog, FILE *out); 18 - 19 - int crprintf_exec(program_t *prog, FILE *stream, ...); 20 - int crsprintf_inner(program_t *prog, char *buf, size_t size, ...); 21 - 22 - #define _CRPRINTF_INIT(prog, fmt) \ 23 - if (!prog) { \ 24 - prog = crprintf_compile(fmt); \ 25 - if (crprintf_debug) crprintf_disasm(prog, stderr); \ 26 - if (crprintf_debug_hex) crprintf_hexdump(prog, stderr); \ 27 - } 28 - 29 - #define crprintf(fmt, ...) ({ \ 30 - static program_t *_cp_prog_ = NULL; \ 31 - _CRPRINTF_INIT(_cp_prog_, fmt); \ 32 - crprintf_exec(_cp_prog_, stdout, ##__VA_ARGS__); \ 33 - }) 34 - 35 - #define crfprintf(stream, fmt, ...) ({ \ 36 - static program_t *_cp_prog_ = NULL; \ 37 - _CRPRINTF_INIT(_cp_prog_, fmt); \ 38 - crprintf_exec(_cp_prog_, stream, ##__VA_ARGS__); \ 39 - }) 40 - 41 - #define crsprintf(buf, size, fmt, ...) ({ \ 42 - static program_t *_cp_prog_ = NULL; \ 43 - _CRPRINTF_INIT(_cp_prog_, fmt); \ 44 - crsprintf_inner(_cp_prog_, buf, size, ##__VA_ARGS__); \ 45 - }) 46 - 47 - #endif
-1
libant/meson.build
··· 36 36 '../src/runtime.c', 37 37 '../src/snapshot.c', 38 38 '../src/esm/remote.c', 39 - '../src/cli/crprintf.c', 40 39 ) + files(module_files) 41 40 42 41 include = include_directories('../include')
-1
meson.build
··· 38 38 'src/cli/pkg.c', 39 39 'src/cli/misc.c', 40 40 'src/cli/version.c', 41 - 'src/cli/crprintf.c', 42 41 ) + files(module_files) 43 42 44 43 include = include_directories('include')
+2 -1
meson/deps/meson.build
··· 85 85 uuidv7_dep = subproject('uuidv7').get_variable('uuidv7_dep') 86 86 argtable3_dep = subproject('argtable3').get_variable('argtable3_dep') 87 87 minicoro_dep = subproject('minicoro').get_variable('minicoro_dep') 88 + crprintf_dep = subproject('crprintf').get_variable('crprintf_dep') 88 89 89 90 lmdb_dep = subproject('lmdb', default_options: [ 90 91 'warning_level=0', ··· 174 175 pkg_build_dir = meson.current_build_dir() 175 176 176 177 ant_deps = [ 177 - libffi_dep, uuid_dep, 178 + libffi_dep, uuid_dep, crprintf_dep, 178 179 llhttp, pcre2_dep, libuv_dep, 179 180 argtable3_dep, tlsuv_dep, libsodium_dep, 180 181 yyjson_dep, minicoro_dep, uuidv7_dep,
-1281
src/cli/crprintf.c
··· 1 - /* 2 - * crprintf - printf with inline color tags, powered by a register-based VM 3 - * 4 - * usage: 5 - * crprintf("<red>error:</red> something went wrong\n"); 6 - * crprintf("<bold><cyan>info:</cyan></bold> hello %s\n", name); 7 - * crprintf("<#ff8800>orange text</#ff8800>\n"); 8 - * crprintf(" <pad=18><green>%s</green></pad> %s\n", cmd->name, cmd->desc); 9 - * 10 - * supported tags: 11 - * <red> <green> <yellow> <blue> <magenta> <cyan> <white> <black> 12 - * <gray/grey> <bright_red> <bright_green> ... etc 13 - * <bg_red> <bg_green> ... <bg_#RGB> <bg_#RRGGBB> 14 - * <bold> <dim> <ul> (underline) 15 - * <bold_red> <dim_cyan> etc - combine styles with underscores 16 - * <bold+red> <dim+cyan+bg_blue> etc - combine styles with + 17 - * <#RRGGBB> or <#RGB> for arbitrary 24-bit foreground colors 18 - * <pad=N> ... </pad> - right-pad contents to N visible columns 19 - * <br/> - emit a newline, <br=N/> - emit N newlines 20 - * <rpad=N> ... </rpad> - left-pad (right-align) contents to N visible columns 21 - * <space=N/> - emit N spaces 22 - * <gap=N/> - emit N spaces (alias for space) 23 - * <let name=style1+style2+...> or <let name=style1, name2=style2...> - define a named style variable 24 - * {let name=style1+style2+...} or {let name=style1, name2=style2...} - alternative syntax 25 - * quoted values: {let label='hello'} or <let label="world"/> - quotes are stripped from value 26 - * <$name> to apply a variable as a style, {name} to emit its value as literal text 27 - * {~name} for lowercase, {^name} for uppercase 28 - * {~'string'} for lowercase literal, {^'string'} for uppercase literal 29 - * </tagname> or </> to reset (pops one level) 30 - * <reset/> to reset all styles (clears entire stack) 31 - * << and >> to emit literal < and > 32 - * %% to emit a literal % 33 - * 34 - */ 35 - 36 - #include "utils.h" 37 - #include "cli/crprintf.h" 38 - 39 - #include <ctype.h> 40 - #include <stdio.h> 41 - #include <stdarg.h> 42 - #include <string.h> 43 - #include <stdlib.h> 44 - #include <stdint.h> 45 - #include <wchar.h> 46 - 47 - bool crprintf_debug = false; 48 - bool crprintf_debug_hex = false; 49 - 50 - typedef enum { 51 - OP_NOP = 0, 52 - OP_EMIT_LIT, 53 - OP_EMIT_FMT, 54 - OP_SET_FG, 55 - OP_SET_BG, 56 - OP_SET_FG_RGB, 57 - OP_SET_BG_RGB, 58 - OP_SET_BOLD, 59 - OP_SET_DIM, 60 - OP_SET_UL, 61 - OP_STYLE_PUSH, 62 - OP_STYLE_FLUSH, 63 - OP_STYLE_RESET, 64 - OP_STYLE_RESET_ALL, 65 - OP_PAD_BEGIN, 66 - OP_RPAD_BEGIN, 67 - OP_PAD_END, 68 - OP_EMIT_SPACES, 69 - OP_EMIT_NEWLINES, 70 - OP_HALT, 71 - OP_MAX 72 - } opcode_t; 73 - 74 - typedef struct { 75 - uint32_t op; 76 - uint32_t operand; 77 - } instruction_t; 78 - 79 - typedef enum { 80 - COL_NONE = 0, 81 - COL_BLACK = 30, COL_RED, COL_GREEN, COL_YELLOW, 82 - COL_BLUE, COL_MAGENTA, COL_CYAN, COL_WHITE, 83 - COL_GRAY = 90, COL_BRIGHT_RED, COL_BRIGHT_GREEN, COL_BRIGHT_YELLOW, 84 - COL_BRIGHT_BLUE, COL_BRIGHT_MAGENTA, COL_BRIGHT_CYAN, COL_BRIGHT_WHITE, 85 - COL_RGB = 0xFF 86 - } color_t; 87 - 88 - #define UNPACK_R(c) (((c)>>16)&0xFF) 89 - #define UNPACK_G(c) (((c)>>8)&0xFF) 90 - #define UNPACK_B(c) ((c)&0xFF) 91 - 92 - #define PACK_RGB(r,g,b) \ 93 - (((uint32_t)(r)<<16)|((uint32_t)(g)<<8)|(uint32_t)(b)) 94 - 95 - typedef struct { 96 - size_t mark; 97 - int width; 98 - int right_align; 99 - } pad_entry_t; 100 - 101 - typedef struct { 102 - uint32_t fg; 103 - uint32_t bg; 104 - uint32_t fg_rgb; 105 - uint32_t bg_rgb; 106 - int bold; 107 - int dim; 108 - int ul; 109 - } style_entry_t; 110 - 111 - typedef struct { 112 - uint32_t fg; 113 - uint32_t bg; 114 - uint32_t fg_rgb; 115 - uint32_t bg_rgb; 116 - 117 - int bold; 118 - int dim; 119 - int ul; 120 - 121 - style_entry_t style_stack[8]; 122 - int style_depth; 123 - 124 - pad_entry_t pad_stack[8]; 125 - int pad_depth; 126 - } vm_regs_t; 127 - 128 - #define MAX_VARS 16 129 - #define MAX_VAR_NAME 32 130 - #define MAX_VAR_VALUE 128 131 - 132 - typedef struct { 133 - char name[MAX_VAR_NAME]; 134 - char value[MAX_VAR_VALUE]; 135 - int nlen; int vlen; int is_fmt; 136 - } crprintf_var_t; 137 - 138 - typedef struct { 139 - crprintf_var_t vars[MAX_VARS]; 140 - int count; 141 - } var_table_t; 142 - 143 - static var_table_t global_vars = {0}; 144 - static const char *scan_var_brace(program_t *p, const char *ptr, const char **lit, var_table_t *vars); 145 - 146 - struct program_t { 147 - instruction_t *code; 148 - size_t code_len; 149 - size_t code_cap; 150 - char *literals; 151 - size_t lit_len; 152 - size_t lit_cap; 153 - }; 154 - 155 - static program_t *program_new(void) { 156 - program_t *p = calloc(1, sizeof(*p)); 157 - *p = (program_t){ 158 - .code_cap = 32, 159 - .code = malloc(32 * sizeof(instruction_t)), 160 - .lit_cap = 256, 161 - .literals = malloc(256), 162 - }; 163 - return p; 164 - } 165 - 166 - static void emit_op(program_t *p, uint32_t op, uint32_t operand) { 167 - if (p->code_len >= p->code_cap) { 168 - p->code_cap *= 2; 169 - p->code = realloc(p->code, p->code_cap * sizeof(instruction_t)); 170 - } 171 - p->code[p->code_len++] = (instruction_t){ op, operand }; 172 - } 173 - 174 - static uint32_t add_literal(program_t *p, const char *s, size_t len) { 175 - while (p->lit_len + len + 1 > p->lit_cap) { 176 - p->lit_cap *= 2; 177 - p->literals = realloc(p->literals, p->lit_cap); 178 - } 179 - 180 - uint32_t off = (uint32_t)p->lit_len; 181 - memcpy(p->literals + p->lit_len, s, len); 182 - 183 - p->literals[p->lit_len + len] = '\0'; 184 - p->lit_len += len + 1; 185 - 186 - return off; 187 - } 188 - 189 - typedef struct { 190 - const char *name; 191 - int nlen; 192 - color_t col; 193 - } color_entry_t; 194 - 195 - static const color_entry_t fg_colors[] = { 196 - {"black",5,COL_BLACK}, {"red",3,COL_RED}, {"green",5,COL_GREEN}, 197 - {"yellow",6,COL_YELLOW}, {"blue",4,COL_BLUE}, {"magenta",7,COL_MAGENTA}, 198 - {"cyan",4,COL_CYAN}, {"white",5,COL_WHITE}, 199 - {"gray",4,COL_GRAY}, {"grey",4,COL_GRAY}, 200 - {"bright_red",10,COL_BRIGHT_RED}, {"bright_green",12,COL_BRIGHT_GREEN}, 201 - {"bright_yellow",13,COL_BRIGHT_YELLOW}, {"bright_blue",11,COL_BRIGHT_BLUE}, 202 - {"bright_magenta",14,COL_BRIGHT_MAGENTA}, {"bright_cyan",11,COL_BRIGHT_CYAN}, 203 - {"bright_white",12,COL_BRIGHT_WHITE}, 204 - }; 205 - 206 - static const color_entry_t bg_colors[] = { 207 - {"bg_black",8,COL_BLACK}, {"bg_red",6,COL_RED}, {"bg_green",8,COL_GREEN}, 208 - {"bg_yellow",9,COL_YELLOW}, {"bg_blue",7,COL_BLUE}, {"bg_magenta",10,COL_MAGENTA}, 209 - {"bg_cyan",7,COL_CYAN}, {"bg_white",8,COL_WHITE}, 210 - }; 211 - 212 - static const color_entry_t seg_bg_colors[] = { 213 - {"black",5,COL_BLACK}, {"red",3,COL_RED}, {"green",5,COL_GREEN}, 214 - {"yellow",6,COL_YELLOW}, {"blue",4,COL_BLUE}, {"magenta",7,COL_MAGENTA}, 215 - {"cyan",4,COL_CYAN}, {"white",5,COL_WHITE}, 216 - }; 217 - 218 - #define FG_COUNT (sizeof(fg_colors)/sizeof(fg_colors[0])) 219 - #define BG_COUNT (sizeof(bg_colors)/sizeof(bg_colors[0])) 220 - #define SEG_BG_COUNT (sizeof(seg_bg_colors)/sizeof(seg_bg_colors[0])) 221 - 222 - static int parse_hex_rgb(const char *hex, int len, uint32_t *rgb) { 223 - int r, g, b; 224 - if (len == 4) { 225 - int r1=hex_digit(hex[1]), g1=hex_digit(hex[2]), b1=hex_digit(hex[3]); 226 - if (r1<0||g1<0||b1<0) return 0; 227 - r=r1*17; g=g1*17; b=b1*17; 228 - } else if (len == 7) { 229 - int r1=hex_digit(hex[1]),r2=hex_digit(hex[2]); 230 - int g1=hex_digit(hex[3]),g2=hex_digit(hex[4]); 231 - int b1=hex_digit(hex[5]),b2=hex_digit(hex[6]); 232 - if (r1<0||r2<0||g1<0||g2<0||b1<0||b2<0) return 0; 233 - r=r1*16+r2; g=g1*16+g2; b=b1*16+b2; 234 - } else return 0; 235 - *rgb = PACK_RGB(r, g, b); 236 - return 1; 237 - } 238 - 239 - static int compile_hex_fg(program_t *p, const char *tag, int len) { 240 - uint32_t rgb; 241 - if (!parse_hex_rgb(tag, len, &rgb)) return 0; 242 - emit_op(p, OP_SET_FG_RGB, rgb); 243 - return 1; 244 - } 245 - 246 - static int compile_hex_bg(program_t *p, const char *hex, int hlen) { 247 - uint32_t rgb; 248 - if (!parse_hex_rgb(hex, hlen, &rgb)) return 0; 249 - emit_op(p, OP_SET_BG_RGB, rgb); 250 - return 1; 251 - } 252 - 253 - static int tag_eq(const char *tag, int len, const char *lit) { 254 - int ll = (int)strlen(lit); 255 - return len == ll && memcmp(tag, lit, ll) == 0; 256 - } 257 - 258 - static int tag_prefix(const char *tag, int len, const char *pfx) { 259 - int pl = (int)strlen(pfx); 260 - return len > pl && memcmp(tag, pfx, pl) == 0; 261 - } 262 - 263 - static int match_fg(program_t *p, const char *s, int len) { 264 - for (int i = 0; i < (int)FG_COUNT; i++) if ( 265 - len == fg_colors[i].nlen && memcmp(s, fg_colors[i].name, len) == 0) { 266 - emit_op(p, OP_SET_FG, fg_colors[i].col); return 1; 267 - } 268 - return 0; 269 - } 270 - 271 - static int match_bg(program_t *p, const char *s, int len) { 272 - for (int i = 0; i < (int)BG_COUNT; i++) if ( 273 - len == bg_colors[i].nlen && memcmp(s, bg_colors[i].name, len) == 0) { 274 - emit_op(p, OP_SET_BG, bg_colors[i].col); return 1; 275 - } 276 - return 0; 277 - } 278 - 279 - static int match_seg_bg(program_t *p, const char *s, int len) { 280 - for (int i = 0; i < (int)SEG_BG_COUNT; i++) if ( 281 - len == seg_bg_colors[i].nlen && memcmp(s, seg_bg_colors[i].name, len) == 0) { 282 - emit_op(p, OP_SET_BG, seg_bg_colors[i].col); return 1; 283 - } 284 - return 0; 285 - } 286 - 287 - typedef struct { 288 - const char *name; 289 - int nlen; 290 - int op; 291 - } attr_entry_t; 292 - 293 - static const attr_entry_t attrs[] = { 294 - { "bold", 4, OP_SET_BOLD }, 295 - { "dim", 3, OP_SET_DIM }, 296 - { "ul", 2, OP_SET_UL }, 297 - }; 298 - 299 - #define ATTR_COUNT (sizeof(attrs) / sizeof(attrs[0])) 300 - 301 - static int match_attr(program_t *p, const char *s, int len) { 302 - for (int i = 0; i < (int)ATTR_COUNT; i++) if ( 303 - len == attrs[i].nlen && memcmp(s, attrs[i].name, len) == 0) { 304 - emit_op(p, attrs[i].op, 1); return 1; 305 - } 306 - return 0; 307 - } 308 - 309 - static const char *next_seg(const char *cur, const char *end, int *out_len) { 310 - const char *sep = cur; 311 - while (sep < end && *sep != '_') sep++; 312 - *out_len = (int)(sep - cur); 313 - return sep; 314 - } 315 - 316 - static int match_plus_seg(program_t *p, const char *seg, int slen) { 317 - if (match_attr(p, seg, slen)) return 1; 318 - if (match_fg(p, seg, slen)) return 1; 319 - if (match_bg(p, seg, slen)) return 1; 320 - if (slen > 0 && seg[0] == '#') return compile_hex_fg(p, seg, slen); 321 - if (tag_prefix(seg, slen, "bg_#")) return compile_hex_bg(p, seg + 3, slen - 3); 322 - if (tag_prefix(seg, slen, "bg_")) return match_seg_bg(p, seg + 3, slen - 3); 323 - return 0; 324 - } 325 - 326 - static int compile_plus_segs(program_t *p, const char *s, int len) { 327 - const char *seg = s; 328 - const char *end = s + len; 329 - int emitted = 0; 330 - 331 - while (seg < end) { 332 - const char *next = seg; 333 - while (next < end && *next != '+') next++; 334 - int slen = (int)(next - seg); 335 - if (!match_plus_seg(p, seg, slen)) return 0; 336 - emitted++; seg = (next < end) ? next + 1 : end; 337 - } 338 - 339 - return emitted; 340 - } 341 - 342 - static int compile_let(var_table_t *vars, const char *body, int len) { 343 - if (len > 0 && body[len - 1] == '/') len--; 344 - 345 - const char *p = body; 346 - const char *end = body + len; 347 - 348 - while (p < end) { 349 - while (p < end && (*p == ' ' || *p == ',')) p++; 350 - if (p >= end) break; 351 - 352 - const char *eq = memchr(p, '=', end - p); 353 - if (!eq) return 0; 354 - 355 - int nlen = (int)(eq - p); 356 - 357 - const char *vstart = eq + 1; 358 - const char *vend = vstart; 359 - 360 - if (vstart < end && (*vstart == '\'' || *vstart == '"')) { 361 - char quote = *vstart; 362 - vstart++; 363 - vend = vstart; 364 - 365 - while (vend < end && *vend != quote) vend++; 366 - if (vend >= end) return 0; 367 - const char *after = vend + 1; 368 - 369 - while (after < end && (*after == ' ' || *after == ',')) after++; 370 - int vlen = (int)(vend - vstart); 371 - 372 - if (nlen <= 0 || nlen >= MAX_VAR_NAME || vlen < 0 || vlen >= MAX_VAR_VALUE) return 0; 373 - if (vars->count >= MAX_VARS) return 0; 374 - 375 - crprintf_var_t *v = &vars->vars[vars->count++]; 376 - memcpy(v->name, p, nlen); 377 - 378 - v->name[nlen] = '\0'; v->nlen = nlen; 379 - memcpy(v->value, vstart, vlen); 380 - 381 - v->value[vlen] = '\0'; v->vlen = vlen; 382 - v->is_fmt = 0; 383 - 384 - for (int j = 0; j < vlen; j++) { 385 - if (vstart[j] == '%' && j + 1 < vlen && vstart[j + 1] != '%') 386 - { v->is_fmt = 1; break; } 387 - } 388 - 389 - p = after; 390 - continue; 391 - } 392 - 393 - while (vend < end && *vend != ',') vend++; 394 - 395 - int vlen = (int)(vend - vstart); 396 - if (nlen <= 0 || nlen >= MAX_VAR_NAME || vlen <= 0 || vlen >= MAX_VAR_VALUE) return 0; 397 - if (vars->count >= MAX_VARS) return 0; 398 - 399 - crprintf_var_t *v = &vars->vars[vars->count++]; 400 - memcpy(v->name, p, nlen); 401 - v->name[nlen] = '\0'; v->nlen = nlen; 402 - 403 - memcpy(v->value, vstart, vlen); 404 - v->value[vlen] = '\0'; v->vlen = vlen; 405 - p = vend; 406 - } 407 - 408 - return 1; 409 - } 410 - 411 - void crprintf_var(const char *name, const char *value) { 412 - if (global_vars.count >= MAX_VARS) return; 413 - int nlen = (int)strlen(name); 414 - int vlen = (int)strlen(value); 415 - if (nlen <= 0 || nlen >= MAX_VAR_NAME || vlen <= 0 || vlen >= MAX_VAR_VALUE) return; 416 - 417 - for (int i = 0; i < global_vars.count; i++) { 418 - crprintf_var_t *v = &global_vars.vars[i]; 419 - if (v->nlen == nlen && memcmp(v->name, name, nlen) == 0) { 420 - memcpy(v->value, value, vlen); 421 - v->value[vlen] = '\0'; v->vlen = vlen; return; 422 - } 423 - } 424 - 425 - crprintf_var_t *v = &global_vars.vars[global_vars.count++]; 426 - memcpy(v->name, name, nlen); 427 - v->name[nlen] = '\0'; v->nlen = nlen; 428 - 429 - memcpy(v->value, value, vlen); 430 - v->value[vlen] = '\0'; v->vlen = vlen; 431 - } 432 - 433 - static int compile_var_ref(program_t *p, var_table_t *vars, const char *tag, int len) { 434 - const char *name = tag + 1; 435 - int nlen = len - 1; 436 - 437 - const char *plus = memchr(name, '+', nlen); 438 - int var_nlen = plus ? (int)(plus - name) : nlen; 439 - 440 - for (int i = 0; i < vars->count; i++) { 441 - crprintf_var_t *v = &vars->vars[i]; 442 - if (var_nlen != v->nlen || memcmp(name, v->name, var_nlen) != 0) continue; 443 - 444 - emit_op(p, OP_STYLE_PUSH, 0); 445 - if (!compile_plus_segs(p, v->value, v->vlen)) return 0; 446 - 447 - if (plus) { 448 - const char *rest = plus + 1; 449 - int rlen = nlen - var_nlen - 1; 450 - if (rlen > 0 && !compile_plus_segs(p, rest, rlen)) return 0; 451 - } 452 - 453 - emit_op(p, OP_STYLE_FLUSH, 0); 454 - return 1; 455 - } 456 - 457 - return 0; 458 - } 459 - 460 - static int match_attr_off(program_t *p, const char *s, int len) { 461 - for (int i = 0; i < (int)ATTR_COUNT; i++) if ( 462 - len == attrs[i].nlen && memcmp(s, attrs[i].name, len) == 0) { 463 - emit_op(p, attrs[i].op, 0); return 1; 464 - } 465 - return 0; 466 - } 467 - 468 - static int match_fg_off(program_t *p, const char *s, int len) { 469 - for (int i = 0; i < (int)FG_COUNT; i++) if ( 470 - len == fg_colors[i].nlen && memcmp(s, fg_colors[i].name, len) == 0) { 471 - emit_op(p, OP_SET_FG, COL_NONE); return 1; 472 - } 473 - if (len > 0 && s[0] == '#') { emit_op(p, OP_SET_FG, COL_NONE); return 1; } 474 - return 0; 475 - } 476 - 477 - static int match_bg_off(program_t *p, const char *s, int len) { 478 - for (int i = 0; i < (int)BG_COUNT; i++) if ( 479 - len == bg_colors[i].nlen && memcmp(s, bg_colors[i].name, len) == 0) { 480 - emit_op(p, OP_SET_BG, COL_NONE); return 1; 481 - } 482 - if (tag_prefix(s, len, "bg_#")) { emit_op(p, OP_SET_BG, COL_NONE); return 1; } 483 - return 0; 484 - } 485 - 486 - static int compile_tag(program_t *p, const char *tag, int len, int closing, var_table_t *vars) { 487 - if (closing) { 488 - if (tag_eq(tag, len, "pad") || tag_eq(tag, len, "rpad")) { 489 - emit_op(p, OP_PAD_END, 0); return 1; 490 - } 491 - 492 - if (match_attr_off(p, tag, len) || match_fg_off(p, tag, len) || match_bg_off(p, tag, len)) { 493 - emit_op(p, OP_STYLE_FLUSH, 0); return 1; 494 - } 495 - 496 - emit_op(p, OP_STYLE_RESET, 0); 497 - return 1; 498 - } 499 - 500 - if (tag_prefix(tag, len, "let ")) return compile_let(vars, tag + 4, len - 4); 501 - if (tag[0] == '$' && len > 1) return compile_var_ref(p, vars, tag, len); 502 - 503 - if (tag_prefix(tag, len, "pad=")) { emit_op(p, OP_PAD_BEGIN, (uint32_t)atoi(tag + 4)); return 1; } 504 - if (tag_prefix(tag, len, "rpad=")) { emit_op(p, OP_RPAD_BEGIN, (uint32_t)atoi(tag + 5)); return 1; } 505 - 506 - if (tag_prefix(tag, len, "space=") && tag[len-1] == '/') { 507 - emit_op(p, OP_EMIT_SPACES, (uint32_t)atoi(tag + 6)); 508 - return 1; 509 - } 510 - 511 - if (tag_prefix(tag, len, "gap=") && tag[len-1] == '/') { 512 - emit_op(p, OP_EMIT_SPACES, (uint32_t)atoi(tag + 4)); 513 - return 1; 514 - } 515 - 516 - if (tag_eq(tag, len, "reset/")) { 517 - emit_op(p, OP_STYLE_RESET_ALL, 0); 518 - return 1; 519 - } 520 - 521 - if (tag_eq(tag, len, "br/")) { 522 - emit_op(p, OP_EMIT_NEWLINES, 1); 523 - return 1; 524 - } 525 - 526 - if (tag_prefix(tag, len, "br=") && tag[len-1] == '/') { 527 - emit_op(p, OP_EMIT_NEWLINES, (uint32_t)atoi(tag + 3)); 528 - return 1; 529 - } 530 - 531 - emit_op(p, OP_STYLE_PUSH, 0); 532 - 533 - if (match_attr(p, tag, len)) { emit_op(p, OP_STYLE_FLUSH, 0); return 1; } 534 - if (match_fg(p, tag, len)) { emit_op(p, OP_STYLE_FLUSH, 0); return 1; } 535 - if (match_bg(p, tag, len)) { emit_op(p, OP_STYLE_FLUSH, 0); return 1; } 536 - 537 - if (tag[0] == '#') { 538 - if (!compile_hex_fg(p, tag, len)) return 0; 539 - emit_op(p, OP_STYLE_FLUSH, 0); return 1; 540 - } 541 - 542 - if (tag_prefix(tag, len, "bg_#")) { 543 - if (!compile_hex_bg(p, tag + 3, len - 3)) return 0; 544 - emit_op(p, OP_STYLE_FLUSH, 0); return 1; 545 - } 546 - 547 - if (memchr(tag, '+', len)) { 548 - if (compile_plus_segs(p, tag, len)) { emit_op(p, OP_STYLE_FLUSH, 0); return 1; } 549 - } 550 - 551 - const char *seg = tag; 552 - const char *end = tag + len; 553 - int emitted = 0; 554 - 555 - while (seg < end) { 556 - int slen; 557 - const char *sep = next_seg(seg, end, &slen); 558 - 559 - if (match_attr(p, seg, slen)) { 560 - } else if (tag_eq(seg, slen, "bg") && sep < end) { 561 - seg = sep + 1; 562 - sep = next_seg(seg, end, &slen); 563 - if (!match_seg_bg(p, seg, slen)) return 0; 564 - } else if (!match_fg(p, seg, slen)) return 0; 565 - 566 - emitted++; 567 - seg = (sep < end) ? sep + 1 : end; 568 - } 569 - 570 - if (emitted) { emit_op(p, OP_STYLE_FLUSH, 0); return 1; } 571 - return 0; 572 - } 573 - 574 - static void flush_lit(program_t *p, const char *lit, const char *end) { 575 - if (end <= lit) return; 576 - uint32_t off = add_literal(p, lit, end - lit); 577 - emit_op(p, OP_EMIT_LIT, off); 578 - } 579 - 580 - static const char *scan_tag(program_t *p, const char *ptr, const char **lit, var_table_t *vars) { 581 - flush_lit(p, *lit, ptr); 582 - 583 - const char *start = ptr + 1; 584 - int closing = 0; 585 - if (*start == '/') { closing = 1; start++; } 586 - 587 - if (closing && *start == '>') { 588 - emit_op(p, OP_STYLE_RESET, 0); 589 - *lit = start + 1; 590 - return *lit; 591 - } 592 - 593 - const char *end = start; 594 - while (*end && *end != '>') end++; 595 - 596 - if (*end == '>' && compile_tag(p, start, (int)(end - start), closing, vars)) { 597 - *lit = end + 1; 598 - return *lit; 599 - } 600 - 601 - uint32_t off = add_literal(p, "<", 1); 602 - emit_op(p, OP_EMIT_LIT, off); 603 - *lit = ptr + 1; 604 - return *lit; 605 - } 606 - 607 - typedef enum { 608 - ARG_NONE = 0, 609 - ARG_INT, 610 - ARG_LONG, 611 - ARG_LLONG, 612 - ARG_SIZE, 613 - ARG_DOUBLE, 614 - ARG_CSTR, 615 - ARG_PTR, 616 - ARG_WINT, 617 - ARG_WSTR, 618 - } arg_class_t; 619 - 620 - static arg_class_t classify_arg(const char *spec, int len) { 621 - char conv = spec[len - 1]; 622 - if (conv == '%' || conv == 'n') return ARG_NONE; 623 - if (conv == 's') return ARG_CSTR; 624 - if (conv == 'p') return ARG_PTR; 625 - if (conv == 'f' || conv == 'F' || conv == 'e' || conv == 'E' || 626 - conv == 'g' || conv == 'G' || conv == 'a' || conv == 'A') 627 - return ARG_DOUBLE; 628 - 629 - const char *p = spec + 1; 630 - while (*p == '-' || *p == '+' || *p == ' ' || *p == '#' || *p == '0') p++; 631 - if (*p == '*') p++; else while (*p >= '0' && *p <= '9') p++; 632 - if (*p == '.') { p++; if (*p == '*') p++; else while (*p >= '0' && *p <= '9') p++; } 633 - 634 - if (p[0] == 'z') return ARG_SIZE; 635 - if (p[0] == 'l' && p[1] == 'l') return ARG_LLONG; 636 - if (p[0] == 'l' && conv == 'c') return ARG_WINT; 637 - if (p[0] == 'l' && conv == 's') return ARG_WSTR; 638 - if (p[0] == 'l') return ARG_LONG; 639 - if (p[0] == 'j') return ARG_LLONG; 640 - 641 - return ARG_INT; 642 - } 643 - 644 - static const char *scan_fmt(program_t *p, const char *ptr, const char **lit) { 645 - flush_lit(p, *lit, ptr); 646 - 647 - const char *fs = ptr + 1; 648 - while (*fs=='-'||*fs=='+'||*fs==' '||*fs=='#'||*fs=='0') fs++; 649 - if (*fs == '*') fs++; else while (*fs >= '0' && *fs <= '9') fs++; 650 - if (*fs == '.') { fs++; if (*fs == '*') fs++; else while (*fs >= '0' && *fs <= '9') fs++; } 651 - while (*fs=='h'||*fs=='l'||*fs=='L'||*fs=='z'||*fs=='j'||*fs=='t') fs++; 652 - if (*fs) fs++; 653 - 654 - uint32_t off = add_literal(p, ptr, fs - ptr); 655 - arg_class_t cls = classify_arg(ptr, (int)(fs - ptr)); 656 - emit_op(p, OP_EMIT_FMT, off | ((uint32_t)cls << 28)); 657 - *lit = fs; 658 - return fs; 659 - } 660 - 661 - static const char *scan_escape( 662 - program_t *p, const char *ptr, 663 - const char **lit, const char *emit, size_t elen 664 - ) { 665 - flush_lit(p, *lit, ptr); 666 - uint32_t off = add_literal(p, emit, elen); 667 - emit_op(p, OP_EMIT_LIT, off); 668 - *lit = ptr + 2; 669 - return *lit; 670 - } 671 - 672 - static void transform_case(char *dst, const char *src, int len, int lower) { 673 - for (int i = 0; i < len; i++) dst[i] = (char)(lower 674 - ? tolower((unsigned char)src[i]) 675 - : toupper((unsigned char)src[i]) 676 - ); 677 - } 678 - 679 - static const char *scan_let_brace(program_t *p, const char *ptr, const char **lit, var_table_t *vars) { 680 - flush_lit(p, *lit, ptr); 681 - 682 - const char *body = ptr + 5; 683 - const char *end = body; 684 - while (*end && *end != '}') end++; 685 - 686 - if (*end == '}' && compile_let(vars, body, (int)(end - body))) { 687 - *lit = end + 1; 688 - return *lit; 689 - } 690 - 691 - uint32_t off = add_literal(p, "{", 1); 692 - emit_op(p, OP_EMIT_LIT, off); 693 - *lit = ptr + 1; 694 - return *lit; 695 - } 696 - 697 - static void compile_fragment(program_t *p, const char *fmt, var_table_t *vars) { 698 - const char *ptr = fmt; 699 - const char *lit = ptr; 700 - 701 - while (*ptr) { 702 - if (*ptr == '<' && ptr[1] == '<') ptr = scan_escape(p, ptr, &lit, "<", 1); 703 - else if (*ptr == '>' && ptr[1] == '>') ptr = scan_escape(p, ptr, &lit, ">", 1); 704 - else if (*ptr == '%' && ptr[1] == '%') ptr = scan_escape(p, ptr, &lit, "%%", 2); 705 - else if (*ptr == '{' && memcmp(ptr, "{let ", 5) == 0) ptr = scan_let_brace(p, ptr, &lit, vars); 706 - else if (*ptr == '{') ptr = scan_var_brace(p, ptr, &lit, vars); 707 - else if (*ptr == '<') ptr = scan_tag(p, ptr, &lit, vars); 708 - else if (*ptr == '%' && ptr[1] && ptr[1] != '%') ptr = scan_fmt(p, ptr, &lit); 709 - else ptr++; 710 - } 711 - 712 - flush_lit(p, lit, ptr); 713 - } 714 - 715 - static const char *scan_var_brace(program_t *p, const char *ptr, const char **lit, var_table_t *vars) { 716 - flush_lit(p, *lit, ptr); 717 - 718 - const char *name = ptr + 1; 719 - const char *end = name; 720 - while (*end && *end != '}') end++; 721 - 722 - if (*end != '}') goto emit_brace; 723 - 724 - int lower = 0, upper = 0; 725 - if (*name == '~') { lower = 1; name++; } 726 - else if (*name == '^') { upper = 1; name++; } 727 - int nlen = (int)(end - name); 728 - 729 - if (*name == '\'' || *name == '"') { 730 - const char *s = name + 1; 731 - const char *e = memchr(s, *name, end - s); 732 - if (!e) goto emit_brace; 733 - 734 - int slen = (int)(e - s); 735 - if (slen > 0 && slen < MAX_VAR_VALUE) { 736 - char buf[MAX_VAR_VALUE]; 737 - if (lower || upper) { transform_case(buf, s, slen, lower); s = buf; } 738 - uint32_t off = add_literal(p, s, slen); 739 - emit_op(p, OP_EMIT_LIT, off); 740 - } 741 - 742 - *lit = end + 1; 743 - return *lit; 744 - } 745 - 746 - for (int i = 0; i < vars->count; i++) { 747 - crprintf_var_t *v = &vars->vars[i]; 748 - if (nlen != v->nlen || memcmp(name, v->name, nlen) != 0) continue; 749 - 750 - const char *val = v->value; 751 - int vlen = v->vlen; 752 - char buf[MAX_VAR_VALUE]; 753 - 754 - if (lower || upper) { 755 - transform_case(buf, val, vlen, lower); 756 - val = buf; 757 - } 758 - 759 - if (memchr(val, '<', vlen)) { 760 - char tmp[MAX_VAR_VALUE + 1]; 761 - memcpy(tmp, val, vlen); 762 - tmp[vlen] = '\0'; 763 - compile_fragment(p, tmp, vars); 764 - } else if (v->is_fmt) { 765 - arg_class_t cls = classify_arg(val, vlen); 766 - uint32_t off = add_literal(p, val, vlen); 767 - emit_op(p, OP_EMIT_FMT, off | ((uint32_t)cls << 28)); 768 - } else { 769 - uint32_t off = add_literal(p, val, vlen); 770 - emit_op(p, OP_EMIT_LIT, off); 771 - } 772 - 773 - *lit = end + 1; 774 - return *lit; 775 - } 776 - 777 - emit_brace:; 778 - uint32_t off = add_literal(p, "{", 1); 779 - emit_op(p, OP_EMIT_LIT, off); 780 - *lit = ptr + 1; 781 - return *lit; 782 - } 783 - 784 - program_t *crprintf_compile(const char *fmt) { 785 - program_t *p = program_new(); 786 - var_table_t vars = global_vars; 787 - 788 - compile_fragment(p, fmt, &vars); 789 - emit_op(p, OP_HALT, 0); 790 - return p; 791 - } 792 - 793 - static size_t visible_len(const char *s, size_t n) { 794 - size_t vis = 0; 795 - for (size_t i = 0; i < n; i++) { 796 - if (s[i] == '\x1b') while (++i < n && !isalpha(s[i])); 797 - else vis++; 798 - } 799 - return vis; 800 - } 801 - 802 - typedef struct { 803 - char *data; 804 - size_t len; 805 - } vm_output_t; 806 - 807 - static vm_output_t crprintf_vm_run(program_t *prog, va_list ap) { 808 - vm_regs_t regs = {0}; 809 - 810 - size_t cap = 512, pos = 0; 811 - char *out = malloc(cap); 812 - if (!out) return (vm_output_t){ NULL, 0 }; 813 - 814 - #define ENSURE(n) ({ \ 815 - while (pos + (n) + 1 > cap) { \ 816 - cap *= 2; out = realloc(out, cap); \ 817 - if (!out) return (vm_output_t){ NULL, 0 }; \ 818 - }}) 819 - 820 - #define OUT_STR(s, l) ({ ENSURE(l); memcpy(out+pos, s, l); pos += (l); }) 821 - #define OUT_CSTR(s) ({ size_t _l = strlen(s); OUT_STR(s, _l); }) 822 - 823 - const instruction_t *ip = prog->code; 824 - static const void *dispatch[OP_MAX] = { 825 - [OP_NOP] = &&op_nop, 826 - [OP_EMIT_LIT] = &&op_emit_lit, 827 - [OP_EMIT_FMT] = &&op_emit_fmt, 828 - [OP_SET_FG] = &&op_set_fg, 829 - [OP_SET_BG] = &&op_set_bg, 830 - [OP_SET_FG_RGB] = &&op_set_fg_rgb, 831 - [OP_SET_BG_RGB] = &&op_set_bg_rgb, 832 - [OP_SET_BOLD] = &&op_set_bold, 833 - [OP_SET_DIM] = &&op_set_dim, 834 - [OP_SET_UL] = &&op_set_ul, 835 - [OP_STYLE_PUSH] = &&op_style_push, 836 - [OP_STYLE_FLUSH] = &&op_style_flush, 837 - [OP_STYLE_RESET] = &&op_style_reset, 838 - [OP_STYLE_RESET_ALL] = &&op_style_reset_all, 839 - [OP_PAD_BEGIN] = &&op_pad_begin, 840 - [OP_RPAD_BEGIN] = &&op_rpad_begin, 841 - [OP_PAD_END] = &&op_pad_end, 842 - [OP_EMIT_SPACES] = &&op_emit_spaces, 843 - [OP_EMIT_NEWLINES] = &&op_emit_newlines, 844 - [OP_HALT] = &&op_halt, 845 - }; 846 - 847 - #define DISPATCH() goto *dispatch[ip->op] 848 - #define NEXT() do { ip++; DISPATCH(); } while(0) 849 - 850 - DISPATCH(); 851 - 852 - op_nop: NEXT(); 853 - 854 - op_emit_lit: { 855 - OUT_CSTR(prog->literals + ip->operand); 856 - NEXT(); 857 - } 858 - 859 - op_emit_fmt: { 860 - uint32_t lit_off = ip->operand & 0x0FFFFFFF; 861 - arg_class_t cls = (arg_class_t)(ip->operand >> 28); 862 - const char *spec = prog->literals + lit_off; 863 - 864 - char tmp[256]; 865 - va_list ap_copy; 866 - va_copy(ap_copy, ap); 867 - 868 - #pragma GCC diagnostic push 869 - #pragma GCC diagnostic ignored "-Wformat-nonliteral" 870 - int n = vsnprintf(tmp, sizeof(tmp), spec, ap_copy); 871 - va_end(ap_copy); 872 - 873 - if (n > 0 && (size_t)n < sizeof(tmp)) { 874 - OUT_STR(tmp, (size_t)n); 875 - } else if (n > 0) { 876 - ENSURE((size_t)n); 877 - va_copy(ap_copy, ap); 878 - vsnprintf(out + pos, (size_t)n + 1, spec, ap_copy); 879 - va_end(ap_copy); 880 - pos += (size_t)n; 881 - } 882 - #pragma GCC diagnostic pop 883 - 884 - switch (cls) { 885 - case ARG_INT: (void)va_arg(ap, int); break; 886 - case ARG_LONG: (void)va_arg(ap, long); break; 887 - case ARG_LLONG: (void)va_arg(ap, long long); break; 888 - case ARG_SIZE: (void)va_arg(ap, size_t); break; 889 - case ARG_DOUBLE: (void)va_arg(ap, double); break; 890 - case ARG_CSTR: (void)va_arg(ap, const char *); break; 891 - case ARG_PTR: (void)va_arg(ap, void *); break; 892 - case ARG_WINT: (void)va_arg(ap, wint_t); break; 893 - case ARG_WSTR: (void)va_arg(ap, wchar_t *); break; 894 - case ARG_NONE: break; 895 - } 896 - NEXT(); 897 - } 898 - 899 - op_set_fg: { 900 - regs.fg = ip->operand; 901 - NEXT(); 902 - } 903 - 904 - op_set_bg: { 905 - regs.bg = ip->operand; 906 - NEXT(); 907 - } 908 - 909 - op_set_bold: { 910 - regs.bold = ip->operand; 911 - NEXT(); 912 - } 913 - 914 - op_set_dim: { 915 - regs.dim = ip->operand; 916 - NEXT(); 917 - } 918 - 919 - op_set_ul: { 920 - regs.ul = ip->operand; 921 - NEXT(); 922 - } 923 - 924 - op_set_fg_rgb: { 925 - regs.fg = COL_RGB; 926 - regs.fg_rgb = ip->operand; 927 - NEXT(); 928 - } 929 - 930 - op_set_bg_rgb: { 931 - regs.bg = COL_RGB; 932 - regs.bg_rgb = ip->operand; 933 - NEXT(); 934 - } 935 - 936 - op_style_push: { 937 - if (regs.style_depth < 8) regs.style_stack[regs.style_depth++] = (style_entry_t){ 938 - regs.fg, regs.bg, regs.fg_rgb, regs.bg_rgb, regs.bold, regs.dim, regs.ul, 939 - }; 940 - NEXT(); 941 - } 942 - 943 - op_pad_begin: { 944 - if (regs.pad_depth < 8) regs.pad_stack[regs.pad_depth++] 945 - = (pad_entry_t){ pos, (int)ip->operand, 0 }; 946 - NEXT(); 947 - } 948 - 949 - op_rpad_begin: { 950 - if (regs.pad_depth < 8) regs.pad_stack[regs.pad_depth++] 951 - = (pad_entry_t){ pos, (int)ip->operand, 1 }; 952 - NEXT(); 953 - } 954 - 955 - op_pad_end: { 956 - if (regs.pad_depth <= 0) NEXT(); 957 - regs.pad_depth--; 958 - pad_entry_t pe = regs.pad_stack[regs.pad_depth]; 959 - size_t vis = visible_len(out + pe.mark, pos - pe.mark); 960 - if ((size_t)pe.width <= vis) NEXT(); 961 - 962 - size_t pad_n = pe.width - vis; 963 - ENSURE(pad_n); 964 - if (pe.right_align) { 965 - memmove(out + pe.mark + pad_n, out + pe.mark, pos - pe.mark); 966 - memset(out + pe.mark, ' ', pad_n); 967 - } else memset(out + pos, ' ', pad_n); 968 - 969 - pos += pad_n; 970 - NEXT(); 971 - } 972 - 973 - op_emit_spaces: { 974 - size_t n = (size_t)ip->operand; 975 - ENSURE(n); 976 - memset(out + pos, ' ', n); 977 - pos += n; 978 - NEXT(); 979 - } 980 - 981 - op_emit_newlines: { 982 - size_t n = (size_t)ip->operand; 983 - ENSURE(n); 984 - memset(out + pos, '\n', n); 985 - pos += n; 986 - NEXT(); 987 - } 988 - 989 - op_style_reset: { 990 - if (regs.style_depth > 0) { 991 - style_entry_t se = regs.style_stack[--regs.style_depth]; 992 - regs.fg = se.fg; regs.bg = se.bg; 993 - regs.fg_rgb = se.fg_rgb; regs.bg_rgb = se.bg_rgb; 994 - regs.bold = se.bold; regs.dim = se.dim; regs.ul = se.ul; 995 - } else { 996 - regs.fg = COL_NONE; regs.bg = COL_NONE; 997 - regs.fg_rgb = 0; regs.bg_rgb = 0; 998 - regs.bold = 0; regs.dim = 0; regs.ul = 0; 999 - } 1000 - 1001 - if (!io_no_color) { 1002 - char esc[128]; 1003 - int n = snprintf(esc, sizeof(esc), "\x1b[0m"); 1004 - if (regs.bold) n += snprintf(esc+n, sizeof(esc)-n, "\x1b[1m"); 1005 - if (regs.dim) n += snprintf(esc+n, sizeof(esc)-n, "\x1b[2m"); 1006 - if (regs.ul) n += snprintf(esc+n, sizeof(esc)-n, "\x1b[4m"); 1007 - if (regs.fg == COL_RGB) 1008 - n += snprintf(esc+n, sizeof(esc)-n, "\x1b[38;2;%d;%d;%dm", 1009 - UNPACK_R(regs.fg_rgb), UNPACK_G(regs.fg_rgb), UNPACK_B(regs.fg_rgb)); 1010 - else if (regs.fg) 1011 - n += snprintf(esc+n, sizeof(esc)-n, "\x1b[%dm", regs.fg); 1012 - if (regs.bg == COL_RGB) 1013 - n += snprintf(esc+n, sizeof(esc)-n, "\x1b[48;2;%d;%d;%dm", 1014 - UNPACK_R(regs.bg_rgb), UNPACK_G(regs.bg_rgb), UNPACK_B(regs.bg_rgb)); 1015 - else if (regs.bg) 1016 - n += snprintf(esc+n, sizeof(esc)-n, "\x1b[%dm", regs.bg + 10); 1017 - OUT_STR(esc, (size_t)n); 1018 - } 1019 - 1020 - NEXT(); 1021 - } 1022 - 1023 - op_style_reset_all: { 1024 - regs.fg = COL_NONE; regs.bg = COL_NONE; 1025 - regs.fg_rgb = 0; regs.bg_rgb = 0; 1026 - regs.bold = 0; regs.dim = 0; regs.ul = 0; 1027 - regs.style_depth = 0; 1028 - if (!io_no_color) { OUT_CSTR("\x1b[0m"); } 1029 - NEXT(); 1030 - } 1031 - 1032 - op_style_flush: { 1033 - if (!io_no_color) { 1034 - char esc[128]; 1035 - int n = snprintf(esc, sizeof(esc), "\x1b[0m"); 1036 - if (regs.bold) n += snprintf(esc+n, sizeof(esc)-n, "\x1b[1m"); 1037 - if (regs.dim) n += snprintf(esc+n, sizeof(esc)-n, "\x1b[2m"); 1038 - if (regs.ul) n += snprintf(esc+n, sizeof(esc)-n, "\x1b[4m"); 1039 - if (regs.fg == COL_RGB) 1040 - n += snprintf(esc+n, sizeof(esc)-n, "\x1b[38;2;%d;%d;%dm", 1041 - UNPACK_R(regs.fg_rgb), UNPACK_G(regs.fg_rgb), UNPACK_B(regs.fg_rgb)); 1042 - else if (regs.fg) 1043 - n += snprintf(esc+n, sizeof(esc)-n, "\x1b[%dm", regs.fg); 1044 - if (regs.bg == COL_RGB) 1045 - n += snprintf(esc+n, sizeof(esc)-n, "\x1b[48;2;%d;%d;%dm", 1046 - UNPACK_R(regs.bg_rgb), UNPACK_G(regs.bg_rgb), UNPACK_B(regs.bg_rgb)); 1047 - else if (regs.bg) 1048 - n += snprintf(esc+n, sizeof(esc)-n, "\x1b[%dm", regs.bg + 10); 1049 - OUT_STR(esc, (size_t)n); 1050 - } 1051 - NEXT(); 1052 - } 1053 - 1054 - op_halt: { 1055 - out[pos] = '\0'; 1056 - return (vm_output_t){ out, pos }; 1057 - } 1058 - 1059 - #undef ENSURE 1060 - #undef OUT_STR 1061 - #undef OUT_CSTR 1062 - } 1063 - 1064 - int crprintf_exec(program_t *prog, FILE *stream, ...) { 1065 - va_list ap; va_start(ap, stream); 1066 - vm_output_t o = crprintf_vm_run(prog, ap); 1067 - va_end(ap); if (!o.data) return -1; 1068 - 1069 - int ret = (int)fwrite(o.data, 1, o.len, stream); 1070 - free(o.data); 1071 - 1072 - return ret; 1073 - } 1074 - 1075 - int crsprintf_inner(program_t *prog, char *buf, size_t size, ...) { 1076 - va_list ap; va_start(ap, size); 1077 - vm_output_t o = crprintf_vm_run(prog, ap); 1078 - va_end(ap); if (!o.data) return -1; 1079 - 1080 - size_t copy = (o.len < size) ? o.len : size - 1; 1081 - memcpy(buf, o.data, copy); 1082 - buf[copy] = '\0'; 1083 - free(o.data); 1084 - 1085 - return (int)o.len; 1086 - } 1087 - 1088 - static const char *op_names[OP_MAX] = { 1089 - [OP_NOP] = "NOP", 1090 - [OP_EMIT_LIT] = "EMIT_LIT", 1091 - [OP_EMIT_FMT] = "EMIT_FMT", 1092 - [OP_SET_FG] = "SET_FG", 1093 - [OP_SET_BG] = "SET_BG", 1094 - [OP_SET_FG_RGB] = "SET_FG_RGB", 1095 - [OP_SET_BG_RGB] = "SET_BG_RGB", 1096 - [OP_SET_BOLD] = "SET_BOLD", 1097 - [OP_SET_DIM] = "SET_DIM", 1098 - [OP_SET_UL] = "SET_UL", 1099 - [OP_STYLE_PUSH] = "STYLE_PUSH", 1100 - [OP_STYLE_FLUSH] = "STYLE_FLUSH", 1101 - [OP_STYLE_RESET] = "STYLE_RESET", 1102 - [OP_STYLE_RESET_ALL] = "STYLE_RESET_ALL", 1103 - [OP_PAD_BEGIN] = "PAD_BEGIN", 1104 - [OP_RPAD_BEGIN] = "RPAD_BEGIN", 1105 - [OP_PAD_END] = "PAD_END", 1106 - [OP_EMIT_SPACES] = "EMIT_SPACES", 1107 - [OP_EMIT_NEWLINES] = "EMIT_NEWLINES", 1108 - [OP_HALT] = "HALT", 1109 - }; 1110 - 1111 - static const char *color_name(uint32_t col) { 1112 - switch (col) { 1113 - case COL_NONE: return "none"; 1114 - case COL_BLACK: return "black"; 1115 - case COL_RED: return "red"; 1116 - case COL_GREEN: return "green"; 1117 - case COL_YELLOW: return "yellow"; 1118 - case COL_BLUE: return "blue"; 1119 - case COL_MAGENTA: return "magenta"; 1120 - case COL_CYAN: return "cyan"; 1121 - case COL_WHITE: return "white"; 1122 - case COL_GRAY: return "gray"; 1123 - case COL_BRIGHT_RED: return "bright_red"; 1124 - case COL_BRIGHT_GREEN: return "bright_green"; 1125 - case COL_BRIGHT_YELLOW: return "bright_yellow"; 1126 - case COL_BRIGHT_BLUE: return "bright_blue"; 1127 - case COL_BRIGHT_MAGENTA: return "bright_magenta"; 1128 - case COL_BRIGHT_CYAN: return "bright_cyan"; 1129 - case COL_BRIGHT_WHITE: return "bright_white"; 1130 - default: return "?"; 1131 - }} 1132 - 1133 - static const char *arg_class_name(arg_class_t cls) { 1134 - switch (cls) { 1135 - case ARG_NONE: return "none"; 1136 - case ARG_INT: return "int"; 1137 - case ARG_LONG: return "long"; 1138 - case ARG_LLONG: return "llong"; 1139 - case ARG_SIZE: return "size_t"; 1140 - case ARG_DOUBLE: return "double"; 1141 - case ARG_CSTR: return "char*"; 1142 - case ARG_PTR: return "void*"; 1143 - case ARG_WINT: return "wint_t"; 1144 - case ARG_WSTR: return "wchar_t*"; 1145 - default: return "?"; 1146 - }} 1147 - 1148 - static void fprint_escaped(FILE *out, const char *s, int max_chars) { 1149 - for (int c = 0; *s && (max_chars < 0 || c < max_chars); s++, c++) { 1150 - if (*s == '\n') fprintf(out, "\\n"); 1151 - else if (*s == '\t') fprintf(out, "\\t"); 1152 - else if (*s == '"') fprintf(out, "\\\""); 1153 - else if (*s < 0x20) fprintf(out, "\\x%02x", (unsigned char)*s); 1154 - else fputc(*s, out); 1155 - } 1156 - if (max_chars >= 0 && *s) fprintf(out, "..."); 1157 - } 1158 - 1159 - static void fprint_quoted(FILE *out, const char *s, int max_chars) { 1160 - fputc('"', out); 1161 - fprint_escaped(out, s, max_chars); 1162 - fputc('"', out); 1163 - } 1164 - 1165 - static void fprint_operand(FILE *out, program_t *prog, instruction_t *ins, bool compact) { 1166 - switch (ins->op) { 1167 - case OP_EMIT_LIT: { 1168 - const char *s = prog->literals + ins->operand; 1169 - fprint_quoted(out, s, compact ? 24 : -1); 1170 - break; 1171 - } 1172 - 1173 - case OP_EMIT_FMT: { 1174 - uint32_t lit_off = ins->operand & 0x0FFFFFFF; 1175 - arg_class_t cls = (arg_class_t)(ins->operand >> 28); 1176 - const char *s = prog->literals + lit_off; 1177 - fprint_quoted(out, s, compact ? 24 : -1); 1178 - fprintf(out, " (%s)", arg_class_name(cls)); 1179 - break; 1180 - } 1181 - 1182 - case OP_SET_FG: 1183 - case OP_SET_BG: 1184 - if (compact) fprintf(out, "%s", color_name(ins->operand)); 1185 - else fprintf(out, "%s (ANSI %u)", color_name(ins->operand), ins->operand); 1186 - break; 1187 - 1188 - case OP_SET_FG_RGB: 1189 - case OP_SET_BG_RGB: 1190 - fprintf(out, "#%02x%02x%02x", 1191 - UNPACK_R(ins->operand), UNPACK_G(ins->operand), UNPACK_B(ins->operand)); 1192 - break; 1193 - 1194 - case OP_SET_BOLD: 1195 - case OP_SET_DIM: 1196 - case OP_SET_UL: 1197 - fprintf(out, "%s", ins->operand ? "ON" : "OFF"); 1198 - break; 1199 - 1200 - case OP_PAD_BEGIN: 1201 - case OP_RPAD_BEGIN: 1202 - fprintf(out, "width=%u", ins->operand); 1203 - break; 1204 - 1205 - case OP_EMIT_SPACES: 1206 - fprintf(out, "%u", ins->operand); 1207 - break; 1208 - 1209 - case OP_EMIT_NEWLINES: 1210 - fprintf(out, "%u", ins->operand); 1211 - break; 1212 - 1213 - case OP_NOP: 1214 - case OP_STYLE_PUSH: 1215 - case OP_STYLE_FLUSH: 1216 - case OP_STYLE_RESET: 1217 - case OP_STYLE_RESET_ALL: 1218 - case OP_PAD_END: 1219 - case OP_HALT: break; 1220 - 1221 - default: 1222 - if (compact) { 1223 - if (ins->operand) fprintf(out, "0x%x", ins->operand); 1224 - } else fprintf(out, "0x%08x", ins->operand); 1225 - break; 1226 - } 1227 - } 1228 - 1229 - void crprintf_disasm(program_t *prog, FILE *out) { 1230 - fprintf(out, "; crprintf bytecode โ€” %zu instructions, %zu bytes literal pool\n", prog->code_len, prog->lit_len); 1231 - fprintf(out, "; %-4s %-16s %s\n", "addr", "opcode", "operand"); 1232 - fprintf(out, "; ---- ---------------- -------\n"); 1233 - 1234 - for (size_t i = 0; i < prog->code_len; i++) { 1235 - instruction_t *ins = &prog->code[i]; 1236 - const char *name = (ins->op < OP_MAX) ? op_names[ins->op] : "???"; 1237 - 1238 - fprintf(out, " %04zu %-16s ", i, name); 1239 - fprint_operand(out, prog, ins, false); 1240 - fputc('\n', out); 1241 - } 1242 - } 1243 - 1244 - void crprintf_hexdump(program_t *prog, FILE *out) { 1245 - fprintf(out, "; crprintf hex dump โ€” %zu instructions, %zu bytes literal pool\n", prog->code_len, prog->lit_len); 1246 - fprintf(out, "; %-4s %-26s %s\n", "addr", "bytes", "decoded"); 1247 - fprintf(out, "; ---- ------------------------- --------\n"); 1248 - 1249 - for (size_t i = 0; i < prog->code_len; i++) { 1250 - instruction_t *ins = &prog->code[i]; 1251 - const uint8_t *raw = (const uint8_t *)ins; 1252 - const char *name = (ins->op < OP_MAX) ? op_names[ins->op] : "???"; 1253 - 1254 - fprintf(out, " %04zu ", i); 1255 - for (size_t b = 0; b < sizeof(instruction_t); b++) fprintf(out, "%02x ", raw[b]); 1256 - 1257 - fprintf(out, " ; %s ", name); 1258 - fprint_operand(out, prog, ins, true); 1259 - fputc('\n', out); 1260 - } 1261 - 1262 - if (prog->lit_len > 0) { 1263 - fprintf(out, "\n; literal pool (%zu bytes):\n", prog->lit_len); 1264 - const uint8_t *lit = (const uint8_t *)prog->literals; 1265 - for (size_t off = 0; off < prog->lit_len; off += 16) { 1266 - fprintf(out, " %04zx ", off); 1267 - 1268 - size_t end = off + 16; 1269 - if (end > prog->lit_len) end = prog->lit_len; 1270 - for (size_t b = off; b < off + 16; b++) { 1271 - if (b < end) fprintf(out, "%02x ", lit[b]); 1272 - else fprintf(out, " "); 1273 - if (b == off + 7) fputc(' ', out); 1274 - } 1275 - 1276 - fprintf(out, " |"); 1277 - for (size_t b = off; b < end; b++) fputc((lit[b] >= 0x20 && lit[b] < 0x7f) ? lit[b] : '.', out); 1278 - fprintf(out, "|\n"); 1279 - } 1280 - } 1281 - }
+3 -3
src/cli/misc.c
··· 1 + #include "cli/misc.h" 2 + 1 3 #include <stdio.h> 2 4 #include <argtable3.h> 3 - 4 - #include "cli/misc.h" 5 - #include "cli/crprintf.h" 5 + #include <crprintf.h> 6 6 7 7 void print_flag(FILE *fp, flag_help_t f) { 8 8 const char *s = f.s, *l = f.l, *d = f.d, *g = f.g;
+4 -4
src/main.c
··· 8 8 #include <unistd.h> 9 9 #include <sys/stat.h> 10 10 #include <argtable3.h> 11 + #include <crprintf.h> 11 12 12 13 #include "ant.h" 13 14 #include "config.h" ··· 22 23 #include "cli/pkg.h" 23 24 #include "cli/misc.h" 24 25 #include "cli/version.h" 25 - #include "cli/crprintf.h" 26 26 27 27 #include "modules/builtin.h" 28 28 #include "modules/buffer.h" ··· 83 83 static void parse_ant_debug(const char *flag) { 84 84 if (strncmp(flag, "dump-crprintf=", 14) == 0) { 85 85 const char *mode = flag + 14; 86 - if (strcmp(mode, "bytecode") == 0 || strcmp(mode, "all") == 0) crprintf_debug = true; 87 - if (strcmp(mode, "hex") == 0 || strcmp(mode, "all") == 0) crprintf_debug_hex = true; 86 + if (strcmp(mode, "bytecode") == 0 || strcmp(mode, "all") == 0) crprintf_set_debug(true); 87 + if (strcmp(mode, "hex") == 0 || strcmp(mode, "all") == 0) crprintf_set_debug_hex(true); 88 88 } 89 89 90 90 else crfprintf(stderr, "{warn}: <bold>Unknown ANT_DEBUG flag: \"%s\"</>\n", flag); ··· 261 261 char **filtered_argv = try_oom(sizeof(char*) * argc); 262 262 for (int i = 0; i < argc; i++) { 263 263 if (strcmp(argv[i], "--verbose") == 0) pkg_verbose = true; 264 - else if (strcmp(argv[i], "--no-color") == 0) io_no_color = true; 264 + else if (strcmp(argv[i], "--no-color") == 0) { crprintf_set_color(false); io_no_color = true; } 265 265 else if (strncmp(argv[i], "--ANT_DEBUG:", 12) == 0) parse_ant_debug(argv[i] + 12); 266 266 else filtered_argv[filtered_argc++] = argv[i]; 267 267 }
+1 -1
src/utils.c
··· 1 1 #include "utils.h" 2 - #include "cli/crprintf.h" 3 2 4 3 #include <stdio.h> 5 4 #include <stdbool.h> 6 5 #include <sys/stat.h> 6 + #include <crprintf.h> 7 7 8 8 static const char *const js_extensions[] = { 9 9 ".js", ".ts",
+4
vendor/crprintf.wrap
··· 1 + [wrap-git] 2 + url = https://github.com/themackabu/crprintf.git 3 + revision = head 4 + depth = 1