]> granicus.if.org Git - json-c/commitdiff
Add an apps directory, and a json_parse program to parse an input file and report...
authorEric Haszlakiewicz <erh+git@nimenees.com>
Tue, 21 Apr 2020 03:51:16 +0000 (03:51 +0000)
committerEric Haszlakiewicz <erh+git@nimenees.com>
Tue, 21 Apr 2020 03:57:56 +0000 (03:57 +0000)
This is intended to provide a way, during development, to test out the memory
and performance impacts of a change.

CMakeLists.txt
ChangeLog
apps/CMakeLists.txt [new file with mode: 0644]
apps/json_parse.c [new file with mode: 0644]
cmake/config.h.in

index 1d09e5075b71e2efbd1e2a36eca3e0bebc7acba3..4d4cc9b717eb4b54e659351e46b3fe60fab34e8d 100644 (file)
@@ -40,6 +40,8 @@ if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING AND
 add_subdirectory(tests)
 endif()
 
+add_subdirectory(apps)
+
 # Set some packaging variables.
 set(CPACK_PACKAGE_NAME              "${PROJECT_NAME}")
 set(CPACK_PACKAGE_VERSION_MAJOR     "${PROJECT_VERSION_MAJOR}")
@@ -108,6 +110,7 @@ check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
 
 check_include_file(unistd.h         HAVE_UNISTD_H)
 check_include_file(sys/types.h      HAVE_SYS_TYPES_H)
+check_include_file(sys/resource.h   HAVE_SYS_RESOURCE_H) # for getrusage
 
 check_include_file("dlfcn.h"        HAVE_DLFCN_H)
 check_include_file("endian.h"       HAVE_ENDIAN_H)
@@ -165,6 +168,9 @@ endif()
 if (HAVE_SYSLOG_H)
     check_symbol_exists(vsyslog     "syslog.h" HAVE_VSYSLOG)
 endif()
+if (HAVE_SYS_RESOURCE_H)
+    check_symbol_exists(getrusage   "sys/resource.h" HAVE_GETRUSAGE)
+endif()
 
 check_symbol_exists(strtoll     "stdlib.h" HAVE_STRTOLL)
 check_symbol_exists(strtoull    "stdlib.h" HAVE_STRTOULL)
index 6b41ab1f6bf5a09b4a26e711a0161a69a9341612..8a58d19798d446e50aba2b7415ce320d0f86e2e3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,8 @@ Deprecated and removed features:
 
 Other changes
 --------------
+* Add a json_parse binary, for use in testing changes (not installed).
+* Issue #471: always create directories with mode 0755, regardless of umask.
 * Added a JSON_TOKENER_ALLOW_TRAILING_CHARS flag to allow multiple objects
   to be parsed even when JSON_TOKENER_STRICT is set.
 
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
new file mode 100644 (file)
index 0000000..dda68a2
--- /dev/null
@@ -0,0 +1,11 @@
+
+# Note: it is intentional that there are no install instructions here yet.
+# When/if the interface of the app(s) listed here settles down enough to
+# publish as part of a regular build that will be added.
+
+add_executable(json_parse json_parse.c)
+#target_compile_definitions(json_parse PRIVATE TEST_FORMATTED=1)
+target_link_libraries(json_parse PRIVATE ${PROJECT_NAME})
+
+include_directories(PUBLIC ${CMAKE_SOURCE_DIR})
+
diff --git a/apps/json_parse.c b/apps/json_parse.c
new file mode 100644 (file)
index 0000000..754666e
--- /dev/null
@@ -0,0 +1,175 @@
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "json_object.h"
+#include "json_tokener.h"
+#include "json_util.h"
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#include <sys/time.h>
+#endif
+
+static int formatted_output = 0;
+static int show_output = 1;
+static int strict_mode = 0;
+static const char *fname = NULL;
+
+static void usage(int exitval, const char *errmsg);
+static void showmem(void);
+static int parseit(int fd, int (*callback)(struct json_object *));
+static int showobj(struct json_object *new_obj);
+
+static void showmem(void)
+{
+#ifdef HAVE_GETRUSAGE
+       struct rusage rusage;
+       memset(&rusage, 0, sizeof(rusage));
+       getrusage(RUSAGE_SELF, &rusage);
+       printf("maxrss: %d KB\n", rusage.ru_maxrss);
+#endif
+}
+
+static int parseit(int fd, int (*callback)(struct json_object *))
+{
+       struct json_object *obj;
+       char buf[32768];
+       int ret;
+       int depth = JSON_TOKENER_DEFAULT_DEPTH;
+       json_tokener *tok;
+
+       tok = json_tokener_new_ex(depth);
+       if (!tok)
+       {
+               fprintf(stderr, "unable to allocate json_tokener: %s\n", strerror(errno));
+               return 1;
+       }
+       json_tokener_set_flags(tok, JSON_TOKENER_STRICT | JSON_TOKENER_ALLOW_TRAILING_CHARS);
+
+       // XXX push this into some kind of json_tokener_parse_fd API?
+       //  json_object_from_fd isn't flexible enough, and mirroring
+       //   everything you can do with a tokener into json_util.c seems
+       //   like the wrong approach.
+       size_t total_read = 0;
+       while ((ret = read(fd, buf, sizeof(buf))) > 0)
+       {
+               total_read += ret;
+               int start_pos = 0;
+               while (start_pos != ret)
+               {
+                       obj = json_tokener_parse_ex(tok, &buf[start_pos], ret - start_pos);
+                       enum json_tokener_error jerr = json_tokener_get_error(tok);
+                       int parse_end = json_tokener_get_parse_end(tok);
+                       if (obj == NULL && jerr != json_tokener_continue)
+                       {
+                               char *aterr = &buf[start_pos + parse_end];
+                               fflush(stdout);
+                               int fail_offset = total_read - ret + start_pos + parse_end;
+                               fprintf(stderr, "Failed at offset %d: %s %c\n", fail_offset,
+                                       json_tokener_error_desc(jerr), aterr[0]);
+                               json_tokener_free(tok);
+                               return 1;
+                       }
+                       if (obj != NULL)
+                       {
+                               int cb_ret = callback(obj);
+                               json_object_put(obj);
+                               if (cb_ret != 0)
+                               {
+                                       json_tokener_free(tok);
+                                       return 1;
+                               }
+                       }
+                       start_pos += json_tokener_get_parse_end(tok);
+                       assert(start_pos <= ret);
+               }
+       }
+       if (ret < 0)
+       {
+               fprintf(stderr, "error reading fd %d: %s\n", fd, strerror(errno));
+       }
+
+       json_tokener_free(tok);
+       return 0;
+}
+
+static int showobj(struct json_object *new_obj)
+{
+       if (new_obj == NULL)
+       {
+               fprintf(stderr, "%s: Failed to parse\n", fname);
+               return 1;
+       }
+
+       printf("Successfully parsed object from %s\n", fname);
+
+       if (show_output)
+       {
+               const char *output;
+               if (formatted_output)
+                       output = json_object_to_json_string(new_obj);
+               else
+                       output = json_object_to_json_string_ext(new_obj, JSON_C_TO_STRING_PRETTY);
+               printf("%s\n", output);
+       }
+
+       showmem();
+       return 0;
+}
+
+static void usage(int exitval, const char *errmsg)
+{
+       FILE *fp = stdout;
+       if (exitval != 0)
+               fp = stderr;
+       if (errmsg != NULL)
+               fprintf(fp, "ERROR: %s\n\n", errmsg);
+       fprintf(fp, "Usage: %s [-f] [-n] [-s]\n");
+       fprintf(fp, "  -f - Format the output with JSON_C_TO_STRING_PRETTY\n");
+       fprintf(fp, "  -n - No output\n");
+       fprintf(fp, "  -s - Parse in strict mode, flags:\n");
+       fprintf(fp, "       JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS\n");
+
+       fprintf(fp, "\nWARNING WARNING WARNING\n");
+       fprintf(fp, "This is a prototype, it may change or be removed at any time!\n");
+       exit(exitval);
+}
+
+int main(int argc, char **argv)
+{
+       json_object *new_obj;
+       int opt;
+
+       while ((opt = getopt(argc, argv, "fns")) != -1)
+       {
+               switch (opt)
+               {
+               case 'f': formatted_output = 1; break;
+               case 'n': show_output = 0; break;
+               case 's': strict_mode = 1; break;
+               default: /* '?' */ fprintf(stderr, "Usage: %s [-f]\n", argv[0]); exit(EXIT_FAILURE);
+               }
+       }
+
+       if (optind >= argc)
+       {
+               fprintf(stderr, "Expected argument after options\n");
+               exit(EXIT_FAILURE);
+       }
+       fname = argv[optind];
+       int fd = open(argv[optind], O_RDONLY, 0);
+       showmem();
+       if (parseit(fd, showobj) != 0)
+               exit(EXIT_FAILURE);
+       showmem();
+
+       exit(EXIT_SUCCESS);
+}
index 5e64e58bd134bcd824487fb3fa13a570fe1813e3..9c6508216a880682b4a11659f9bf183e11f4f8e1 100644 (file)
@@ -54,6 +54,9 @@
 /* Define to 1 if you have the <sys/param.h> header file. */
 #cmakedefine HAVE_SYS_PARAM_H @HAVE_SYS_PARAM_H@
 
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#cmakedefine HAVE_SYS_RESOURCE_H
+
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #cmakedefine HAVE_SYS_STAT_H
 
 /* Define to 1 if you have the `vsyslog' function. */
 #cmakedefine HAVE_VSYSLOG @HAVE_VSYSLOG@
 
+/* Define if you have the `getrusage' function. */
+#cmakedefine HAVE_GETRUSAGE
+
 #cmakedefine HAVE_STRTOLL
 #if !defined(HAVE_STRTOLL)
 #define strtoll @json_c_strtoll@