1 /*
2 * DBText library
3 *
4 * Copyright (C) 2001-2003 FhG Fokus
5 *
6 * This file is part of Kamailio, a free SIP server.
7 *
8 * Kamailio is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
12 *
13 * Kamailio is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <string.h>
27 #include <regex.h>
28 #include <ctype.h>
29
30 #include "../../core/mem/mem.h"
31
32 #include "dbt_raw_util.h"
33
34 static const char* _regexp = "\\s*(and|or|where|,)?\\s*(\\w*)\\s*(>=|<=|<>|=|>|<)\\s*([0-9\\.]+)?(\"([^\\\\\"]|\\\\\")*\")?";
35
log_regerror(int errcode,regex_t * compiled)36 void log_regerror(int errcode, regex_t *compiled)
37 {
38 size_t length = regerror (errcode, compiled, NULL, 0);
39 char *buffer = pkg_malloc (length);
40 (void) regerror (errcode, compiled, buffer, length);
41 LM_ERR("error compiling regex : %s\n", buffer);
42 pkg_free(buffer);
43 }
44
dbt_str_split(char * a_str,const char a_delim,int * c)45 char** dbt_str_split(char* a_str, const char a_delim, int* c)
46 {
47 char** result = 0;
48 size_t count = 0;
49 char* tmp = a_str;
50 char* last_comma = 0;
51 char delim[2];
52 delim[0] = a_delim;
53 delim[1] = 0;
54 int len = 0;
55
56 /* Count how many elements will be extracted. */
57 while (*tmp)
58 {
59 if (a_delim == *tmp)
60 {
61 count++;
62 last_comma = tmp;
63 }
64 tmp++;
65 }
66
67 /* Add space for trailing token. */
68 count += last_comma < (a_str + strlen(a_str) - 1);
69
70 *c = count;
71
72 /* Add space for terminating null string so caller
73 knows where the list of returned strings ends. */
74 count++;
75
76 result = pkg_malloc(sizeof(char*) * count);
77
78 if (result)
79 {
80 size_t idx = 0;
81 char* token = strtok(a_str, delim);
82
83 while (token)
84 {
85 assert(idx < count);
86 len = strlen(token);
87 char* ptr = pkg_malloc( (len+1) * sizeof(char));
88 memcpy(ptr, token, len);
89 ptr[len] = '\0';
90 *(result + idx) = dbt_trim(ptr);
91 token = strtok(0, delim);
92 idx++;
93 }
94 assert(idx == count - 1);
95 *(result + idx) = 0;
96 }
97
98 return result;
99 }
100
101
dbt_trim(char * str)102 char* dbt_trim(char *str)
103 {
104 size_t len = 0;
105 char *frontp = str;
106 char *endp = NULL;
107
108 if( str == NULL ) { return NULL; }
109 if( str[0] == '\0' ) { return str; }
110
111 len = strlen(str);
112 endp = str + len;
113
114 /* Move the front and back pointers to address the first non-whitespace
115 * characters from each end.
116 */
117 while( isspace(*frontp) ) { ++frontp; }
118 if( endp != frontp )
119 {
120 while( isspace(*(--endp)) && endp != frontp ) {}
121 }
122
123 if( str + len - 1 != endp )
124 *(endp + 1) = '\0';
125 else if( frontp != str && endp == frontp )
126 *str = '\0';
127
128 /* Shift the string so that it starts at str so that if it's dynamically
129 * allocated, we can still free it on the returned pointer. Note the reuse
130 * of endp to mean the front of the string buffer now.
131 */
132 endp = str;
133 if( frontp != str )
134 {
135 while( *frontp ) { *endp++ = *frontp++; }
136 *endp = '\0';
137 }
138
139
140 return str;
141 }
142
143
144 #define MAX_MATCH 10
145 #define MAX_CLAUSES 20
146
dbt_clean_where(int n,db_key_t * _k,db_op_t * _op,db_val_t * _v)147 void dbt_clean_where(int n, db_key_t* _k, db_op_t* _op, db_val_t* _v)
148 {
149 int i;
150 if(_k) {
151 for(i=0; i < n; i++) {
152 pkg_free(_k[i]->s);
153 pkg_free(_k[i]);
154 }
155 pkg_free(_k);
156 }
157
158 if(_op) {
159 for(i=0; i < n; i++) {
160 pkg_free((char*)_op[i]);
161 }
162 pkg_free(_op);
163 }
164
165 if(_v) {
166 for(i=0; i < n; i++) {
167 if(_v[i].type == DB1_STR)
168 pkg_free(_v[i].val.str_val.s);
169 }
170 pkg_free(_v);
171 }
172 }
173
dbt_build_where(char * where,db_key_t ** _k,db_op_t ** _o,db_val_t ** _v)174 int dbt_build_where(char* where, db_key_t** _k, db_op_t** _o, db_val_t** _v)
175 {
176 db_key_t* _k1 = NULL;
177 char** _o1 = NULL;
178 db_val_t* _v1 = NULL;
179 regmatch_t* matches = NULL;
180 int l;
181 int len;
182 regex_t preg;
183 int offset = 0;
184 int idx = -1;
185 char int_buf[50];
186 int res;
187
188 *_k = NULL;
189 *_o = NULL;
190 *_v = NULL;
191
192 len = strlen(where);
193
194 res = regcomp(&preg, _regexp, REG_EXTENDED);
195 if(res) {
196 log_regerror(res, &preg);
197 return -1;
198 }
199
200 _k1 = pkg_malloc(sizeof(db_key_t) * MAX_CLAUSES);
201 _o1 = pkg_malloc(sizeof(char*) * MAX_CLAUSES);
202 _v1 = pkg_malloc(sizeof(db_val_t) * MAX_CLAUSES);
203 matches = (regmatch_t*)pkg_malloc(sizeof(regmatch_t) * MAX_MATCH);
204
205 if(_k1==NULL || _o1==NULL || _v1==NULL || matches==NULL) {
206 LM_ERR("error getting pkg memory\n");
207 if(_k1) pkg_free(_k1);
208 if(_o1) pkg_free(_o1);
209 if(_v1) pkg_free(_v1);
210 if(matches) pkg_free(matches);
211 return -1;
212 }
213 memset(_k1, 0, sizeof(db_key_t) * MAX_CLAUSES);
214 memset(_o1, 0, sizeof(char*) * MAX_CLAUSES);
215 memset(_v1, 0, sizeof(db_val_t) * MAX_CLAUSES);
216
217 while(offset < len) {
218 char* buffer = where + offset;
219
220 if (regexec(&preg, buffer, MAX_MATCH, matches, REG_ICASE)) {
221 LM_ERR("error running regexp %i '%s'\n", idx, buffer);
222 break;
223 }
224 if(matches[0].rm_so == -1) {
225 break;
226 }
227 idx++;
228
229 // TODO figure out a way to combine and / or
230 // needs changes in dbt_query / dbt_row_match
231
232 l = matches[2].rm_eo - matches[2].rm_so;
233 _k1[idx] = pkg_malloc(sizeof(str));
234 _k1[idx]->len = l;
235 _k1[idx]->s = pkg_malloc(sizeof(char) * (l+1));
236 strncpy(_k1[idx]->s, buffer+matches[2].rm_so, l);
237 _k1[idx]->s[l]='\0';
238
239 l = matches[3].rm_eo - matches[3].rm_so;
240 _o1[idx] = (char*) pkg_malloc(l+1);
241 strncpy(_o1[idx], buffer+matches[3].rm_so, l);
242 _o1[idx][l]='\0';
243
244 if(matches[5].rm_so == -1) {
245 l = matches[4].rm_eo - matches[4].rm_so;
246 strncpy(int_buf, buffer+matches[4].rm_so, l);
247 int_buf[l] = '\0';
248 _v1[idx].type = DB1_INT;
249 _v1[idx].val.int_val = atoi(int_buf);
250 } else {
251 char *start = buffer+matches[5].rm_so+1;
252 int writer = 0, reader = 0;
253 l = matches[5].rm_eo - matches[5].rm_so - 2;
254 _v1[idx].type = DB1_STR;
255 _v1[idx].val.str_val.len = l;
256 _v1[idx].val.str_val.s = pkg_malloc(l+1);
257
258 for(reader=0; reader < l; reader++) {
259 if(start[reader] == '\\' && start[reader+1] == '\"')
260 continue;
261 _v1[idx].val.str_val.s[writer++] = start[reader];
262 }
263 _v1[idx].val.str_val.s[writer] = '\0';
264 _v1[idx].val.str_val.len = writer;
265 }
266 if(matches[0].rm_eo != -1)
267 offset += matches[0].rm_eo;
268
269 }
270 regfree(&preg);
271 pkg_free(matches);
272
273 *_k = _k1;
274 *_o = (db_op_t*)_o1;
275 *_v = _v1;
276
277 return idx+1;
278 }
279