/*
* crprintf - printf with inline color tags and variables, powered by a register-based VM
*
* Copyright (c) 2026 theMackabu (me@themackabu.dev)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* usage:
* crprintf("error: something went wrong\n");
* crprintf("info: hello %s\n", name);
* crprintf("<#ff8800>orange text#ff8800>\n");
* crprintf(" %s %s\n", cmd->name, cmd->desc);
*
* supported tags:
*
* ... etc
* ...
* (underline)
* etc - combine styles with underscores
* etc - combine styles with +
* <#RRGGBB> or <#RGB> for arbitrary 24-bit foreground colors
* ... - right-pad contents to N visible columns
*
- emit a newline,
- emit N newlines
* ... - left-pad (right-align) contents to N visible columns
* - emit N spaces
* - emit N spaces (alias for space)
* or - define a named style variable
* {let name=style1+style2+...} or {let name=style1, name2=style2...} - alternative syntax
* quoted values: {let label='hello'} or - quotes are stripped from value
* <$name> to apply a variable as a style, {name} to emit its value as literal text
* {~name} for lowercase, {^name} for uppercase
* {~'string'} for lowercase literal, {^'string'} for uppercase literal
* or > to reset (pops one level)
* to reset all styles (clears entire stack)
* << and >> to emit literal < and >
* %% to emit a literal %
*/
#ifndef CRPRINTF_H
#define CRPRINTF_H
#include
#include
#include
typedef struct crprintf_state crprintf_state;
typedef struct crprintf_compiled crprintf_compiled;
void crprintf_set_color(bool enable);
bool crprintf_get_color(void);
void crprintf_set_debug(bool enable);
bool crprintf_get_debug(void);
void crprintf_set_debug_hex(bool enable);
bool crprintf_get_debug_hex(void);
crprintf_compiled *crprintf_compile(const char *fmt);
int crprintf_exec(struct crprintf_compiled *prog, FILE *stream, ...);
int crsprintf_inner(struct crprintf_compiled *prog, char *buf, size_t size, ...);
void crprintf_var(const char *name, const char *value);
void crprintf_hexdump(struct crprintf_compiled *prog, FILE *out);
void crprintf_disasm(struct crprintf_compiled *prog, FILE *out);
crprintf_state *crprintf_state_new(void);
void crprintf_state_free(crprintf_state *state);
crprintf_state *crprintf_state_clone(const crprintf_state *state);
bool crprintf_state_eq(const crprintf_state *a, const crprintf_state *b);
int crsprintf_stateful(char *buf, size_t size, crprintf_state *state, const char *fmt, ...);
int crfprintf_stateful(FILE *stream, crprintf_state *state, const char *fmt, ...);
crprintf_compiled *crprintf_recompile(crprintf_compiled *prev, const char *fmt);
int crsprintf_compiled(char *buf, size_t size, crprintf_state *state, crprintf_compiled *prog, ...);
void crprintf_compiled_free(crprintf_compiled *prog);
#define _CRPRINTF_INIT(prog, fmt) \
if (!prog) { \
prog = crprintf_compile(fmt); \
if (crprintf_get_debug()) crprintf_disasm(prog, stderr); \
if (crprintf_get_debug_hex()) crprintf_hexdump(prog, stderr); \
}
#define crprintf(fmt, ...) ({ \
static crprintf_compiled *_cp_prog_ = NULL; \
_CRPRINTF_INIT(_cp_prog_, fmt); \
crprintf_exec(_cp_prog_, stdout, ##__VA_ARGS__); \
})
#define crfprintf(stream, fmt, ...) ({ \
static crprintf_compiled *_cp_prog_ = NULL; \
_CRPRINTF_INIT(_cp_prog_, fmt); \
crprintf_exec(_cp_prog_, stream, ##__VA_ARGS__); \
})
#define crsprintf(buf, size, fmt, ...) ({ \
static crprintf_compiled *_cp_prog_ = NULL; \
_CRPRINTF_INIT(_cp_prog_, fmt); \
crsprintf_inner(_cp_prog_, buf, size, ##__VA_ARGS__); \
})
#endif