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