aboutsummaryrefslogtreecommitdiff
path: root/tests/json.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/json.c')
-rw-r--r--tests/json.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/tests/json.c b/tests/json.c
new file mode 100644
index 0000000..f2c2380
--- /dev/null
+++ b/tests/json.c
@@ -0,0 +1,286 @@
+/* grecs - Gray's Extensible Configuration System
+ Copyright (C) 2007-2012, 2015 Sergey Poznyakoff
+
+ Grecs is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ Grecs is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Grecs. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "grecs.h"
+#include "json.h"
+
+size_t indent;
+int pretty_print;
+int precision = -1;
+
+static void
+usage(const char *arg, FILE *fp, int code)
+{
+ fprintf(fp,
+ "usage: %s [-file=FILE][-indent=N][-precision=N] [expr]\n",
+ arg);
+ exit(code);
+}
+
+static void
+json_indent(FILE *fp, size_t level)
+{
+ level *= indent;
+ while (level--)
+ fputc(' ', fp);
+}
+
+static void
+json_format_delim(FILE *fp, size_t level)
+{
+ fputc(',', fp);
+ if (indent) {
+ fputc('\n', fp);
+ json_indent(fp, level);
+ } else
+ fputc(' ', fp);
+}
+
+static int
+escape(char c, char *o)
+{
+ static char transtab[] = "\\\\\"\"//b\bf\fn\nr\rt\t";
+ char *p;
+
+ for (p = transtab; *p; p += 2) {
+ if (p[1] == c) {
+ *o = p[0];
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static void
+json_format_string(FILE *fp, const char *s)
+{
+ fputc('"', fp);
+ for (; *s; s++) {
+ char c;
+ if (!escape(*s, &c)) {
+ fputc('\\', fp);
+ fputc(c, fp);
+ } else
+ fputc(*s, fp);
+ }
+ fputc('"', fp);
+}
+
+static int
+collect_keypairs(void *sym, void *data)
+{
+ struct json_pair *p = sym;
+ struct json_pair ***kp = data;
+ **kp = p;
+ ++*kp;
+ return 0;
+}
+
+static void json_format_value(FILE *fp, struct json_value *obj, size_t level);
+
+static int
+keypair_cmp_name(const void *a, const void *b)
+{
+ struct json_pair const * const *kpa = a;
+ struct json_pair const * const *kpb = b;
+ return strcmp((*kpa)->k, (*kpb)->k);
+}
+
+static void
+json_format_obj(FILE *fp, struct json_value *obj, size_t level)
+{
+ size_t count, i;
+ struct json_pair **keypairs, **kp;
+
+ count = grecs_symtab_count_entries(obj->v.o);
+ keypairs = grecs_calloc(count, sizeof(*keypairs));
+ kp = keypairs;
+ grecs_symtab_enumerate(obj->v.o, collect_keypairs, &kp);
+ qsort(keypairs, count, sizeof(*keypairs), keypair_cmp_name);
+
+ fputc('{', fp);
+ if (count) {
+ if (indent)
+ fputc('\n', fp);
+ for (i = 0; i < count; i++) {
+ (i ? json_format_delim : json_indent)(fp, level);
+ json_format_string(fp, keypairs[i]->k);
+ fputc(':', fp);
+ if (indent)
+ fputc(' ', fp);
+ json_format_value(fp, keypairs[i]->v, level);
+ }
+ if (indent) {
+ fputc('\n', fp);
+ json_indent(fp, level-1);
+ }
+ }
+ fputc('}', fp);
+}
+
+static void
+json_format_array(FILE *fp, struct json_value *obj, size_t level)
+{
+ size_t i;
+
+ fputc('[', fp);
+ if (obj->v.a->oc) {
+ if (indent)
+ fputc('\n', fp);
+ for (i = 0; i < obj->v.a->oc; i++) {
+ (i ? json_format_delim : json_indent)(fp, level);
+ json_format_value(fp, obj->v.a->ov[i], level);
+ }
+ if (indent) {
+ fputc('\n', fp);
+ json_indent(fp, level-1);
+ }
+ }
+ fputc(']', fp);
+}
+
+static void
+json_format_value(FILE *fp, struct json_value *obj, size_t level)
+{
+ if (!obj) {
+ fprintf(fp, "null");
+ return;
+ }
+
+ ++level;
+ switch (obj->type) {
+ case json_null:
+ fprintf(fp, "null");
+ break;
+
+ case json_bool:
+ fprintf(fp, "%s", obj->v.b ? "true" : "false");
+ break;
+
+ case json_number:
+ if (precision == -1)
+ fprintf(fp, "%e", obj->v.n);
+ else
+ fprintf(fp, "%.*f", precision, obj->v.n);
+ break;
+
+ case json_string:
+ json_format_string(fp, obj->v.s);
+ break;
+
+ case json_arr:
+ json_format_array(fp, obj, level);
+ break;
+
+ case json_object:
+ json_format_obj(fp, obj, level);
+ break;
+ }
+}
+
+
+int
+main(int argc, char **argv)
+{
+ char *progname = argv[0];
+ char *file = NULL;
+ char *input;
+ size_t size;
+ struct json_value *obj;
+ char *key = NULL;
+
+ while (--argc) {
+ char *arg = *++argv;
+ if (strncmp(arg, "-file=", 6) == 0)
+ file = arg + 6;
+ else if (strncmp(arg, "-indent=", 8) == 0)
+ indent = atoi(arg + 8);
+ else if (strncmp(arg, "-search=", 8) == 0)
+ key = arg + 8;
+ else if (strncmp(arg, "-precision=", 11) == 0)
+ precision = atoi(arg + 11);
+ else if (arg[0] == '-')
+ usage(progname, stderr, 1);
+ else
+ break;
+ }
+
+ if (file) {
+ struct stat st;
+ int fd;
+ ssize_t n;
+
+ if (argc != 0)
+ usage(progname, stderr, 1);
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ perror(file);
+ return 2;
+ }
+ if (fstat(fd, &st)) {
+ perror("fstat");
+ return 2;
+ }
+ size = (size_t) st.st_size;
+ if (size != st.st_size)
+ abort();
+ input = grecs_malloc(size + 1);
+ n = read(fd, input, size);
+ if (n == -1) {
+ perror("read");
+ return 2;
+ }
+ if (n != size) {
+ fprintf(stderr, "%s: short read from %s\n",
+ progname, file);
+ return 2;
+ }
+ input[n] = 0;
+ close(fd);
+ } else if (argc == 1) {
+ if (file)
+ usage(progname, stderr, 1);
+ input = *argv;
+ size = strlen(input);
+ } else
+ usage(progname, stderr, 1);
+
+ obj = json_parse_string(input, size);
+ if (!obj) {
+ json_err_locus.beg.file = json_err_locus.end.file =
+ file ? file : "input";
+ grecs_error(&json_err_locus, 0, "%s", json_err_diag);
+ return 3;
+ }
+ if (key) {
+ struct json_value *p = json_value_lookup(obj, key);
+ if (!p)
+ return 4;
+ obj = p;
+ }
+ json_format_value(stdout, obj, 0);
+ putchar('\n');
+ return 0;
+}

Return to:

Send suggestions and report system problems to the System administrator.