xref: /spdk/test/app/jsoncat/jsoncat.c (revision a6dbe3721eb3b5990707fc3e378c95e505dd8ab5)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse  *   Copyright (C) 2016 Intel Corporation.
396084b40SSeth Howell  *   All rights reserved.
496084b40SSeth Howell  */
596084b40SSeth Howell 
696084b40SSeth Howell /* Simple JSON "cat" utility */
796084b40SSeth Howell 
896084b40SSeth Howell #include "spdk/stdinc.h"
996084b40SSeth Howell 
1096084b40SSeth Howell #include "spdk/json.h"
11ad8bd8e3SChangpeng Liu #include "spdk/file.h"
1296084b40SSeth Howell 
1396084b40SSeth Howell static void
usage(const char * prog)1496084b40SSeth Howell usage(const char *prog)
1596084b40SSeth Howell {
1696084b40SSeth Howell 	printf("usage: %s [-c] [-f] file.json\n", prog);
1796084b40SSeth Howell 	printf("Options:\n");
1896084b40SSeth Howell 	printf("-c\tallow comments in input (non-standard)\n");
1996084b40SSeth Howell 	printf("-f\tformatted output (default: compact output)\n");
2096084b40SSeth Howell }
2196084b40SSeth Howell 
2296084b40SSeth Howell static void
print_json_error(FILE * pf,int rc,const char * filename)2396084b40SSeth Howell print_json_error(FILE *pf, int rc, const char *filename)
2496084b40SSeth Howell {
2596084b40SSeth Howell 	switch (rc) {
2696084b40SSeth Howell 	case SPDK_JSON_PARSE_INVALID:
2796084b40SSeth Howell 		fprintf(pf, "%s: invalid JSON\n", filename);
2896084b40SSeth Howell 		break;
2996084b40SSeth Howell 	case SPDK_JSON_PARSE_INCOMPLETE:
3096084b40SSeth Howell 		fprintf(pf, "%s: incomplete JSON\n", filename);
3196084b40SSeth Howell 		break;
3296084b40SSeth Howell 	case SPDK_JSON_PARSE_MAX_DEPTH_EXCEEDED:
3396084b40SSeth Howell 		fprintf(pf, "%s: maximum nesting depth exceeded\n", filename);
3496084b40SSeth Howell 		break;
3596084b40SSeth Howell 	default:
3696084b40SSeth Howell 		fprintf(pf, "%s: unknown JSON parse error\n", filename);
3796084b40SSeth Howell 		break;
3896084b40SSeth Howell 	}
3996084b40SSeth Howell }
4096084b40SSeth Howell 
4196084b40SSeth Howell static int
json_write_cb(void * cb_ctx,const void * data,size_t size)4296084b40SSeth Howell json_write_cb(void *cb_ctx, const void *data, size_t size)
4396084b40SSeth Howell {
4496084b40SSeth Howell 	FILE *f = cb_ctx;
4596084b40SSeth Howell 	size_t rc;
4696084b40SSeth Howell 
4796084b40SSeth Howell 	rc = fwrite(data, 1, size, f);
4896084b40SSeth Howell 	return rc == size ? 0 : -1;
4996084b40SSeth Howell }
5096084b40SSeth Howell 
5196084b40SSeth Howell static int
process_file(const char * filename,FILE * f,uint32_t parse_flags,uint32_t write_flags)5296084b40SSeth Howell process_file(const char *filename, FILE *f, uint32_t parse_flags, uint32_t write_flags)
5396084b40SSeth Howell {
5496084b40SSeth Howell 	size_t size;
5596084b40SSeth Howell 	void *buf, *end;
5696084b40SSeth Howell 	ssize_t rc;
5796084b40SSeth Howell 	struct spdk_json_val *values;
5896084b40SSeth Howell 	size_t num_values;
5996084b40SSeth Howell 	struct spdk_json_write_ctx *w;
6096084b40SSeth Howell 
61ad8bd8e3SChangpeng Liu 	buf = spdk_posix_file_load(f, &size);
6296084b40SSeth Howell 	if (buf == NULL) {
6396084b40SSeth Howell 		fprintf(stderr, "%s: file read error\n", filename);
6496084b40SSeth Howell 		return 1;
6596084b40SSeth Howell 	}
6696084b40SSeth Howell 
6796084b40SSeth Howell 	rc = spdk_json_parse(buf, size, NULL, 0, NULL, parse_flags);
6896084b40SSeth Howell 	if (rc <= 0) {
6996084b40SSeth Howell 		print_json_error(stderr, rc, filename);
7096084b40SSeth Howell 		free(buf);
7196084b40SSeth Howell 		return 1;
7296084b40SSeth Howell 	}
7396084b40SSeth Howell 
7496084b40SSeth Howell 	num_values = (size_t)rc;
7596084b40SSeth Howell 	values = calloc(num_values, sizeof(*values));
7696084b40SSeth Howell 	if (values == NULL) {
7796084b40SSeth Howell 		perror("values calloc");
7896084b40SSeth Howell 		free(buf);
7996084b40SSeth Howell 		return 1;
8096084b40SSeth Howell 	}
8196084b40SSeth Howell 
8296084b40SSeth Howell 	rc = spdk_json_parse(buf, size, values, num_values, &end,
8396084b40SSeth Howell 			     parse_flags | SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
8496084b40SSeth Howell 	if (rc <= 0) {
8596084b40SSeth Howell 		print_json_error(stderr, rc, filename);
8696084b40SSeth Howell 		free(values);
8796084b40SSeth Howell 		free(buf);
8896084b40SSeth Howell 		return 1;
8996084b40SSeth Howell 	}
9096084b40SSeth Howell 
9196084b40SSeth Howell 	w = spdk_json_write_begin(json_write_cb, stdout, write_flags);
9296084b40SSeth Howell 	if (w == NULL) {
9396084b40SSeth Howell 		fprintf(stderr, "json_write_begin failed\n");
9496084b40SSeth Howell 		free(values);
9596084b40SSeth Howell 		free(buf);
9696084b40SSeth Howell 		return 1;
9796084b40SSeth Howell 	}
9896084b40SSeth Howell 
9996084b40SSeth Howell 	spdk_json_write_val(w, values);
10096084b40SSeth Howell 	spdk_json_write_end(w);
10196084b40SSeth Howell 	printf("\n");
10296084b40SSeth Howell 
10396084b40SSeth Howell 	if (end != buf + size) {
10496084b40SSeth Howell 		fprintf(stderr, "%s: garbage at end of file\n", filename);
10596084b40SSeth Howell 		free(values);
10696084b40SSeth Howell 		free(buf);
10796084b40SSeth Howell 		return 1;
10896084b40SSeth Howell 	}
10996084b40SSeth Howell 
11096084b40SSeth Howell 	free(values);
11196084b40SSeth Howell 	free(buf);
11296084b40SSeth Howell 	return 0;
11396084b40SSeth Howell }
11496084b40SSeth Howell 
11596084b40SSeth Howell int
main(int argc,char ** argv)11696084b40SSeth Howell main(int argc, char **argv)
11796084b40SSeth Howell {
11896084b40SSeth Howell 	FILE *f;
11996084b40SSeth Howell 	int ch;
12096084b40SSeth Howell 	int rc;
12196084b40SSeth Howell 	uint32_t parse_flags = 0, write_flags = 0;
12296084b40SSeth Howell 	const char *filename;
12396084b40SSeth Howell 
12496084b40SSeth Howell 	while ((ch = getopt(argc, argv, "cf")) != -1) {
12596084b40SSeth Howell 		switch (ch) {
12696084b40SSeth Howell 		case 'c':
12796084b40SSeth Howell 			parse_flags |= SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS;
12896084b40SSeth Howell 			break;
12996084b40SSeth Howell 		case 'f':
13096084b40SSeth Howell 			write_flags |= SPDK_JSON_WRITE_FLAG_FORMATTED;
13196084b40SSeth Howell 			break;
13296084b40SSeth Howell 		default:
13396084b40SSeth Howell 			usage(argv[0]);
13496084b40SSeth Howell 			return 1;
13596084b40SSeth Howell 		}
13696084b40SSeth Howell 	}
13796084b40SSeth Howell 
13896084b40SSeth Howell 	if (optind == argc) {
13996084b40SSeth Howell 		filename = "-";
14096084b40SSeth Howell 	} else if (optind == argc - 1) {
14196084b40SSeth Howell 		filename = argv[optind];
14296084b40SSeth Howell 	} else {
14396084b40SSeth Howell 		usage(argv[0]);
14496084b40SSeth Howell 		return 1;
14596084b40SSeth Howell 	}
14696084b40SSeth Howell 
14796084b40SSeth Howell 	if (strcmp(filename, "-") == 0) {
14896084b40SSeth Howell 		f = stdin;
14996084b40SSeth Howell 	} else {
15096084b40SSeth Howell 		f = fopen(filename, "r");
15196084b40SSeth Howell 		if (f == NULL) {
15296084b40SSeth Howell 			perror("fopen");
15396084b40SSeth Howell 			return 1;
15496084b40SSeth Howell 		}
15596084b40SSeth Howell 	}
15696084b40SSeth Howell 
15796084b40SSeth Howell 	rc = process_file(filename, f, parse_flags, write_flags);
15896084b40SSeth Howell 
15996084b40SSeth Howell 	if (f != stdin) {
16096084b40SSeth Howell 		fclose(f);
16196084b40SSeth Howell 	}
16296084b40SSeth Howell 
16396084b40SSeth Howell 	return rc;
16496084b40SSeth Howell }
165