xref: /spdk/test/app/jsoncat/jsoncat.c (revision 0098e636761237b77c12c30c2408263a5d2260cc)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 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
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
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
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
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
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