summaryrefslogtreecommitdiff
path: root/com32/gpllib
diff options
context:
space:
mode:
Diffstat (limited to 'com32/gpllib')
-rw-r--r--com32/gpllib/Makefile7
-rw-r--r--com32/gpllib/acpi/acpi.c19
-rw-r--r--com32/gpllib/cpuid.c175
-rw-r--r--com32/gpllib/zzjson/zzjson_create.c240
-rw-r--r--com32/gpllib/zzjson/zzjson_free.c29
-rw-r--r--com32/gpllib/zzjson/zzjson_parse.c490
-rw-r--r--com32/gpllib/zzjson/zzjson_print.c110
-rw-r--r--com32/gpllib/zzjson/zzjson_query.c63
8 files changed, 1122 insertions, 11 deletions
diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile
index a1740610..4b7b8468 100644
--- a/com32/gpllib/Makefile
+++ b/com32/gpllib/Makefile
@@ -4,11 +4,12 @@
# Include configuration rules
topdir = ../..
-include ../lib/MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/lib.mk
-REQFLAGS += -I../gplinclude
+REQFLAGS += -I../gplinclude -I../gplinclude/zzjson
-GPLDIRS := . disk dmi vpd acpi
+GPLDIRS := . disk dmi vpd acpi zzjson
LIBOBJS := $(foreach dir,$(GPLDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c)))
BINDIR = /usr/bin
diff --git a/com32/gpllib/acpi/acpi.c b/com32/gpllib/acpi/acpi.c
index 8e5ee29c..d2bf29e5 100644
--- a/com32/gpllib/acpi/acpi.c
+++ b/com32/gpllib/acpi/acpi.c
@@ -32,6 +32,25 @@
#include <memory.h>
#include "acpi/acpi.h"
+/* M1PS flags have to be interpreted as strings */
+char *flags_to_string(char *buffer, uint16_t flags)
+{
+ memset(buffer, 0, sizeof(buffer));
+ strcpy(buffer, "default");
+ if ((flags & POLARITY_ACTIVE_HIGH) == POLARITY_ACTIVE_HIGH)
+ strcpy(buffer, "high");
+ else if ((flags & POLARITY_ACTIVE_LOW) == POLARITY_ACTIVE_LOW)
+ strcpy(buffer, "low");
+ if ((flags & TRIGGER_EDGE) == TRIGGER_EDGE)
+ strncat(buffer, " edge", 5);
+ else if ((flags & TRIGGER_LEVEL) == TRIGGER_LEVEL)
+ strncat(buffer, " level", 6);
+ else
+ strncat(buffer, " default", 8);
+
+ return buffer;
+}
+
void dbg_printf(const char *fmt, ...)
{
va_list args;
diff --git a/com32/gpllib/cpuid.c b/com32/gpllib/cpuid.c
index 2d5b5ce9..2abd0bda 100644
--- a/com32/gpllib/cpuid.c
+++ b/com32/gpllib/cpuid.c
@@ -20,8 +20,31 @@
#include <string.h>
#include "cpuid.h"
+const char *cpu_flags_names[] = {
+ CPU_FLAGS(STRUCT_MEMBER_NAMES)
+};
+
+size_t cpu_flags_offset[] = {
+ CPU_FLAGS(STRUCTURE_MEMBER_OFFSETS)
+};
+
+size_t cpu_flags_count = sizeof cpu_flags_names / sizeof *cpu_flags_names;
+
struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = { };
+bool get_cpu_flag_value_from_name(s_cpu *cpu, const char * flag_name) {
+ size_t i;
+ bool cpu_flag_present=false, *flag_value = &cpu_flag_present;
+
+ for (i = 0; i < cpu_flags_count; i++) {
+ if (strcmp(cpu_flags_names[i],flag_name) == 0) {
+ flag_value = (bool *)((char *)&cpu->flags + cpu_flags_offset[i]);
+ }
+ }
+ return *flag_value;
+}
+
+
/*
* CPUID functions returning a single datum
*/
@@ -73,6 +96,48 @@ static struct cpu_dev transmeta_cpu_dev = {
.c_ident = {"GenuineTMx86", "TransmetaCPU"}
};
+static struct cpu_dev nsc_cpu_dev = {
+ .c_vendor = "National Semiconductor",
+ .c_ident = {"Geode by NSC"}
+};
+
+static struct cpu_dev unknown_cpu_dev = {
+ .c_vendor = "Unknown Vendor",
+ .c_ident = {"Unknown CPU"}
+};
+
+/*
+ * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
+ */
+void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+{
+ unsigned char ccr2, ccr3;
+
+ /* we test for DEVID by checking whether CCR3 is writable */
+ ccr3 = getCx86(CX86_CCR3);
+ setCx86(CX86_CCR3, ccr3 ^ 0x80);
+ getCx86(0xc0); /* dummy to change bus */
+
+ if (getCx86(CX86_CCR3) == ccr3) { /* no DEVID regs. */
+ ccr2 = getCx86(CX86_CCR2);
+ setCx86(CX86_CCR2, ccr2 ^ 0x04);
+ getCx86(0xc0); /* dummy */
+
+ if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */
+ *dir0 = 0xfd;
+ else { /* Cx486S A step */
+ setCx86(CX86_CCR2, ccr2);
+ *dir0 = 0xfe;
+ }
+ } else {
+ setCx86(CX86_CCR3, ccr3); /* restore CCR3 */
+
+ /* read DIR0 and DIR1 CPU registers */
+ *dir0 = getCx86(CX86_DIR0);
+ *dir1 = getCx86(CX86_DIR1);
+ }
+}
+
void init_cpu_devs(void)
{
cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev;
@@ -83,6 +148,8 @@ void init_cpu_devs(void)
cpu_devs[X86_VENDOR_CENTAUR] = &centaur_cpu_dev;
cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev;
cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev;
+ cpu_devs[X86_VENDOR_NSC] = &nsc_cpu_dev;
+ cpu_devs[X86_VENDOR_UNKNOWN] = &unknown_cpu_dev;
}
void get_cpu_vendor(struct cpuinfo_x86 *c)
@@ -90,7 +157,7 @@ void get_cpu_vendor(struct cpuinfo_x86 *c)
char *v = c->x86_vendor_id;
int i;
init_cpu_devs();
- for (i = 0; i < X86_VENDOR_NUM; i++) {
+ for (i = 0; i < X86_VENDOR_NUM-1; i++) {
if (cpu_devs[i]) {
if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
(cpu_devs[i]->c_ident[1] &&
@@ -177,6 +244,96 @@ void detect_cache(uint32_t xlvl, struct cpuinfo_x86 *c)
c->x86_l2_cache_size = l2size;
}
+void detect_cyrix(struct cpuinfo_x86 *c) {
+ unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
+ char *buf = c->x86_model_id;
+ char Cx86_cb[] = "?.5x Core/Bus Clock";
+ const char cyrix_model_mult1[] = "12??43";
+ const char cyrix_model_mult2[] = "12233445";
+ const char *p = NULL;
+
+ do_cyrix_devid(&dir0, &dir1);
+ dir0_msn = dir0 >> 4; /* identifies CPU "family" */
+ dir0_lsn = dir0 & 0xf; /* model or clock multiplier */
+ c->x86_model = (dir1 >> 4) + 1;
+ c->x86_mask = dir1 & 0xf;
+ switch (dir0_msn) {
+ unsigned char tmp;
+
+ case 0: /* Cx486SLC/DLC/SRx/DRx */
+ p = Cx486_name[dir0_lsn & 7];
+ break;
+
+ case 1: /* Cx486S/DX/DX2/DX4 */
+ p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5] : Cx486S_name[dir0_lsn & 3];
+ break;
+
+ case 2: /* 5x86 */
+ Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
+ p = Cx86_cb+2;
+ break;
+
+ case 3: /* 6x86/6x86L */
+ Cx86_cb[1] = ' ';
+ Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
+ if (dir1 > 0x21) { /* 686L */
+ Cx86_cb[0] = 'L';
+ p = Cx86_cb;
+ (c->x86_model)++;
+ } else /* 686 */
+ p = Cx86_cb+1;
+
+ c->coma_bug = 1;
+ break;
+ case 4:
+ c->x86_l1_data_cache_size = 16; /* Yep 16K integrated cache thats it */
+ if (c->cpuid_level != 2) { /* Media GX */
+ Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
+ p = Cx86_cb+2;
+ }
+ break;
+
+ case 5: /* 6x86MX/M II */
+ if (dir1 > 7) {
+ dir0_msn++; /* M II */
+ } else {
+ c->coma_bug = 1; /* 6x86MX, it has the bug. */
+ }
+
+ tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
+ Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
+ p = Cx86_cb+tmp;
+ if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
+ (c->x86_model)++;
+ break;
+
+ case 0xf: /* Cyrix 486 without DEVID registers */
+ switch (dir0_lsn) {
+ case 0xd: /* either a 486SLC or DLC w/o DEVID */
+ dir0_msn = 0;
+ p = Cx486_name[(c->hard_math) ? 1 : 0];
+ break;
+
+ case 0xe: /* a 486S A step */
+ dir0_msn = 0;
+ p = Cx486S_name[0];
+ break;
+ }
+ break;
+
+ default:
+ dir0_msn = 7;
+ break;
+ }
+
+ /* If the processor is unknown, we keep the model name we got
+ * from the generic call */
+ if (dir0_msn < 7) {
+ strcpy(buf, Cx86_model[dir0_msn & 7]);
+ if (p) strcat(buf, p);
+ }
+}
+
void generic_identify(struct cpuinfo_x86 *c)
{
uint32_t tfms, xlvl;
@@ -222,6 +379,13 @@ void generic_identify(struct cpuinfo_x86 *c)
get_model_name(c); /* Default name */
}
+ /* Specific detection code */
+ switch (c->x86_vendor) {
+ case X86_VENDOR_CYRIX:
+ case X86_VENDOR_NSC: detect_cyrix(c); break;
+ default: break;
+ }
+
/* Detecting the number of cores */
switch (c->x86_vendor) {
case X86_VENDOR_AMD:
@@ -435,17 +599,12 @@ void set_generic_info(struct cpuinfo_x86 *c, s_cpu * cpu)
void detect_cpu(s_cpu * cpu)
{
struct cpuinfo_x86 c;
+ memset(&c,0,sizeof(c));
c.x86_clflush_size = 32;
- c.x86_l1_data_cache_size = 0;
- c.x86_l1_instruction_cache_size = 0;
- c.x86_l2_cache_size = 0;
c.x86_vendor = X86_VENDOR_UNKNOWN;
c.cpuid_level = -1; /* CPUID not detected */
- c.x86_model = c.x86_mask = 0; /* So far unknown... */
c.x86_num_cores = 1;
- memset(&c.x86_capability, 0, sizeof(c.x86_capability));
- memset(&c.x86_vendor_id, 0, sizeof(c.x86_vendor_id));
- memset(&c.x86_model_id, 0, sizeof(c.x86_model_id));
+ memset(&cpu->flags, 0, sizeof(s_cpu_flags));
if (!have_cpuid_p())
return;
diff --git a/com32/gpllib/zzjson/zzjson_create.c b/com32/gpllib/zzjson/zzjson_create.c
new file mode 100644
index 00000000..7e6bd5bd
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_create.c
@@ -0,0 +1,240 @@
+/* JSON Create ZZJSON structures
+ * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifdef CONFIG_NO_ERROR_MESSAGES
+#define ERROR(x...)
+#else
+#define ERROR(x...) config->error(config->ehandle, ##x)
+#endif
+#define MEMERROR() ERROR("out of memory")
+
+static ZZJSON *zzjson_create_templ(ZZJSON_CONFIG *config, ZZJSON_TYPE type) {
+ ZZJSON *zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) MEMERROR();
+ else zzjson->type = type;
+ return zzjson;
+}
+
+ZZJSON *zzjson_create_true(ZZJSON_CONFIG *config) {
+ return zzjson_create_templ(config, ZZJSON_TRUE);
+}
+
+ZZJSON *zzjson_create_false(ZZJSON_CONFIG *config) {
+ return zzjson_create_templ(config, ZZJSON_FALSE);
+}
+
+ZZJSON *zzjson_create_null(ZZJSON_CONFIG *config) {
+ return zzjson_create_templ(config, ZZJSON_NULL);
+}
+
+ZZJSON *zzjson_create_number_d(ZZJSON_CONFIG *config, double d) {
+ ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_DOUBLE);
+ if (zzjson)
+ zzjson->value.number.val.dval = d;
+ return zzjson;
+}
+
+ZZJSON *zzjson_create_number_i(ZZJSON_CONFIG *config, long long i) {
+ ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_NEGINT);
+ if (zzjson) {
+ zzjson->type = i<0LL ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT;
+ zzjson->value.number.val.ival = llabs(i);
+ }
+ return zzjson;
+}
+
+/* sdup mimics strdup, but avoids having another function pointer in config */
+static char *sdup(ZZJSON_CONFIG *config, char *s) {
+ size_t slen = strlen(s)+1;
+ char *scopy = config->malloc(slen);
+
+ if (!scopy) MEMERROR();
+ else memcpy(scopy, s, slen);
+ return scopy;
+}
+
+ZZJSON *zzjson_create_string(ZZJSON_CONFIG *config, char *s) {
+ ZZJSON *zzjson = NULL;
+ char *scopy;
+
+ if (!(scopy = sdup(config,s))) return zzjson;
+
+ if ((zzjson = zzjson_create_templ(config, ZZJSON_STRING)))
+ zzjson->value.string.string = scopy;
+ else
+ config->free(scopy);
+
+ return zzjson;
+}
+
+ZZJSON *zzjson_create_array(ZZJSON_CONFIG *config, ...) {
+ ZZJSON *zzjson, *retval, *val;
+ va_list ap;
+
+ if (!(zzjson = zzjson_create_templ(config, ZZJSON_ARRAY))) return zzjson;
+ retval = zzjson;
+
+ va_start(ap, config);
+ val = va_arg(ap, ZZJSON *);
+ while (val) {
+ zzjson->value.array.val = val;
+ val = va_arg(ap, ZZJSON *);
+
+ if (val) {
+ ZZJSON *next = zzjson_create_templ(config, ZZJSON_ARRAY);
+ if (!next) {
+ while (retval) {
+ next = retval->next;
+ config->free(retval);
+ retval = next;
+ }
+ break;
+ }
+ zzjson->next = next;
+ zzjson = next;
+ }
+ }
+ va_end(ap);
+ return retval;
+}
+
+ZZJSON *zzjson_create_object(ZZJSON_CONFIG *config, ...) {
+ ZZJSON *zzjson, *retval, *val;
+ char *label, *labelcopy;
+ va_list ap;
+
+ if (!(zzjson = zzjson_create_templ(config, ZZJSON_OBJECT))) return zzjson;
+ retval = zzjson;
+
+ va_start(ap, config);
+ label = va_arg(ap, char *);
+ while (label) {
+ val = va_arg(ap, ZZJSON *);
+ labelcopy = sdup(config, label);
+
+ if (!labelcopy) {
+ zzjson_free(config, retval);
+ retval = NULL;
+ break;
+ }
+
+ zzjson->value.object.label = labelcopy;
+ zzjson->value.object.val = val;
+
+ label = va_arg(ap, char *);
+
+ if (label) {
+ ZZJSON *next = zzjson_create_templ(config, ZZJSON_OBJECT);
+ if (!next) {
+ while (retval) {
+ next = retval->next;
+ config->free(retval->value.object.label);
+ config->free(retval);
+ retval = next;
+ }
+ break;
+ }
+ zzjson->next = next;
+ zzjson = next;
+ }
+ }
+ va_end(ap);
+ return retval;
+}
+
+ZZJSON *zzjson_array_prepend(ZZJSON_CONFIG *config, ZZJSON *array,
+ ZZJSON *val) {
+ ZZJSON *zzjson;
+
+ if (!array->value.array.val) { /* empty array */
+ array->value.array.val = val;
+ return array;
+ }
+
+ zzjson = zzjson_create_templ(config, ZZJSON_ARRAY);
+ if (zzjson) {
+ zzjson->value.array.val = val;
+ zzjson->next = array;
+ }
+ return zzjson;
+}
+
+ZZJSON *zzjson_array_append(ZZJSON_CONFIG *config, ZZJSON *array,
+ ZZJSON *val) {
+ ZZJSON *retval = array, *zzjson;
+
+ if (!array->value.array.val) { /* empty array */
+ array->value.array.val = val;
+ return array;
+ }
+
+ zzjson = zzjson_create_templ(config, ZZJSON_ARRAY);
+ if (!zzjson) return NULL;
+
+ while (array->next) array = array->next;
+
+ zzjson->value.array.val = val;
+ array->next = zzjson;
+
+ return retval;
+}
+
+ZZJSON *zzjson_object_prepend(ZZJSON_CONFIG *config, ZZJSON *object,
+ char *label, ZZJSON *val) {
+ ZZJSON *zzjson = NULL;
+ char *labelcopy = sdup(config, label);
+
+ if (!labelcopy) return zzjson;
+
+ if (!object->value.object.label) { /* empty object */
+ object->value.object.label = labelcopy;
+ object->value.object.val = val;
+ return object;
+ }
+
+ zzjson = zzjson_create_templ(config, ZZJSON_OBJECT);
+ if (zzjson) {
+ zzjson->value.object.label = labelcopy;
+ zzjson->value.object.val = val;
+ zzjson->next = object;
+ } else {
+ config->free(labelcopy);
+ }
+ return zzjson;
+}
+
+ZZJSON *zzjson_object_append(ZZJSON_CONFIG *config, ZZJSON *object,
+ char *label, ZZJSON *val) {
+ ZZJSON *retval = object, *zzjson = NULL;
+ char *labelcopy = sdup(config, label);
+
+ if (!labelcopy) return zzjson;
+
+ if (!object->value.object.label) { /* empty object */
+ object->value.object.label = labelcopy;
+ object->value.object.val = val;
+ return object;
+ }
+
+ zzjson = zzjson_create_templ(config, ZZJSON_OBJECT);
+ if (!zzjson) {
+ config->free(labelcopy);
+ return NULL;
+ }
+
+ while (object->next) object = object->next;
+
+ zzjson->value.object.label = labelcopy;
+ zzjson->value.object.val = val;
+ object->next = zzjson;
+
+ return retval;
+}
+
diff --git a/com32/gpllib/zzjson/zzjson_free.c b/com32/gpllib/zzjson/zzjson_free.c
new file mode 100644
index 00000000..01dfd242
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_free.c
@@ -0,0 +1,29 @@
+/* JSON free
+ * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+
+void zzjson_free(ZZJSON_CONFIG *config, ZZJSON *zzjson) {
+ while (zzjson) {
+ ZZJSON *next;
+ switch(zzjson->type) {
+ case ZZJSON_OBJECT:
+ config->free(zzjson->value.object.label);
+ zzjson_free(config, zzjson->value.object.val);
+ break;
+ case ZZJSON_ARRAY:
+ zzjson_free(config, zzjson->value.array.val);
+ break;
+ case ZZJSON_STRING:
+ config->free(zzjson->value.string.string);
+ break;
+ default:
+ break;
+ }
+ next = zzjson->next;
+ config->free(zzjson);
+ zzjson = next;
+ }
+}
diff --git a/com32/gpllib/zzjson/zzjson_parse.c b/com32/gpllib/zzjson/zzjson_parse.c
new file mode 100644
index 00000000..ecb6f61e
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_parse.c
@@ -0,0 +1,490 @@
+/* JSON Parser
+ * ZZJSON - Copyright (C) 2008-2009 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+
+#define GETC() config->getchar(config->ihandle)
+#define UNGETC(c) config->ungetchar(c, config->ihandle)
+#define SKIPWS() skipws(config)
+#ifdef CONFIG_NO_ERROR_MESSAGES
+#define ERROR(x...)
+#else
+#define ERROR(x...) config->error(config->ehandle, ##x)
+#endif
+#define MEMERROR() ERROR("out of memory")
+
+#define ALLOW_EXTRA_COMMA (config->strictness & ZZJSON_ALLOW_EXTRA_COMMA)
+#define ALLOW_ILLEGAL_ESCAPE (config->strictness & ZZJSON_ALLOW_ILLEGAL_ESCAPE)
+#define ALLOW_CONTROL_CHARS (config->strictness & ZZJSON_ALLOW_CONTROL_CHARS)
+#define ALLOW_GARBAGE_AT_END (config->strictness & ZZJSON_ALLOW_GARBAGE_AT_END)
+#define ALLOW_COMMENTS (config->strictness & ZZJSON_ALLOW_COMMENTS)
+
+static ZZJSON *parse_array(ZZJSON_CONFIG *config);
+static ZZJSON *parse_object(ZZJSON_CONFIG *config);
+
+static void skipws(ZZJSON_CONFIG *config) {
+ int d, c = GETC();
+morews:
+ while (isspace(c)) c = GETC();
+ if (!ALLOW_COMMENTS) goto endws;
+ if (c != '/') goto endws;
+ d = GETC();
+ if (d != '*') goto endws; /* pushing back c will generate a parse error */
+ c = GETC();
+morecomments:
+ while (c != '*') {
+ if (c == EOF) goto endws;
+ c = GETC();
+ }
+ c = GETC();
+ if (c != '/') goto morecomments;
+ c = GETC();
+ if (isspace(c) || c == '/') goto morews;
+endws:
+ UNGETC(c);
+}
+
+static char *parse_string(ZZJSON_CONFIG *config) {
+ unsigned int len = 16, pos = 0;
+ int c;
+ char *str = NULL;
+
+ SKIPWS();
+ c = GETC();
+ if (c != '"') {
+ ERROR("string: expected \" at the start");
+ return NULL;
+ }
+
+ str = config->malloc(len);
+ if (!str) {
+ MEMERROR();
+ return NULL;
+ }
+ c = GETC();
+ while (c > 0 && c != '"') {
+ if (!ALLOW_CONTROL_CHARS && c >= 0 && c <= 31) {
+ ERROR("string: control characters not allowed");
+ goto errout;
+ }
+ if (c == '\\') {
+ c = GETC();
+ switch (c) {
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'u': {
+ UNGETC(c); /* ignore \uHHHH, copy verbatim */
+ c = '\\';
+ break;
+ }
+ case '\\': case '/': case '"':
+ break;
+ default:
+ if (!ALLOW_ILLEGAL_ESCAPE) {
+ ERROR("string: illegal escape character");
+ goto errout;
+ }
+ }
+ }
+ str[pos++] = c;
+ if (pos == len-1) {
+ void *tmp = str;
+ len *= 2;
+ str = config->realloc(str, len);
+ if (!str) {
+ MEMERROR();
+ str = tmp;
+ goto errout;
+ }
+ }
+ c = GETC();
+ }
+ if (c != '"') {
+ ERROR("string: expected \" at the end");
+ goto errout;
+ }
+ str[pos] = 0;
+ return str;
+
+errout:
+ config->free(str);
+ return NULL;
+}
+
+static ZZJSON *parse_string2(ZZJSON_CONFIG *config) {
+ ZZJSON *zzjson = NULL;
+ char *str;
+
+ str = parse_string(config);
+ if (str) {
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ config->free(str);
+ return NULL;
+ }
+ zzjson->type = ZZJSON_STRING;
+ zzjson->value.string.string = str;
+ }
+ return zzjson;
+}
+
+static ZZJSON *parse_number(ZZJSON_CONFIG *config) {
+ ZZJSON *zzjson;
+ unsigned long long ival = 0, expo = 0;
+ double dval = 0.0, frac = 0.0, fracshft = 10.0;
+ int c, dbl = 0, sign = 1, signexpo = 1;
+
+ SKIPWS();
+ c = GETC();
+ if (c == '-') {
+ sign = -1;
+ c = GETC();
+ }
+ if (c == '0') {
+ c = GETC();
+ goto skip;
+ }
+
+ if (!isdigit(c)) {
+ ERROR("number: digit expected");
+ return NULL;
+ }
+
+ while (isdigit(c)) {
+ ival *= 10;
+ ival += c - '0';
+ c = GETC();
+ }
+
+skip:
+ if (c != '.') goto skipfrac;
+
+ dbl = 1;
+
+ c = GETC();
+ if (!isdigit(c)) {
+ ERROR("number: digit expected");
+ return NULL;
+ }
+
+ while (isdigit(c)) {
+ frac += (double)(c - '0') / fracshft;
+ fracshft *= 10.0;
+ c = GETC();
+ }
+
+skipfrac:
+ if (c != 'e' && c != 'E') goto skipexpo;
+
+ dbl = 1;
+
+ c = GETC();
+ if (c == '+')
+ c = GETC();
+ else if (c == '-') {
+ signexpo = -1;
+ c = GETC();
+ }
+
+ if (!isdigit(c)) {
+ ERROR("number: digit expected");
+ return NULL;
+ }
+
+ while (isdigit(c)) {
+ expo *= 10;
+ expo += c - '0';
+ c = GETC();
+ }
+
+skipexpo:
+ UNGETC(c);
+
+ if (dbl) {
+ dval = sign * (long long) ival;
+ dval += sign * frac;
+ dval *= pow(10.0, (double) signexpo * expo);
+ }
+
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ return NULL;
+ }
+ if (dbl) {
+ zzjson->type = ZZJSON_NUMBER_DOUBLE;
+ zzjson->value.number.val.dval = dval;
+ } else {
+ zzjson->type = sign < 0 ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT;
+ zzjson->value.number.val.ival = ival;
+ }
+
+ return zzjson;
+}
+
+static ZZJSON *parse_literal(ZZJSON_CONFIG *config, char *s, ZZJSON_TYPE t) {
+ char b[strlen(s)+1];
+ unsigned int i;
+
+ for (i=0; i<strlen(s); i++) b[i] = GETC();
+ b[i] = 0;
+
+ if (!strcmp(b,s)) {
+ ZZJSON *zzjson;
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ return NULL;
+ }
+ zzjson->type = t;
+ return zzjson;
+ }
+ ERROR("literal: expected %s", s);
+ return NULL;
+}
+
+static ZZJSON *parse_true(ZZJSON_CONFIG *config) {
+ return parse_literal(config, (char *)"true", ZZJSON_TRUE);
+}
+
+static ZZJSON *parse_false(ZZJSON_CONFIG *config) {
+ return parse_literal(config, (char *)"false", ZZJSON_FALSE);
+}
+
+static ZZJSON *parse_null(ZZJSON_CONFIG *config) {
+ return parse_literal(config, (char *)"null", ZZJSON_NULL);
+}
+
+static ZZJSON *parse_value(ZZJSON_CONFIG *config) {
+ ZZJSON *retval = NULL;
+ int c;
+
+ SKIPWS();
+ c = GETC();
+ UNGETC(c);
+ switch (c) {
+ case '"': retval = parse_string2(config); break;
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case '-':
+ retval = parse_number(config); break;
+ case '{': retval = parse_object(config); break;
+ case '[': retval = parse_array(config); break;
+ case 't': retval = parse_true(config); break;
+ case 'f': retval = parse_false(config); break;
+ case 'n': retval = parse_null(config); break;
+ }
+
+ if (!retval) {
+ ERROR("value: invalid value");
+ return retval;
+ }
+
+ return retval;
+}
+
+static ZZJSON *parse_array(ZZJSON_CONFIG *config) {
+ ZZJSON *retval = NULL, **next = &retval;
+ int c;
+
+ SKIPWS();
+ c = GETC();
+ if (c != '[') {
+ ERROR("array: expected '['");
+ return NULL;
+ }
+
+ SKIPWS();
+ c = GETC();
+ while (c > 0 && c != ']') {
+ ZZJSON *zzjson = NULL, *val = NULL;
+
+ UNGETC(c);
+
+ SKIPWS();
+ val = parse_value(config);
+ if (!val) {
+ ERROR("array: value expected");
+ goto errout;
+ }
+
+ SKIPWS();
+ c = GETC();
+ if (c != ',' && c != ']') {
+ ERROR("array: expected ',' or ']'");
+errout_with_val:
+ zzjson_free(config, val);
+ goto errout;
+ }
+ if (c == ',') {
+ SKIPWS();
+ c = GETC();
+ if (c == ']' && !ALLOW_EXTRA_COMMA) {
+ ERROR("array: expected value after ','");
+ goto errout_with_val;
+ }
+ }
+ UNGETC(c);
+
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ zzjson_free(config, val);
+ goto errout_with_val;
+ }
+ zzjson->type = ZZJSON_ARRAY;
+ zzjson->value.array.val = val;
+ *next = zzjson;
+ next = &zzjson->next;
+
+ c = GETC();
+ }
+
+ if (c != ']') {
+ ERROR("array: expected ']'");
+ goto errout;
+ }
+
+ if (!retval) { /* empty array, [ ] */
+ retval = config->calloc(1, sizeof(ZZJSON));
+ if (!retval) {
+ MEMERROR();
+ return NULL;
+ }
+ retval->type = ZZJSON_ARRAY;
+ }
+
+ return retval;
+
+errout:
+ zzjson_free(config, retval);
+ return NULL;
+}
+
+static ZZJSON *parse_object(ZZJSON_CONFIG *config) {
+ ZZJSON *retval = NULL;
+ int c;
+ ZZJSON **next = &retval;
+
+ SKIPWS();
+ c = GETC();
+ if (c != '{') {
+ ERROR("object: expected '{'");
+ return NULL;
+ }
+
+ SKIPWS();
+ c = GETC();
+ while (c > 0 && c != '}') {
+ ZZJSON *zzjson = NULL, *val = NULL;
+ char *str;
+
+ UNGETC(c);
+
+ str = parse_string(config);
+ if (!str) {
+ ERROR("object: expected string");
+errout_with_str:
+ config->free(str);
+ goto errout;
+ }
+
+ SKIPWS();
+ c = GETC();
+ if (c != ':') {
+ ERROR("object: expected ':'");
+ goto errout_with_str;
+ }
+
+ SKIPWS();
+ val = parse_value(config);
+ if (!val) {
+ ERROR("object: value expected");
+ goto errout_with_str;
+ }
+
+ SKIPWS();
+ c = GETC();
+ if (c != ',' && c != '}') {
+ ERROR("object: expected ',' or '}'");
+errout_with_str_and_val:
+ zzjson_free(config, val);
+ goto errout_with_str;
+ }
+ if (c == ',') {
+ SKIPWS();
+ c = GETC();
+ if (c == '}' && !ALLOW_EXTRA_COMMA) {
+ ERROR("object: expected pair after ','");
+ goto errout_with_str_and_val;
+ }
+ }
+ UNGETC(c);
+
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ goto errout_with_str_and_val;
+ }
+ zzjson->type = ZZJSON_OBJECT;
+ zzjson->value.object.label = str;
+ zzjson->value.object.val = val;
+ *next = zzjson;
+ next = &zzjson->next;
+
+ c = GETC();
+ }
+
+ if (c != '}') {
+ ERROR("object: expected '}'");
+ goto errout;
+ }
+
+ if (!retval) { /* empty object, { } */
+ retval = config->calloc(1, sizeof(ZZJSON));
+ if (!retval) {
+ MEMERROR();
+ return NULL;
+ }
+ retval->type = ZZJSON_OBJECT;
+ }
+
+ return retval;
+
+errout:
+ zzjson_free(config, retval);
+ return NULL;
+}
+
+ZZJSON *zzjson_parse(ZZJSON_CONFIG *config) {
+ ZZJSON *retval;
+ int c;
+
+ SKIPWS();
+ c = GETC();
+ UNGETC(c);
+ if (c == '[') retval = parse_array(config);
+ else if (c == '{') retval = parse_object(config);
+ else { ERROR("expected '[' or '{'"); return NULL; }
+
+ if (!retval) return NULL;
+
+ SKIPWS();
+ c = GETC();
+ if (c >= 0 && !ALLOW_GARBAGE_AT_END) {
+ ERROR("parse: garbage at end of file");
+ zzjson_free(config, retval);
+ return NULL;
+ }
+
+ return retval;
+}
diff --git a/com32/gpllib/zzjson/zzjson_print.c b/com32/gpllib/zzjson/zzjson_print.c
new file mode 100644
index 00000000..a59b3b09
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_print.c
@@ -0,0 +1,110 @@
+/* JSON Printer
+ * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+
+#define PRINT(fmt...) if (config->print(config->ohandle, ##fmt) < 0) return -1;
+//#define PUTC(c) if (config->putchar(c, config->ohandle) < 0) return -1;
+#define PUTC(c) PRINT("%c",c)
+#define INC 4
+
+static int print_string(ZZJSON_CONFIG *config, char *s) {
+ int c, bs;
+ if (!s) return 0;
+ while ((c = *s++)) {
+ bs = 1;
+ switch (c) {
+// case '/': // useless escape of forward slash
+ case '\\':
+ if (*s == 'u') bs = 0; // copy \uHHHH verbatim
+ break;
+ case '"': break;
+ case '\b': c = 'b'; break;
+ case '\f': c = 'f'; break;
+ case '\n': c = 'n'; break;
+ case '\r': c = 'r'; break;
+ case '\t': c = 't'; break;
+ default: bs = 0; break;
+ }
+ if (bs) PUTC('\\');
+ PUTC(c);
+ }
+ return 0;
+}
+
+static int zzjson_print2(ZZJSON_CONFIG *config, ZZJSON *zzjson,
+ unsigned int indent, unsigned int objval) {
+ char c = 0, d = 0;
+ if (!zzjson) return -1;
+
+ switch(zzjson->type) {
+ case ZZJSON_OBJECT: c = '{'; d = '}'; break;
+ case ZZJSON_ARRAY: c = '['; d = ']'; break;
+ default: break;
+ }
+
+ if (c) PRINT("%s%*s%c", indent ? "\n" : "", indent, "", c);
+
+ while (zzjson) {
+ switch(zzjson->type) {
+ case ZZJSON_OBJECT:
+ if (zzjson->value.object.val) {
+ PRINT("\n%*s\"", indent+INC, "");
+ if (print_string(config, zzjson->value.object.label) < 0)
+ return -1;
+ PRINT("\" :");
+ if (zzjson_print2(config, zzjson->value.object.val,
+ indent+INC, 1) < 0) return -1;
+ }
+ break;
+ case ZZJSON_ARRAY:
+ if (zzjson->value.array.val)
+ if (zzjson_print2(config, zzjson->value.array.val,
+ indent+INC, 0) < 0) return -1;
+ break;
+ case ZZJSON_STRING:
+ PRINT(objval ? " \"" : "\n%*s\"", indent, "");
+ if (print_string(config, zzjson->value.string.string)<0) return -1;
+ PUTC('"');
+ break;
+ case ZZJSON_FALSE:
+ PRINT(objval ? " false" : "\n%*sfalse", indent, "");
+ break;
+ case ZZJSON_NULL:
+ PRINT(objval ? " null" : "\n%*snull", indent, "");
+ break;
+ case ZZJSON_TRUE:
+ PRINT(objval ? " true" : "\n%*strue", indent, "");
+ break;
+ case ZZJSON_NUMBER_NEGINT:
+ case ZZJSON_NUMBER_POSINT:
+ case ZZJSON_NUMBER_DOUBLE:
+ PRINT(objval ? " " : "\n%*s", indent, "");
+ if (zzjson->type == ZZJSON_NUMBER_DOUBLE) {
+ PRINT("%16.16e", zzjson->value.number.val.dval);
+ } else {
+ if (zzjson->type == ZZJSON_NUMBER_NEGINT) PUTC('-');
+ PRINT("%llu", zzjson->value.number.val.ival);
+ }
+ default:
+ break;
+ }
+ zzjson = zzjson->next;
+ if (zzjson) PUTC(',');
+ }
+
+ if (d) PRINT("\n%*s%c", indent, "", d);
+
+ return 0;
+}
+
+int zzjson_print(ZZJSON_CONFIG *config, ZZJSON *zzjson) {
+ int retval = zzjson_print2(config, zzjson, 0, 0);
+// if (retval >= 0) retval = config->putchar('\n', config->ohandle);
+#ifndef CONFIG_NO_ERROR_MESSAGES
+ if (retval < 0) config->error(config->ehandle, "print: unable to print");
+#endif
+ return retval;
+}
diff --git a/com32/gpllib/zzjson/zzjson_query.c b/com32/gpllib/zzjson/zzjson_query.c
new file mode 100644
index 00000000..35ba7b79
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_query.c
@@ -0,0 +1,63 @@
+/* JSON query
+ * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+#include <string.h>
+#include <stdarg.h>
+
+ZZJSON *zzjson_object_find_label(ZZJSON *zzjson, char *label) {
+ if (zzjson->type != ZZJSON_OBJECT) return NULL;
+
+ while (zzjson) {
+ char *string = zzjson->value.object.label;
+
+ if (zzjson->type != ZZJSON_OBJECT) return NULL;
+ if (!string) return NULL;
+
+ if (!strcmp(string, label))
+ return zzjson->value.object.val;
+ zzjson = zzjson->next;
+ }
+ return NULL;
+}
+
+ZZJSON *zzjson_object_find_labels(ZZJSON *zzjson, ...) {
+ va_list ap;
+ char *lbl;
+
+ va_start(ap, zzjson);
+ lbl = va_arg(ap, char *);
+ while (lbl) {
+ zzjson = zzjson_object_find_label(zzjson, lbl);
+ if (!zzjson) break;
+ lbl = va_arg(ap, char *);
+ }
+ va_end(ap);
+
+ return zzjson;
+}
+
+unsigned int zzjson_object_count(ZZJSON *zzjson) {
+ unsigned int count = 1;
+
+ if (zzjson->type != ZZJSON_OBJECT) return 0;
+ if (!zzjson->value.object.label) return 0; /* empty { } */
+
+ while ((zzjson = zzjson->next)) count++;
+
+ return count;
+}
+
+unsigned int zzjson_array_count(ZZJSON *zzjson) {
+ unsigned int count = 1;
+
+ if (zzjson->type != ZZJSON_ARRAY) return 0;
+ if (!zzjson->value.array.val) return 0; /* empty [ ] */
+
+ while ((zzjson = zzjson->next)) count++;
+
+ return count;
+}
+