GCC Code Coverage Report


Directory: ./
File: submodules/json-c/apps/json_parse.c
Date: 2023-09-29 04:53:15
Exec Total Coverage
Lines: 0 69 0.0%
Branches: 0 37 0.0%

Line Branch Exec Source
1 #include <assert.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <getopt.h>
5 #include <stddef.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10
11 #include "apps_config.h"
12
13 /* XXX for a regular program, these should be <json-c/foo.h>
14 * but that's inconvenient when building in the json-c source tree.
15 */
16 #include "json_object.h"
17 #include "json_tokener.h"
18 #include "json_util.h"
19
20 #ifdef HAVE_SYS_RESOURCE_H
21 #include <sys/resource.h>
22 #include <sys/time.h>
23 #endif
24
25 #ifndef JSON_NORETURN
26 #if defined(_MSC_VER)
27 #define JSON_NORETURN __declspec(noreturn)
28 #elif defined(__OS400__)
29 #define JSON_NORETURN
30 #else
31 /* 'cold' attribute is for optimization, telling the computer this code
32 * path is unlikely.
33 */
34 #define JSON_NORETURN __attribute__((noreturn, cold))
35 #endif
36 #endif
37
38 static int formatted_output = 0;
39 static int show_output = 1;
40 static int strict_mode = 0;
41 static const char *fname = NULL;
42
43 #ifndef HAVE_JSON_TOKENER_GET_PARSE_END
44 #define json_tokener_get_parse_end(tok) ((tok)->char_offset)
45 #endif
46
47 JSON_NORETURN static void usage(const char *argv0, int exitval, const char *errmsg);
48 static void showmem(void);
49 static int parseit(int fd, int (*callback)(struct json_object *));
50 static int showobj(struct json_object *new_obj);
51
52 static void showmem(void)
53 {
54 #ifdef HAVE_GETRUSAGE
55 struct rusage rusage;
56 memset(&rusage, 0, sizeof(rusage));
57 getrusage(RUSAGE_SELF, &rusage);
58 printf("maxrss: %ld KB\n", rusage.ru_maxrss);
59 #endif
60 }
61
62 static int parseit(int fd, int (*callback)(struct json_object *))
63 {
64 struct json_object *obj;
65 char buf[32768];
66 ssize_t ret;
67 int depth = JSON_TOKENER_DEFAULT_DEPTH;
68 json_tokener *tok;
69
70 tok = json_tokener_new_ex(depth);
71 if (!tok)
72 {
73 fprintf(stderr, "unable to allocate json_tokener: %s\n", strerror(errno));
74 return 1;
75 }
76 json_tokener_set_flags(tok, JSON_TOKENER_STRICT
77 #ifdef JSON_TOKENER_ALLOW_TRAILING_CHARS
78 | JSON_TOKENER_ALLOW_TRAILING_CHARS
79 #endif
80 );
81
82 // XXX push this into some kind of json_tokener_parse_fd API?
83 // json_object_from_fd isn't flexible enough, and mirroring
84 // everything you can do with a tokener into json_util.c seems
85 // like the wrong approach.
86 size_t total_read = 0;
87 while ((ret = read(fd, buf, sizeof(buf))) > 0)
88 {
89 size_t retu = (size_t)ret; // We know it's positive
90 total_read += retu;
91 size_t start_pos = 0;
92 while (start_pos != retu)
93 {
94 obj = json_tokener_parse_ex(tok, &buf[start_pos], retu - start_pos);
95 enum json_tokener_error jerr = json_tokener_get_error(tok);
96 size_t parse_end = json_tokener_get_parse_end(tok);
97 if (obj == NULL && jerr != json_tokener_continue)
98 {
99 const char *aterr = (start_pos + parse_end < (int)sizeof(buf)) ?
100 &buf[start_pos + parse_end] : "";
101 fflush(stdout);
102 size_t fail_offset = total_read - retu + start_pos + parse_end;
103 fprintf(stderr, "Failed at offset %lu: %s %c\n", (unsigned long)fail_offset,
104 json_tokener_error_desc(jerr), aterr[0]);
105 json_tokener_free(tok);
106 return 1;
107 }
108 if (obj != NULL)
109 {
110 int cb_ret = callback(obj);
111 json_object_put(obj);
112 if (cb_ret != 0)
113 {
114 json_tokener_free(tok);
115 return 1;
116 }
117 }
118 start_pos += json_tokener_get_parse_end(tok);
119 assert(start_pos <= retu);
120 }
121 }
122 if (ret < 0)
123 {
124 fprintf(stderr, "error reading fd %d: %s\n", fd, strerror(errno));
125 }
126
127 json_tokener_free(tok);
128 return 0;
129 }
130
131 static int showobj(struct json_object *new_obj)
132 {
133 if (new_obj == NULL)
134 {
135 fprintf(stderr, "%s: Failed to parse\n", fname);
136 return 1;
137 }
138
139 printf("Successfully parsed object from %s\n", fname);
140
141 if (show_output)
142 {
143 const char *output;
144 if (formatted_output)
145 output = json_object_to_json_string(new_obj);
146 else
147 output = json_object_to_json_string_ext(new_obj, JSON_C_TO_STRING_PRETTY);
148 printf("%s\n", output);
149 }
150
151 showmem();
152 return 0;
153 }
154
155 static void usage(const char *argv0, int exitval, const char *errmsg)
156 {
157 FILE *fp = stdout;
158 if (exitval != 0)
159 fp = stderr;
160 if (errmsg != NULL)
161 fprintf(fp, "ERROR: %s\n\n", errmsg);
162 fprintf(fp, "Usage: %s [-f] [-n] [-s]\n", argv0);
163 fprintf(fp, " -f - Format the output with JSON_C_TO_STRING_PRETTY\n");
164 fprintf(fp, " -n - No output\n");
165 fprintf(fp, " -s - Parse in strict mode, flags:\n");
166 fprintf(fp, " JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS\n");
167
168 fprintf(fp, "\nWARNING WARNING WARNING\n");
169 fprintf(fp, "This is a prototype, it may change or be removed at any time!\n");
170 exit(exitval);
171 }
172
173 int main(int argc, char **argv)
174 {
175 int opt;
176
177 while ((opt = getopt(argc, argv, "fhns")) != -1)
178 {
179 switch (opt)
180 {
181 case 'f': formatted_output = 1; break;
182 case 'n': show_output = 0; break;
183 case 's': strict_mode = 1; break;
184 case 'h': usage(argv[0], 0, NULL);
185 default: /* '?' */ usage(argv[0], EXIT_FAILURE, "Unknown arguments");
186 }
187 }
188 if (optind >= argc)
189 {
190 usage(argv[0], EXIT_FAILURE, "Expected argument after options");
191 }
192 fname = argv[optind];
193
194 int fd = open(argv[optind], O_RDONLY, 0);
195 showmem();
196 if (parseit(fd, showobj) != 0)
197 exit(EXIT_FAILURE);
198 showmem();
199
200 exit(EXIT_SUCCESS);
201 }
202