10ef50b4eSJason Evans #ifndef JEMALLOC_INTERNAL_EMITTER_H
20ef50b4eSJason Evans #define JEMALLOC_INTERNAL_EMITTER_H
30ef50b4eSJason Evans
40ef50b4eSJason Evans #include "jemalloc/internal/ql.h"
50ef50b4eSJason Evans
60ef50b4eSJason Evans typedef enum emitter_output_e emitter_output_t;
70ef50b4eSJason Evans enum emitter_output_e {
80ef50b4eSJason Evans emitter_output_json,
90ef50b4eSJason Evans emitter_output_table
100ef50b4eSJason Evans };
110ef50b4eSJason Evans
120ef50b4eSJason Evans typedef enum emitter_justify_e emitter_justify_t;
130ef50b4eSJason Evans enum emitter_justify_e {
140ef50b4eSJason Evans emitter_justify_left,
150ef50b4eSJason Evans emitter_justify_right,
160ef50b4eSJason Evans /* Not for users; just to pass to internal functions. */
170ef50b4eSJason Evans emitter_justify_none
180ef50b4eSJason Evans };
190ef50b4eSJason Evans
200ef50b4eSJason Evans typedef enum emitter_type_e emitter_type_t;
210ef50b4eSJason Evans enum emitter_type_e {
220ef50b4eSJason Evans emitter_type_bool,
230ef50b4eSJason Evans emitter_type_int,
240ef50b4eSJason Evans emitter_type_unsigned,
250ef50b4eSJason Evans emitter_type_uint32,
260ef50b4eSJason Evans emitter_type_uint64,
270ef50b4eSJason Evans emitter_type_size,
280ef50b4eSJason Evans emitter_type_ssize,
290ef50b4eSJason Evans emitter_type_string,
300ef50b4eSJason Evans /*
310ef50b4eSJason Evans * A title is a column title in a table; it's just a string, but it's
320ef50b4eSJason Evans * not quoted.
330ef50b4eSJason Evans */
340ef50b4eSJason Evans emitter_type_title,
350ef50b4eSJason Evans };
360ef50b4eSJason Evans
370ef50b4eSJason Evans typedef struct emitter_col_s emitter_col_t;
380ef50b4eSJason Evans struct emitter_col_s {
390ef50b4eSJason Evans /* Filled in by the user. */
400ef50b4eSJason Evans emitter_justify_t justify;
410ef50b4eSJason Evans int width;
420ef50b4eSJason Evans emitter_type_t type;
430ef50b4eSJason Evans union {
440ef50b4eSJason Evans bool bool_val;
450ef50b4eSJason Evans int int_val;
460ef50b4eSJason Evans unsigned unsigned_val;
470ef50b4eSJason Evans uint32_t uint32_val;
48*c5ad8142SEric van Gyzen uint32_t uint32_t_val;
490ef50b4eSJason Evans uint64_t uint64_val;
50*c5ad8142SEric van Gyzen uint64_t uint64_t_val;
510ef50b4eSJason Evans size_t size_val;
520ef50b4eSJason Evans ssize_t ssize_val;
530ef50b4eSJason Evans const char *str_val;
540ef50b4eSJason Evans };
550ef50b4eSJason Evans
560ef50b4eSJason Evans /* Filled in by initialization. */
570ef50b4eSJason Evans ql_elm(emitter_col_t) link;
580ef50b4eSJason Evans };
590ef50b4eSJason Evans
600ef50b4eSJason Evans typedef struct emitter_row_s emitter_row_t;
610ef50b4eSJason Evans struct emitter_row_s {
620ef50b4eSJason Evans ql_head(emitter_col_t) cols;
630ef50b4eSJason Evans };
640ef50b4eSJason Evans
650ef50b4eSJason Evans typedef struct emitter_s emitter_t;
660ef50b4eSJason Evans struct emitter_s {
670ef50b4eSJason Evans emitter_output_t output;
680ef50b4eSJason Evans /* The output information. */
690ef50b4eSJason Evans void (*write_cb)(void *, const char *);
700ef50b4eSJason Evans void *cbopaque;
710ef50b4eSJason Evans int nesting_depth;
720ef50b4eSJason Evans /* True if we've already emitted a value at the given depth. */
730ef50b4eSJason Evans bool item_at_depth;
74*c5ad8142SEric van Gyzen /* True if we emitted a key and will emit corresponding value next. */
75*c5ad8142SEric van Gyzen bool emitted_key;
760ef50b4eSJason Evans };
770ef50b4eSJason Evans
780ef50b4eSJason Evans /* Internal convenience function. Write to the emitter the given string. */
790ef50b4eSJason Evans JEMALLOC_FORMAT_PRINTF(2, 3)
800ef50b4eSJason Evans static inline void
emitter_printf(emitter_t * emitter,const char * format,...)810ef50b4eSJason Evans emitter_printf(emitter_t *emitter, const char *format, ...) {
820ef50b4eSJason Evans va_list ap;
830ef50b4eSJason Evans
840ef50b4eSJason Evans va_start(ap, format);
850ef50b4eSJason Evans malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
860ef50b4eSJason Evans va_end(ap);
870ef50b4eSJason Evans }
880ef50b4eSJason Evans
89*c5ad8142SEric van Gyzen static inline const char * JEMALLOC_FORMAT_ARG(3)
emitter_gen_fmt(char * out_fmt,size_t out_size,const char * fmt_specifier,emitter_justify_t justify,int width)900ef50b4eSJason Evans emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
910ef50b4eSJason Evans emitter_justify_t justify, int width) {
920ef50b4eSJason Evans size_t written;
93*c5ad8142SEric van Gyzen fmt_specifier++;
940ef50b4eSJason Evans if (justify == emitter_justify_none) {
950ef50b4eSJason Evans written = malloc_snprintf(out_fmt, out_size,
960ef50b4eSJason Evans "%%%s", fmt_specifier);
970ef50b4eSJason Evans } else if (justify == emitter_justify_left) {
980ef50b4eSJason Evans written = malloc_snprintf(out_fmt, out_size,
990ef50b4eSJason Evans "%%-%d%s", width, fmt_specifier);
1000ef50b4eSJason Evans } else {
1010ef50b4eSJason Evans written = malloc_snprintf(out_fmt, out_size,
1020ef50b4eSJason Evans "%%%d%s", width, fmt_specifier);
1030ef50b4eSJason Evans }
1040ef50b4eSJason Evans /* Only happens in case of bad format string, which *we* choose. */
1050ef50b4eSJason Evans assert(written < out_size);
106*c5ad8142SEric van Gyzen return out_fmt;
1070ef50b4eSJason Evans }
1080ef50b4eSJason Evans
1090ef50b4eSJason Evans /*
1100ef50b4eSJason Evans * Internal. Emit the given value type in the relevant encoding (so that the
1110ef50b4eSJason Evans * bool true gets mapped to json "true", but the string "true" gets mapped to
1120ef50b4eSJason Evans * json "\"true\"", for instance.
1130ef50b4eSJason Evans *
1140ef50b4eSJason Evans * Width is ignored if justify is emitter_justify_none.
1150ef50b4eSJason Evans */
1160ef50b4eSJason Evans static inline void
emitter_print_value(emitter_t * emitter,emitter_justify_t justify,int width,emitter_type_t value_type,const void * value)1170ef50b4eSJason Evans emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
1180ef50b4eSJason Evans emitter_type_t value_type, const void *value) {
1190ef50b4eSJason Evans size_t str_written;
1200ef50b4eSJason Evans #define BUF_SIZE 256
1210ef50b4eSJason Evans #define FMT_SIZE 10
1220ef50b4eSJason Evans /*
1230ef50b4eSJason Evans * We dynamically generate a format string to emit, to let us use the
1240ef50b4eSJason Evans * snprintf machinery. This is kinda hacky, but gets the job done
1250ef50b4eSJason Evans * quickly without having to think about the various snprintf edge
1260ef50b4eSJason Evans * cases.
1270ef50b4eSJason Evans */
1280ef50b4eSJason Evans char fmt[FMT_SIZE];
1290ef50b4eSJason Evans char buf[BUF_SIZE];
1300ef50b4eSJason Evans
1310ef50b4eSJason Evans #define EMIT_SIMPLE(type, format) \
132*c5ad8142SEric van Gyzen emitter_printf(emitter, \
133*c5ad8142SEric van Gyzen emitter_gen_fmt(fmt, FMT_SIZE, format, justify, width), \
134*c5ad8142SEric van Gyzen *(const type *)value);
1350ef50b4eSJason Evans
1360ef50b4eSJason Evans switch (value_type) {
1370ef50b4eSJason Evans case emitter_type_bool:
138*c5ad8142SEric van Gyzen emitter_printf(emitter,
139*c5ad8142SEric van Gyzen emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width),
140*c5ad8142SEric van Gyzen *(const bool *)value ? "true" : "false");
1410ef50b4eSJason Evans break;
1420ef50b4eSJason Evans case emitter_type_int:
143*c5ad8142SEric van Gyzen EMIT_SIMPLE(int, "%d")
1440ef50b4eSJason Evans break;
1450ef50b4eSJason Evans case emitter_type_unsigned:
146*c5ad8142SEric van Gyzen EMIT_SIMPLE(unsigned, "%u")
1470ef50b4eSJason Evans break;
1480ef50b4eSJason Evans case emitter_type_ssize:
149*c5ad8142SEric van Gyzen EMIT_SIMPLE(ssize_t, "%zd")
1500ef50b4eSJason Evans break;
1510ef50b4eSJason Evans case emitter_type_size:
152*c5ad8142SEric van Gyzen EMIT_SIMPLE(size_t, "%zu")
1530ef50b4eSJason Evans break;
1540ef50b4eSJason Evans case emitter_type_string:
1550ef50b4eSJason Evans str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"",
1560ef50b4eSJason Evans *(const char *const *)value);
1570ef50b4eSJason Evans /*
1580ef50b4eSJason Evans * We control the strings we output; we shouldn't get anything
1590ef50b4eSJason Evans * anywhere near the fmt size.
1600ef50b4eSJason Evans */
1610ef50b4eSJason Evans assert(str_written < BUF_SIZE);
162*c5ad8142SEric van Gyzen emitter_printf(emitter,
163*c5ad8142SEric van Gyzen emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width), buf);
1640ef50b4eSJason Evans break;
1650ef50b4eSJason Evans case emitter_type_uint32:
166*c5ad8142SEric van Gyzen EMIT_SIMPLE(uint32_t, "%" FMTu32)
1670ef50b4eSJason Evans break;
1680ef50b4eSJason Evans case emitter_type_uint64:
169*c5ad8142SEric van Gyzen EMIT_SIMPLE(uint64_t, "%" FMTu64)
1700ef50b4eSJason Evans break;
1710ef50b4eSJason Evans case emitter_type_title:
172*c5ad8142SEric van Gyzen EMIT_SIMPLE(char *const, "%s");
1730ef50b4eSJason Evans break;
1740ef50b4eSJason Evans default:
1750ef50b4eSJason Evans unreachable();
1760ef50b4eSJason Evans }
1770ef50b4eSJason Evans #undef BUF_SIZE
1780ef50b4eSJason Evans #undef FMT_SIZE
1790ef50b4eSJason Evans }
1800ef50b4eSJason Evans
1810ef50b4eSJason Evans
1820ef50b4eSJason Evans /* Internal functions. In json mode, tracks nesting state. */
1830ef50b4eSJason Evans static inline void
emitter_nest_inc(emitter_t * emitter)1840ef50b4eSJason Evans emitter_nest_inc(emitter_t *emitter) {
1850ef50b4eSJason Evans emitter->nesting_depth++;
1860ef50b4eSJason Evans emitter->item_at_depth = false;
1870ef50b4eSJason Evans }
1880ef50b4eSJason Evans
1890ef50b4eSJason Evans static inline void
emitter_nest_dec(emitter_t * emitter)1900ef50b4eSJason Evans emitter_nest_dec(emitter_t *emitter) {
1910ef50b4eSJason Evans emitter->nesting_depth--;
1920ef50b4eSJason Evans emitter->item_at_depth = true;
1930ef50b4eSJason Evans }
1940ef50b4eSJason Evans
1950ef50b4eSJason Evans static inline void
emitter_indent(emitter_t * emitter)1960ef50b4eSJason Evans emitter_indent(emitter_t *emitter) {
1970ef50b4eSJason Evans int amount = emitter->nesting_depth;
1980ef50b4eSJason Evans const char *indent_str;
1990ef50b4eSJason Evans if (emitter->output == emitter_output_json) {
2000ef50b4eSJason Evans indent_str = "\t";
2010ef50b4eSJason Evans } else {
2020ef50b4eSJason Evans amount *= 2;
2030ef50b4eSJason Evans indent_str = " ";
2040ef50b4eSJason Evans }
2050ef50b4eSJason Evans for (int i = 0; i < amount; i++) {
2060ef50b4eSJason Evans emitter_printf(emitter, "%s", indent_str);
2070ef50b4eSJason Evans }
2080ef50b4eSJason Evans }
2090ef50b4eSJason Evans
2100ef50b4eSJason Evans static inline void
emitter_json_key_prefix(emitter_t * emitter)2110ef50b4eSJason Evans emitter_json_key_prefix(emitter_t *emitter) {
212*c5ad8142SEric van Gyzen if (emitter->emitted_key) {
213*c5ad8142SEric van Gyzen emitter->emitted_key = false;
214*c5ad8142SEric van Gyzen return;
215*c5ad8142SEric van Gyzen }
2160ef50b4eSJason Evans emitter_printf(emitter, "%s\n", emitter->item_at_depth ? "," : "");
2170ef50b4eSJason Evans emitter_indent(emitter);
2180ef50b4eSJason Evans }
2190ef50b4eSJason Evans
220*c5ad8142SEric van Gyzen /******************************************************************************/
221*c5ad8142SEric van Gyzen /* Public functions for emitter_t. */
222e1c167d0SJason Evans
223e1c167d0SJason Evans static inline void
emitter_init(emitter_t * emitter,emitter_output_t emitter_output,void (* write_cb)(void *,const char *),void * cbopaque)224*c5ad8142SEric van Gyzen emitter_init(emitter_t *emitter, emitter_output_t emitter_output,
225*c5ad8142SEric van Gyzen void (*write_cb)(void *, const char *), void *cbopaque) {
226*c5ad8142SEric van Gyzen emitter->output = emitter_output;
227*c5ad8142SEric van Gyzen emitter->write_cb = write_cb;
228*c5ad8142SEric van Gyzen emitter->cbopaque = cbopaque;
229*c5ad8142SEric van Gyzen emitter->item_at_depth = false;
230*c5ad8142SEric van Gyzen emitter->emitted_key = false;
231*c5ad8142SEric van Gyzen emitter->nesting_depth = 0;
232e1c167d0SJason Evans }
233*c5ad8142SEric van Gyzen
234*c5ad8142SEric van Gyzen /******************************************************************************/
235*c5ad8142SEric van Gyzen /* JSON public API. */
236e1c167d0SJason Evans
237f2cb2907SJason Evans /*
238*c5ad8142SEric van Gyzen * Emits a key (e.g. as appears in an object). The next json entity emitted will
239*c5ad8142SEric van Gyzen * be the corresponding value.
240f2cb2907SJason Evans */
241e1c167d0SJason Evans static inline void
emitter_json_key(emitter_t * emitter,const char * json_key)242*c5ad8142SEric van Gyzen emitter_json_key(emitter_t *emitter, const char *json_key) {
243*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
244*c5ad8142SEric van Gyzen emitter_json_key_prefix(emitter);
245*c5ad8142SEric van Gyzen emitter_printf(emitter, "\"%s\": ", json_key);
246*c5ad8142SEric van Gyzen emitter->emitted_key = true;
247*c5ad8142SEric van Gyzen }
248*c5ad8142SEric van Gyzen }
249*c5ad8142SEric van Gyzen
250*c5ad8142SEric van Gyzen static inline void
emitter_json_value(emitter_t * emitter,emitter_type_t value_type,const void * value)251*c5ad8142SEric van Gyzen emitter_json_value(emitter_t *emitter, emitter_type_t value_type,
252*c5ad8142SEric van Gyzen const void *value) {
253*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
254*c5ad8142SEric van Gyzen emitter_json_key_prefix(emitter);
255*c5ad8142SEric van Gyzen emitter_print_value(emitter, emitter_justify_none, -1,
256*c5ad8142SEric van Gyzen value_type, value);
257*c5ad8142SEric van Gyzen emitter->item_at_depth = true;
258*c5ad8142SEric van Gyzen }
259*c5ad8142SEric van Gyzen }
260*c5ad8142SEric van Gyzen
261*c5ad8142SEric van Gyzen /* Shorthand for calling emitter_json_key and then emitter_json_value. */
262*c5ad8142SEric van Gyzen static inline void
emitter_json_kv(emitter_t * emitter,const char * json_key,emitter_type_t value_type,const void * value)263*c5ad8142SEric van Gyzen emitter_json_kv(emitter_t *emitter, const char *json_key,
264*c5ad8142SEric van Gyzen emitter_type_t value_type, const void *value) {
265*c5ad8142SEric van Gyzen emitter_json_key(emitter, json_key);
266*c5ad8142SEric van Gyzen emitter_json_value(emitter, value_type, value);
267*c5ad8142SEric van Gyzen }
268*c5ad8142SEric van Gyzen
269*c5ad8142SEric van Gyzen static inline void
emitter_json_array_begin(emitter_t * emitter)270*c5ad8142SEric van Gyzen emitter_json_array_begin(emitter_t *emitter) {
271*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
272*c5ad8142SEric van Gyzen emitter_json_key_prefix(emitter);
273*c5ad8142SEric van Gyzen emitter_printf(emitter, "[");
274*c5ad8142SEric van Gyzen emitter_nest_inc(emitter);
275*c5ad8142SEric van Gyzen }
276*c5ad8142SEric van Gyzen }
277*c5ad8142SEric van Gyzen
278*c5ad8142SEric van Gyzen /* Shorthand for calling emitter_json_key and then emitter_json_array_begin. */
279*c5ad8142SEric van Gyzen static inline void
emitter_json_array_kv_begin(emitter_t * emitter,const char * json_key)280*c5ad8142SEric van Gyzen emitter_json_array_kv_begin(emitter_t *emitter, const char *json_key) {
281*c5ad8142SEric van Gyzen emitter_json_key(emitter, json_key);
282*c5ad8142SEric van Gyzen emitter_json_array_begin(emitter);
283*c5ad8142SEric van Gyzen }
284*c5ad8142SEric van Gyzen
285*c5ad8142SEric van Gyzen static inline void
emitter_json_array_end(emitter_t * emitter)286*c5ad8142SEric van Gyzen emitter_json_array_end(emitter_t *emitter) {
287*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
288*c5ad8142SEric van Gyzen assert(emitter->nesting_depth > 0);
289*c5ad8142SEric van Gyzen emitter_nest_dec(emitter);
290*c5ad8142SEric van Gyzen emitter_printf(emitter, "\n");
291*c5ad8142SEric van Gyzen emitter_indent(emitter);
292*c5ad8142SEric van Gyzen emitter_printf(emitter, "]");
293*c5ad8142SEric van Gyzen }
294*c5ad8142SEric van Gyzen }
295*c5ad8142SEric van Gyzen
296*c5ad8142SEric van Gyzen static inline void
emitter_json_object_begin(emitter_t * emitter)297*c5ad8142SEric van Gyzen emitter_json_object_begin(emitter_t *emitter) {
298*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
299*c5ad8142SEric van Gyzen emitter_json_key_prefix(emitter);
300*c5ad8142SEric van Gyzen emitter_printf(emitter, "{");
301*c5ad8142SEric van Gyzen emitter_nest_inc(emitter);
302*c5ad8142SEric van Gyzen }
303*c5ad8142SEric van Gyzen }
304*c5ad8142SEric van Gyzen
305*c5ad8142SEric van Gyzen /* Shorthand for calling emitter_json_key and then emitter_json_object_begin. */
306*c5ad8142SEric van Gyzen static inline void
emitter_json_object_kv_begin(emitter_t * emitter,const char * json_key)307*c5ad8142SEric van Gyzen emitter_json_object_kv_begin(emitter_t *emitter, const char *json_key) {
308*c5ad8142SEric van Gyzen emitter_json_key(emitter, json_key);
309*c5ad8142SEric van Gyzen emitter_json_object_begin(emitter);
310*c5ad8142SEric van Gyzen }
311*c5ad8142SEric van Gyzen
312*c5ad8142SEric van Gyzen static inline void
emitter_json_object_end(emitter_t * emitter)313*c5ad8142SEric van Gyzen emitter_json_object_end(emitter_t *emitter) {
314*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
315*c5ad8142SEric van Gyzen assert(emitter->nesting_depth > 0);
316*c5ad8142SEric van Gyzen emitter_nest_dec(emitter);
317*c5ad8142SEric van Gyzen emitter_printf(emitter, "\n");
318*c5ad8142SEric van Gyzen emitter_indent(emitter);
319*c5ad8142SEric van Gyzen emitter_printf(emitter, "}");
320*c5ad8142SEric van Gyzen }
321*c5ad8142SEric van Gyzen }
322*c5ad8142SEric van Gyzen
323*c5ad8142SEric van Gyzen
324*c5ad8142SEric van Gyzen /******************************************************************************/
325*c5ad8142SEric van Gyzen /* Table public API. */
326*c5ad8142SEric van Gyzen
327*c5ad8142SEric van Gyzen static inline void
emitter_table_dict_begin(emitter_t * emitter,const char * table_key)328*c5ad8142SEric van Gyzen emitter_table_dict_begin(emitter_t *emitter, const char *table_key) {
329*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_table) {
330*c5ad8142SEric van Gyzen emitter_indent(emitter);
331*c5ad8142SEric van Gyzen emitter_printf(emitter, "%s\n", table_key);
332*c5ad8142SEric van Gyzen emitter_nest_inc(emitter);
333*c5ad8142SEric van Gyzen }
334*c5ad8142SEric van Gyzen }
335*c5ad8142SEric van Gyzen
336*c5ad8142SEric van Gyzen static inline void
emitter_table_dict_end(emitter_t * emitter)337*c5ad8142SEric van Gyzen emitter_table_dict_end(emitter_t *emitter) {
338*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_table) {
339*c5ad8142SEric van Gyzen emitter_nest_dec(emitter);
340*c5ad8142SEric van Gyzen }
341*c5ad8142SEric van Gyzen }
342*c5ad8142SEric van Gyzen
343*c5ad8142SEric van Gyzen static inline void
emitter_table_kv_note(emitter_t * emitter,const char * table_key,emitter_type_t value_type,const void * value,const char * table_note_key,emitter_type_t table_note_value_type,const void * table_note_value)344*c5ad8142SEric van Gyzen emitter_table_kv_note(emitter_t *emitter, const char *table_key,
3450ef50b4eSJason Evans emitter_type_t value_type, const void *value,
3460ef50b4eSJason Evans const char *table_note_key, emitter_type_t table_note_value_type,
3470ef50b4eSJason Evans const void *table_note_value) {
348*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_table) {
3490ef50b4eSJason Evans emitter_indent(emitter);
3500ef50b4eSJason Evans emitter_printf(emitter, "%s: ", table_key);
3510ef50b4eSJason Evans emitter_print_value(emitter, emitter_justify_none, -1,
3520ef50b4eSJason Evans value_type, value);
3530ef50b4eSJason Evans if (table_note_key != NULL) {
3540ef50b4eSJason Evans emitter_printf(emitter, " (%s: ", table_note_key);
3550ef50b4eSJason Evans emitter_print_value(emitter, emitter_justify_none, -1,
3560ef50b4eSJason Evans table_note_value_type, table_note_value);
3570ef50b4eSJason Evans emitter_printf(emitter, ")");
3580ef50b4eSJason Evans }
3590ef50b4eSJason Evans emitter_printf(emitter, "\n");
3600ef50b4eSJason Evans }
3610ef50b4eSJason Evans emitter->item_at_depth = true;
3620ef50b4eSJason Evans }
3630ef50b4eSJason Evans
3640ef50b4eSJason Evans static inline void
emitter_table_kv(emitter_t * emitter,const char * table_key,emitter_type_t value_type,const void * value)365*c5ad8142SEric van Gyzen emitter_table_kv(emitter_t *emitter, const char *table_key,
3660ef50b4eSJason Evans emitter_type_t value_type, const void *value) {
367*c5ad8142SEric van Gyzen emitter_table_kv_note(emitter, table_key, value_type, value, NULL,
3680ef50b4eSJason Evans emitter_type_bool, NULL);
3690ef50b4eSJason Evans }
3700ef50b4eSJason Evans
371f2cb2907SJason Evans
372*c5ad8142SEric van Gyzen /* Write to the emitter the given string, but only in table mode. */
373*c5ad8142SEric van Gyzen JEMALLOC_FORMAT_PRINTF(2, 3)
374f2cb2907SJason Evans static inline void
emitter_table_printf(emitter_t * emitter,const char * format,...)375*c5ad8142SEric van Gyzen emitter_table_printf(emitter_t *emitter, const char *format, ...) {
3760ef50b4eSJason Evans if (emitter->output == emitter_output_table) {
377*c5ad8142SEric van Gyzen va_list ap;
378*c5ad8142SEric van Gyzen va_start(ap, format);
379*c5ad8142SEric van Gyzen malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
380*c5ad8142SEric van Gyzen va_end(ap);
3810ef50b4eSJason Evans }
3820ef50b4eSJason Evans }
3830ef50b4eSJason Evans
3840ef50b4eSJason Evans static inline void
emitter_table_row(emitter_t * emitter,emitter_row_t * row)3850ef50b4eSJason Evans emitter_table_row(emitter_t *emitter, emitter_row_t *row) {
3860ef50b4eSJason Evans if (emitter->output != emitter_output_table) {
3870ef50b4eSJason Evans return;
3880ef50b4eSJason Evans }
3890ef50b4eSJason Evans emitter_col_t *col;
3900ef50b4eSJason Evans ql_foreach(col, &row->cols, link) {
3910ef50b4eSJason Evans emitter_print_value(emitter, col->justify, col->width,
3920ef50b4eSJason Evans col->type, (const void *)&col->bool_val);
3930ef50b4eSJason Evans }
3940ef50b4eSJason Evans emitter_table_printf(emitter, "\n");
3950ef50b4eSJason Evans }
3960ef50b4eSJason Evans
397*c5ad8142SEric van Gyzen static inline void
emitter_row_init(emitter_row_t * row)398*c5ad8142SEric van Gyzen emitter_row_init(emitter_row_t *row) {
399*c5ad8142SEric van Gyzen ql_new(&row->cols);
400*c5ad8142SEric van Gyzen }
401*c5ad8142SEric van Gyzen
402*c5ad8142SEric van Gyzen static inline void
emitter_col_init(emitter_col_t * col,emitter_row_t * row)403*c5ad8142SEric van Gyzen emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
404*c5ad8142SEric van Gyzen ql_elm_new(col, link);
405*c5ad8142SEric van Gyzen ql_tail_insert(&row->cols, col, link);
406*c5ad8142SEric van Gyzen }
407*c5ad8142SEric van Gyzen
408*c5ad8142SEric van Gyzen
409*c5ad8142SEric van Gyzen /******************************************************************************/
410*c5ad8142SEric van Gyzen /*
411*c5ad8142SEric van Gyzen * Generalized public API. Emits using either JSON or table, according to
412*c5ad8142SEric van Gyzen * settings in the emitter_t. */
413*c5ad8142SEric van Gyzen
414*c5ad8142SEric van Gyzen /*
415*c5ad8142SEric van Gyzen * Note emits a different kv pair as well, but only in table mode. Omits the
416*c5ad8142SEric van Gyzen * note if table_note_key is NULL.
417*c5ad8142SEric van Gyzen */
418*c5ad8142SEric van Gyzen static inline void
emitter_kv_note(emitter_t * emitter,const char * json_key,const char * table_key,emitter_type_t value_type,const void * value,const char * table_note_key,emitter_type_t table_note_value_type,const void * table_note_value)419*c5ad8142SEric van Gyzen emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
420*c5ad8142SEric van Gyzen emitter_type_t value_type, const void *value,
421*c5ad8142SEric van Gyzen const char *table_note_key, emitter_type_t table_note_value_type,
422*c5ad8142SEric van Gyzen const void *table_note_value) {
423*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
424*c5ad8142SEric van Gyzen emitter_json_key(emitter, json_key);
425*c5ad8142SEric van Gyzen emitter_json_value(emitter, value_type, value);
426*c5ad8142SEric van Gyzen } else {
427*c5ad8142SEric van Gyzen emitter_table_kv_note(emitter, table_key, value_type, value,
428*c5ad8142SEric van Gyzen table_note_key, table_note_value_type, table_note_value);
429*c5ad8142SEric van Gyzen }
430*c5ad8142SEric van Gyzen emitter->item_at_depth = true;
431*c5ad8142SEric van Gyzen }
432*c5ad8142SEric van Gyzen
433*c5ad8142SEric van Gyzen static inline void
emitter_kv(emitter_t * emitter,const char * json_key,const char * table_key,emitter_type_t value_type,const void * value)434*c5ad8142SEric van Gyzen emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key,
435*c5ad8142SEric van Gyzen emitter_type_t value_type, const void *value) {
436*c5ad8142SEric van Gyzen emitter_kv_note(emitter, json_key, table_key, value_type, value, NULL,
437*c5ad8142SEric van Gyzen emitter_type_bool, NULL);
438*c5ad8142SEric van Gyzen }
439*c5ad8142SEric van Gyzen
440*c5ad8142SEric van Gyzen static inline void
emitter_dict_begin(emitter_t * emitter,const char * json_key,const char * table_header)441*c5ad8142SEric van Gyzen emitter_dict_begin(emitter_t *emitter, const char *json_key,
442*c5ad8142SEric van Gyzen const char *table_header) {
443*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
444*c5ad8142SEric van Gyzen emitter_json_key(emitter, json_key);
445*c5ad8142SEric van Gyzen emitter_json_object_begin(emitter);
446*c5ad8142SEric van Gyzen } else {
447*c5ad8142SEric van Gyzen emitter_table_dict_begin(emitter, table_header);
448*c5ad8142SEric van Gyzen }
449*c5ad8142SEric van Gyzen }
450*c5ad8142SEric van Gyzen
451*c5ad8142SEric van Gyzen static inline void
emitter_dict_end(emitter_t * emitter)452*c5ad8142SEric van Gyzen emitter_dict_end(emitter_t *emitter) {
453*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
454*c5ad8142SEric van Gyzen emitter_json_object_end(emitter);
455*c5ad8142SEric van Gyzen } else {
456*c5ad8142SEric van Gyzen emitter_table_dict_end(emitter);
457*c5ad8142SEric van Gyzen }
458*c5ad8142SEric van Gyzen }
459*c5ad8142SEric van Gyzen
460*c5ad8142SEric van Gyzen static inline void
emitter_begin(emitter_t * emitter)461*c5ad8142SEric van Gyzen emitter_begin(emitter_t *emitter) {
462*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
463*c5ad8142SEric van Gyzen assert(emitter->nesting_depth == 0);
464*c5ad8142SEric van Gyzen emitter_printf(emitter, "{");
465*c5ad8142SEric van Gyzen emitter_nest_inc(emitter);
466*c5ad8142SEric van Gyzen } else {
467*c5ad8142SEric van Gyzen /*
468*c5ad8142SEric van Gyzen * This guarantees that we always call write_cb at least once.
469*c5ad8142SEric van Gyzen * This is useful if some invariant is established by each call
470*c5ad8142SEric van Gyzen * to write_cb, but doesn't hold initially: e.g., some buffer
471*c5ad8142SEric van Gyzen * holds a null-terminated string.
472*c5ad8142SEric van Gyzen */
473*c5ad8142SEric van Gyzen emitter_printf(emitter, "%s", "");
474*c5ad8142SEric van Gyzen }
475*c5ad8142SEric van Gyzen }
476*c5ad8142SEric van Gyzen
477*c5ad8142SEric van Gyzen static inline void
emitter_end(emitter_t * emitter)478*c5ad8142SEric van Gyzen emitter_end(emitter_t *emitter) {
479*c5ad8142SEric van Gyzen if (emitter->output == emitter_output_json) {
480*c5ad8142SEric van Gyzen assert(emitter->nesting_depth == 1);
481*c5ad8142SEric van Gyzen emitter_nest_dec(emitter);
482*c5ad8142SEric van Gyzen emitter_printf(emitter, "\n}\n");
483*c5ad8142SEric van Gyzen }
484*c5ad8142SEric van Gyzen }
485*c5ad8142SEric van Gyzen
4860ef50b4eSJason Evans #endif /* JEMALLOC_INTERNAL_EMITTER_H */
487