Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F118309980
mkjson.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
mkjson.c
View Options
/* mkjson.c - a part of mkjson library
*
* Copyright (C) 2018 Jacek Wieczorek
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#include
<mkjson.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<stdarg.h>
#include
<string.h>
// Works like asprintf, but it's always there
// I don't want the name to collide with anything
static
int
allsprintf
(
char
**
strp
,
const
char
*
fmt
,
...
)
{
int
len
;
va_list
ap
;
va_start
(
ap
,
fmt
);
#ifdef _GNU_SOURCE
// Just hand everything to vasprintf, if it's available
len
=
vasprintf
(
strp
,
fmt
,
ap
);
#else
// Or do it the manual way
char
*
buf
;
len
=
vsnprintf
(
NULL
,
0
,
fmt
,
ap
);
if
(
len
>=
0
)
{
buf
=
malloc
(
++
len
);
if
(
buf
!=
NULL
)
{
// Hopefully, that's the right way to do it
va_end
(
ap
);
va_start
(
ap
,
fmt
);
// Write and return the data
len
=
vsnprintf
(
buf
,
len
,
fmt
,
ap
);
if
(
len
>=
0
)
{
*
strp
=
buf
;
}
else
{
free
(
buf
);
}
}
}
#endif
va_end
(
ap
);
return
len
;
}
// Return JSON string built from va_arg arguments
// If no longer needed, should be passed to free() by user
char
*
mkjson
(
enum
mkjson_container_type
otype
,
int
count
,
...
)
{
int
i
,
len
,
goodchunks
=
0
,
failure
=
0
;
char
*
json
,
*
prefix
,
**
chunks
,
ign
;
// Value - type and data
enum
mkjson_value_type
vtype
;
const
char
*
key
;
long
long
int
intval
;
long
double
dblval
;
const
char
*
strval
;
// Since v0.9 count cannot be a negative value and datatype is indicated by a separate argument
// Since I'm not sure whether it's right to put assertions in libraries, the next line is commented out
// assert( count >= 0 && "After v0.9 negative count is prohibited; please use otype argument instead" );
if
(
count
<
0
||
(
otype
!=
MKJSON_OBJ
&&
otype
!=
MKJSON_ARR
)
)
return
NULL
;
// Allocate chunk pointer array - on standard platforms each one should be NULL
chunks
=
calloc
(
count
,
sizeof
(
char
*
)
);
if
(
chunks
==
NULL
)
return
NULL
;
// This should rather be at the point of no return
va_list
ap
;
va_start
(
ap
,
count
);
// Create chunks
for
(
i
=
0
;
i
<
count
&&
!
failure
;
i
++
)
{
// Get value type
vtype
=
va_arg
(
ap
,
enum
mkjson_value_type
);
// Get key
if
(
otype
==
MKJSON_OBJ
)
{
key
=
va_arg
(
ap
,
char
*
);
if
(
key
==
NULL
)
{
failure
=
1
;
break
;
}
}
else
key
=
""
;
// Generate prefix
if
(
allsprintf
(
&
prefix
,
"%s%s%s"
,
otype
==
MKJSON_OBJ
?
"
\"
"
:
""
,
// Quote before key
key
,
// Key
otype
==
MKJSON_OBJ
?
"
\"
: "
:
""
)
==
-1
)
// Quote and colon after key
{
failure
=
1
;
break
;
}
// Depending on value type
ign
=
0
;
switch
(
vtype
)
{
// Ignore string / JSON data
case
MKJSON_IGN_STRING
:
case
MKJSON_IGN_JSON
:
(
void
)
va_arg
(
ap
,
const
char
*
);
ign
=
1
;
break
;
// Ignore string / JSON data and pass the pointer to free
case
MKJSON_IGN_STRING_FREE
:
case
MKJSON_IGN_JSON_FREE
:
free
(
va_arg
(
ap
,
char
*
)
);
ign
=
1
;
break
;
// Ignore int / long long int
case
MKJSON_IGN_INT
:
case
MKJSON_IGN_LLINT
:
if
(
vtype
==
MKJSON_IGN_INT
)
(
void
)
va_arg
(
ap
,
int
);
else
(
void
)
va_arg
(
ap
,
long
long
int
);
ign
=
1
;
break
;
// Ignore double / long double
case
MKJSON_IGN_DOUBLE
:
case
MKJSON_IGN_LDOUBLE
:
if
(
vtype
==
MKJSON_IGN_DOUBLE
)
(
void
)
va_arg
(
ap
,
double
);
else
(
void
)
va_arg
(
ap
,
long
double
);
ign
=
1
;
break
;
// Ignore boolean
case
MKJSON_IGN_BOOL
:
(
void
)
va_arg
(
ap
,
int
);
ign
=
1
;
break
;
// Ignore null value
case
MKJSON_IGN_NULL
:
ign
=
1
;
break
;
// A null-terminated string
case
MKJSON_STRING
:
case
MKJSON_STRING_FREE
:
strval
=
va_arg
(
ap
,
const
char
*
);
// If the pointer points to NULL, the string will be replaced with JSON null value
if
(
strval
==
NULL
)
{
if
(
allsprintf
(
chunks
+
i
,
"%snull"
,
prefix
)
==
-1
)
chunks
[
i
]
=
NULL
;
}
else
{
if
(
allsprintf
(
chunks
+
i
,
"%s
\"
%s
\"
"
,
prefix
,
strval
)
==
-1
)
chunks
[
i
]
=
NULL
;
}
// Optional free
if
(
vtype
==
MKJSON_STRING_FREE
)
free
(
(
char
*
)
strval
);
break
;
// Embed JSON data
case
MKJSON_JSON
:
case
MKJSON_JSON_FREE
:
strval
=
va_arg
(
ap
,
const
char
*
);
// If the pointer points to NULL, the JSON data is replaced with null value
if
(
allsprintf
(
chunks
+
i
,
"%s%s"
,
prefix
,
strval
==
NULL
?
"null"
:
strval
)
==
-1
)
chunks
[
i
]
=
NULL
;
// Optional free
if
(
vtype
==
MKJSON_JSON_FREE
)
free
(
(
char
*
)
strval
);
break
;
// int / long long int
case
MKJSON_INT
:
case
MKJSON_LLINT
:
if
(
vtype
==
MKJSON_INT
)
intval
=
va_arg
(
ap
,
int
);
else
intval
=
va_arg
(
ap
,
long
long
int
);
if
(
allsprintf
(
chunks
+
i
,
"%s%Ld"
,
prefix
,
intval
)
==
-1
)
chunks
[
i
]
=
NULL
;
break
;
// double / long double
case
MKJSON_DOUBLE
:
case
MKJSON_LDOUBLE
:
if
(
vtype
==
MKJSON_DOUBLE
)
dblval
=
va_arg
(
ap
,
double
);
else
dblval
=
va_arg
(
ap
,
long
double
);
if
(
allsprintf
(
chunks
+
i
,
"%s%Lf"
,
prefix
,
dblval
)
==
-1
)
chunks
[
i
]
=
NULL
;
break
;
// double / long double
case
MKJSON_SCI_DOUBLE
:
case
MKJSON_SCI_LDOUBLE
:
if
(
vtype
==
MKJSON_SCI_DOUBLE
)
dblval
=
va_arg
(
ap
,
double
);
else
dblval
=
va_arg
(
ap
,
long
double
);
if
(
allsprintf
(
chunks
+
i
,
"%s%Le"
,
prefix
,
dblval
)
==
-1
)
chunks
[
i
]
=
NULL
;
break
;
// Boolean
case
MKJSON_BOOL
:
intval
=
va_arg
(
ap
,
int
);
if
(
allsprintf
(
chunks
+
i
,
"%s%s"
,
prefix
,
intval
?
"true"
:
"false"
)
==
-1
)
chunks
[
i
]
=
NULL
;
break
;
// JSON null
case
MKJSON_NULL
:
if
(
allsprintf
(
chunks
+
i
,
"%snull"
,
prefix
)
==
-1
)
chunks
[
i
]
=
NULL
;
break
;
// Bad type specifier
default
:
chunks
[
i
]
=
NULL
;
break
;
}
// Free prefix memory
free
(
prefix
);
// NULL chunk without ignore flag indicates failure
if
(
!
ign
&&
chunks
[
i
]
==
NULL
)
failure
=
1
;
// NULL chunk now indicates ignore flag
if
(
ign
)
chunks
[
i
]
=
NULL
;
else
goodchunks
++
;
}
// We won't use ap anymore
va_end
(
ap
);
// If everything is fine, merge chunks and create full JSON table
if
(
!
failure
)
{
// Get total length (this is without NUL byte)
len
=
0
;
for
(
i
=
0
;
i
<
count
;
i
++
)
if
(
chunks
[
i
]
!=
NULL
)
len
+=
strlen
(
chunks
[
i
]
);
// Total length = Chunks length + 2 brackets + separators
if
(
goodchunks
==
0
)
goodchunks
=
1
;
len
=
len
+
2
+
(
goodchunks
-
1
)
*
2
;
// Allocate memory for the whole thing
json
=
calloc
(
len
+
1
,
sizeof
(
char
)
);
if
(
json
!=
NULL
)
{
// Merge chunks (and do not overwrite the first bracket)
for
(
i
=
0
;
i
<
count
;
i
++
)
{
// Add separators:
// - not on the begining
// - always after valid chunk
// - between two valid chunks
// - between valid and ignored chunk if the latter isn't the last one
if
(
i
!=
0
&&
chunks
[
i
-
1
]
!=
NULL
&&
(
chunks
[
i
]
!=
NULL
||
(
chunks
[
i
]
==
NULL
&&
i
!=
count
-
1
)
)
)
strcat
(
json
+
1
,
", "
);
if
(
chunks
[
i
]
!=
NULL
)
strcat
(
json
+
1
,
chunks
[
i
]
);
}
// Add proper brackets
json
[
0
]
=
otype
==
MKJSON_OBJ
?
'{'
:
'['
;
json
[
len
-
1
]
=
otype
==
MKJSON_OBJ
?
'}'
:
']'
;
}
}
else
json
=
NULL
;
// Free chunks
for
(
i
=
0
;
i
<
count
;
i
++
)
free
(
chunks
[
i
]
);
free
(
chunks
);
return
json
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, Oct 17, 12:54 AM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4399357
Default Alt Text
mkjson.c (7 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment