|
|
@ -3,7 +3,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
======================================================
|
|
|
|
======================================================
|
|
|
|
SFSEXP: Small, Fast S-Expression Library version 1.2
|
|
|
|
SFSEXP: Small, Fast S-Expression Library version 1.2
|
|
|
|
Written by Matthew Sottile (matt@cs.uoregon.edu)
|
|
|
|
Written by Matthew Sottile (mjsottile@gmail.com)
|
|
|
|
======================================================
|
|
|
|
======================================================
|
|
|
|
|
|
|
|
|
|
|
|
Copyright (2003-2006). The Regents of the University of California. This
|
|
|
|
Copyright (2003-2006). The Regents of the University of California. This
|
|
|
@ -34,16 +34,9 @@ LA-CC-04-094
|
|
|
|
|
|
|
|
|
|
|
|
@endcond
|
|
|
|
@endcond
|
|
|
|
**/
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Ported to Jari OS by Alfeiks Kaanoken <madtirra@jarios.org>
|
|
|
|
|
|
|
|
* (c) Jari OS Core dev team 2005-2009 <http://jarios.org>
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include <sexpr/sexp.h>
|
|
|
|
#include <sexpr/sexp.h>
|
|
|
|
#include <sexpr/faststack.h>
|
|
|
|
#include <sexpr/faststack.h>
|
|
|
|
|
|
|
|
|
|
|
@ -84,7 +77,9 @@ parse_data_t;
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* parse_data_t stack - similar malloc prevention to sexp_t_cache.
|
|
|
|
* parse_data_t stack - similar malloc prevention to sexp_t_cache.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _NO_MEMORY_MANAGEMENT_
|
|
|
|
faststack_t *pd_cache;
|
|
|
|
faststack_t *pd_cache;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* The global <I>sexp_t_cache</I> is a faststack implementing a cache of
|
|
|
|
* The global <I>sexp_t_cache</I> is a faststack implementing a cache of
|
|
|
@ -94,7 +89,9 @@ faststack_t *pd_cache;
|
|
|
|
* This should be left alone and manipulated only by the sexp_t_allocate and
|
|
|
|
* This should be left alone and manipulated only by the sexp_t_allocate and
|
|
|
|
* sexp_t_deallocate functions. Touching the stack is bad.
|
|
|
|
* sexp_t_deallocate functions. Touching the stack is bad.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _NO_MEMORY_MANAGEMENT_
|
|
|
|
faststack_t *sexp_t_cache;
|
|
|
|
faststack_t *sexp_t_cache;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* sexp_t allocation
|
|
|
|
* sexp_t allocation
|
|
|
@ -104,7 +101,7 @@ sexp_t *
|
|
|
|
sexp_t_allocate(void) {
|
|
|
|
sexp_t_allocate(void) {
|
|
|
|
sexp_t *sx = sexp_calloc(1, sizeof(sexp_t));
|
|
|
|
sexp_t *sx = sexp_calloc(1, sizeof(sexp_t));
|
|
|
|
if (sx == NULL) {
|
|
|
|
if (sx == NULL) {
|
|
|
|
sexp_errno = SEXP_MEMORY;
|
|
|
|
sexp_errno = SEXP_ERR_MEMORY;
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -237,6 +234,14 @@ void sexp_cleanup(void) {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* allocation
|
|
|
|
* allocation
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef _NO_MEMORY_MANAGEMENT_
|
|
|
|
|
|
|
|
parse_data_t *
|
|
|
|
|
|
|
|
pd_allocate(void) {
|
|
|
|
|
|
|
|
parse_data_t *p = NULL;
|
|
|
|
|
|
|
|
p = sexp_malloc(sizeof(parse_data_t));
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
parse_data_t *
|
|
|
|
parse_data_t *
|
|
|
|
pd_allocate(void) {
|
|
|
|
pd_allocate(void) {
|
|
|
|
parse_data_t *p;
|
|
|
|
parse_data_t *p;
|
|
|
@ -281,10 +286,17 @@ pd_allocate(void) {
|
|
|
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _NO_MEMORY_MANAGEMENT_ */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* de-allocation
|
|
|
|
* de-allocation
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef _NO_MEMORY_MANAGEMENT_
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
|
|
pd_deallocate(parse_data_t *p) {
|
|
|
|
|
|
|
|
sexp_free(p, sizeof(parse_data_t));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
void
|
|
|
|
void
|
|
|
|
pd_deallocate(parse_data_t *p) {
|
|
|
|
pd_deallocate(parse_data_t *p) {
|
|
|
|
if (pd_cache == NULL) {
|
|
|
|
if (pd_cache == NULL) {
|
|
|
@ -298,6 +310,101 @@ pd_deallocate(parse_data_t *p) {
|
|
|
|
|
|
|
|
|
|
|
|
pd_cache = push(pd_cache, p);
|
|
|
|
pd_cache = push(pd_cache, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _NO_MEMORY_MANAGEMENT_ */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* print the current parsing state based on the contents of the parser
|
|
|
|
|
|
|
|
* continuation. Useful for error reporting if an error is detected
|
|
|
|
|
|
|
|
* while the current expression being parsed is incomplete.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
void print_pcont(pcont_t * pc, char * buf, size_t buflen) {
|
|
|
|
|
|
|
|
char *cur = buf;
|
|
|
|
|
|
|
|
int loc = 0;
|
|
|
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
stack_lvl_t *lvl;
|
|
|
|
|
|
|
|
parse_data_t *pdata;
|
|
|
|
|
|
|
|
sexp_t *sx;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* return if either the buffer or continuation are null */
|
|
|
|
|
|
|
|
if (buf == NULL) return;
|
|
|
|
|
|
|
|
if (pc == NULL) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* if continuation has no stack, return */
|
|
|
|
|
|
|
|
if (pc->stack == NULL) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* start at the bottom of the stack */
|
|
|
|
|
|
|
|
lvl = pc->stack->bottom;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* go until we either run out of buffer space or we hit the
|
|
|
|
|
|
|
|
top of the stack */
|
|
|
|
|
|
|
|
while (loc < buflen-1 && lvl != NULL) {
|
|
|
|
|
|
|
|
/* get the data at the current stack level */
|
|
|
|
|
|
|
|
pdata = (parse_data_t *)lvl->data;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* if this is null, we're at a level with nothing added yet */
|
|
|
|
|
|
|
|
if (pdata == NULL) break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* get first fully parsed sexpr for this level. this could be
|
|
|
|
|
|
|
|
any sub-expression, like an atom or a full s-expression */
|
|
|
|
|
|
|
|
sx = pdata->fst;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* spin through all of the s-expressions at this level */
|
|
|
|
|
|
|
|
while (sx != NULL) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* if we have a list that has no contents, just add the open
|
|
|
|
|
|
|
|
paren. this means we haven't finished this expression and the
|
|
|
|
|
|
|
|
stack contains it's partial contents. Just print the open paren
|
|
|
|
|
|
|
|
and break out so we can pop up the stack. */
|
|
|
|
|
|
|
|
if (sx->ty == SEXP_LIST && sx->list == NULL) {
|
|
|
|
|
|
|
|
cur[0] = '(';
|
|
|
|
|
|
|
|
cur++;
|
|
|
|
|
|
|
|
loc++;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* print the fully parsed sub-expression */
|
|
|
|
|
|
|
|
n = print_sexp(cur,buflen-loc,sx);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* add a space between this and the next expression. note that
|
|
|
|
|
|
|
|
this may induce spaces that were not part of the original
|
|
|
|
|
|
|
|
expression. */
|
|
|
|
|
|
|
|
cur[n] = ' ';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* increment n to compensate for the space we added */
|
|
|
|
|
|
|
|
n++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* push the pointer into the output buffer forward by n */
|
|
|
|
|
|
|
|
cur += n;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* increment counter for location in buffer by n */
|
|
|
|
|
|
|
|
loc += n;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* go to next s-expr */
|
|
|
|
|
|
|
|
sx = sx->next;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* go up to next level in stack */
|
|
|
|
|
|
|
|
lvl = lvl->above;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* at this point, all that may remain is a partially parsed string
|
|
|
|
|
|
|
|
that hasn't been turned into a sexpr yet. attach it to the
|
|
|
|
|
|
|
|
output string. */
|
|
|
|
|
|
|
|
if (pc->val_used < (buflen-loc)-1) {
|
|
|
|
|
|
|
|
strncpy(cur, pc->val, pc->val_used);
|
|
|
|
|
|
|
|
cur += pc->val_used;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* don't bother if we're so close to the end of the buffer that
|
|
|
|
|
|
|
|
we can't attach our null terminator. */
|
|
|
|
|
|
|
|
if (buflen-loc > 2) {
|
|
|
|
|
|
|
|
strncpy(cur, pc->val, (buflen-loc)-2);
|
|
|
|
|
|
|
|
cur += (buflen-loc)-2;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* add null terminator */
|
|
|
|
|
|
|
|
cur[0] = '\0';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Destroy a continuation by freeing all of its fields that it is responsible
|
|
|
|
* Destroy a continuation by freeing all of its fields that it is responsible
|
|
|
@ -378,7 +485,6 @@ parse_sexp (char *s, size_t len)
|
|
|
|
pc = cparse_sexp (s, len, pc);
|
|
|
|
pc = cparse_sexp (s, len, pc);
|
|
|
|
if (pc == NULL) return NULL; /* assume that cparse_sexp set sexp_errno */
|
|
|
|
if (pc == NULL) return NULL; /* assume that cparse_sexp set sexp_errno */
|
|
|
|
sx = pc->last_sexp;
|
|
|
|
sx = pc->last_sexp;
|
|
|
|
sexp_errno = pc->error;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
destroy_continuation(pc);
|
|
|
|
destroy_continuation(pc);
|
|
|
|
|
|
|
|
|
|
|
@ -476,7 +582,6 @@ iparse_sexp (char *s, size_t len, pcont_t *cc) {
|
|
|
|
if (pc == NULL) return NULL; /* assume cparse_sexp set sexp_errno */
|
|
|
|
if (pc == NULL) return NULL; /* assume cparse_sexp set sexp_errno */
|
|
|
|
|
|
|
|
|
|
|
|
if (cc->last_sexp != NULL) {
|
|
|
|
if (cc->last_sexp != NULL) {
|
|
|
|
sexp_errno = cc->error;
|
|
|
|
|
|
|
|
sx = cc->last_sexp;
|
|
|
|
sx = cc->last_sexp;
|
|
|
|
cc->last_sexp = NULL;
|
|
|
|
cc->last_sexp = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -526,7 +631,13 @@ cparse_sexp (char *str, size_t len, pcont_t *lc)
|
|
|
|
parser_event_handlers_t *event_handlers = NULL;
|
|
|
|
parser_event_handlers_t *event_handlers = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/*** define a macro used for stashing continuation state away ***/
|
|
|
|
/*** define a macro used for stashing continuation state away ***/
|
|
|
|
/** NOTE: sbuffer is set manually as appropriate. **/
|
|
|
|
/** NOTE1: sbuffer is set manually as appropriate. **/
|
|
|
|
|
|
|
|
/** NOTE2: this also sets sexp_errno to the same value as the
|
|
|
|
|
|
|
|
error field in the continuation. This used to be
|
|
|
|
|
|
|
|
done in iparse_sexp and parse_sexp, but that meant that
|
|
|
|
|
|
|
|
direct callers of cparse_sexp would see inconsistent errors.
|
|
|
|
|
|
|
|
sexp_errno could say one thing, but cc would say the other.
|
|
|
|
|
|
|
|
This has been fixed. **/
|
|
|
|
#define SAVE_CONT_STATE(err,ls) { \
|
|
|
|
#define SAVE_CONT_STATE(err,ls) { \
|
|
|
|
cc->bindata = bindata; \
|
|
|
|
cc->bindata = bindata; \
|
|
|
|
cc->binread = binread; \
|
|
|
|
cc->binread = binread; \
|
|
|
@ -546,6 +657,7 @@ cparse_sexp (char *str, size_t len, pcont_t *lc)
|
|
|
|
cc->last_sexp = (ls); \
|
|
|
|
cc->last_sexp = (ls); \
|
|
|
|
cc->error = (err); \
|
|
|
|
cc->error = (err); \
|
|
|
|
cc->event_handlers = event_handlers; \
|
|
|
|
cc->event_handlers = event_handlers; \
|
|
|
|
|
|
|
|
sexp_errno = (err); \
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*** end continuation state saving macro ***/
|
|
|
|
/*** end continuation state saving macro ***/
|
|
|
|
|
|
|
|
|
|
|
@ -1424,12 +1536,7 @@ cparse_sexp (char *str, size_t len, pcont_t *lc)
|
|
|
|
state = 15;
|
|
|
|
state = 15;
|
|
|
|
vcur[0] = '\0';
|
|
|
|
vcur[0] = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
binexpected = atoi(val);
|
|
|
|
binexpected = (size_t) atoi(val);
|
|
|
|
|
|
|
|
|
|
|
|
if (binexpected < 0) {
|
|
|
|
|
|
|
|
SAVE_CONT_STATE(SEXP_ERR_BADCONTENT, NULL);
|
|
|
|
|
|
|
|
return cc;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
binread = 0;
|
|
|
|
binread = 0;
|
|
|
|
if (binexpected > 0) {
|
|
|
|
if (binexpected > 0) {
|
|
|
@ -1562,7 +1669,7 @@ cparse_sexp (char *str, size_t len, pcont_t *lc)
|
|
|
|
state = 1;
|
|
|
|
state = 1;
|
|
|
|
SAVE_CONT_STATE(SEXP_ERR_OK, sx);
|
|
|
|
SAVE_CONT_STATE(SEXP_ERR_OK, sx);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
SAVE_CONT_STATE(SEXP_ERR_OK, NULL);
|
|
|
|
SAVE_CONT_STATE(SEXP_ERR_INCOMPLETE, NULL);
|
|
|
|
if (t[0] == '\0' || t == bufEnd)
|
|
|
|
if (t[0] == '\0' || t == bufEnd)
|
|
|
|
cc->lastPos = NULL;
|
|
|
|
cc->lastPos = NULL;
|
|
|
|
else
|
|
|
|
else
|
|
|
|