From 4c55f26d2c20f7a7d6a02df9ebf3ac8b179b3f2b Mon Sep 17 00:00:00 2001 From: teodor Date: Tue, 8 Jul 2008 17:03:06 +0000 Subject: [PATCH] Implement simple query_string parser --- Makefile | 4 +- expected/prsqs | 7 +++ prs_hmap.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++ prs_hmap.h | 1 + prstest.c | 58 +++++++++++++++++++++++ sfxstr.c | 2 +- tests/prsqs | 1 + 7 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 expected/prsqs create mode 100644 prstest.c create mode 100644 tests/prsqs diff --git a/Makefile b/Makefile index da86c8b..a387934 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ topbuilddir=. PROGRAM=sfxtest hextest inftest kilter psortex flatdbtest \ - tbtreetest gendata memtest glisttest + tbtreetest gendata memtest glisttest prstest LIBRARY=libtedtools.a LIBOBJ=tlog.o tmalloc.o tools.o prs_hmap.o sfxstr.o \ @@ -20,7 +20,7 @@ test: all @[ -d results ] || mkdir results @[ -d diffs ] || mkdir diffs @[ -d temp ] || mkdir temp - @for FILE in btree flatdb hex inf mem psort sfxmem glist ; do \ + @for FILE in btree flatdb hex inf mem psort sfxmem glist prsqs ; do \ echo -n $$FILE " ........ " ; \ if sh tests/$$FILE > results/$$FILE 2>results/$$FILE.errout && diff -c expected/$$FILE results/$$FILE > diffs/$$FILE ; then \ echo ok ; \ diff --git a/expected/prsqs b/expected/prsqs new file mode 100644 index 0000000..3d22720 --- /dev/null +++ b/expected/prsqs @@ -0,0 +1,7 @@ +PARSE: 3 + key:'foo' value:'bar' + key:'qwerty' value:' wo w%2' + key:'asd' value:'1 2' +PARSE: 1 + key:'f oo' value:'ba%1gr' + key:'qwe rty' value:'' diff --git a/prs_hmap.c b/prs_hmap.c index 76e0769..ad79ffe 100644 --- a/prs_hmap.c +++ b/prs_hmap.c @@ -148,3 +148,126 @@ parse_hmap(char *in, HMap ** m) { else if (!(state == CS_WAITDELIM || state == CS_WAITKEY)) tlog(TL_ALARM|TL_EXIT,"parse_hmap: unexpected end of line\n"); } + +static int +getnumber(char c) { + if ( c == '\0' ) + return 0; + else if ( c >= '0' && c <= '9' ) + return c - '0'; + else if ( c >= 'A' && c <= 'F' ) + return c - 'A' + 10; + else if ( c >= 'a' && c <= 'f' ) + return c - 'a' + 10; + + return -1; +} + +static char * +unescape(char *str, int len) { + char *in = str, *out = tmalloc(sizeof(char)*(len+1)); + char *res = out; + + while(in - str < len ) { + char c = *in; + + if ( c == '+' ) + c = ' '; + else if ( c == '%' ) { + char *ptr = in; + int i1, i2; + + ptr++; + if ( ptr - str >= len || (i1=getnumber(*ptr)) < 0 ) + goto process; + ptr++; + if ( ptr - str >= len || (i2=getnumber(*ptr)) < 0 ) + goto process; + + c = (i1<<4) | i2; + + in+=2; + } + +process: + *out = c; + out++; in++; + } + + *out = '\0'; + + return res; +} + +#define QS_WAITKEY 1 +#define QS_INKEY 2 +#define QS_WAITVAL 3 +#define QS_INVAL 4 + +int +parse_query_string(char *in, HMap ** m) { + HMap *mptr; + char *ptr = in, + *begin = NULL; + char num = 0; + int state = QS_WAITKEY; + + while (*ptr) + { + if (*ptr == '&') + num++; + ptr++; + } + + *m = mptr = (HMap *) t0malloc(sizeof(HMap) * (num + 2)); + ptr = in; + while (*ptr) { + if ( state == QS_WAITKEY ) { + if ( !( *ptr == '&' || *ptr == '=' ) ) { + begin = ptr; + state = QS_INKEY; + } + } else if ( state == QS_INKEY ) { + if ( *ptr == '=' ) { + mptr->key = unescape( begin , ptr-begin ); + state = QS_WAITVAL; + } else if ( *ptr == '&' ) { + mptr->key = unescape( begin , ptr-begin ); + mptr->value = t0malloc(sizeof(char)); + mptr++; + state = QS_WAITKEY; + } + } else if ( state == QS_WAITVAL ) { + if ( *ptr == '&' ) { + mptr->value = t0malloc(sizeof(char)); + state = QS_WAITKEY; + mptr++; + } else { + begin = ptr; + state = QS_INVAL; + } + } else if ( state == QS_INVAL ) { + if ( *ptr == '&' ) { + mptr->value = unescape( begin , ptr-begin ); + mptr++; + state = QS_WAITKEY; + } + } else + tlog( TL_CRIT|TL_EXIT,"Wrong state of QUERY_STRING parser"); + + ptr++; + } + + if ( state == QS_INVAL ) { + mptr->value = unescape( begin , ptr-begin ); + mptr++; + } if ( state == QS_INKEY ) { + mptr->key = unescape( begin , ptr-begin ); + mptr->value = t0malloc(sizeof(char)); + mptr++; + } else if ( state == QS_WAITVAL ) { + mptr->value = t0malloc(sizeof(char)); + } + + return mptr - *m; +} diff --git a/prs_hmap.h b/prs_hmap.h index 1363070..4e7c668 100644 --- a/prs_hmap.h +++ b/prs_hmap.h @@ -37,5 +37,6 @@ typedef struct { } HMap; void parse_hmap(char *in, HMap ** m); +int parse_query_string(char *in, HMap ** m); #endif diff --git a/prstest.c b/prstest.c new file mode 100644 index 0000000..d274253 --- /dev/null +++ b/prstest.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008 Teodor Sigaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "prs_hmap.h" +#include "tools.h" +#include "tmalloc.h" +#include "tlog.h" + + +int +main(int argn, char *argv[]) { + HMap *res; + + + printf ( "PARSE: %d\n" , parse_query_string("foo=bar&qwerty=%20wo%20w%2&asd=1+2", &res)); + while( res->key ) { + printf("\tkey:'%s'\tvalue:'%s'\n", res->key, res->value); + res ++; + } + + printf ( "PARSE: %d\n" , parse_query_string("f%20oo=ba%1gr&qwe++rty=", &res)); + while( res->key ) { + printf("\tkey:'%s'\tvalue:'%s'\n", res->key, res->value); + res ++; + } + + return 0; +} diff --git a/sfxstr.c b/sfxstr.c index 3429470..b9a048e 100644 --- a/sfxstr.c +++ b/sfxstr.c @@ -1021,7 +1021,7 @@ SFSWriteDump(SFSTree *info, char *filename, void *extradata, u_int32_t extrasize SFSTreeDumpHeader dh; if ( (fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0 ) - tlog(TL_CRIT|TL_EXIT, "Can not open file '%s': %s", strerror(errno)); + tlog(TL_CRIT|TL_EXIT, "Can not open file '%s': %s", filename, strerror(errno)); if ( flock(fd, LOCK_EX) < 0 ) tlog(TL_CRIT|TL_EXIT, "flock failed: %s", strerror(errno)); diff --git a/tests/prsqs b/tests/prsqs new file mode 100644 index 0000000..ce2818a --- /dev/null +++ b/tests/prsqs @@ -0,0 +1 @@ +./prstest -- 2.46.1