Implement simple query_string parser
authorteodor <teodor>
Tue, 8 Jul 2008 17:03:06 +0000 (17:03 +0000)
committerteodor <teodor>
Tue, 8 Jul 2008 17:03:06 +0000 (17:03 +0000)
Makefile
expected/prsqs [new file with mode: 0644]
prs_hmap.c
prs_hmap.h
prstest.c [new file with mode: 0644]
sfxstr.c
tests/prsqs [new file with mode: 0644]

index da86c8b..a387934 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 topbuilddir=.
 
 PROGRAM=sfxtest hextest inftest kilter psortex flatdbtest \
 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 \
 
 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
        @[ -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 ; \
                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 (file)
index 0000000..3d22720
--- /dev/null
@@ -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:''
index 76e0769..ad79ffe 100644 (file)
@@ -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");
 }
        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;
+}
index 1363070..4e7c668 100644 (file)
@@ -37,5 +37,6 @@ typedef struct {
 }       HMap;
 
 void  parse_hmap(char *in, HMap ** m);
 }       HMap;
 
 void  parse_hmap(char *in, HMap ** m);
+int      parse_query_string(char *in, HMap ** m);
 
 #endif
 
 #endif
diff --git a/prstest.c b/prstest.c
new file mode 100644 (file)
index 0000000..d274253
--- /dev/null
+++ b/prstest.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008 Teodor Sigaev <teodor@sigaev.ru>
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}      
index 3429470..b9a048e 100644 (file)
--- 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 )
        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));
 
        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 (file)
index 0000000..ce2818a
--- /dev/null
@@ -0,0 +1 @@
+./prstest