fmt.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  2. /*
  3. * Copyright 2017 Red Hat, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. #include "jose.h"
  18. #include <stdbool.h>
  19. #include <stdint.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <getopt.h>
  23. #include <ctype.h>
  24. #define SUMMARY "Converts JSON between serialization formats"
  25. #define JAIN json_array_insert_new
  26. #ifdef __MINGW32__
  27. #define sscanf __mingw_sscanf
  28. #endif
  29. static const char *prefix = "jose fmt [OPTIONS]\n\n" SUMMARY;
  30. typedef struct {
  31. json_t *args;
  32. } jcmd_opt_t;
  33. static size_t
  34. convert_int(const json_t *arr, const char *arg)
  35. {
  36. ssize_t indx = 0;
  37. if (sscanf(arg, "%zd", &indx) != 1)
  38. return SIZE_MAX;
  39. if (indx < 0)
  40. indx += json_array_size(arr);
  41. if (indx < 0)
  42. return SIZE_MAX;
  43. return indx;
  44. }
  45. static void
  46. jcmd_opt_cleanup(jcmd_opt_t *opt)
  47. {
  48. json_decref(opt->args);
  49. }
  50. static bool
  51. cmd_output(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  52. {
  53. const int wflags = JSON_ENCODE_ANY | JSON_COMPACT | JSON_SORT_KEYS;
  54. const char *s = json_string_value(arg);
  55. FILE *file = NULL;
  56. bool ret = false;
  57. if (strcmp(s, "-") == 0)
  58. file = stdout;
  59. else
  60. file = fopen(s, "w");
  61. if (!file)
  62. return false;
  63. if (json_dumpf(cur, file, wflags) < 0)
  64. goto egress;
  65. if (isatty(fileno(file)) && fwrite("\n", 1, 1, file) != 1)
  66. goto egress;
  67. ret = true;
  68. egress:
  69. if (strcmp(s, "-") != 0)
  70. fclose(file);
  71. return ret;
  72. }
  73. static bool
  74. cmd_foreach(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  75. {
  76. const int wflags = JSON_ENCODE_ANY | JSON_COMPACT | JSON_SORT_KEYS;
  77. const char *s = json_string_value(arg);
  78. FILE *file = NULL;
  79. bool ret = false;
  80. if (!json_is_array(cur) && !json_is_object(cur))
  81. return false;
  82. if (strcmp(s, "-") == 0)
  83. file = stdout;
  84. else
  85. file = fopen(s, "w");
  86. if (!file)
  87. return false;
  88. if (json_is_array(cur)) {
  89. json_t *v = NULL;
  90. size_t i = 0;
  91. json_array_foreach(cur, i, v) {
  92. if (json_dumpf(v, file, wflags) < 0 ||
  93. fprintf(file, "\n") < 0)
  94. goto egress;
  95. }
  96. } else if (json_is_object(cur)) {
  97. const char *k = NULL;
  98. json_t *v = NULL;
  99. json_object_foreach(cur, k, v) {
  100. if (fprintf(file, "%s=", k) < 0 ||
  101. json_dumpf(v, file, wflags) < 0 ||
  102. fprintf(file, "\n") < 0)
  103. goto egress;
  104. }
  105. }
  106. ret = true;
  107. egress:
  108. if (strcmp(s, "-") != 0)
  109. fclose(file);
  110. return ret;
  111. }
  112. static bool
  113. cmd_unquote(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  114. {
  115. const char *s = json_string_value(arg);
  116. FILE *file = NULL;
  117. bool ret = false;
  118. if (!json_is_string(cur))
  119. return false;
  120. if (strcmp(s, "-") == 0)
  121. return fprintf(stdout, "%s\n", json_string_value(cur)) >= 0;
  122. file = fopen(s, "w");
  123. if (!file)
  124. return false;
  125. ret = fprintf(file, "%s\n", json_string_value(cur)) >= 0;
  126. fclose(file);
  127. return ret;
  128. }
  129. static bool
  130. cmd_move(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  131. {
  132. json_int_t i = json_integer_value(arg);
  133. if (json_array_insert(stk, i + 1, cur) < 0)
  134. return false;
  135. if (json_array_remove(stk, 0) < 0)
  136. return false;
  137. return true;
  138. }
  139. static bool
  140. cmd_trunc(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  141. {
  142. size_t i = json_integer_value(arg);
  143. size_t s;
  144. for (s = json_array_size(cur); s > i; s--) {
  145. if (json_array_remove(cur, s - 1) < 0)
  146. return false;
  147. }
  148. return true;
  149. }
  150. static bool
  151. cmd_insert(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  152. {
  153. size_t i = json_integer_value(arg);
  154. return json_array_insert(lst, i, cur) >= 0;
  155. }
  156. static bool
  157. cmd_append(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  158. {
  159. if (json_is_array(lst))
  160. return json_array_append(lst, cur) >= 0;
  161. if (json_is_object(lst))
  162. return json_object_update_missing(lst, cur) >= 0;
  163. return false;
  164. }
  165. static bool
  166. cmd_extend(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  167. {
  168. if (json_is_array(lst))
  169. return json_array_extend(lst, cur) >= 0;
  170. if (json_is_object(lst))
  171. return json_object_update(lst, cur) >= 0;
  172. return false;
  173. }
  174. static bool
  175. cmd_delete(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  176. {
  177. const char *s = json_string_value(arg);
  178. if (json_is_array(cur)) {
  179. size_t indx;
  180. indx = convert_int(cur, s);
  181. if (indx == SIZE_MAX)
  182. return false;
  183. return json_array_remove(cur, indx) >= 0;
  184. }
  185. if (json_is_object(cur))
  186. return json_object_del(cur, s) >= 0;
  187. return false;
  188. }
  189. static bool
  190. cmd_length(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  191. {
  192. size_t count = 0;
  193. if (json_is_array(cur))
  194. count = json_array_size(cur);
  195. else if (json_is_object(cur))
  196. count = json_object_size(cur);
  197. else if (json_is_string(cur))
  198. count = json_string_length(cur);
  199. else
  200. return false;
  201. return json_array_insert_new(stk, 0, json_integer(count)) >= 0;
  202. }
  203. static bool
  204. cmd_empty(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  205. {
  206. if (json_is_array(cur))
  207. return json_array_clear(cur) >= 0;
  208. if (json_is_object(cur))
  209. return json_object_clear(cur) >= 0;
  210. return false;
  211. }
  212. static bool
  213. cmd_get(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  214. {
  215. const char *s = json_string_value(arg);
  216. json_t *v = NULL;
  217. if (json_is_array(cur)) {
  218. size_t indx;
  219. indx = convert_int(cur, s);
  220. if (indx == SIZE_MAX)
  221. return false;
  222. v = json_array_get(cur, indx);
  223. } else if (json_is_object(cur)) {
  224. v = json_object_get(cur, s);
  225. } else {
  226. return false;
  227. }
  228. return json_array_insert(stk, 0, v) >= 0;
  229. }
  230. static bool
  231. cmd_set(const json_t *arg, json_t *stk, json_t *cur, json_t *lst)
  232. {
  233. const char *s = json_string_value(arg);
  234. if (json_is_array(lst)) {
  235. size_t indx;
  236. indx = convert_int(lst, s);
  237. if (indx == SIZE_MAX)
  238. return false;
  239. return json_array_set(lst, indx, cur) >= 0;
  240. }
  241. if (json_is_object(lst))
  242. return json_object_set(lst, s, cur) >= 0;
  243. return false;
  244. }
  245. static const jcmd_doc_t doc_not[] = {
  246. { .doc = "Invert the following assertion" },
  247. {}
  248. };
  249. static const jcmd_doc_t doc_object[] = {
  250. { .doc = "Assert TOP to be an object" },
  251. {}
  252. };
  253. static const jcmd_doc_t doc_array[] = {
  254. { .doc = "Assert TOP to be an array" },
  255. {}
  256. };
  257. static const jcmd_doc_t doc_string[] = {
  258. { .doc = "Assert TOP to be a string" },
  259. {}
  260. };
  261. static const jcmd_doc_t doc_int[] = {
  262. { .doc = "Assert TOP to be an integer" },
  263. {}
  264. };
  265. static const jcmd_doc_t doc_real[] = {
  266. { .doc = "Assert TOP to be a real" },
  267. {}
  268. };
  269. static const jcmd_doc_t doc_number[] = {
  270. { .doc = "Assert TOP to be a number" },
  271. {}
  272. };
  273. static const jcmd_doc_t doc_true[] = {
  274. { .doc = "Assert TOP to be true" },
  275. {}
  276. };
  277. static const jcmd_doc_t doc_false[] = {
  278. { .doc = "Assert TOP to be false" },
  279. {}
  280. };
  281. static const jcmd_doc_t doc_bool[] = {
  282. { .doc = "Assert TOP to be a boolean" },
  283. {}
  284. };
  285. static const jcmd_doc_t doc_null[] = {
  286. { .doc = "Assert TOP to be null" },
  287. {}
  288. };
  289. static const jcmd_doc_t doc_equal[] = {
  290. { .doc = "Assert TOP to be equal to PREV" },
  291. {}
  292. };
  293. static const jcmd_doc_t doc_json[] = {
  294. { .arg = "JSON", .doc = "Parse JSON constant, push onto TOP" },
  295. { .arg = "FILE", .doc = "Read from FILE, push onto TOP" },
  296. { .arg = "-", .doc = "Read from STDIN, push onto TOP" },
  297. {}
  298. };
  299. static const jcmd_doc_t doc_quote[] = {
  300. { .arg = "STR", .doc = "Convert STR to a string, push onto TOP" },
  301. {}
  302. };
  303. static const jcmd_doc_t doc_output[] = {
  304. { .arg = "FILE", .doc = "Write TOP to FILE" },
  305. { .arg = "-", .doc = "Write TOP to STDOUT" },
  306. {}
  307. };
  308. static const jcmd_doc_t doc_foreach[] = {
  309. { .arg = "FILE", .doc = "Write TOP (obj./arr.) to FILE, one line/item" },
  310. { .arg = "-", .doc = "Write TOP (obj./arr.) to STDOUT, one line/item" },
  311. {}
  312. };
  313. static const jcmd_doc_t doc_unquote[] = {
  314. { .arg = "FILE", .doc = "Write TOP (str.) to FILE without quotes" },
  315. { .arg = "-", .doc = "Write TOP (str.) to STDOUT without quotes" },
  316. {}
  317. };
  318. static const jcmd_doc_t doc_copy[] = {
  319. { .doc = "Deep copy TOP, push onto TOP" },
  320. {}
  321. };
  322. static const jcmd_doc_t doc_query[] = {
  323. { .doc = "Query the stack by deep copying and pushing onto TOP" },
  324. {}
  325. };
  326. static const jcmd_doc_t doc_move[] = {
  327. { .arg = "#", .doc = "Move TOP back # places on the stack" },
  328. {}
  329. };
  330. static const jcmd_doc_t doc_unwind[] = {
  331. { .doc = "Discard TOP from the stack" },
  332. {}
  333. };
  334. static const jcmd_doc_t doc_trunc[] = {
  335. { .arg = "#", .doc = "Shrink TOP (arr.) to length #" },
  336. { .arg = "-#", .doc = "Discard last # items from TOP (arr.)" },
  337. {}
  338. };
  339. static const jcmd_doc_t doc_insert[] = {
  340. { .arg = "#", .doc = "Insert TOP into PREV (arr.) at #" },
  341. {}
  342. };
  343. static const jcmd_doc_t doc_append[] = {
  344. { .doc = "Append TOP to the end of PREV (arr.)" },
  345. { .doc = "Set missing values from TOP (obj.) into PREV (obj.)" },
  346. {}
  347. };
  348. static const jcmd_doc_t doc_extend[] = {
  349. { .doc = "Append items from TOP to the end of PREV (arr.)" },
  350. { .doc = "Set all values from TOP (obj.) into PREV (obj.)" },
  351. {}
  352. };
  353. static const jcmd_doc_t doc_delete[] = {
  354. { .arg = "NAME", .doc = "Delete NAME from TOP (obj.)" },
  355. { .arg = "#", .doc = "Delete # from TOP (arr.)" },
  356. { .arg = "-#", .doc = "Delete # from the end of TOP (arr.)" },
  357. {}
  358. };
  359. static const jcmd_doc_t doc_length[] = {
  360. { .doc = "Push length of TOP (arr./str./obj.) to TOP" },
  361. {}
  362. };
  363. static const jcmd_doc_t doc_empty[] = {
  364. { .doc = "Erase all items from TOP (arr./obj.)" },
  365. {}
  366. };
  367. static const jcmd_doc_t doc_get[] = {
  368. { .arg = "NAME", .doc = "Get item with NAME from TOP (obj.), push to TOP" },
  369. { .arg = "#", .doc = "Get # item from TOP (arr.), push to TOP" },
  370. { .arg = "-#", .doc = "Get # item from the end of TOP (arr.), push to TOP" },
  371. {}
  372. };
  373. static const jcmd_doc_t doc_set[] = {
  374. { .arg = "NAME", .doc = "Sets TOP into PREV (obj.) with NAME" },
  375. { .arg = "#", .doc = "Sets TOP into PREV (obj.) at #" },
  376. { .arg = "-#", .doc = "Sets TOP into PREV (obj.) at # from the end" },
  377. {}
  378. };
  379. static const jcmd_doc_t doc_b64l[] = {
  380. { .doc = "URL-safe Base64 decode TOP (str.), push onto TOP" },
  381. {}
  382. };
  383. static const jcmd_doc_t doc_b64d[] = {
  384. { .doc = "URL-safe Base64 encode TOP, push onto TOP" },
  385. {}
  386. };
  387. static bool
  388. opt_set_null(const jcmd_cfg_t *cfg, void *vopt, const char *arg)
  389. {
  390. json_t **x = vopt;
  391. if (!*x) *x = json_array();
  392. return json_array_append_new(*x, json_pack("[i,n]", cfg->opt.val)) >= 0;
  393. }
  394. static bool
  395. opt_set_str(const jcmd_cfg_t *cfg, void *vopt, const char *arg)
  396. {
  397. json_t **x = vopt;
  398. if (!*x) *x = json_array();
  399. return json_array_append_new(*x, json_pack("[i,s]", cfg->opt.val, arg)) >= 0;
  400. }
  401. static bool
  402. opt_set_int(const jcmd_cfg_t *cfg, void *vopt, const char *arg)
  403. {
  404. json_t **x = vopt;
  405. json_int_t j = 0;
  406. int i = 0;
  407. if (sscanf(arg, "%d", &i) != 1)
  408. return false;
  409. j = i;
  410. if (!*x) *x = json_array();
  411. return json_array_append_new(*x, json_pack("[i,I]", cfg->opt.val, j)) >= 0;
  412. }
  413. static bool
  414. opt_set_uint(const jcmd_cfg_t *cfg, void *vopt, const char *arg)
  415. {
  416. unsigned int i = 0;
  417. json_t **x = vopt;
  418. json_int_t j = 0;
  419. if (sscanf(arg, "%u", &i) != 1)
  420. return false;
  421. j = i;
  422. if (!*x) *x = json_array();
  423. return json_array_append_new(*x, json_pack("[i,I]", cfg->opt.val, j)) >= 0;
  424. }
  425. static bool
  426. opt_set_json(const jcmd_cfg_t *cfg, void *vopt, const char *arg)
  427. {
  428. json_auto_t *j = NULL;
  429. json_t **x = vopt;
  430. if (!jcmd_opt_set_json(cfg, &j, arg))
  431. return false;
  432. if (!*x) *x = json_array();
  433. return json_array_append_new(*x, json_pack("[i,O]", cfg->opt.val, j)) >= 0;
  434. }
  435. static const jcmd_cfg_t cfgs[] = {
  436. { .opt = { "not", no_argument, .val = 'X' }, .doc = doc_not,
  437. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  438. { .opt = { "object", no_argument, .val = 'O' }, .doc = doc_object,
  439. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  440. { .opt = { "array", no_argument, .val = 'A' }, .doc = doc_array,
  441. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  442. { .opt = { "string", no_argument, .val = 'S' }, .doc = doc_string,
  443. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  444. { .opt = { "integer", no_argument, .val = 'I' }, .doc = doc_int,
  445. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  446. { .opt = { "real", no_argument, .val = 'R' }, .doc = doc_real,
  447. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  448. { .opt = { "number", no_argument, .val = 'N' }, .doc = doc_number,
  449. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  450. { .opt = { "true", no_argument, .val = 'T' }, .doc = doc_true,
  451. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  452. { .opt = { "false", no_argument, .val = 'F' }, .doc = doc_false,
  453. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  454. { .opt = { "boolean", no_argument, .val = 'B' }, .doc = doc_bool,
  455. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  456. { .opt = { "null", no_argument, .val = '0' }, .doc = doc_null,
  457. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  458. { .opt = { "equal", no_argument, .val = 'E' }, .doc = doc_equal,
  459. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  460. { .opt = { "query", no_argument, .val = 'Q' }, .doc = doc_query,
  461. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  462. { .opt = { "move", required_argument, .val = 'M' }, .doc = doc_move,
  463. .set = opt_set_uint, .off = offsetof(jcmd_opt_t, args) },
  464. { .opt = { "unwind", no_argument, .val = 'U' }, .doc = doc_unwind,
  465. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  466. { .opt = { "json", required_argument, .val = 'j' }, .doc = doc_json,
  467. .set = opt_set_json, .off = offsetof(jcmd_opt_t, args) },
  468. { .opt = { "copy", no_argument, .val = 'c' }, .doc = doc_copy,
  469. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  470. { .opt = { "quote", required_argument, .val = 'q' }, .doc = doc_quote,
  471. .set = opt_set_str, .off = offsetof(jcmd_opt_t, args) },
  472. { .opt = { "output", required_argument, .val = 'o' }, .doc = doc_output,
  473. .set = opt_set_str, .off = offsetof(jcmd_opt_t, args) },
  474. { .opt = { "foreach", required_argument, .val = 'f' }, .doc = doc_foreach,
  475. .set = opt_set_str, .off = offsetof(jcmd_opt_t, args) },
  476. { .opt = { "unquote", required_argument, .val = 'u' }, .doc = doc_unquote,
  477. .set = opt_set_str, .off = offsetof(jcmd_opt_t, args) },
  478. { .opt = { "truncate", required_argument, .val = 't' }, .doc = doc_trunc,
  479. .set = opt_set_int, .off = offsetof(jcmd_opt_t, args) },
  480. { .opt = { "insert", required_argument, .val = 'i' }, .doc = doc_insert,
  481. .set = opt_set_uint, .off = offsetof(jcmd_opt_t, args) },
  482. { .opt = { "append", no_argument, .val = 'a' }, .doc = doc_append,
  483. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  484. { .opt = { "extend", no_argument, .val = 'x' }, .doc = doc_extend,
  485. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  486. { .opt = { "delete", required_argument, .val = 'd' }, .doc = doc_delete,
  487. .set = opt_set_str, .off = offsetof(jcmd_opt_t, args) },
  488. { .opt = { "length", no_argument, .val = 'l' }, .doc = doc_length,
  489. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  490. { .opt = { "empty", no_argument, .val = 'e' }, .doc = doc_empty,
  491. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  492. { .opt = { "get", required_argument, .val = 'g' }, .doc = doc_get,
  493. .set = opt_set_str, .off = offsetof(jcmd_opt_t, args) },
  494. { .opt = { "set", required_argument, .val = 's' }, .doc = doc_set,
  495. .set = opt_set_str, .off = offsetof(jcmd_opt_t, args) },
  496. { .opt = { "b64load", no_argument, .val = 'y' }, .doc = doc_b64l,
  497. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  498. { .opt = { "b64dump", no_argument, .val = 'Y' }, .doc = doc_b64d,
  499. .set = opt_set_null, .off = offsetof(jcmd_opt_t, args) },
  500. {}
  501. };
  502. static int
  503. jcmd_fmt(int argc, char *argv[])
  504. {
  505. json_auto_t *stk = json_array();
  506. jcmd_opt_auto_t opt = {};
  507. unsigned char ret = 0;
  508. bool not = false;
  509. if (!jcmd_opt_parse(argc, argv, cfgs, &opt, prefix))
  510. return -1;
  511. for (size_t i = 0; i < json_array_size(opt.args); i++) {
  512. json_t *lst = NULL;
  513. json_t *cur = NULL;
  514. json_t *p = NULL;
  515. bool ok = false;
  516. int o = 0;
  517. if (json_unpack(json_array_get(opt.args, i), "[i,o!]", &o, &p) < 0)
  518. return ++ret;
  519. if (not && !strchr("OASIRNTFB0E", o))
  520. return ret;
  521. cur = json_array_get(stk, 0);
  522. lst = json_array_get(stk, 1);
  523. ret++;
  524. switch (o) {
  525. case 'X': ok = not = true; break;
  526. case 'O': ok = not ^ json_is_object(cur); not = false; break;
  527. case 'A': ok = not ^ json_is_array(cur); not = false; break;
  528. case 'S': ok = not ^ json_is_string(cur); not = false; break;
  529. case 'I': ok = not ^ json_is_integer(cur); not = false; break;
  530. case 'R': ok = not ^ json_is_real(cur); not = false; break;
  531. case 'N': ok = not ^ json_is_number(cur); not = false; break;
  532. case 'T': ok = not ^ json_is_true(cur); not = false; break;
  533. case 'F': ok = not ^ json_is_false(cur); not = false; break;
  534. case 'B': ok = not ^ json_is_boolean(cur); not = false; break;
  535. case '0': ok = not ^ json_is_null(cur); not = false; break;
  536. case 'E': ok = not ^ json_equal(cur, lst); not = false; break;
  537. case 'Q': ok = JAIN(stk, 0, json_deep_copy(stk)) >= 0; break;
  538. case 'M': ok = cmd_move(p, stk, cur, lst); break;
  539. case 'U': ok = json_array_remove(stk, 0) >= 0; break;
  540. case 'j': ok = json_array_insert(stk, 0, p) >= 0; break;
  541. case 'c': ok = JAIN(stk, 0, json_deep_copy(cur)) >= 0; break;
  542. case 'q': ok = json_array_insert(stk, 0, p) >= 0; break;
  543. case 'o': ok = cmd_output(p, stk, cur, lst); break;
  544. case 'f': ok = cmd_foreach(p, stk, cur, lst); break;
  545. case 'u': ok = cmd_unquote(p, stk, cur, lst); break;
  546. case 't': ok = cmd_trunc(p, stk, cur, lst); break;
  547. case 'i': ok = cmd_insert(p, stk, cur, lst); break;
  548. case 'a': ok = cmd_append(p, stk, cur, lst); break;
  549. case 'x': ok = cmd_extend(p, stk, cur, lst); break;
  550. case 'd': ok = cmd_delete(p, stk, cur, lst); break;
  551. case 'l': ok = cmd_length(p, stk, cur, lst); break;
  552. case 'e': ok = cmd_empty(p, stk, cur, lst); break;
  553. case 'g': ok = cmd_get(p, stk, cur, lst); break;
  554. case 's': ok = cmd_set(p, stk, cur, lst); break;
  555. case 'Y': ok = JAIN(stk, 0, jose_b64_enc_dump(cur)) >= 0; break;
  556. case 'y': ok = JAIN(stk, 0, jose_b64_dec_load(cur)) >= 0; break;
  557. default: ok = false; break;
  558. }
  559. if (!ok)
  560. return ret;
  561. }
  562. if (not)
  563. return ret;
  564. return EXIT_SUCCESS;
  565. }
  566. JCMD_REGISTER(SUMMARY, jcmd_fmt, "fmt")