+# 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, .. ]
# \t
# \u four-hex-digits
-
# Helpers
function json_gettype(value, key, sort, n, i)
{
return "object"
return "array"
} else {
+ if (value == 0 && value == "")
+ return "null"
if (value == value + 0)
return "number"
if (value == value "")
case "array": return json_write_array(value, pad)
case "number": return json_write_number(value)
case "string": return json_write_string(value)
+ case "null": return "null"
default: return "error"
}
}
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 "\""
}
# Read functions
-function json_tokenize(str, tokens, i, items, table, type, found)
+function json_tokenize(str, tokens, i, line, items, table, type, found)
{
table["term"] = "^[\\[\\]{}:,]"
- table["str"] = "^\"[^\"]*\""
- table["num"] = "^[0-9]+"
+ table["str"] = "^\"([^\\\\\"]|\\\\.)*\""
+ table["num"] = "^[+-]?[0-9]+(.[0-9]+)?"
table["var"] = "^(true|false|null)"
- table["space"] = "^[ \\t\\n]+"
- i = 0
+ table["space"] = "^[ \\t]+"
+ table["line"] = "^\n"
+ i = 0;
+ line = 1;
while (length(str) > 0) {
found = 0
for (type in table) {
#print "match: str=["str"] type="type" regex=/"table[type]"/"
if (match(str, table[type], items) > 0) {
#print " len="RLENGTH" item=["items[0]"]"
+ if (type == "line")
+ line++;
if (type == "term")
type = items[0]
- if (type != "space") {
+ if (type != "space" && type != "line") {
+ tokens[i]["line"] = line
tokens[i]["type"] = type
tokens[i]["text"] = items[0]
i++
}
}
if (!found) {
- debug("error tokenizing")
+ debug("line " line ": error tokenizing")
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, type, text)
+function json_parse_value(tokens, i, value, key, line, type, text)
{
if (!i ) i = 0;
if (!depth) depth = 0
depth++
+ line = tokens[i]["line"]
type = tokens[i]["type"]
text = tokens[i]["text"]
#printf "parse %d: i=%-2d type=%-3s text=%s\n", depth, i, type, text
case "str": i = json_parse_string(tokens, i, value, key); break
case "num": i = json_parse_number(tokens, i, value, key); break
case "var": i = json_parse_var(tokens, i, value, key); break
- default: debug("error: type="type" text="text); return 0
+ default: debug("line "line": error type="type" text="text); return 0
}
depth--
return i
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;
function json_parse_array(tokens, i, value, key, array, k, v)
{
- #print "parse_array: .."
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;
function json_parse_string(tokens, i, value, key, text)
{
text = tokens[i++]["text"]
- text = substr(text, 2, length(text)-2)
+ 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
+ #print "parse_string: [" text "]"
return i
}
-function json_parse_var(tokens, i, value, key, text)
+function json_parse_var(tokens, i, value, key, text, null)
{
- text = tokens[i++]["text"]
- json_copy(value, key, text == "true")
+ switch (tokens[i++]["text"]) {
+ case "true": json_copy(value, key, 1==1); break;
+ case "false": json_copy(value, key, 1==2); break;
+ case "null": json_copy(value, key, null); break;
+ }
#print "parse_var: " text " -> " text == "true"
return i
}
-# Nice API?
-function json_load(file, var, line, text, tokens, data, key)
+# String API
+function json_decode(string, var, tokens, data, key)
{
- while ((getline line < file) > 0)
- text = text line
- close(file)
- if (!json_tokenize(text, tokens))
+ if (!json_tokenize(string, tokens))
return ""
if (!json_parse_value(tokens, 0, data, 0))
return ""
return data[0]
for (key in data[0])
json_copy(var, key, data[0][key])
+ return 1
+}
+
+function json_encode(var, pad)
+{
+ return json_write_value(var, pad)
+}
+
+# File API
+function json_load(file, var, line, string)
+{
+ delete var
+ while ((getline line < file) > 0)
+ string = string line "\n"
+ return json_decode(string, var)
}
function json_save(file, var, cmd, tmp)
{
- cmd = "mktemp ." file ".XXX"
+ cmd = "mktemp " file ".XXX"
cmd | getline tmp
close(cmd)
- print json_write_value(var) > tmp
+ print json_encode(var) > tmp
close(tmp)
system("mv " tmp " " file)
}
# Test functions
function json_test_write()
{
+ print "Testing JSON Write:"
num = 42
str = "hello, world"
arr[0] = "zero"
json_copy(mix, "obj", obj);
json_copy(dub, "first", mix);
json_copy(dub, "second", mix);
- print json_write_value(num)
- print json_write_value(str)
- print json_write_value(arr)
- print json_write_value(obj)
- print json_write_value(mix)
- print json_write_value(dub)
+ print json_encode(num)
+ print json_encode(str)
+ print json_encode(arr)
+ print json_encode(obj)
+ print json_encode(mix)
+ print json_encode(dub)
}
function json_test_read()
{
- json_tokenize("[8, \"abc\", 9]", tokens)
- json_parse_value(tokens, 0, array, 0)
- json_print write_value(array[0])
-
- json_tokenize("{\"abc\": 1, \"def\": 2}", tokens)
- json_parse_value(tokens, 0, array, 0)
- json_print write_value(array[0])
-
- json = "{ \"first\": { \"arr\": [ \"zero\", " \
- " \"one\", " \
- " \"two\" ], " \
- " \"number\": 42, " \
- " \"obj\": { \"A\": \"a!\", " \
- " \"B\": \"b!\", " \
- " \"C\": \"c!\" }, " \
- " \"str\": \"hello, world\" }, " \
- " \"second\": { \"arr\": [ \"zero\", " \
- " \"one\", " \
- " \"two\" ], " \
- " \"number\": 42, " \
- " \"obj\": { \"A\": \"a!\", " \
- " \"B\": \"b!\", " \
- " \"C\": \"c!\" }, " \
- " \"str\": \"hello, world\" } }"
-
- json_tokenize(json, tokens)
- json_parse_value(tokens, 0, array, 0)
- print json_write_value(array[0])
+ print "Testing JSON Read:"
+
+ json_decode("[8, \"abc\", 9]", array);
+ print json_encode(array)
+
+ json_decode("{\"abc\": 1, \"def\": 2}", array)
+ print json_encode(array)
+
+ json = "{ \"first\": { \"arr\": [ \"\", \n" \
+ " -1, \n" \
+ " 1.2, \n" \
+ " true, \n" \
+ " 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" \
+ " \"\\\"\t\r\b\" ], \n" \
+ " \"number\": 42, \n" \
+ " \"obj\": { \"A\": \"a!\", \n" \
+ " \"B\": \"b!\", \n" \
+ " \"C\": \"c!\" }, \n" \
+ " \"str\": \"hello, world\" } }\n"
+
+ json_decode(json, array)
+ print json_encode(array)
}
function json_test_files()
{
+ print "Testing JSON Files:"
print "load: [" json_load("email.txt", mail) "]"
- print "mail: " json_write_value(mail, " ")
+ print "mail: " json_encode(mail, " ")
mail["andy753421"] = "andy753421@gmail.com"
mail["andy"] = "andy@gmail.com"
mail["somebody"] = "foo@example.com"
- print "mail: " json_write_value(mail, " ")
+ print "mail: " json_encode(mail, " ")
print "save: [" json_save("email.txt", mail) "]"
}