iproute2/lib/json_print.c
<<
>>
Prefs
   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@cumulusnetworks.com>
  10 */
  11
  12#include <stdarg.h>
  13#include <stdio.h>
  14
  15#include "utils.h"
  16#include "json_print.h"
  17
  18static 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
  23static void __new_json_obj(int json, bool have_array)
  24{
  25        if (json) {
  26                _jw = jsonw_new(stdout);
  27                if (!_jw) {
  28                        perror("json object");
  29                        exit(1);
  30                }
  31                if (pretty)
  32                        jsonw_pretty(_jw, true);
  33                if (have_array)
  34                        jsonw_start_array(_jw);
  35        }
  36}
  37
  38static void __delete_json_obj(bool have_array)
  39{
  40        if (_jw) {
  41                if (have_array)
  42                        jsonw_end_array(_jw);
  43                jsonw_destroy(&_jw);
  44        }
  45}
  46
  47void new_json_obj(int json)
  48{
  49        __new_json_obj(json, true);
  50}
  51
  52void delete_json_obj(void)
  53{
  54        __delete_json_obj(true);
  55}
  56
  57void new_json_obj_plain(int json)
  58{
  59        __new_json_obj(json, false);
  60}
  61
  62void delete_json_obj_plain(void)
  63{
  64        __delete_json_obj(false);
  65}
  66
  67bool is_json_context(void)
  68{
  69        return _jw != NULL;
  70}
  71
  72json_writer_t *get_json_writer(void)
  73{
  74        return _jw;
  75}
  76
  77void open_json_object(const char *str)
  78{
  79        if (_IS_JSON_CONTEXT(PRINT_JSON)) {
  80                if (str)
  81                        jsonw_name(_jw, str);
  82                jsonw_start_object(_jw);
  83        }
  84}
  85
  86void close_json_object(void)
  87{
  88        if (_IS_JSON_CONTEXT(PRINT_JSON))
  89                jsonw_end_object(_jw);
  90}
  91
  92/*
  93 * Start json array or string array using
  94 * the provided string as json key (if not null)
  95 * or as array delimiter in non-json context.
  96 */
  97void open_json_array(enum output_type type, const char *str)
  98{
  99        if (_IS_JSON_CONTEXT(type)) {
 100                if (str)
 101                        jsonw_name(_jw, str);
 102                jsonw_start_array(_jw);
 103        } else if (_IS_FP_CONTEXT(type)) {
 104                printf("%s", str);
 105        }
 106}
 107
 108/*
 109 * End json array or string array
 110 */
 111void close_json_array(enum output_type type, const char *str)
 112{
 113        if (_IS_JSON_CONTEXT(type)) {
 114                jsonw_end_array(_jw);
 115        } else if (_IS_FP_CONTEXT(type)) {
 116                printf("%s", str);
 117        }
 118}
 119
 120/*
 121 * pre-processor directive to generate similar
 122 * functions handling different types
 123 */
 124#define _PRINT_FUNC(type_name, type)                                    \
 125        __attribute__((format(printf, 4, 0)))                           \
 126        int print_color_##type_name(enum output_type t,                 \
 127                                    enum color_attr color,              \
 128                                    const char *key,                    \
 129                                    const char *fmt,                    \
 130                                    type value)                         \
 131        {                                                               \
 132                int ret = 0;                                            \
 133                if (_IS_JSON_CONTEXT(t)) {                              \
 134                        if (!key)                                       \
 135                                jsonw_##type_name(_jw, value);          \
 136                        else                                            \
 137                                jsonw_##type_name##_field(_jw, key, value); \
 138                } else if (_IS_FP_CONTEXT(t)) {                         \
 139                        ret = color_fprintf(stdout, color, fmt, value); \
 140                }                                                       \
 141                return ret;                                             \
 142        }
 143_PRINT_FUNC(int, int);
 144_PRINT_FUNC(s64, int64_t);
 145_PRINT_FUNC(hhu, unsigned char);
 146_PRINT_FUNC(hu, unsigned short);
 147_PRINT_FUNC(uint, unsigned int);
 148_PRINT_FUNC(u64, uint64_t);
 149_PRINT_FUNC(luint, unsigned long);
 150_PRINT_FUNC(lluint, unsigned long long);
 151_PRINT_FUNC(float, double);
 152#undef _PRINT_FUNC
 153
 154#define _PRINT_NAME_VALUE_FUNC(type_name, type, format_char)             \
 155        void print_##type_name##_name_value(const char *name, type value)\
 156        {                                                                \
 157                SPRINT_BUF(format);                                      \
 158                                                                         \
 159                snprintf(format, SPRINT_BSIZE,                           \
 160                         "%s %%"#format_char, name);                     \
 161                print_##type_name(PRINT_ANY, name, format, value);       \
 162        }
 163_PRINT_NAME_VALUE_FUNC(uint, unsigned int, u);
 164_PRINT_NAME_VALUE_FUNC(string, const char*, s);
 165#undef _PRINT_NAME_VALUE_FUNC
 166
 167int print_color_string(enum output_type type,
 168                       enum color_attr color,
 169                       const char *key,
 170                       const char *fmt,
 171                       const char *value)
 172{
 173        int ret = 0;
 174
 175        if (_IS_JSON_CONTEXT(type)) {
 176                if (key && !value)
 177                        jsonw_name(_jw, key);
 178                else if (!key && value)
 179                        jsonw_string(_jw, value);
 180                else
 181                        jsonw_string_field(_jw, key, value);
 182        } else if (_IS_FP_CONTEXT(type)) {
 183                ret = color_fprintf(stdout, color, fmt, value);
 184        }
 185
 186        return ret;
 187}
 188
 189/*
 190 * value's type is bool. When using this function in FP context you can't pass
 191 * a value to it, you will need to use "is_json_context()" to have different
 192 * branch for json and regular output. grep -r "print_bool" for example
 193 */
 194int print_color_bool(enum output_type type,
 195                     enum color_attr color,
 196                     const char *key,
 197                     const char *fmt,
 198                     bool value)
 199{
 200        int ret = 0;
 201
 202        if (_IS_JSON_CONTEXT(type)) {
 203                if (key)
 204                        jsonw_bool_field(_jw, key, value);
 205                else
 206                        jsonw_bool(_jw, value);
 207        } else if (_IS_FP_CONTEXT(type)) {
 208                ret = color_fprintf(stdout, color, fmt,
 209                                    value ? "true" : "false");
 210        }
 211
 212        return ret;
 213}
 214
 215/*
 216 * In JSON context uses hardcode %#x format: 42 -> 0x2a
 217 */
 218int print_color_0xhex(enum output_type type,
 219                      enum color_attr color,
 220                      const char *key,
 221                      const char *fmt,
 222                      unsigned long long hex)
 223{
 224        int ret = 0;
 225
 226        if (_IS_JSON_CONTEXT(type)) {
 227                SPRINT_BUF(b1);
 228
 229                snprintf(b1, sizeof(b1), "%#llx", hex);
 230                print_string(PRINT_JSON, key, NULL, b1);
 231        } else if (_IS_FP_CONTEXT(type)) {
 232                ret = color_fprintf(stdout, color, fmt, hex);
 233        }
 234
 235        return ret;
 236}
 237
 238int print_color_hex(enum output_type type,
 239                    enum color_attr color,
 240                    const char *key,
 241                    const char *fmt,
 242                    unsigned int hex)
 243{
 244        int ret = 0;
 245
 246        if (_IS_JSON_CONTEXT(type)) {
 247                SPRINT_BUF(b1);
 248
 249                snprintf(b1, sizeof(b1), "%x", hex);
 250                if (key)
 251                        jsonw_string_field(_jw, key, b1);
 252                else
 253                        jsonw_string(_jw, b1);
 254        } else if (_IS_FP_CONTEXT(type)) {
 255                ret = color_fprintf(stdout, color, fmt, hex);
 256        }
 257
 258        return ret;
 259}
 260
 261/*
 262 * In JSON context we don't use the argument "value" we simply call jsonw_null
 263 * whereas FP context can use "value" to output anything
 264 */
 265int print_color_null(enum output_type type,
 266                     enum color_attr color,
 267                     const char *key,
 268                     const char *fmt,
 269                     const char *value)
 270{
 271        int ret = 0;
 272
 273        if (_IS_JSON_CONTEXT(type)) {
 274                if (key)
 275                        jsonw_null_field(_jw, key);
 276                else
 277                        jsonw_null(_jw);
 278        } else if (_IS_FP_CONTEXT(type)) {
 279                ret = color_fprintf(stdout, color, fmt, value);
 280        }
 281
 282        return ret;
 283}
 284
 285/* Print line separator (if not in JSON mode) */
 286void print_nl(void)
 287{
 288        if (!_jw)
 289                printf("%s", _SL_);
 290}
 291