Home | History | Annotate | Download | only in lib
      1 /*
      2  * json_print.c		"print regular or json output, based on json_writer".
      3  *
      4  *             This program is free software; you can redistribute it and/or
      5  *             modify it under the terms of the GNU General Public License
      6  *             as published by the Free Software Foundation; either version
      7  *             2 of the License, or (at your option) any later version.
      8  *
      9  * Authors:    Julien Fortin, <julien (at) cumulusnetworks.com>
     10  */
     11 
     12 #include <stdarg.h>
     13 #include <stdio.h>
     14 
     15 #include "utils.h"
     16 #include "json_print.h"
     17 
     18 static json_writer_t *_jw;
     19 
     20 #define _IS_JSON_CONTEXT(type) ((type & PRINT_JSON || type & PRINT_ANY) && _jw)
     21 #define _IS_FP_CONTEXT(type) (!_jw && (type & PRINT_FP || type & PRINT_ANY))
     22 
     23 void new_json_obj(int json)
     24 {
     25 	if (json) {
     26 		_jw = jsonw_new(stdout);
     27 		if (!_jw) {
     28 			perror("json object");
     29 			exit(1);
     30 		}
     31 		jsonw_pretty(_jw, true);
     32 		jsonw_start_array(_jw);
     33 	}
     34 }
     35 
     36 void delete_json_obj(void)
     37 {
     38 	if (_jw) {
     39 		jsonw_end_array(_jw);
     40 		jsonw_destroy(&_jw);
     41 	}
     42 }
     43 
     44 bool is_json_context(void)
     45 {
     46 	return _jw != NULL;
     47 }
     48 
     49 json_writer_t *get_json_writer(void)
     50 {
     51 	return _jw;
     52 }
     53 
     54 void open_json_object(const char *str)
     55 {
     56 	if (_IS_JSON_CONTEXT(PRINT_JSON)) {
     57 		if (str)
     58 			jsonw_name(_jw, str);
     59 		jsonw_start_object(_jw);
     60 	}
     61 }
     62 
     63 void close_json_object(void)
     64 {
     65 	if (_IS_JSON_CONTEXT(PRINT_JSON))
     66 		jsonw_end_object(_jw);
     67 }
     68 
     69 /*
     70  * Start json array or string array using
     71  * the provided string as json key (if not null)
     72  * or as array delimiter in non-json context.
     73  */
     74 void open_json_array(enum output_type type, const char *str)
     75 {
     76 	if (_IS_JSON_CONTEXT(type)) {
     77 		if (str)
     78 			jsonw_name(_jw, str);
     79 		jsonw_start_array(_jw);
     80 	} else if (_IS_FP_CONTEXT(type)) {
     81 		printf("%s", str);
     82 	}
     83 }
     84 
     85 /*
     86  * End json array or string array
     87  */
     88 void close_json_array(enum output_type type, const char *str)
     89 {
     90 	if (_IS_JSON_CONTEXT(type)) {
     91 		jsonw_pretty(_jw, false);
     92 		jsonw_end_array(_jw);
     93 		jsonw_pretty(_jw, true);
     94 	} else if (_IS_FP_CONTEXT(type)) {
     95 		printf("%s", str);
     96 	}
     97 }
     98 
     99 /*
    100  * pre-processor directive to generate similar
    101  * functions handling different types
    102  */
    103 #define _PRINT_FUNC(type_name, type)					\
    104 	void print_color_##type_name(enum output_type t,		\
    105 				     enum color_attr color,		\
    106 				     const char *key,			\
    107 				     const char *fmt,			\
    108 				     type value)			\
    109 	{								\
    110 		if (_IS_JSON_CONTEXT(t)) {				\
    111 			if (!key)					\
    112 				jsonw_##type_name(_jw, value);		\
    113 			else						\
    114 				jsonw_##type_name##_field(_jw, key, value); \
    115 		} else if (_IS_FP_CONTEXT(t)) {				\
    116 			color_fprintf(stdout, color, fmt, value);          \
    117 		}							\
    118 	}
    119 _PRINT_FUNC(int, int);
    120 _PRINT_FUNC(hu, unsigned short);
    121 _PRINT_FUNC(uint, uint64_t);
    122 _PRINT_FUNC(lluint, unsigned long long int);
    123 #undef _PRINT_FUNC
    124 
    125 void print_color_string(enum output_type type,
    126 			enum color_attr color,
    127 			const char *key,
    128 			const char *fmt,
    129 			const char *value)
    130 {
    131 	if (_IS_JSON_CONTEXT(type)) {
    132 		if (key && !value)
    133 			jsonw_name(_jw, key);
    134 		else if (!key && value)
    135 			jsonw_string(_jw, value);
    136 		else
    137 			jsonw_string_field(_jw, key, value);
    138 	} else if (_IS_FP_CONTEXT(type)) {
    139 		color_fprintf(stdout, color, fmt, value);
    140 	}
    141 }
    142 
    143 /*
    144  * value's type is bool. When using this function in FP context you can't pass
    145  * a value to it, you will need to use "is_json_context()" to have different
    146  * branch for json and regular output. grep -r "print_bool" for example
    147  */
    148 void print_color_bool(enum output_type type,
    149 		      enum color_attr color,
    150 		      const char *key,
    151 		      const char *fmt,
    152 		      bool value)
    153 {
    154 	if (_IS_JSON_CONTEXT(type)) {
    155 		if (key)
    156 			jsonw_bool_field(_jw, key, value);
    157 		else
    158 			jsonw_bool(_jw, value);
    159 	} else if (_IS_FP_CONTEXT(type)) {
    160 		color_fprintf(stdout, color, fmt, value ? "true" : "false");
    161 	}
    162 }
    163 
    164 /*
    165  * In JSON context uses hardcode %#x format: 42 -> 0x2a
    166  */
    167 void print_color_0xhex(enum output_type type,
    168 		       enum color_attr color,
    169 		       const char *key,
    170 		       const char *fmt,
    171 		       unsigned int hex)
    172 {
    173 	if (_IS_JSON_CONTEXT(type)) {
    174 		SPRINT_BUF(b1);
    175 
    176 		snprintf(b1, sizeof(b1), "%#x", hex);
    177 		print_string(PRINT_JSON, key, NULL, b1);
    178 	} else if (_IS_FP_CONTEXT(type)) {
    179 		color_fprintf(stdout, color, fmt, hex);
    180 	}
    181 }
    182 
    183 void print_color_hex(enum output_type type,
    184 		     enum color_attr color,
    185 		     const char *key,
    186 		     const char *fmt,
    187 		     unsigned int hex)
    188 {
    189 	if (_IS_JSON_CONTEXT(type)) {
    190 		SPRINT_BUF(b1);
    191 
    192 		snprintf(b1, sizeof(b1), "%x", hex);
    193 		if (key)
    194 			jsonw_string_field(_jw, key, b1);
    195 		else
    196 			jsonw_string(_jw, b1);
    197 	} else if (_IS_FP_CONTEXT(type)) {
    198 		color_fprintf(stdout, color, fmt, hex);
    199 	}
    200 }
    201 
    202 /*
    203  * In JSON context we don't use the argument "value" we simply call jsonw_null
    204  * whereas FP context can use "value" to output anything
    205  */
    206 void print_color_null(enum output_type type,
    207 		      enum color_attr color,
    208 		      const char *key,
    209 		      const char *fmt,
    210 		      const char *value)
    211 {
    212 	if (_IS_JSON_CONTEXT(type)) {
    213 		if (key)
    214 			jsonw_null_field(_jw, key);
    215 		else
    216 			jsonw_null(_jw);
    217 	} else if (_IS_FP_CONTEXT(type)) {
    218 		color_fprintf(stdout, color, fmt, value);
    219 	}
    220 }
    221