/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 2010-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* xml method
*
* Glenn Fowler
* AT&T Research
*/
static const char usage[] =
"[+DESCRIPTION?The \bdss\b xml method reads XML data in two formats: "
"pure XML (\aname=value\a attributes within tags ignored) and JSON. In "
"general XML data provides field names but not type information, so by "
"default all fields are treated as strings. Only fields specified in the "
"\bdss\b(1) \aexpression\a are parsed from the data. Fields are named "
"using \b.\b'd notation, where each prefix name represents XML tag "
"nesting. For XML data, if all records have the same XML tag prefix then "
"that prefix may be omitted, except that all field names must have at "
"least one prefix component. For example, \busers.user.name\b and "
"\buser.name\b are valid, but \bname\b is not.]"
"[+?The xml method schema is an XML document that specifies the type of "
"one or more fields, and any libraries required to support those types.]"
"[T:test?Enable implementation-specific tests and tracing.]#[mask]"
"[+TAGS?The supported tags are:]{"
;
#include <dsslib.h>
#include <ctype.h>
{
};
{
};
{
};
{
};
{
char* root;
int image;
int maxname;
int maxlevel;
int prefix;
};
extern Dsslib_t dss_lib_xml;
/*
* type==0 for prefix components
*/
static Cxvariable_t*
{
char* s;
int n;
int i;
if (*name == '.')
{
{
return 0;
}
return 0;
if ((val->number = cxisnumber(var->type)) && !(val->internalf = var->type->internalf) && var->type->base)
if (type)
{
n = 0;
for (s = name; *s; s++)
if (*s == '.')
{
*s = 0;
*s = '.';
if (i)
return 0;
n++;
}
{
else
{
return 0;
}
}
}
}
return var;
}
/*
* xml identf
*/
static int
{
}
/*
* refill the input buffer and return the next char, -1 on error
*/
static int
{
size_t n;
{
if (f->rec)
{
{
{
return -1;
}
}
if (n > 1)
f->prvlen += n;
}
return -1;
if (f->rec)
c = f->save;
*f->end = 0;
}
return c;
}
#define RESIZE() \
do \
{ \
f->maxvalue += 1024; \
{ \
return -1; \
} \
} while (0)
/*
* xml readf -- consume 1 xml record and retain field values of interest
*/
static int
{
register char* np;
register char* ne;
register char* vp;
register char* ve;
register int c;
char* vb;
Cxvariable_t* v;
ssize_t o;
int q;
f->record++;
f->rec = 0;
f->prvlen = 0;
for (;;)
{
/* find the next tag */
for (;;)
{
while (!xml_beg_tag[*f->cur++]);
if (*(f->cur - 1))
break;
if (c == '<')
break;
}
tag:
if (!(c = *f->cur++))
REFILL(f, c, -1);
switch (c)
{
case '/':
if (f->level)
f->level--;
/*FALLTHROUGH*/
case '?':
for (;;)
{
while (!xml_end_tag[*f->cur++]);
if (*(f->cur - 1))
break;
REFILL(f, o, goto incomplete);
if (o == '>')
break;
}
{
return 1;
}
break;
default:
{
*np = 0;
{
RESIZE();
*vp++ = '1';
RESIZE();
*vp++ = 0;
}
}
else
f->level++;
*np++ = '.';
*np++ = c;
q = 0;
for (;;)
{
while (!xml_end_tag[c = *f->cur++])
*np++ = c;
else
q = c;
if (c)
break;
REFILL(f, c, goto incomplete);
if (c == '>')
break;
*np++ = c;
else
q = c;
}
{
/* null tag */
if (f->level)
f->level--;
}
else
{
/* ignore tag name=value attributes -- why did they allow them */
if (c == ' ')
{
q = 0;
for (;;)
{
while (!xml_end_att[c = *f->cur++]);
if (!c)
REFILL(f, c, goto incomplete);
if (c == '"')
q = !q;
else if (!q && c == '>')
break;
}
}
{
*np = 0;
{
for (;;)
{
while (!xml_beg_tag[c = *f->cur++])
{
RESIZE();
*vp++ = c;
}
if (*(f->cur - 1))
break;
REFILL(f, c, goto incomplete);
if (c == '<')
break;
RESIZE();
*vp++ = c;
}
RESIZE();
*vp++ = 0;
goto tag;
}
}
}
break;
}
}
done:
return 0;
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: record %I*u incomplete", file->path, sizeof(f->record), f->record);
return -1;
}
/*
* xml writef -- output current record
*/
static int
{
size_t n;
{
return -1;
}
{
return -1;
}
return 0;
}
/*
* xml fopenf
*/
static int
{
register unsigned char* s;
register unsigned char* t;
register int n;
File_t* f;
int c;
int m;
int x;
unsigned char* buf;
unsigned char* end;
buf = 0;
{
{
{
{
(*disc->errorf)(NiL, disc, 2, "%s variable names must be qualified by at least the immediate containing tag", file->format->name);
return -1;
}
x = *end;
*end = 0;
s = buf;
n = 0;
m = -1;
for (;;)
{
while (!xml_beg_tag[*s++]);
if (*(s - 1))
{
t = s;
while (!xml_end_tag[*s++]);
if (*t == '/')
{
if (m > 0)
{
m--;
n -= s - t - 2;
}
}
else if (*t != '?')
{
m++;
n += (c = s - t - 1);
break;
}
}
else if (s >= end)
break;
}
*end = x;
}
else
{
}
}
}
{
return -1;
}
{
if (buf)
{
*end = 0;
}
else
f->maxvalue = 1024;
{
return -1;
}
}
return 0;
}
/*
* xml fclosef
*/
static int
{
return -1;
return 0;
}
{
"xml",
"xml format (2010-05-19)",
CXH,
0,
0,
0,
0
};
/*
* json identf
*/
static int
{
register char* s;
register char* e;
register const char* m;
s = buf;
e = s + n;
for (m = magic; s < e; s++)
if (isspace(*s))
;
else if (*s != *m)
return 0;
else if (!*++m)
return 1;
return 0;
}
/*
* json readf
*/
static int
{
register char* np;
register char* ne;
register char* vp;
register char* ve;
register int c;
char* vb;
Cxvariable_t* v;
size_t o;
int a;
int e;
int q;
int n;
f->record++;
f->rec = 0;
f->prvlen = 0;
for (;;)
{
beg:
do
{
while (!json_beg_tag[c = *f->cur++]);
if (!c)
if (c == '}')
{
if (!f->level)
{
return 1;
}
}
} while (c != '{' && c != ',');
tag:
do
{
if (!c)
REFILL(f, c, goto incomplete);
} while (json_end_val[c] == 1);
else
f->level++;
*np++ = '.';
*np++ = c;
for (;;)
{
while (!json_end_val[c = *f->cur++])
*np++ = c;
if (!c)
REFILL(f, c, goto incomplete);
if (c == '"')
{
q = !q;
continue;
}
else if (c == '\\')
{
if (!(c = *f->cur++))
REFILL(f, c, goto incomplete);
}
else if (!q)
{
if (c == '}')
{
if (!f->level)
{
return 1;
}
break;
}
else if (c == ':')
{
do
{
if (!c)
REFILL(f, c, goto incomplete);
} while (json_end_val[c] == 1);
if (c == '{')
{
{
*np = 0;
{
RESIZE();
*vp++ = '1';
RESIZE();
*vp++ = 0;
}
}
goto tag;
}
a = 0;
q = 0;
{
*np = 0;
{
e = c == 'n';
for (;;)
{
if (c == '"')
{
q = !q;
goto ignore;
}
else if (c == '\\')
{
if (!(c = *f->cur++))
REFILL(f, c, goto incomplete);
if (c != '\\' && c != '"' && c != ',' && c != '}')
{
RESIZE();
*vp++ = '\\';
}
}
else if (!q)
{
if (c == '[')
{
a++;
goto ignore;
}
else if (c == ']')
{
if (a)
a--;
goto ignore;
}
else if (json_end_val[c] == 1)
goto ignore;
else if (a)
/*array*/;
else if (c == '}')
{
if (!f->level)
{
return 1;
}
break;
}
else if (c == ',')
break;
}
RESIZE();
*vp++ = c;
while (!json_end_val[c = *f->cur++])
{
RESIZE();
*vp++ = c;
}
if (!c)
REFILL(f, c, goto incomplete);
}
if (e)
*vp++ = 0;
if (!f->level)
{
return 1;
}
if (c == ',')
goto tag;
goto beg;
}
}
n = 1;
for (;;)
{
if (c == '"')
q = !q;
else if (c == '\\')
{
if (!(c = *f->cur++))
REFILL(f, c, goto incomplete);
}
else if (!q)
{
if (c == '[')
a++;
else if (c == ']')
{
if (a)
a--;
}
else if (a)
/*array*/;
else if (c == '{')
n++;
else if (c == '}' && !--n)
{
if (!f->level)
{
return 1;
}
break;
}
else if (c == ',' && n == 1)
break;
}
while (!json_end_val[c = *f->cur++]);
if (!c)
}
if (!f->level)
{
return 1;
}
if (c == ',')
goto tag;
goto beg;
}
else if (json_end_val[c] == 1)
continue;
}
*np++ = c;
}
}
done:
if (!f->level)
return 0;
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: record %I*u incomplete", file->path, sizeof(f->record), f->record);
return -1;
}
/*
* xml writef -- output current record
*/
static int
{
size_t n;
{
return -1;
}
{
return -1;
}
return 0;
}
{
"json",
"json format (2010-05-19)",
CXH,
0,
0,
0,
0
};
static int
op_get(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
{
char* s;
if (v)
{
else
{
s = (char*)null;
v->size = 0;
}
if (!v->internalf)
{
}
else if ((*v->internalf)(cx, pc->data.variable->type, NiL, &pc->data.variable->format, r, s, v->size, cx->rm, disc) < 0)
return -1;
}
return 0;
}
static int
op_ref(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
{
}
{
};
static int
{
{
return -1;
}
return 0;
}
static int
{
char* s;
if (!*s)
s = "number";
{
return -1;
}
{
}
{
if (streq(s, "string"))
else if (streq(s, "buffer"))
}
return 0;
}
{
"NAME", "Field name.",
0,0,xml_field_name_dat,0,
"TYPE", "Field type. The intrinsic types are number and"
" string. Other types are defined in optional"
" method and schema libraries.",
0,0,xml_field_type_dat,0,
0
};
static int
{
{
return -1;
}
return 0;
}
static int
{
{
return -1;
}
return 0;
}
static int
{
register Library_t* p;
{
return -1;
}
if (!xml->lastlibrary)
else
return 0;
}
static Tags_t*
{
Field_t* f;
if (name)
{
{
return 0;
}
else
}
return &tags_xml_field[0];
}
static int
{
{
return -1;
}
return 0;
}
{
"NAME", "Schema name.",
0,0,xml_name_dat,0,
"DESCRIPTION", "Schema description.",
0,0,xml_description_dat,0,
" more than one library may be specified.",
0,0,xml_library_dat,0,
"FIELD", "Field info.",
0
};
static Tags_t*
{
return &tags_xml[0];
}
{
"METHOD", "Method name; must be xml.",
0,0,0,0,
"XML", "xml method schema.",
0,xml_beg,0,0,
0
};
/*
* methf
*/
static Dssmeth_t*
xmlmeth(const char* name, const char* options, const char* schema, Dssdisc_t* disc, Dssmeth_t* meth)
{
Library_t* p;
char* s;
{
return 0;
}
sp = 0;
if (options)
{
goto drop;
goto drop;
goto drop;
sp = 0;
for (;;)
{
{
case 'T':
continue;
case '?':
goto drop;
case ':':
goto drop;
}
break;
}
}
{
return 0;
goto drop;
sp = 0;
}
return 0;
return meth;
drop:
if (sp)
return 0;
}
/*
* openf
*/
static int
{
Field_t* f;
Field_t* g;
Cxvariable_t* v;
int i;
if (xml)
{
for (i = 0; i < elementsof(local_callouts); i++)
return -1;
xml_beg_tag[0] = 1;
xml_end_tag[0] = 1;
xml_end_att[0] = 1;
json_beg_tag[0] = 2;
json_end_val[0] = 2;
{
g = f->next;
return -1;
free(f);
}
}
return 0;
}
{
"xml",
"xml and json method",
CXH,
0,
0
};
{
"xml",
"xml method"
"[-1ls5Pp0?\n@(#)$Id: dss xml method (AT&T Research) 2010-04-22 $\n]"
CXH,
0,
&method,
};