]> Pileus Git - ~andy/rhawk/blobdiff - json.awk
Handle special JSON characters
[~andy/rhawk] / json.awk
index 94c561f4b77cb7673e599e8368d023e0a963ed0e..70d68f4d0d0edc7d798d45bfa5a11250ea7c5c3a 100644 (file)
--- a/json.awk
+++ b/json.awk
@@ -1,3 +1,12 @@
+# usage:
+#      @include "json.awk"
+#      BEGIN {
+#              src["hello"] = "world"
+#              json_save("test.json", src)
+#              json_load("test.json", dst)
+#              print dst["hello"]
+#      }
+#
 # value:
 #      object: { string : value, .. }
 #      array:  [ value, .. ]
@@ -108,7 +117,14 @@ function json_write_number(number)
 
 function json_write_string(string)
 {
-       # todo: special characters
+       gsub(/\\/, "\\\\", string)
+       gsub(/"/,  "\\\"", string)
+       gsub(/\b/, "\\b",  string)
+       gsub(/\f/, "\\f",  string)
+       gsub(/\n/, "\\n",  string)
+       gsub(/\r/, "\\r",  string)
+       gsub(/\t/, "\\t",  string)
+
        return "\"" string "\""
 }
 
@@ -117,7 +133,7 @@ function json_write_string(string)
 function json_tokenize(str, tokens,   i, line, items, table, type, found)
 {
        table["term"]  = "^[\\[\\]{}:,]"
-       table["str"]   = "^\"[^\"]*\""
+       table["str"]   = "^\"([^\\\\\"]|\\\\.)*\""
        table["num"]   = "^[+-]?[0-9]+(.[0-9]+)?"
        table["var"]   = "^(true|false|null)"
        table["space"] = "^[ \\t]+"
@@ -150,11 +166,12 @@ function json_tokenize(str, tokens,   i, line, items, table, type, found)
                        return 0
                }
        }
-       return i
 
        #for (i = 0; i < length(tokens); i++)
        #       printf "%-3s %-5s [%s]\n", i":",
        #               tokens[i]["type"], tokens[i]["text"]
+
+       return i
 }
 
 function json_parse_value(tokens, i, value, key,   line, type, text)
@@ -183,18 +200,20 @@ function json_parse_object(tokens, i, value, key,   object, k, v)
        if (tokens[i++]["text"] != "{")
                return 0;
 
-       do {
-               delete k
-               delete v
-               if (!(i=json_parse_value(tokens, i, k, 0)))
-                       return 0
-               if (tokens[i++]["text"] != ":")
-                       return 0
-               if (!(i=json_parse_value(tokens, i, v, 0)))
-                       return 0
-               json_copy(object, k[0], v[0]) 
-       } while (tokens[i++]["text"] == ",")
-       i--
+       if (tokens[i]["text"] != "}") {
+               do {
+                       delete k
+                       delete v
+                       if (!(i=json_parse_value(tokens, i, k, 0)))
+                               return 0
+                       if (tokens[i++]["text"] != ":")
+                               return 0
+                       if (!(i=json_parse_value(tokens, i, v, 0)))
+                               return 0
+                       json_copy(object, k[0], v[0]) 
+               } while (tokens[i++]["text"] == ",")
+               i--
+       }
 
        if (tokens[i++]["text"] != "}")
                return 0;
@@ -208,13 +227,15 @@ function json_parse_array(tokens, i, value, key,   array, k, v)
        if (tokens[i++]["text"] != "[")
                return 0;
 
-       do {
-               delete v
-               if (!(i=json_parse_value(tokens, i, v, 0)))
-                       return 0
-               json_copy(array, k++, v[0]) 
-       } while (tokens[i++]["text"] == ",")
-       i--
+       if (tokens[i]["text"] != "]") {
+               do {
+                       delete v
+                       if (!(i=json_parse_value(tokens, i, v, 0)))
+                               return 0
+                       json_copy(array, k++, v[0]) 
+               } while (tokens[i++]["text"] == ",")
+               i--
+       }
 
        if (tokens[i++]["text"] != "]")
                return 0;
@@ -236,6 +257,15 @@ function json_parse_string(tokens, i, value, key,   text)
        text = tokens[i++]["text"]
        len  = length(text);
        text = len == 2 ? "" : substr(text, 2, len-2)
+
+       gsub(/\\\\/, "\\", text)
+       gsub(/\\"/,  "\"", text)
+       gsub(/\\b/,  "\b", text)
+       gsub(/\\f/,  "\f", text)
+       gsub(/\\n/,  "\n", text)
+       gsub(/\\r/,  "\r", text)
+       gsub(/\\t/,  "\t", text)
+
        json_copy(value, key, text)
        #print "parse_string: [" text "]"
        return i
@@ -257,7 +287,7 @@ function json_parse_var(tokens, i, value, key,   text, null)
 function json_load(file, var,   line, text, tokens, data, key)
 {
        while ((getline line < file) > 0)
-               text = text line
+               text = text line "\n"
        close(file)
        if (!json_tokenize(text, tokens))
                return ""
@@ -323,13 +353,16 @@ function json_test_read()
               "                              false,            \n" \
               "                              null    ],        \n" \
               "                \"number\": 42,                 \n" \
+              "                \"eobj\":   [ ],                \n" \
+              "                \"earr\":   { },                \n" \
               "                \"obj\":    { \"A\": \"a!\",    \n" \
               "                              \"B\": \"b!\",    \n" \
               "                              \"C\": \"c!\" },  \n" \
               "                \"str\":    \"hello, world\" }, \n" \
               "  \"second\": { \"arr\":    [ \"zero\",         \n" \
               "                              \"one\",          \n" \
-              "                              \"two\" ],        \n" \
+              "                              \"two\",          \n" \
+              "                              \"\\\"\t\r\b\" ], \n" \
               "                \"number\": 42,                 \n" \
               "                \"obj\":    { \"A\": \"a!\",    \n" \
               "                              \"B\": \"b!\",    \n" \