1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2016 Intel Corporation.
3 * All rights reserved.
4 */
5
6 /* Simple JSON "cat" utility */
7
8 #include "spdk/stdinc.h"
9
10 #include "spdk/json.h"
11 #include "spdk/file.h"
12
13 static void
usage(const char * prog)14 usage(const char *prog)
15 {
16 printf("usage: %s [-c] [-f] file.json\n", prog);
17 printf("Options:\n");
18 printf("-c\tallow comments in input (non-standard)\n");
19 printf("-f\tformatted output (default: compact output)\n");
20 }
21
22 static void
print_json_error(FILE * pf,int rc,const char * filename)23 print_json_error(FILE *pf, int rc, const char *filename)
24 {
25 switch (rc) {
26 case SPDK_JSON_PARSE_INVALID:
27 fprintf(pf, "%s: invalid JSON\n", filename);
28 break;
29 case SPDK_JSON_PARSE_INCOMPLETE:
30 fprintf(pf, "%s: incomplete JSON\n", filename);
31 break;
32 case SPDK_JSON_PARSE_MAX_DEPTH_EXCEEDED:
33 fprintf(pf, "%s: maximum nesting depth exceeded\n", filename);
34 break;
35 default:
36 fprintf(pf, "%s: unknown JSON parse error\n", filename);
37 break;
38 }
39 }
40
41 static int
json_write_cb(void * cb_ctx,const void * data,size_t size)42 json_write_cb(void *cb_ctx, const void *data, size_t size)
43 {
44 FILE *f = cb_ctx;
45 size_t rc;
46
47 rc = fwrite(data, 1, size, f);
48 return rc == size ? 0 : -1;
49 }
50
51 static int
process_file(const char * filename,FILE * f,uint32_t parse_flags,uint32_t write_flags)52 process_file(const char *filename, FILE *f, uint32_t parse_flags, uint32_t write_flags)
53 {
54 size_t size;
55 void *buf, *end;
56 ssize_t rc;
57 struct spdk_json_val *values;
58 size_t num_values;
59 struct spdk_json_write_ctx *w;
60
61 buf = spdk_posix_file_load(f, &size);
62 if (buf == NULL) {
63 fprintf(stderr, "%s: file read error\n", filename);
64 return 1;
65 }
66
67 rc = spdk_json_parse(buf, size, NULL, 0, NULL, parse_flags);
68 if (rc <= 0) {
69 print_json_error(stderr, rc, filename);
70 free(buf);
71 return 1;
72 }
73
74 num_values = (size_t)rc;
75 values = calloc(num_values, sizeof(*values));
76 if (values == NULL) {
77 perror("values calloc");
78 free(buf);
79 return 1;
80 }
81
82 rc = spdk_json_parse(buf, size, values, num_values, &end,
83 parse_flags | SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
84 if (rc <= 0) {
85 print_json_error(stderr, rc, filename);
86 free(values);
87 free(buf);
88 return 1;
89 }
90
91 w = spdk_json_write_begin(json_write_cb, stdout, write_flags);
92 if (w == NULL) {
93 fprintf(stderr, "json_write_begin failed\n");
94 free(values);
95 free(buf);
96 return 1;
97 }
98
99 spdk_json_write_val(w, values);
100 spdk_json_write_end(w);
101 printf("\n");
102
103 if (end != buf + size) {
104 fprintf(stderr, "%s: garbage at end of file\n", filename);
105 free(values);
106 free(buf);
107 return 1;
108 }
109
110 free(values);
111 free(buf);
112 return 0;
113 }
114
115 int
main(int argc,char ** argv)116 main(int argc, char **argv)
117 {
118 FILE *f;
119 int ch;
120 int rc;
121 uint32_t parse_flags = 0, write_flags = 0;
122 const char *filename;
123
124 while ((ch = getopt(argc, argv, "cf")) != -1) {
125 switch (ch) {
126 case 'c':
127 parse_flags |= SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS;
128 break;
129 case 'f':
130 write_flags |= SPDK_JSON_WRITE_FLAG_FORMATTED;
131 break;
132 default:
133 usage(argv[0]);
134 return 1;
135 }
136 }
137
138 if (optind == argc) {
139 filename = "-";
140 } else if (optind == argc - 1) {
141 filename = argv[optind];
142 } else {
143 usage(argv[0]);
144 return 1;
145 }
146
147 if (strcmp(filename, "-") == 0) {
148 f = stdin;
149 } else {
150 f = fopen(filename, "r");
151 if (f == NULL) {
152 perror("fopen");
153 return 1;
154 }
155 }
156
157 rc = process_file(filename, f, parse_flags, write_flags);
158
159 if (f != stdin) {
160 fclose(f);
161 }
162
163 return rc;
164 }
165