Ver Fonte

don't use fmemopen in xs_json_loads

this is a workaround for a bug in the illumos stdlib
Aleteoryx há 1 mês atrás
pai
commit
597c3fb308
1 ficheiros alterados com 93 adições e 33 exclusões
  1. 93 33
      xs_json.h

+ 93 - 33
xs_json.h

@@ -8,6 +8,12 @@
 #define MAX_JSON_DEPTH 32
 #endif
 
+typedef struct {
+    union { FILE *f; const char *b; } src;
+    const char *b_end;
+} json_src;
+
+
 void xs_json_dump_value(const xs_val *data, int level, int indent, FILE *f);
 int xs_json_dump(const xs_val *data, int indent, FILE *f);
 xs_str *xs_json_dumps(const xs_val *data, int indent);
@@ -17,11 +23,11 @@ xs_val *xs_json_loads_full(const xs_str *json, int maxdepth);
 #define xs_json_load(f) xs_json_load_full(f, MAX_JSON_DEPTH)
 #define xs_json_loads(s) xs_json_loads_full(s, MAX_JSON_DEPTH)
 
-xstype xs_json_load_type(FILE *f);
-int xs_json_load_array_iter(FILE *f, xs_val **value, xstype *pt, int *c);
-int xs_json_load_object_iter(FILE *f, xs_str **key, xs_val **value, xstype *pt, int *c);
-int xs_json_load_array(FILE *f, int maxdepth, xs_list **l);
-int xs_json_load_object(FILE *f, int maxdepth, xs_dict **d);
+xstype xs_json_load_type(json_src *f);
+int xs_json_load_array_iter(json_src *f, xs_val **value, xstype *pt, int *c);
+int xs_json_load_object_iter(json_src *f, xs_str **key, xs_val **value, xstype *pt, int *c);
+int xs_json_load_array(json_src *f, int maxdepth, xs_list **l);
+int xs_json_load_object(json_src *f, int maxdepth, xs_dict **d);
 
 
 #ifdef XS_IMPLEMENTATION
@@ -211,8 +217,56 @@ typedef enum {
     JS_OBJECT
 } js_type;
 
+static int jgetc(json_src *f)
+/* calls fgetc on an underlying file, otherwise reads the buffer */
+{
+    if (f->b_end == NULL)
+        return fgetc(f->src.f);
+    else
+    if (f->src.b >= f->b_end)
+        return EOF;
+    else
+        return *(f->src.b)++;
+}
+
+
+static int jungetc(int c, json_src *f)
+/* calls ungetc on an underlying file, otherwise decrements the buf ptr */
+/* this function will NOT mutate an underlying buffer */
+{
+    if (f->b_end == NULL)
+        return ungetc(c, f->src.f);
+    else
+    if (c == EOF)
+        return EOF;
+    else {
+        f->src.b--;
+        return c;
+    }
+}
+
+
+#define jscanf(f, fmt, arg) _jscanf(f, fmt, fmt "%n", arg)
+static int _jscanf(json_src *restrict f, const char *restrict fmt, const char *restrict fmt2, void *arg)
+/* calls fscanf on an underlying file, otherwise reads the buffer. */
+{
+    if (f->b_end == NULL)
+        return fscanf(f->src.f, fmt, arg);
+    else
+    if (f->src.b >= f->b_end)
+        return EOF;
+    else {
+        int n, b;
+
+        n = sscanf(f->src.b, fmt2, arg, &b);
+        if (n >= 0)
+            f->src.b += b;
+        return n;
+    }
+}
+
 
-static xs_val *_xs_json_load_lexer(FILE *f, js_type *t)
+static xs_val *_xs_json_load_lexer(json_src *f, js_type *t)
 {
     int c;
     xs_val *v = NULL;
@@ -221,7 +275,7 @@ static xs_val *_xs_json_load_lexer(FILE *f, js_type *t)
     *t = JS_ERROR;
 
     /* skip blanks */
-    while ((c = fgetc(f)) == ' ' || c == '\t' || c == '\n' || c == '\r');
+    while ((c = jgetc(f)) == ' ' || c == '\t' || c == '\n' || c == '\r');
 
     if (c == '{')
         *t = JS_OCURLY;
@@ -247,9 +301,9 @@ static xs_val *_xs_json_load_lexer(FILE *f, js_type *t)
         v = xs_str_new(NULL);
         offset = 0;
 
-        while ((c = fgetc(f)) != '"' && c != EOF && *t != JS_ERROR) {
+        while ((c = jgetc(f)) != '"' && c != EOF && *t != JS_ERROR) {
             if (c == '\\') {
-                unsigned int cp = fgetc(f);
+                unsigned int cp = jgetc(f);
 
                 switch (cp) {
                 case 'n': cp = '\n'; break;
@@ -259,20 +313,20 @@ static xs_val *_xs_json_load_lexer(FILE *f, js_type *t)
                 case '\\': cp = '\\'; break;
                 case '/': cp = '/'; break;
                 case 'u': /* Unicode codepoint as an hex char */
-                    if (fscanf(f, "%04x", &cp) != 1) {
+                    if (jscanf(f, "%04x", &cp) != 1) {
                         *t = JS_ERROR;
                         break;
                     }
 
                     if (xs_is_surrogate(cp)) {
                         /* \u must follow */
-                        if (fgetc(f) != '\\' || fgetc(f) != 'u') {
+                        if (jgetc(f) != '\\' || jgetc(f) != 'u') {
                             *t = JS_ERROR;
                             break;
                         }
 
                         unsigned int p2;
-                        if (fscanf(f, "%04x", &p2) != 1) {
+                        if (jscanf(f, "%04x", &p2) != 1) {
                             *t = JS_ERROR;
                             break;
                         }
@@ -317,30 +371,30 @@ static xs_val *_xs_json_load_lexer(FILE *f, js_type *t)
     if (c == '-' || (c >= '0' && c <= '9') || c == '.') {
         double d;
 
-        ungetc(c, f);
-        if (fscanf(f, "%lf", &d) == 1) {
+        jungetc(c, f);
+        if (jscanf(f, "%lf", &d) == 1) {
             *t = JS_NUMBER;
             v = xs_number_new(d);
         }
     }
     else
     if (c == 't') {
-        if (fgetc(f) == 'r' && fgetc(f) == 'u' && fgetc(f) == 'e') {
+        if (jgetc(f) == 'r' && jgetc(f) == 'u' && jgetc(f) == 'e') {
             *t = JS_TRUE;
             v = xs_val_new(XSTYPE_TRUE);
         }
     }
     else
     if (c == 'f') {
-        if (fgetc(f) == 'a' && fgetc(f) == 'l' &&
-            fgetc(f) == 's' && fgetc(f) == 'e') {
+        if (jgetc(f) == 'a' && jgetc(f) == 'l' &&
+            jgetc(f) == 's' && jgetc(f) == 'e') {
             *t = JS_FALSE;
             v = xs_val_new(XSTYPE_FALSE);
         }
     }
     else
     if (c == 'n') {
-        if (fgetc(f) == 'u' && fgetc(f) == 'l' && fgetc(f) == 'l') {
+        if (jgetc(f) == 'u' && jgetc(f) == 'l' && jgetc(f) == 'l') {
             *t = JS_NULL;
             v = xs_val_new(XSTYPE_NULL);
         }
@@ -353,7 +407,7 @@ static xs_val *_xs_json_load_lexer(FILE *f, js_type *t)
 }
 
 
-int xs_json_load_array_iter(FILE *f, xs_val **value, xstype *pt, int *c)
+int xs_json_load_array_iter(json_src *f, xs_val **value, xstype *pt, int *c)
 /* loads the next scalar value from the JSON stream */
 /* if the value ahead is compound, value is NULL and pt is set */
 {
@@ -393,7 +447,7 @@ int xs_json_load_array_iter(FILE *f, xs_val **value, xstype *pt, int *c)
 }
 
 
-int xs_json_load_array(FILE *f, int maxdepth, xs_list **l)
+int xs_json_load_array(json_src *f, int maxdepth, xs_list **l)
 /* loads a full JSON array (after the initial OBRACK) */
 /* l can be NULL for the content to be dropped */
 {
@@ -441,7 +495,7 @@ int xs_json_load_array(FILE *f, int maxdepth, xs_list **l)
 }
 
 
-int xs_json_load_object_iter(FILE *f, xs_str **key, xs_val **value, xstype *pt, int *c)
+int xs_json_load_object_iter(json_src *f, xs_str **key, xs_val **value, xstype *pt, int *c)
 /* loads the next key and scalar value from the JSON stream */
 /* if the value ahead is compound, value is NULL and pt is set */
 {
@@ -491,7 +545,7 @@ int xs_json_load_object_iter(FILE *f, xs_str **key, xs_val **value, xstype *pt,
 }
 
 
-int xs_json_load_object(FILE *f, int maxdepth, xs_dict **d)
+int xs_json_load_object(json_src *f, int maxdepth, xs_dict **d)
 /* loads a full JSON object (after the initial OCURLY) */
 /* d can be NULL for the content to be dropped */
 {
@@ -540,7 +594,7 @@ int xs_json_load_object(FILE *f, int maxdepth, xs_dict **d)
 }
 
 
-xstype xs_json_load_type(FILE *f)
+xstype xs_json_load_type(json_src *f)
 /* identifies the type of a JSON stream */
 {
     xstype t = XSTYPE_NULL;
@@ -558,8 +612,7 @@ xstype xs_json_load_type(FILE *f)
 }
 
 
-xs_val *xs_json_load_full(FILE *f, int maxdepth)
-/* loads a JSON file */
+static xs_val *_xs_json_load(json_src *f, int maxdepth)
 {
     xs_val *v = NULL;
     xstype t = xs_json_load_type(f);
@@ -578,18 +631,25 @@ xs_val *xs_json_load_full(FILE *f, int maxdepth)
 }
 
 
+xs_val *xs_json_load_full(FILE *fp, int maxdepth)
+/* loads a JSON file */
+{
+    json_src f;
+    f.src.f = fp;
+    f.b_end = NULL;
+
+    return _xs_json_load(&f, maxdepth);
+}
+
+
 xs_val *xs_json_loads_full(const xs_str *json, int maxdepth)
 /* loads a string in JSON format and converts to a multiple data */
 {
-    FILE *f;
-    xs_val *v = NULL;
+    json_src f;
+    f.src.b = json;
+    f.b_end = json+strlen(json);
 
-    if ((f = fmemopen((char *)json, strlen(json), "r")) != NULL) {
-        v = xs_json_load_full(f, maxdepth);
-        fclose(f);
-    }
-
-    return v;
+    return _xs_json_load(&f, maxdepth);
 }