Skip to content

Commit

Permalink
Merge pull request #32 from flightaware/better-array-parsing
Browse files Browse the repository at this point in the history
Better array parsing
  • Loading branch information
lehenbauer authored May 7, 2018
2 parents 7ee16a6 + 584979e commit 1ae0fe8
Show file tree
Hide file tree
Showing 9 changed files with 338 additions and 10 deletions.
3 changes: 2 additions & 1 deletion README.FreeBSD
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
#

autoconf
./configure --with-tcl=/usr/local/lib/tcl8.6 --mandir=/usr/local/man --enable-symbols
./configure --with-tcl=/usr/local/lib/tcl8.6 --mandir=/usr/local/man
#--enable-symbols

6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

### This is yajl-tcl, a direct Tcl interface to the yajl JSON generator library.

*Version 1.6.2*
*Version 1.7.0*

This package is a freely available open source package under the "Berkeley" license, same as Tcl. You can do virtually anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. See the file "LICENSE" for complete information.

Expand Down Expand Up @@ -178,6 +178,10 @@ innerType = Feature, geom = type Point coordinates {-106.6091944 35.0401944}
innerType = Feature, geom = type Point coordinates {-118.3586667 34.206667}
```

A slight variation of json2dict is ```yajl::json2dict_ex```. This version turns JSON into a fully traversable Tcl dictionary by virtue of that it expands JSON arrays into key-value pairs, as might be done with a map, where the keys are synthetized sequential integers starting from zero.

After having parsed a list of channels returned from the Slack API, for instance, to fetch the ID of the third member of the fourth channel you might say ```dict get $dict channels 3 members 2```. See the tests file json2dict_ex.test included in the distro for a nice big JSON structure that hopefully will make clear what's going on.

Parsing to huddle
=================

Expand Down
2 changes: 1 addition & 1 deletion configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dnl to configure the system for the local environment.
# so you can encode the package version directly into the source files.
#-----------------------------------------------------------------------

AC_INIT([yajltcl], [1.6.2])
AC_INIT([yajltcl], [1.7.0])

#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
Expand Down
2 changes: 1 addition & 1 deletion doc/yajl-tcl.man
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[manpage_begin yajl-tcl n 1.6.1]
[manpage_begin yajl-tcl n 1.7.0]
[moddesc {Tcl bindings for Yet Another JSON Library (YAJL)}]
[copyright {2010 FlightAware LLC (BSD License)}]
[titledesc {Tcl bindings for Yet Another JSON Library (YAJL)}]
Expand Down
165 changes: 160 additions & 5 deletions generic/yajltcl.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,20 @@ parse2dict_start_sublist_callback (void *context)
return 1;
}

/* parse2dict_start_array_callback - start an array
*/
static int
parse2dict_start_array_callback (void *context)
{
yajltcl_clientData *yajlData = context;

// start a sublist unless we're at the top level
if (yajlData->p2dDepth++ > 0) {
Tcl_DStringStartSublist (&yajlData->p2dString);
}
return 1;
}

/* parse2dict_end_sublist_callback - finish a sublist
*/
static int
Expand All @@ -281,6 +295,19 @@ parse2dict_end_sublist_callback (void *context)
return 1;
}

/* parse2dict_end_array_callback - finish an array
*/
static int
parse2dict_end_array_callback (void *context)
{
yajltcl_clientData *yajlData = context;

if (--yajlData->p2dDepth > 0) {
Tcl_DStringEndSublist (&yajlData->p2dString);
}
return 1;
}

/* define the yajl callbacks table */
static yajl_callbacks parse2dict_callbacks = {
parse2dict_null_callback,
Expand All @@ -292,8 +319,122 @@ static yajl_callbacks parse2dict_callbacks = {
parse2dict_start_sublist_callback,
parse2dict_string_callback,
parse2dict_end_sublist_callback,
parse2dict_start_sublist_callback,
parse2dict_end_sublist_callback
parse2dict_start_array_callback,
parse2dict_end_array_callback
};

static void
parse2dictex_possibly_insert_array_index (yajltcl_clientData *yajlData) {
// fprintf (stderr, "parse2dictex_possibly_insert_array_index level %d, element value %d\n", yajlData->p2dDepth, yajlData->arrayElement[yajlData->p2dDepth]);
if (yajlData->arrayElement[yajlData->p2dDepth] == -1) return;

int elementNum = yajlData->arrayElement[yajlData->p2dDepth]++;
char str[16];
snprintf (str, 16, "%d", elementNum);
Tcl_DStringSetLength (&yajlData->dString, 0);
Tcl_DStringAppend (&yajlData->dString, str, -1);
Tcl_DStringAppendElement (&yajlData->p2dString, Tcl_DStringValue (&yajlData->dString));
}

/* parse2dictex_null_callback - append a null element to the dynamic string
*/
static int
parse2dictex_null_callback (void *context)
{
yajltcl_clientData *yajlData = context;

parse2dictex_possibly_insert_array_index (yajlData);
Tcl_DStringAppendElement (&yajlData->p2dString, "null");
return 1;
}

/* parse2dictex_boolean_callback - append a boolean element to the dynamic string
*/
static int
parse2dictex_boolean_callback (void *context, int boolean)
{
yajltcl_clientData *yajlData = context;

parse2dictex_possibly_insert_array_index (yajlData);
Tcl_DStringAppendElement (&yajlData->p2dString, boolean ? "1" : "0");
return 1;
}

/* parse2dictex_number_callback - append a number element to the dynamic string
*/
static int
parse2dictex_number_callback (void *context, const char *s, size_t l)
{
yajltcl_clientData *yajlData = context;

parse2dictex_possibly_insert_array_index (yajlData);
Tcl_DStringSetLength (&yajlData->dString, 0);
Tcl_DStringAppend (&yajlData->dString, s, l);
Tcl_DStringAppendElement (&yajlData->p2dString, Tcl_DStringValue (&yajlData->dString));
return 1;
}

/* parse2dictex_string_callback - append a element to the dynamic string
*/
static int
parse2dictex_string_callback (void *context, const unsigned char *stringVal, size_t stringLen)
{
yajltcl_clientData *yajlData = context;

parse2dictex_possibly_insert_array_index (yajlData);
Tcl_DStringSetLength (&yajlData->dString, 0);
Tcl_DStringAppend (&yajlData->dString, (const char *)stringVal, stringLen);
Tcl_DStringAppendElement (&yajlData->p2dString, Tcl_DStringValue (&yajlData->dString));
return 1;
}

/* parse2dictex_start_sublist_callback - start a sublist
*/
static int
parse2dictex_start_sublist_callback (void *context)
{
yajltcl_clientData *yajlData = context;

parse2dictex_possibly_insert_array_index (yajlData);
// start a sublist unless we're at the top level
if (yajlData->p2dDepth++ > 0) {
Tcl_DStringStartSublist (&yajlData->p2dString);
}
// fprintf (stderr, "parse2dictex_start_sublist_callback level %d\n", yajlData->p2dDepth);
yajlData->arrayElement[yajlData->p2dDepth] = -1;
return 1;
}

/* parse2dictex_start_array_callback - start an array
*/
static int
parse2dictex_start_array_callback (void *context)
{
yajltcl_clientData *yajlData = context;

parse2dictex_possibly_insert_array_index (yajlData);
// start a sublist unless we're at the top level
if (yajlData->p2dDepth++ > 0) {
Tcl_DStringStartSublist (&yajlData->p2dString);
}
// fprintf (stderr, "parse2dictex_start_array_callback level %d\n", yajlData->p2dDepth);
yajlData->arrayElement[yajlData->p2dDepth] = 0;
return 1;
}

/* define the yajl callbacks table */
static yajl_callbacks parse2dictex_callbacks = {
parse2dictex_null_callback,
parse2dictex_boolean_callback,
NULL,
NULL,
parse2dictex_number_callback,
parse2dictex_string_callback,
parse2dictex_start_sublist_callback,
parse2dictex_string_callback,
parse2dict_end_sublist_callback,
parse2dictex_start_array_callback,
parse2dict_end_array_callback
};

// }}}
Expand Down Expand Up @@ -452,6 +593,10 @@ yajltcl_free_parsers (yajltcl_clientData *yajlData)
yajl_free (yajlData->parse2dictHandle);
}

if (yajlData->parse2dictexHandle != NULL) {
yajl_free (yajlData->parse2dictexHandle);
}

if (yajlData->parse2huddleHandle != NULL) {
yajl_free (yajlData->parse2huddleHandle);
}
Expand Down Expand Up @@ -506,6 +651,7 @@ yajltcl_recreate_parsers (yajltcl_clientData *yajlData)

yajlData->parseHandle = yajltcl_make_parser (yajlData, &callbacks);
yajlData->parse2dictHandle = yajltcl_make_parser (yajlData, &parse2dict_callbacks);
yajlData->parse2dictexHandle = yajltcl_make_parser (yajlData, &parse2dictex_callbacks);
yajlData->parse2huddleHandle = yajltcl_make_parser (yajlData, &parse2huddle_callbacks);
}

Expand Down Expand Up @@ -658,6 +804,7 @@ yajltcl_yajlObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Obj
"delete",
"parse",
"parse2dict",
"parse2dict_ex",
"parse2huddle",
"parse_complete",
NULL
Expand All @@ -682,6 +829,7 @@ yajltcl_yajlObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Obj
OPT_DELETE,
OPT_PARSE,
OPT_PARSE2DICT,
OPT_PARSE2DICT_EX,
OPT_PARSE2HUDDLE,
OPT_PARSE_COMPLETE
};
Expand Down Expand Up @@ -855,6 +1003,7 @@ yajltcl_yajlObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Obj
// parse? generate a parse of the following json text
// and return
case OPT_PARSE2DICT:
case OPT_PARSE2DICT_EX:
case OPT_PARSE2HUDDLE:
case OPT_PARSE: {
char *string;
Expand All @@ -869,6 +1018,7 @@ yajltcl_yajlObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Obj
switch ((enum options) optIndex) {
case OPT_PARSE: parseHandle = yajlData->parseHandle; break;
case OPT_PARSE2DICT: parseHandle = yajlData->parse2dictHandle; break;
case OPT_PARSE2DICT_EX: parseHandle = yajlData->parse2dictexHandle; break;
case OPT_PARSE2HUDDLE: parseHandle = yajlData->parse2huddleHandle; break;
default: break;
}
Expand All @@ -884,9 +1034,9 @@ yajltcl_yajlObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Obj
return TCL_ERROR;
}

// parse2dict? set the Tcl result to the dynamic string
// we've been building
if ((enum options) optIndex == OPT_PARSE2DICT) {
// parse2dict or parse2dictex? set the Tcl result to
// the dynamic string we've been building
if (((enum options) optIndex == OPT_PARSE2DICT) || ((enum options) optIndex == OPT_PARSE2DICT_EX)) {
Tcl_DStringResult (interp, &yajlData->p2dString);
}

Expand All @@ -900,6 +1050,7 @@ yajltcl_yajlObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Obj
case OPT_PARSE_COMPLETE: {
yajl_complete_parse (yajlData->parseHandle);
yajl_complete_parse (yajlData->parse2dictHandle);
yajl_complete_parse (yajlData->parse2dictexHandle);
yajl_complete_parse (yajlData->parse2huddleHandle);
break;
}
Expand Down Expand Up @@ -1065,8 +1216,10 @@ yajltcl_yajlObjCmd(clientData, interp, objc, objv)
yajlData->genHandle = NULL;
yajlData->parseHandle = NULL;
yajlData->parse2dictHandle = NULL;
yajlData->parse2dictexHandle = NULL;
yajlData->parse2huddleHandle = NULL;
yajlData->p2dDepth = 0;
yajlData->arrayElement[0] = -1;
Tcl_DStringInit (&yajlData->dString);
Tcl_DStringInit (&yajlData->p2dString);

Expand Down Expand Up @@ -1147,3 +1300,5 @@ yajltcl_yajlObjCmd(clientData, interp, objc, objv)
return TCL_OK;
}
// }}}
//
// # vim: set ts=8 sw=4 sts=4 noet :
4 changes: 4 additions & 0 deletions generic/yajltcl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
extern int
yajltcl_yajlObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objvp[]);

#define YAJLTCL_MAX_DEPTH 100

typedef struct yajltcl_clientData
{
Tcl_Interp *interp;
Expand All @@ -33,6 +35,7 @@ typedef struct yajltcl_clientData

yajl_handle parseHandle;
yajl_handle parse2dictHandle;
yajl_handle parse2dictexHandle;
yajl_handle parse2huddleHandle;

struct my_parser_config {
Expand All @@ -41,5 +44,6 @@ typedef struct yajltcl_clientData
} parseConfig;

Tcl_Command cmdToken;
int arrayElement[YAJLTCL_MAX_DEPTH];
} yajltcl_clientData;

Loading

0 comments on commit 1ae0fe8

Please sign in to comment.