// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* Simple streaming JSON writer
*
* This takes care of the annoying bits of JSON syntax like the commas
* after elements
*
* Authors: Stephen Hemminger <stephen@networkplumber.org>
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <assert.h>
#include <malloc.h>
#include <inttypes.h>
#include <stdint.h>
#include "json_writer.h"
struct json_writer {
FILE *out;
/* output file */
unsigned depth;
/* nesting */
bool pretty;
/* optional whitepace */
char sep;
/* either nul or comma */
};
/* indentation for pretty print */
static void jsonw_indent(json_writer_t *self)
{
unsigned i;
for (i =
0 ; i < self->depth; ++i)
fputs(
" " , self->out);
}
/* end current line and indent if pretty printing */
static void jsonw_eol(json_writer_t *self)
{
if (!self->pretty)
return ;
putc(
'\n' , self->out);
jsonw_indent(self);
}
/* If current object is not empty print a comma */
static void jsonw_eor(json_writer_t *self)
{
if (self->sep !=
'\0' )
putc(self->sep, self->out);
self->sep =
',' ;
}
/* Output JSON encoded string */
/* Handles C escapes, does not do Unicode */
static void jsonw_puts(json_writer_t *self,
const char *str)
{
putc(
'"' , self->out);
for (; *str; ++str)
switch (*str) {
case '\t' :
fputs(
"\\t" , self->out);
break ;
case '\n' :
fputs(
"\\n" , self->out);
break ;
case '\r' :
fputs(
"\\r" , self->out);
break ;
case '\f' :
fputs(
"\\f" , self->out);
break ;
case '\b' :
fputs(
"\\b" , self->out);
break ;
case '\\' :
fputs(
"\\\\" , self->out);
break ;
case '"' :
fputs(
"\\\" ", self->out);
break ;
default :
putc(*str, self->out);
}
putc(
'"' , self->out);
}
/* Create a new JSON stream */
json_writer_t *jsonw_new(FILE *f)
{
json_writer_t *self = malloc(
sizeof (*self));
if (self) {
self->out = f;
self->depth =
0 ;
self->pretty =
false ;
self->sep =
'\0' ;
}
return self;
}
/* End output to JSON stream */
void jsonw_destroy(json_writer_t **self_p)
{
json_writer_t *self = *self_p;
assert(self->depth ==
0 );
fputs(
"\n" , self->out);
fflush(self->out);
free(self);
*self_p = NULL;
}
void jsonw_pretty(json_writer_t *self,
bool on)
{
self->pretty = on;
}
void jsonw_reset(json_writer_t *self)
{
assert(self->depth ==
0 );
self->sep =
'\0' ;
}
/* Basic blocks */
static void jsonw_begin(json_writer_t *self,
int c)
{
jsonw_eor(self);
putc(c, self->out);
++self->depth;
self->sep =
'\0' ;
}
static void jsonw_end(json_writer_t *self,
int c)
{
assert(self->depth >
0 );
--self->depth;
if (self->sep !=
'\0' )
jsonw_eol(self);
putc(c, self->out);
self->sep =
',' ;
}
/* Add a JSON property name */
void jsonw_name(json_writer_t *self,
const char *name)
{
jsonw_eor(self);
jsonw_eol(self);
self->sep =
'\0' ;
jsonw_puts(self, name);
putc(
':' , self->out);
if (self->pretty)
putc(
' ' , self->out);
}
void jsonw_vprintf_enquote(json_writer_t *self,
const char *fmt, va_list ap)
{
jsonw_eor(self);
putc(
'"' , self->out);
vfprintf(self->out, fmt, ap);
putc(
'"' , self->out);
}
void jsonw_printf(json_writer_t *self,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
jsonw_eor(self);
vfprintf(self->out, fmt, ap);
va_end(ap);
}
/* Collections */
void jsonw_start_object(json_writer_t *self)
{
jsonw_begin(self,
'{' );
}
void jsonw_end_object(json_writer_t *self)
{
jsonw_end(self,
'}' );
}
void jsonw_start_array(json_writer_t *self)
{
jsonw_begin(self,
'[' );
}
void jsonw_end_array(json_writer_t *self)
{
jsonw_end(self,
']' );
}
/* JSON value types */
void jsonw_string(json_writer_t *self,
const char *value)
{
jsonw_eor(self);
jsonw_puts(self, value);
}
void jsonw_bool(json_writer_t *self,
bool val)
{
jsonw_printf(self,
"%s" , val ?
"true" :
"false" );
}
void jsonw_null(json_writer_t *self)
{
jsonw_printf(self,
"null" );
}
void jsonw_float_fmt(json_writer_t *self,
const char *fmt,
double num)
{
jsonw_printf(self, fmt, num);
}
#ifdef notused
void jsonw_float(json_writer_t *self,
double num)
{
jsonw_printf(self,
"%g" , num);
}
#endif
void jsonw_hu(json_writer_t *self,
unsigned short num)
{
jsonw_printf(self,
"%hu" , num);
}
void jsonw_uint(json_writer_t *self, uint64_t num)
{
jsonw_printf(self,
"%" PRIu64, num);
}
void jsonw_lluint(json_writer_t *self,
unsigned long long int num)
{
jsonw_printf(self,
"%llu" , num);
}
void jsonw_int(json_writer_t *self, int64_t num)
{
jsonw_printf(self,
"%" PRId64, num);
}
/* Basic name/value objects */
void jsonw_string_field(json_writer_t *self,
const char *prop,
const char *val)
{
jsonw_name(self, prop);
jsonw_string(self, val);
}
void jsonw_bool_field(json_writer_t *self,
const char *prop,
bool val)
{
jsonw_name(self, prop);
jsonw_bool(self, val);
}
#ifdef notused
void jsonw_float_field(json_writer_t *self,
const char *prop,
double val)
{
jsonw_name(self, prop);
jsonw_float(self, val);
}
#endif
void jsonw_float_field_fmt(json_writer_t *self,
const char *prop,
const char *fmt,
double val)
{
jsonw_name(self, prop);
jsonw_float_fmt(self, fmt, val);
}
void jsonw_uint_field(json_writer_t *self,
const char *prop, uint64_t num)
{
jsonw_name(self, prop);
jsonw_uint(self, num);
}
void jsonw_hu_field(json_writer_t *self,
const char *prop,
unsigned short num)
{
jsonw_name(self, prop);
jsonw_hu(self, num);
}
void jsonw_lluint_field(json_writer_t *self,
const char *prop,
unsigned long long int num)
{
jsonw_name(self, prop);
jsonw_lluint(self, num);
}
void jsonw_int_field(json_writer_t *self,
const char *prop, int64_t num)
{
jsonw_name(self, prop);
jsonw_int(self, num);
}
void jsonw_null_field(json_writer_t *self,
const char *prop)
{
jsonw_name(self, prop);
jsonw_null(self);
}
#ifdef TEST
int main(
int argc,
char **argv)
{
json_writer_t *wr = jsonw_new(stdout);
jsonw_start_object(wr);
jsonw_pretty(wr,
true );
jsonw_name(wr,
"Vyatta" );
jsonw_start_object(wr);
jsonw_string_field(wr,
"url" ,
"http://vyatta.com ");
jsonw_uint_field(wr,
"downloads" ,
2000000 ul);
jsonw_float_field(wr,
"stock" ,
8 .
16 );
jsonw_name(wr,
"ARGV" );
jsonw_start_array(wr);
while (--argc)
jsonw_string(wr, *++argv);
jsonw_end_array(wr);
jsonw_name(wr,
"empty" );
jsonw_start_array(wr);
jsonw_end_array(wr);
jsonw_name(wr,
"NIL" );
jsonw_start_object(wr);
jsonw_end_object(wr);
jsonw_null_field(wr,
"my_null" );
jsonw_name(wr,
"special chars" );
jsonw_start_array(wr);
jsonw_string_field(wr,
"slash" ,
"/" );
jsonw_string_field(wr,
"newline" ,
"\n" );
jsonw_string_field(wr,
"tab" ,
"\t" );
jsonw_string_field(wr,
"ff" ,
"\f" );
jsonw_string_field(wr,
"quote" ,
"\" ");
jsonw_string_field(wr,
"tick" ,
"\'" );
jsonw_string_field(wr,
"backslash" ,
"\\" );
jsonw_end_array(wr);
jsonw_end_object(wr);
jsonw_end_object(wr);
jsonw_destroy(&wr);
return 0 ;
}
#endif
Messung V0.5 in Prozent C=97 H=87 G=91
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland