add .gitignore
[tedtools.git] / prs_hmap.c
1 /*
2  * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *        notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *        notice, this list of conditions and the following disclaimer in the
12  *        documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of any co-contributors
14  *        may be used to endorse or promote products derived from this software
15  *        without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #include "tlog.h"
35 #include "tmalloc.h"
36 #include "prs_hmap.h"
37
38
39
40 #define CS_WAITKEY      0
41 #define CS_INKEY        1
42 #define CS_WAITEQ       2
43 #define CS_WAITVALUE    3
44 #define CS_INVALUE      4
45 #define CS_IN2VALUE 5
46 #define CS_WAITDELIM    6
47 #define CS_INESC        7
48 #define CS_IN2ESC       8
49
50 static char *
51 nstrdup(char *ptr, int len) {
52         char       *res = tmalloc(len + 1),
53                            *cptr;
54
55         memcpy(res, ptr, len);
56         res[len] = '\0';
57         cptr = ptr = res;
58         while (*ptr) {
59                 if (*ptr == '\\')
60                         ptr++;
61                 *cptr = *ptr;
62                 ptr++;
63                 cptr++;
64         }
65         *cptr = '\0';
66
67         return res;
68 }
69
70 void
71 parse_hmap(char *in, HMap ** m) {
72         HMap               *mptr;
73         char       *ptr = in,
74                            *begin = NULL;
75         char            num = 0;
76         int                     state = CS_WAITKEY;
77
78         while (*ptr)
79         {
80                 if (*ptr == ',')
81                         num++;
82                 ptr++;
83         }
84
85         *m = mptr = (HMap *) t0malloc(sizeof(HMap) * (num + 2));
86         ptr = in;
87         while (*ptr) {
88                 if (state == CS_WAITKEY) {
89                         if (isalpha((unsigned char) *ptr)) {
90                                 begin = ptr;
91                                 state = CS_INKEY;
92                         } else if (!isspace((unsigned char) *ptr))      
93                                 tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr);
94                 } else if (state == CS_INKEY) {
95                         if (isspace((unsigned char) *ptr)) {
96                                 mptr->key = nstrdup(begin, ptr - begin);
97                                 state = CS_WAITEQ;
98                         } else if (*ptr == '=') {
99                                 mptr->key = nstrdup(begin, ptr - begin);
100                                 state = CS_WAITVALUE;
101                         } else if (!isalpha((unsigned char) *ptr))
102                                 tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr);
103                 } else if (state == CS_WAITEQ) {
104                         if (*ptr == '=')
105                                 state = CS_WAITVALUE;
106                         else if (!isspace((unsigned char) *ptr))
107                                 tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr);
108                 } else if (state == CS_WAITVALUE) {
109                         if (*ptr == '"') {
110                                 begin = ptr + 1;
111                                 state = CS_INVALUE;
112                         } else if (!isspace((unsigned char) *ptr)) {
113                                 begin = ptr;
114                                 state = CS_IN2VALUE;
115                         }
116                 } else if (state == CS_INVALUE) {
117                         if (*ptr == '"') {
118                                 mptr->value = nstrdup(begin, ptr - begin);
119                                 mptr++;
120                                 state = CS_WAITDELIM;
121                         } else if (*ptr == '\\')
122                                 state = CS_INESC;
123                 } else if (state == CS_IN2VALUE) {
124                         if (isspace((unsigned char) *ptr) || *ptr == ',') {
125                                 mptr->value = nstrdup(begin, ptr - begin);
126                                 mptr++;
127                                 state = (*ptr == ',') ? CS_WAITKEY : CS_WAITDELIM;
128                         } else if (*ptr == '\\')
129                                 state = CS_INESC;
130                 } else if (state == CS_WAITDELIM) {
131                         if (*ptr == ',')
132                                 state = CS_WAITKEY;
133                         else if (!isspace((unsigned char) *ptr))
134                                 tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr);
135                 } else if (state == CS_INESC)
136                         state = CS_INVALUE;
137                 else if (state == CS_IN2ESC)
138                         state = CS_IN2VALUE;
139                 else
140                         tlog(TL_CRIT|TL_EXIT,"parse_hmap: Bad parser state %d at position %d near \"%c\"\n", state, (int) (ptr - in), *ptr);
141                 ptr++;
142         }
143
144         if (state == CS_IN2VALUE) {
145                 mptr->value = nstrdup(begin, ptr - begin);
146                 mptr++;
147         }
148         else if (!(state == CS_WAITDELIM || state == CS_WAITKEY))
149                 tlog(TL_ALARM|TL_EXIT,"parse_hmap: unexpected end of line\n");
150 }
151
152 static int 
153 getnumber(char c)  {
154         if ( c == '\0' )
155                 return 0;
156         else if ( c >= '0' && c <= '9' )
157                 return c - '0';
158         else if ( c >= 'A' && c <= 'F' )
159                 return c - 'A' + 10;
160         else if ( c >= 'a' && c <= 'f' )
161                 return c - 'a' + 10;
162
163         return -1;
164 }
165
166 static char * 
167 unescape(char *str, int len) {
168         char *in = str, *out = tmalloc(sizeof(char)*(len+1));
169         char *res = out; 
170
171         while(in - str < len )  {
172                 char c = *in;
173
174                 if ( c == '+' ) 
175                         c = ' ';
176                 else if ( c == '%' ) {
177                         char *ptr = in;
178                         int  i1, i2;
179
180                         ptr++;
181                         if ( ptr - str >= len || (i1=getnumber(*ptr)) < 0 ) 
182                                 goto process;
183                         ptr++;
184                         if ( ptr - str >= len || (i2=getnumber(*ptr)) < 0 ) 
185                                 goto process;
186
187                         c = (i1<<4) | i2;
188
189                         in+=2;
190                 }
191
192 process:
193                 *out = c;
194                 out++; in++;
195         }
196
197         *out = '\0';
198
199         return res;
200 }
201
202 #define QS_WAITKEY      1
203 #define QS_INKEY        2
204 #define QS_WAITVAL      3
205 #define QS_INVAL        4
206
207 int   
208 parse_query_string(char *in, HMap ** m) {
209         HMap            *mptr;
210         char            *ptr = in,
211                                 *begin = NULL;
212         char            num = 0;
213         int                     state = QS_WAITKEY;
214
215         while (*ptr)
216         {
217                 if (*ptr == '&')
218                         num++;
219                 ptr++;
220         }
221
222         *m = mptr = (HMap *) t0malloc(sizeof(HMap) * (num + 2));
223         ptr = in;
224         while (*ptr) {
225                 if ( state == QS_WAITKEY ) {
226                         if ( !( *ptr == '&'  || *ptr == '=' ) ) {
227                                 begin = ptr;
228                                 state = QS_INKEY;
229                         }
230                 } else if ( state == QS_INKEY ) {
231                         if ( *ptr == '=' ) {
232                                 mptr->key = unescape( begin , ptr-begin );
233                                 state = QS_WAITVAL;
234                         } else if ( *ptr == '&' ) {
235                                 mptr->key = unescape( begin , ptr-begin );
236                                 mptr->value = t0malloc(sizeof(char));
237                                 mptr++;
238                                 state = QS_WAITKEY;
239                         }
240                 } else if ( state == QS_WAITVAL ) {
241                         if ( *ptr == '&' ) {
242                                 mptr->value = t0malloc(sizeof(char));
243                                 state = QS_WAITKEY;
244                                 mptr++;
245                         } else {
246                                 begin = ptr;
247                                 state = QS_INVAL;
248                         }
249                 } else if ( state == QS_INVAL ) {
250                         if ( *ptr == '&' ) {
251                                 mptr->value = unescape( begin , ptr-begin );
252                                 mptr++;
253                                 state = QS_WAITKEY;
254                         } 
255                 } else
256                         tlog( TL_CRIT|TL_EXIT,"Wrong state of QUERY_STRING parser");
257
258                 ptr++;
259         }
260
261         if ( state == QS_INVAL ) {
262                 mptr->value = unescape( begin , ptr-begin );
263                 mptr++;
264         } if ( state == QS_INKEY ) {
265                 mptr->key = unescape( begin , ptr-begin );
266                 mptr->value = t0malloc(sizeof(char));
267                 mptr++;
268         } else if ( state == QS_WAITVAL ) {
269                 mptr->value = t0malloc(sizeof(char));
270         }
271
272         return mptr - *m;
273 }