]> git.saurik.com Git - apple/system_cmds.git/blame - lsmp.tproj/json.h
system_cmds-790.tar.gz
[apple/system_cmds.git] / lsmp.tproj / json.h
CommitLineData
887d5eed
A
1/*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23/*
24 * Provides a stream-based API for generating JSON output
25 *
26 * Handles tedious tasks like worrying about comma placement (and avoiding trailing commas).
27 * Assumes strings are already escaped (if necessary) and does no error checking (thus it
28 * may produce invalid JSON when used improperly).
29 *
30 * As a convenience, when the provided `json` stream is NULL (i.e. it was never initialized
31 * by `JSON_OPEN`) these APIs will do nothing.
32 *
33 * Example usage:
34 *
35 * JSON_t json = JSON_OPEN("/path/to/output.json")
36 * JSON_OBJECT_BEGIN(json); // root object
37 *
38 * JSON_OBJECT_SET(json, version, %.1f, 1.0);
39 * JSON_OBJECT_SET_BOOL(json, has_fruit, 1);
40 *
41 * // Note the required quotes for strings (formatted or not)
42 * char *mystr = "hello";
43 * JSON_OBJECT_SET(json, formatted_string, "%s", mystr);
44 * JSON_OBJECT_SET(json, literal_string, "my literal string");
45 *
46 * JSON_KEY(json, fruit_array);
47 * JSON_ARRAY_BEGIN(json); // fruit_array
48 * JSON_ARRAY_APPEND(json, "my literal string");
49 * JSON_ARRAY_APPEND(json, "<0x%08llx>", 0xface);
50 * JSON_ARRAY_APPEND(json, %d, 3);
51 * JSON_ARRAY_END(json); // fruit_array
52 *
53 * JSON_OBJECT_END(json); // root object
54 * JSON_CLOSE(json);
55 */
56
57#ifndef _JSON_H_
58#define _JSON_H_
59
60#include <stdio.h>
61#include <stdlib.h>
62#include <stdbool.h>
63
64#define _JSON_IF(json, code) \
65 if (json != NULL) { \
66 code; \
67 }
68#define _JSON_COMMA(json) \
69 if (json->require_comma) { \
70 fprintf(json->stream, ","); \
71 }
72
73struct _JSON {
74 FILE* stream;
75 bool require_comma;
76};
77typedef struct _JSON * JSON_t;
78
79#pragma mark Open/Close
80/* Return a new JSON_t stream */
81static inline JSON_t JSON_OPEN(const char *path) {
82 JSON_t p = malloc(sizeof(struct _JSON));
83 p->stream = fopen(path, "w+");
84 p->require_comma = false;
85 return p;
86}
87
88/* Close an existing JSON stream, removing trailing commas */
89#define JSON_CLOSE(json) _JSON_IF(json, fclose(json->stream); free(json))
90
91#pragma mark Keys/Values
92/* Output the `key` half of a key/value pair */
93#define JSON_KEY(json, key) _JSON_IF(json, _JSON_COMMA(json); fprintf(json->stream, "\"" #key "\":"); json->require_comma = false)
94/* Output the `value` half of a key/value pair */
95#define JSON_VALUE(json, format, ...) _JSON_IF(json, fprintf(json->stream, #format, ##__VA_ARGS__); json->require_comma = true)
96
97#define _JSON_BEGIN(json, character) _JSON_COMMA(json); fprintf(json->stream, #character); json->require_comma = false;
98#define _JSON_END(json, character) fprintf(json->stream, #character); json->require_comma = true;
99#define _JSON_BOOL(val) ( val ? "true" : "false" )
100
101#pragma mark Objects
102/* Start a new JSON object */
103#define JSON_OBJECT_BEGIN(json) _JSON_IF(json, _JSON_BEGIN(json, {))
104/* Set a value in the current JSON object */
105#define JSON_OBJECT_SET(json, key, format, ...) _JSON_IF(json, JSON_KEY(json, key); JSON_VALUE(json, format, ##__VA_ARGS__))
106/* Set a boolean in the current JSON object */
107#define JSON_OBJECT_SET_BOOL(json, key, value) JSON_OBJECT_SET(json, key, %s, _JSON_BOOL(value))
108/* End the current JSON object */
109#define JSON_OBJECT_END(json) _JSON_IF(json, _JSON_END(json, }))
110
111#pragma mark Arrays
112/* Start a new JSON array */
113#define JSON_ARRAY_BEGIN(json) _JSON_IF(json, _JSON_BEGIN(json, [))
114/* Append a value to the current JSON array */
115#define JSON_ARRAY_APPEND(json, format, ...) _JSON_IF(json, _JSON_COMMA(json); JSON_VALUE(json, format, ##__VA_ARGS__))
116/* End the current JSON array */
117#define JSON_ARRAY_END(json) _JSON_IF(json, _JSON_END(json, ]))
118
119#endif /* _JSON_H_ */