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