1*8e33eff8Schristos #ifndef JEMALLOC_INTERNAL_EMITTER_H 2*8e33eff8Schristos #define JEMALLOC_INTERNAL_EMITTER_H 3*8e33eff8Schristos 4*8e33eff8Schristos #include "jemalloc/internal/ql.h" 5*8e33eff8Schristos 6*8e33eff8Schristos typedef enum emitter_output_e emitter_output_t; 7*8e33eff8Schristos enum emitter_output_e { 8*8e33eff8Schristos emitter_output_json, 9*8e33eff8Schristos emitter_output_table 10*8e33eff8Schristos }; 11*8e33eff8Schristos 12*8e33eff8Schristos typedef enum emitter_justify_e emitter_justify_t; 13*8e33eff8Schristos enum emitter_justify_e { 14*8e33eff8Schristos emitter_justify_left, 15*8e33eff8Schristos emitter_justify_right, 16*8e33eff8Schristos /* Not for users; just to pass to internal functions. */ 17*8e33eff8Schristos emitter_justify_none 18*8e33eff8Schristos }; 19*8e33eff8Schristos 20*8e33eff8Schristos typedef enum emitter_type_e emitter_type_t; 21*8e33eff8Schristos enum emitter_type_e { 22*8e33eff8Schristos emitter_type_bool, 23*8e33eff8Schristos emitter_type_int, 24*8e33eff8Schristos emitter_type_unsigned, 25*8e33eff8Schristos emitter_type_uint32, 26*8e33eff8Schristos emitter_type_uint64, 27*8e33eff8Schristos emitter_type_size, 28*8e33eff8Schristos emitter_type_ssize, 29*8e33eff8Schristos emitter_type_string, 30*8e33eff8Schristos /* 31*8e33eff8Schristos * A title is a column title in a table; it's just a string, but it's 32*8e33eff8Schristos * not quoted. 33*8e33eff8Schristos */ 34*8e33eff8Schristos emitter_type_title, 35*8e33eff8Schristos }; 36*8e33eff8Schristos 37*8e33eff8Schristos typedef struct emitter_col_s emitter_col_t; 38*8e33eff8Schristos struct emitter_col_s { 39*8e33eff8Schristos /* Filled in by the user. */ 40*8e33eff8Schristos emitter_justify_t justify; 41*8e33eff8Schristos int width; 42*8e33eff8Schristos emitter_type_t type; 43*8e33eff8Schristos union { 44*8e33eff8Schristos bool bool_val; 45*8e33eff8Schristos int int_val; 46*8e33eff8Schristos unsigned unsigned_val; 47*8e33eff8Schristos uint32_t uint32_val; 48*8e33eff8Schristos uint64_t uint64_val; 49*8e33eff8Schristos size_t size_val; 50*8e33eff8Schristos ssize_t ssize_val; 51*8e33eff8Schristos const char *str_val; 52*8e33eff8Schristos }; 53*8e33eff8Schristos 54*8e33eff8Schristos /* Filled in by initialization. */ 55*8e33eff8Schristos ql_elm(emitter_col_t) link; 56*8e33eff8Schristos }; 57*8e33eff8Schristos 58*8e33eff8Schristos typedef struct emitter_row_s emitter_row_t; 59*8e33eff8Schristos struct emitter_row_s { 60*8e33eff8Schristos ql_head(emitter_col_t) cols; 61*8e33eff8Schristos }; 62*8e33eff8Schristos 63*8e33eff8Schristos static inline void 64*8e33eff8Schristos emitter_row_init(emitter_row_t *row) { 65*8e33eff8Schristos ql_new(&row->cols); 66*8e33eff8Schristos } 67*8e33eff8Schristos 68*8e33eff8Schristos static inline void 69*8e33eff8Schristos emitter_col_init(emitter_col_t *col, emitter_row_t *row) { 70*8e33eff8Schristos ql_elm_new(col, link); 71*8e33eff8Schristos ql_tail_insert(&row->cols, col, link); 72*8e33eff8Schristos } 73*8e33eff8Schristos 74*8e33eff8Schristos typedef struct emitter_s emitter_t; 75*8e33eff8Schristos struct emitter_s { 76*8e33eff8Schristos emitter_output_t output; 77*8e33eff8Schristos /* The output information. */ 78*8e33eff8Schristos void (*write_cb)(void *, const char *); 79*8e33eff8Schristos void *cbopaque; 80*8e33eff8Schristos int nesting_depth; 81*8e33eff8Schristos /* True if we've already emitted a value at the given depth. */ 82*8e33eff8Schristos bool item_at_depth; 83*8e33eff8Schristos }; 84*8e33eff8Schristos 85*8e33eff8Schristos static inline void 86*8e33eff8Schristos emitter_init(emitter_t *emitter, emitter_output_t emitter_output, 87*8e33eff8Schristos void (*write_cb)(void *, const char *), void *cbopaque) { 88*8e33eff8Schristos emitter->output = emitter_output; 89*8e33eff8Schristos emitter->write_cb = write_cb; 90*8e33eff8Schristos emitter->cbopaque = cbopaque; 91*8e33eff8Schristos emitter->item_at_depth = false; 92*8e33eff8Schristos emitter->nesting_depth = 0; 93*8e33eff8Schristos } 94*8e33eff8Schristos 95*8e33eff8Schristos /* Internal convenience function. Write to the emitter the given string. */ 96*8e33eff8Schristos JEMALLOC_FORMAT_PRINTF(2, 3) 97*8e33eff8Schristos static inline void 98*8e33eff8Schristos emitter_printf(emitter_t *emitter, const char *format, ...) { 99*8e33eff8Schristos va_list ap; 100*8e33eff8Schristos 101*8e33eff8Schristos va_start(ap, format); 102*8e33eff8Schristos malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap); 103*8e33eff8Schristos va_end(ap); 104*8e33eff8Schristos } 105*8e33eff8Schristos 106*8e33eff8Schristos /* Write to the emitter the given string, but only in table mode. */ 107*8e33eff8Schristos JEMALLOC_FORMAT_PRINTF(2, 3) 108*8e33eff8Schristos static inline void 109*8e33eff8Schristos emitter_table_printf(emitter_t *emitter, const char *format, ...) { 110*8e33eff8Schristos if (emitter->output == emitter_output_table) { 111*8e33eff8Schristos va_list ap; 112*8e33eff8Schristos va_start(ap, format); 113*8e33eff8Schristos malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap); 114*8e33eff8Schristos va_end(ap); 115*8e33eff8Schristos } 116*8e33eff8Schristos } 117*8e33eff8Schristos 118*8e33eff8Schristos static inline const char * __attribute__((__format_arg__(3))) 119*8e33eff8Schristos emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier, 120*8e33eff8Schristos emitter_justify_t justify, int width) { 121*8e33eff8Schristos size_t written; 122*8e33eff8Schristos fmt_specifier++; 123*8e33eff8Schristos if (justify == emitter_justify_none) { 124*8e33eff8Schristos written = malloc_snprintf(out_fmt, out_size, 125*8e33eff8Schristos "%%%s", fmt_specifier); 126*8e33eff8Schristos } else if (justify == emitter_justify_left) { 127*8e33eff8Schristos written = malloc_snprintf(out_fmt, out_size, 128*8e33eff8Schristos "%%-%d%s", width, fmt_specifier); 129*8e33eff8Schristos } else { 130*8e33eff8Schristos written = malloc_snprintf(out_fmt, out_size, 131*8e33eff8Schristos "%%%d%s", width, fmt_specifier); 132*8e33eff8Schristos } 133*8e33eff8Schristos /* Only happens in case of bad format string, which *we* choose. */ 134*8e33eff8Schristos assert(written < out_size); 135*8e33eff8Schristos return out_fmt; 136*8e33eff8Schristos } 137*8e33eff8Schristos 138*8e33eff8Schristos /* 139*8e33eff8Schristos * Internal. Emit the given value type in the relevant encoding (so that the 140*8e33eff8Schristos * bool true gets mapped to json "true", but the string "true" gets mapped to 141*8e33eff8Schristos * json "\"true\"", for instance. 142*8e33eff8Schristos * 143*8e33eff8Schristos * Width is ignored if justify is emitter_justify_none. 144*8e33eff8Schristos */ 145*8e33eff8Schristos static inline void 146*8e33eff8Schristos emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width, 147*8e33eff8Schristos emitter_type_t value_type, const void *value) { 148*8e33eff8Schristos size_t str_written; 149*8e33eff8Schristos #define BUF_SIZE 256 150*8e33eff8Schristos #define FMT_SIZE 10 151*8e33eff8Schristos /* 152*8e33eff8Schristos * We dynamically generate a format string to emit, to let us use the 153*8e33eff8Schristos * snprintf machinery. This is kinda hacky, but gets the job done 154*8e33eff8Schristos * quickly without having to think about the various snprintf edge 155*8e33eff8Schristos * cases. 156*8e33eff8Schristos */ 157*8e33eff8Schristos char fmt[FMT_SIZE]; 158*8e33eff8Schristos char buf[BUF_SIZE]; 159*8e33eff8Schristos 160*8e33eff8Schristos #define EMIT_SIMPLE(type, format) \ 161*8e33eff8Schristos emitter_printf(emitter, \ 162*8e33eff8Schristos emitter_gen_fmt(fmt, FMT_SIZE, format, justify, width), \ 163*8e33eff8Schristos *(const type *)value); 164*8e33eff8Schristos 165*8e33eff8Schristos switch (value_type) { 166*8e33eff8Schristos case emitter_type_bool: 167*8e33eff8Schristos emitter_printf(emitter, 168*8e33eff8Schristos emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width), 169*8e33eff8Schristos *(const bool *)value ? "true" : "false"); 170*8e33eff8Schristos break; 171*8e33eff8Schristos case emitter_type_int: 172*8e33eff8Schristos EMIT_SIMPLE(int, "%d") 173*8e33eff8Schristos break; 174*8e33eff8Schristos case emitter_type_unsigned: 175*8e33eff8Schristos EMIT_SIMPLE(unsigned, "%u") 176*8e33eff8Schristos break; 177*8e33eff8Schristos case emitter_type_ssize: 178*8e33eff8Schristos EMIT_SIMPLE(ssize_t, "%zd") 179*8e33eff8Schristos break; 180*8e33eff8Schristos case emitter_type_size: 181*8e33eff8Schristos EMIT_SIMPLE(size_t, "%zu") 182*8e33eff8Schristos break; 183*8e33eff8Schristos case emitter_type_string: 184*8e33eff8Schristos str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"", 185*8e33eff8Schristos *(const char *const *)value); 186*8e33eff8Schristos /* 187*8e33eff8Schristos * We control the strings we output; we shouldn't get anything 188*8e33eff8Schristos * anywhere near the fmt size. 189*8e33eff8Schristos */ 190*8e33eff8Schristos assert(str_written < BUF_SIZE); 191*8e33eff8Schristos emitter_printf(emitter, 192*8e33eff8Schristos emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width), buf); 193*8e33eff8Schristos break; 194*8e33eff8Schristos case emitter_type_uint32: 195*8e33eff8Schristos EMIT_SIMPLE(uint32_t, "%" FMTu32) 196*8e33eff8Schristos break; 197*8e33eff8Schristos case emitter_type_uint64: 198*8e33eff8Schristos EMIT_SIMPLE(uint64_t, "%" FMTu64) 199*8e33eff8Schristos break; 200*8e33eff8Schristos case emitter_type_title: 201*8e33eff8Schristos EMIT_SIMPLE(char *const, "%s"); 202*8e33eff8Schristos break; 203*8e33eff8Schristos default: 204*8e33eff8Schristos unreachable(); 205*8e33eff8Schristos } 206*8e33eff8Schristos #undef BUF_SIZE 207*8e33eff8Schristos #undef FMT_SIZE 208*8e33eff8Schristos } 209*8e33eff8Schristos 210*8e33eff8Schristos 211*8e33eff8Schristos /* Internal functions. In json mode, tracks nesting state. */ 212*8e33eff8Schristos static inline void 213*8e33eff8Schristos emitter_nest_inc(emitter_t *emitter) { 214*8e33eff8Schristos emitter->nesting_depth++; 215*8e33eff8Schristos emitter->item_at_depth = false; 216*8e33eff8Schristos } 217*8e33eff8Schristos 218*8e33eff8Schristos static inline void 219*8e33eff8Schristos emitter_nest_dec(emitter_t *emitter) { 220*8e33eff8Schristos emitter->nesting_depth--; 221*8e33eff8Schristos emitter->item_at_depth = true; 222*8e33eff8Schristos } 223*8e33eff8Schristos 224*8e33eff8Schristos static inline void 225*8e33eff8Schristos emitter_indent(emitter_t *emitter) { 226*8e33eff8Schristos int amount = emitter->nesting_depth; 227*8e33eff8Schristos const char *indent_str; 228*8e33eff8Schristos if (emitter->output == emitter_output_json) { 229*8e33eff8Schristos indent_str = "\t"; 230*8e33eff8Schristos } else { 231*8e33eff8Schristos amount *= 2; 232*8e33eff8Schristos indent_str = " "; 233*8e33eff8Schristos } 234*8e33eff8Schristos for (int i = 0; i < amount; i++) { 235*8e33eff8Schristos emitter_printf(emitter, "%s", indent_str); 236*8e33eff8Schristos } 237*8e33eff8Schristos } 238*8e33eff8Schristos 239*8e33eff8Schristos static inline void 240*8e33eff8Schristos emitter_json_key_prefix(emitter_t *emitter) { 241*8e33eff8Schristos emitter_printf(emitter, "%s\n", emitter->item_at_depth ? "," : ""); 242*8e33eff8Schristos emitter_indent(emitter); 243*8e33eff8Schristos } 244*8e33eff8Schristos 245*8e33eff8Schristos static inline void 246*8e33eff8Schristos emitter_begin(emitter_t *emitter) { 247*8e33eff8Schristos if (emitter->output == emitter_output_json) { 248*8e33eff8Schristos assert(emitter->nesting_depth == 0); 249*8e33eff8Schristos emitter_printf(emitter, "{"); 250*8e33eff8Schristos emitter_nest_inc(emitter); 251*8e33eff8Schristos } else { 252*8e33eff8Schristos // tabular init 253*8e33eff8Schristos emitter_printf(emitter, "%s", ""); 254*8e33eff8Schristos } 255*8e33eff8Schristos } 256*8e33eff8Schristos 257*8e33eff8Schristos static inline void 258*8e33eff8Schristos emitter_end(emitter_t *emitter) { 259*8e33eff8Schristos if (emitter->output == emitter_output_json) { 260*8e33eff8Schristos assert(emitter->nesting_depth == 1); 261*8e33eff8Schristos emitter_nest_dec(emitter); 262*8e33eff8Schristos emitter_printf(emitter, "\n}\n"); 263*8e33eff8Schristos } 264*8e33eff8Schristos } 265*8e33eff8Schristos 266*8e33eff8Schristos /* 267*8e33eff8Schristos * Note emits a different kv pair as well, but only in table mode. Omits the 268*8e33eff8Schristos * note if table_note_key is NULL. 269*8e33eff8Schristos */ 270*8e33eff8Schristos static inline void 271*8e33eff8Schristos emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key, 272*8e33eff8Schristos emitter_type_t value_type, const void *value, 273*8e33eff8Schristos const char *table_note_key, emitter_type_t table_note_value_type, 274*8e33eff8Schristos const void *table_note_value) { 275*8e33eff8Schristos if (emitter->output == emitter_output_json) { 276*8e33eff8Schristos assert(emitter->nesting_depth > 0); 277*8e33eff8Schristos emitter_json_key_prefix(emitter); 278*8e33eff8Schristos emitter_printf(emitter, "\"%s\": ", json_key); 279*8e33eff8Schristos emitter_print_value(emitter, emitter_justify_none, -1, 280*8e33eff8Schristos value_type, value); 281*8e33eff8Schristos } else { 282*8e33eff8Schristos emitter_indent(emitter); 283*8e33eff8Schristos emitter_printf(emitter, "%s: ", table_key); 284*8e33eff8Schristos emitter_print_value(emitter, emitter_justify_none, -1, 285*8e33eff8Schristos value_type, value); 286*8e33eff8Schristos if (table_note_key != NULL) { 287*8e33eff8Schristos emitter_printf(emitter, " (%s: ", table_note_key); 288*8e33eff8Schristos emitter_print_value(emitter, emitter_justify_none, -1, 289*8e33eff8Schristos table_note_value_type, table_note_value); 290*8e33eff8Schristos emitter_printf(emitter, ")"); 291*8e33eff8Schristos } 292*8e33eff8Schristos emitter_printf(emitter, "\n"); 293*8e33eff8Schristos } 294*8e33eff8Schristos emitter->item_at_depth = true; 295*8e33eff8Schristos } 296*8e33eff8Schristos 297*8e33eff8Schristos static inline void 298*8e33eff8Schristos emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key, 299*8e33eff8Schristos emitter_type_t value_type, const void *value) { 300*8e33eff8Schristos emitter_kv_note(emitter, json_key, table_key, value_type, value, NULL, 301*8e33eff8Schristos emitter_type_bool, NULL); 302*8e33eff8Schristos } 303*8e33eff8Schristos 304*8e33eff8Schristos static inline void 305*8e33eff8Schristos emitter_json_kv(emitter_t *emitter, const char *json_key, 306*8e33eff8Schristos emitter_type_t value_type, const void *value) { 307*8e33eff8Schristos if (emitter->output == emitter_output_json) { 308*8e33eff8Schristos emitter_kv(emitter, json_key, NULL, value_type, value); 309*8e33eff8Schristos } 310*8e33eff8Schristos } 311*8e33eff8Schristos 312*8e33eff8Schristos static inline void 313*8e33eff8Schristos emitter_table_kv(emitter_t *emitter, const char *table_key, 314*8e33eff8Schristos emitter_type_t value_type, const void *value) { 315*8e33eff8Schristos if (emitter->output == emitter_output_table) { 316*8e33eff8Schristos emitter_kv(emitter, NULL, table_key, value_type, value); 317*8e33eff8Schristos } 318*8e33eff8Schristos } 319*8e33eff8Schristos 320*8e33eff8Schristos static inline void 321*8e33eff8Schristos emitter_dict_begin(emitter_t *emitter, const char *json_key, 322*8e33eff8Schristos const char *table_header) { 323*8e33eff8Schristos if (emitter->output == emitter_output_json) { 324*8e33eff8Schristos emitter_json_key_prefix(emitter); 325*8e33eff8Schristos emitter_printf(emitter, "\"%s\": {", json_key); 326*8e33eff8Schristos emitter_nest_inc(emitter); 327*8e33eff8Schristos } else { 328*8e33eff8Schristos emitter_indent(emitter); 329*8e33eff8Schristos emitter_printf(emitter, "%s\n", table_header); 330*8e33eff8Schristos emitter_nest_inc(emitter); 331*8e33eff8Schristos } 332*8e33eff8Schristos } 333*8e33eff8Schristos 334*8e33eff8Schristos static inline void 335*8e33eff8Schristos emitter_dict_end(emitter_t *emitter) { 336*8e33eff8Schristos if (emitter->output == emitter_output_json) { 337*8e33eff8Schristos assert(emitter->nesting_depth > 0); 338*8e33eff8Schristos emitter_nest_dec(emitter); 339*8e33eff8Schristos emitter_printf(emitter, "\n"); 340*8e33eff8Schristos emitter_indent(emitter); 341*8e33eff8Schristos emitter_printf(emitter, "}"); 342*8e33eff8Schristos } else { 343*8e33eff8Schristos emitter_nest_dec(emitter); 344*8e33eff8Schristos } 345*8e33eff8Schristos } 346*8e33eff8Schristos 347*8e33eff8Schristos static inline void 348*8e33eff8Schristos emitter_json_dict_begin(emitter_t *emitter, const char *json_key) { 349*8e33eff8Schristos if (emitter->output == emitter_output_json) { 350*8e33eff8Schristos emitter_dict_begin(emitter, json_key, NULL); 351*8e33eff8Schristos } 352*8e33eff8Schristos } 353*8e33eff8Schristos 354*8e33eff8Schristos static inline void 355*8e33eff8Schristos emitter_json_dict_end(emitter_t *emitter) { 356*8e33eff8Schristos if (emitter->output == emitter_output_json) { 357*8e33eff8Schristos emitter_dict_end(emitter); 358*8e33eff8Schristos } 359*8e33eff8Schristos } 360*8e33eff8Schristos 361*8e33eff8Schristos static inline void 362*8e33eff8Schristos emitter_table_dict_begin(emitter_t *emitter, const char *table_key) { 363*8e33eff8Schristos if (emitter->output == emitter_output_table) { 364*8e33eff8Schristos emitter_dict_begin(emitter, NULL, table_key); 365*8e33eff8Schristos } 366*8e33eff8Schristos } 367*8e33eff8Schristos 368*8e33eff8Schristos static inline void 369*8e33eff8Schristos emitter_table_dict_end(emitter_t *emitter) { 370*8e33eff8Schristos if (emitter->output == emitter_output_table) { 371*8e33eff8Schristos emitter_dict_end(emitter); 372*8e33eff8Schristos } 373*8e33eff8Schristos } 374*8e33eff8Schristos 375*8e33eff8Schristos static inline void 376*8e33eff8Schristos emitter_json_arr_begin(emitter_t *emitter, const char *json_key) { 377*8e33eff8Schristos if (emitter->output == emitter_output_json) { 378*8e33eff8Schristos emitter_json_key_prefix(emitter); 379*8e33eff8Schristos emitter_printf(emitter, "\"%s\": [", json_key); 380*8e33eff8Schristos emitter_nest_inc(emitter); 381*8e33eff8Schristos } 382*8e33eff8Schristos } 383*8e33eff8Schristos 384*8e33eff8Schristos static inline void 385*8e33eff8Schristos emitter_json_arr_end(emitter_t *emitter) { 386*8e33eff8Schristos if (emitter->output == emitter_output_json) { 387*8e33eff8Schristos assert(emitter->nesting_depth > 0); 388*8e33eff8Schristos emitter_nest_dec(emitter); 389*8e33eff8Schristos emitter_printf(emitter, "\n"); 390*8e33eff8Schristos emitter_indent(emitter); 391*8e33eff8Schristos emitter_printf(emitter, "]"); 392*8e33eff8Schristos } 393*8e33eff8Schristos } 394*8e33eff8Schristos 395*8e33eff8Schristos static inline void 396*8e33eff8Schristos emitter_json_arr_obj_begin(emitter_t *emitter) { 397*8e33eff8Schristos if (emitter->output == emitter_output_json) { 398*8e33eff8Schristos emitter_json_key_prefix(emitter); 399*8e33eff8Schristos emitter_printf(emitter, "{"); 400*8e33eff8Schristos emitter_nest_inc(emitter); 401*8e33eff8Schristos } 402*8e33eff8Schristos } 403*8e33eff8Schristos 404*8e33eff8Schristos static inline void 405*8e33eff8Schristos emitter_json_arr_obj_end(emitter_t *emitter) { 406*8e33eff8Schristos if (emitter->output == emitter_output_json) { 407*8e33eff8Schristos assert(emitter->nesting_depth > 0); 408*8e33eff8Schristos emitter_nest_dec(emitter); 409*8e33eff8Schristos emitter_printf(emitter, "\n"); 410*8e33eff8Schristos emitter_indent(emitter); 411*8e33eff8Schristos emitter_printf(emitter, "}"); 412*8e33eff8Schristos } 413*8e33eff8Schristos } 414*8e33eff8Schristos 415*8e33eff8Schristos static inline void 416*8e33eff8Schristos emitter_json_arr_value(emitter_t *emitter, emitter_type_t value_type, 417*8e33eff8Schristos const void *value) { 418*8e33eff8Schristos if (emitter->output == emitter_output_json) { 419*8e33eff8Schristos emitter_json_key_prefix(emitter); 420*8e33eff8Schristos emitter_print_value(emitter, emitter_justify_none, -1, 421*8e33eff8Schristos value_type, value); 422*8e33eff8Schristos } 423*8e33eff8Schristos } 424*8e33eff8Schristos 425*8e33eff8Schristos static inline void 426*8e33eff8Schristos emitter_table_row(emitter_t *emitter, emitter_row_t *row) { 427*8e33eff8Schristos if (emitter->output != emitter_output_table) { 428*8e33eff8Schristos return; 429*8e33eff8Schristos } 430*8e33eff8Schristos emitter_col_t *col; 431*8e33eff8Schristos ql_foreach(col, &row->cols, link) { 432*8e33eff8Schristos emitter_print_value(emitter, col->justify, col->width, 433*8e33eff8Schristos col->type, (const void *)&col->bool_val); 434*8e33eff8Schristos } 435*8e33eff8Schristos emitter_table_printf(emitter, "\n"); 436*8e33eff8Schristos } 437*8e33eff8Schristos 438*8e33eff8Schristos #endif /* JEMALLOC_INTERNAL_EMITTER_H */ 439