1 /* Copyright (C) 2000-2015 Lavtech.com corp. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "udm_config.h"
19 #define DSTR_PRIVATE
20
21 #include <string.h>
22 #include <ctype.h>
23 #include "udm_common.h"
24 #include "udm_utils.h"
25 #include "udm_wild.h"
26 #include "udm_searchtool.h"
27 #include "udm_coords.h"
28 #include "udm_contentencoding.h"
29 #include "udm_sgml.h"
30 #include "udm_match.h"
31
32
33 const char *
UdmDSTRPtr(const UDM_DSTR * dstr)34 UdmDSTRPtr(const UDM_DSTR *dstr)
35 {
36 return dstr->Val.str;
37 }
38
39
40 size_t
UdmDSTRLength(const UDM_DSTR * dstr)41 UdmDSTRLength(const UDM_DSTR *dstr)
42 {
43 return dstr->Val.length;
44 }
45
46
47 static udm_rc_t
UdmDSTRAllocBuffer(UDM_DSTR * dstr,size_t nbytes)48 UdmDSTRAllocBuffer(UDM_DSTR *dstr, size_t nbytes)
49 {
50 dstr->Val.str= (char*) UdmMalloc(nbytes);
51 return dstr->Val.str ? UDM_OK : UDM_ERROR;
52 }
53
54
55 udm_rc_t
UdmDSTRInit(UDM_DSTR * dstr,size_t size_page)56 UdmDSTRInit(UDM_DSTR *dstr, size_t size_page)
57 {
58 UDM_ASSERT(size_page > 0);
59 if (UDM_OK != UdmDSTRAllocBuffer(dstr, size_page))
60 {
61 bzero(dstr, sizeof(*dstr));
62 return UDM_ERROR;
63 }
64 dstr->Val.str[0]= 0;
65 dstr->Val.length= 0;
66 dstr->size_page= size_page;
67 dstr->size_alloced= size_page;
68 return UDM_OK;
69 }
70
71
72 void
UdmDSTRFree(UDM_DSTR * dstr)73 UdmDSTRFree(UDM_DSTR *dstr)
74 {
75 dstr->size_alloced= dstr->Val.length= 0;
76 UdmFree(dstr->Val.str);
77 }
78
79
80 udm_rc_t
UdmDSTRAlloc(UDM_DSTR * dstr,size_t size_data)81 UdmDSTRAlloc(UDM_DSTR *dstr, size_t size_data)
82 {
83 size_t asize;
84
85 if (size_data <= dstr->size_alloced)
86 return UDM_OK;
87
88 asize= (size_data / dstr->size_page + 1) * dstr->size_page;
89 UdmDSTRFree(dstr);
90 if (UDM_OK != UdmDSTRAllocBuffer(dstr, asize))
91 return UDM_ERROR;
92 dstr->size_alloced= asize;
93 return UDM_OK;
94 }
95
96
97 udm_rc_t
UdmDSTRRealloc(UDM_DSTR * dstr,size_t size_data)98 UdmDSTRRealloc(UDM_DSTR *dstr, size_t size_data)
99 {
100 char *tmp;
101 size_t asize;
102
103 if (size_data <= dstr->size_alloced)
104 return UDM_OK;
105 asize= (size_data / dstr->size_page + 1) * dstr->size_page;
106 if (!(tmp= (char*) UdmRealloc(dstr->Val.str, asize)))
107 return UDM_ERROR;
108 dstr->size_alloced= asize;
109 dstr->Val.str= tmp;
110 return UDM_OK;
111 }
112
113
114 udm_rc_t
UdmDSTRReserve(UDM_DSTR * dstr,size_t additional_size)115 UdmDSTRReserve(UDM_DSTR *dstr, size_t additional_size)
116 {
117 return UdmDSTRRealloc(dstr, dstr->Val.length + additional_size);
118 }
119
120
121 size_t
UdmDSTRAppend(UDM_DSTR * dstr,const char * data,size_t size_data)122 UdmDSTRAppend(UDM_DSTR *dstr, const char *data, size_t size_data)
123 {
124 size_t bytes_left= dstr->size_alloced - dstr->Val.length;
125 size_t asize;
126 char *tmp;
127
128 if (!data || !size_data)
129 return 0;
130
131 if (bytes_left <= size_data)
132 {
133 asize= dstr->size_alloced + ((size_data - bytes_left) / dstr->size_page + 1) * dstr->size_page;
134 if (!(tmp= (char*) UdmRealloc(dstr->Val.str, asize)))
135 return 0;
136 dstr->Val.str= tmp;
137 dstr->size_alloced= asize;
138 }
139 memcpy(dstr->Val.str + dstr->Val.length, data, size_data);
140 dstr->Val.length+= size_data;
141 dstr->Val.str[dstr->Val.length]= 0;
142 return size_data;
143 }
144
145
146 udm_rc_t
UdmDSTRAppendURLDecode(UDM_DSTR * dstr,const char * str,size_t length)147 UdmDSTRAppendURLDecode(UDM_DSTR *dstr, const char *str, size_t length)
148 {
149 size_t newlen= UdmDSTRLength(dstr) + length + 1;
150 if (UDM_OK != UdmDSTRRealloc(dstr, newlen))
151 return UDM_ERROR;
152 newlen= UdmURLDecode(dstr->Val.str + dstr->Val.length, str, length);
153 dstr->Val.length+= newlen;
154 return UDM_OK;
155 }
156
157
158 udm_rc_t
UdmDSTRAppendConv(UDM_DSTR * dstr,UDM_CONV * conv,const char * src,size_t srclen,int flags)159 UdmDSTRAppendConv(UDM_DSTR *dstr, UDM_CONV *conv,
160 const char *src, size_t srclen, int flags)
161 {
162 size_t bytes_needed= UdmConvSizeNeeded(conv, srclen, flags);
163 size_t converted_length;
164
165 if (UDM_OK != UdmDSTRRealloc(dstr, dstr->Val.length + bytes_needed + 1))
166 return UDM_ERROR;
167 converted_length= UdmConv(conv,
168 dstr->Val.str + dstr->Val.length,
169 dstr->size_alloced - dstr->Val.length - 1,
170 src, srclen, flags);
171 dstr->Val.length+= converted_length;
172 dstr->Val.str[dstr->Val.length]= 0;
173 UDM_ASSERT(dstr->Val.length < dstr->size_alloced);
174 return UDM_OK;
175 }
176
177
178 static char hex_digits[]= "0123456789ABCDEF";
179
180 /*
181 This function does not put trailing \x00 character.
182 */
183 size_t
UdmDSTRAppendHex(UDM_DSTR * dstr,const char * s,size_t slen)184 UdmDSTRAppendHex(UDM_DSTR *dstr, const char *s, size_t slen)
185 {
186 char *d;
187 size_t new_size= dstr->Val.length + 2 * slen;
188 if (!slen || (UDM_OK != UdmDSTRRealloc(dstr, new_size)))
189 return 0;
190 for (d= dstr->Val.str + dstr->Val.length; slen; slen--, s++)
191 {
192 unsigned char ch= *((const unsigned char*) s);
193 *d++= hex_digits[(ch >> 4) & 0x0F];
194 *d++= hex_digits[ch & 0x0F];
195 }
196 dstr->Val.length= new_size;
197 return dstr->Val.length;
198 }
199
200
201 size_t
UdmDSTRAppendSTR(UDM_DSTR * dstr,const char * data)202 UdmDSTRAppendSTR(UDM_DSTR *dstr, const char *data)
203 {
204 return UdmDSTRAppend(dstr, data, strlen(data));
205 }
206
207
208 size_t
UdmDSTRAppendINT4(UDM_DSTR * s,int i)209 UdmDSTRAppendINT4(UDM_DSTR *s, int i)
210 {
211 char buf[4];
212 udm_put_int4(i, buf);
213 return UdmDSTRAppend(s, buf, 4);
214 }
215
216
217 size_t
UdmDSTRAppendINT2LE(UDM_DSTR * s,int i)218 UdmDSTRAppendINT2LE(UDM_DSTR *s, int i)
219 {
220 char buf[2];
221 buf[0]= (char) (((unsigned int) i) & 0xFF);
222 buf[1]= (char) (((unsigned int) i) >> 8);
223 return UdmDSTRAppend(s, buf, 2);
224 }
225
226
227 size_t
UdmDSTRAppendINT2BE(UDM_DSTR * s,int i)228 UdmDSTRAppendINT2BE(UDM_DSTR *s, int i)
229 {
230 char buf[2];
231 buf[0]= (char) (((unsigned int) i) >> 8);
232 buf[1]= (char) (((unsigned int) i) & 0xFF);
233 return UdmDSTRAppend(s, buf, 2);
234 }
235
236
237 int
UdmDSTRAppendf(UDM_DSTR * dstr,const char * fmt,...)238 UdmDSTRAppendf(UDM_DSTR *dstr, const char *fmt, ...)
239 {
240 va_list ap;
241 int nc;
242 char *tmp;
243
244 while (1)
245 {
246 size_t asize;
247 size_t bytes_left= dstr->size_alloced - dstr->Val.length;
248 va_start(ap, fmt);
249 nc= vsnprintf(dstr->Val.str + dstr->Val.length, bytes_left, fmt, ap);
250 va_end(ap);
251
252 if (nc > -1 && nc + 1 < (int) bytes_left)
253 break;
254
255 if (nc < 0 || nc + 1 == (int) bytes_left)
256 asize= dstr->size_alloced + dstr->size_page;
257 else
258 asize= dstr->size_alloced + ((nc - bytes_left) / dstr->size_page + 1) * dstr->size_page;
259
260 if(!(tmp= (char*) UdmRealloc(dstr->Val.str, asize)))
261 {
262 nc= 0;
263 break;
264 }
265 dstr->size_alloced= asize;
266 dstr->Val.str= tmp;
267 }
268
269 dstr->Val.length+= nc;
270 return(nc);
271 }
272
273 void
UdmDSTRReset(UDM_DSTR * dstr)274 UdmDSTRReset(UDM_DSTR *dstr)
275 {
276 dstr->Val.length= 0;
277 if (dstr->Val.str)
278 dstr->Val.str[0]= '\0';
279 }
280
281
282 udm_rc_t
UdmDSTRAppendRemoveHiLight(UDM_DSTR * dstr,const char * src,size_t length)283 UdmDSTRAppendRemoveHiLight(UDM_DSTR *dstr, const char *src, size_t length)
284 {
285 if (UdmDSTRReserve(dstr, length + 1))
286 return UDM_ERROR;
287 dstr->Val.length+= UdmRemoveHiLight(dstr->Val.str + dstr->Val.length,
288 length, src, length);
289 dstr->Val.str[dstr->Val.length]= 0;
290 UDM_ASSERT(dstr->Val.length < dstr->size_alloced);
291 return UDM_OK;
292 }
293
294
UdmDSTRShrinkLast(UDM_DSTR * dstr)295 void UdmDSTRShrinkLast(UDM_DSTR *dstr)
296 {
297 UDM_ASSERT(dstr->Val.length > 0);
298 dstr->Val.length--;
299 dstr->Val.str[dstr->Val.length]= '\0';
300 }
301
302
303 void
UdmDSTRToConstStr(const UDM_DSTR * dstr,UDM_CONST_STR * to)304 UdmDSTRToConstStr(const UDM_DSTR *dstr, UDM_CONST_STR *to)
305 {
306 UdmConstStrSet(to, dstr->Val.str, dstr->Val.length);
307 }
308
309
UdmDSTRToDouble(const UDM_DSTR * dstr)310 double UdmDSTRToDouble(const UDM_DSTR *dstr)
311 {
312 return atof(dstr->Val.str);
313 }
314
315
UdmDSTRToInt(const UDM_DSTR * dstr)316 int UdmDSTRToInt(const UDM_DSTR *dstr)
317 {
318 return atoi(dstr->Val.str);
319 }
320
321
UdmDSTRCmp(const UDM_DSTR * s1,const UDM_DSTR * s2)322 int UdmDSTRCmp(const UDM_DSTR *s1, const UDM_DSTR *s2)
323 {
324 size_t minlen= UDM_MIN(s1->Val.length, s2->Val.length);
325 int res= memcmp(s1->Val.str, s2->Val.str, minlen);
326 return res ? res :
327 s1->Val.length == s2->Val.length ? 0 :
328 s1->Val.length < s2->Val.length ? -1 : 1;
329 }
330
331
UdmDSTRCaseCmp(const UDM_DSTR * s1,const UDM_DSTR * s2)332 int UdmDSTRCaseCmp(const UDM_DSTR *s1, const UDM_DSTR *s2)
333 {
334 return udm_strnncasecmp(s1->Val.str, s1->Val.length,
335 s2->Val.str, s2->Val.length);
336 }
337
338
UdmDSTRWildCaseCmp(const UDM_DSTR * str,const UDM_DSTR * pattern)339 int UdmDSTRWildCaseCmp(const UDM_DSTR *str, const UDM_DSTR *pattern)
340 {
341 return UdmWildCaseCmp(str->Val.str, pattern->Val.str);
342 }
343
344
345 udm_rc_t
UdmDSTRAppendCoord(UDM_DSTR * dstr,uint4 coord)346 UdmDSTRAppendCoord(UDM_DSTR *dstr, uint4 coord)
347 {
348 size_t length;
349 if (UDM_OK != UdmDSTRReserve(dstr, 6))
350 return UDM_ERROR;
351 length= udm_coord_put(coord,
352 (unsigned char*) dstr->Val.str + dstr->Val.length,
353 (unsigned char*) dstr->Val.str + dstr->Val.length + 6);
354 if (!length)
355 return UDM_ERROR;
356 dstr->Val.length+= length;
357 return UDM_OK;
358 }
359
360
361 udm_rc_t
UdmDSTRReadFile(UDM_DSTR * dstr,int fd,size_t count)362 UdmDSTRReadFile(UDM_DSTR *dstr, int fd, size_t count)
363 {
364 ssize_t nbytes;
365 if (UDM_OK != (UdmDSTRAlloc(dstr, count + 1)))
366 return UDM_ERROR;
367 if ((nbytes= read(fd, dstr->Val.str, count)) != (ssize_t) count)
368 return UDM_ERROR;
369 dstr->Val.length= count;
370 dstr->Val.str[count]= '\0';
371 return UDM_OK;
372 }
373
374
375 void
UdmDSTRRemoveHighlightWithOffset(UDM_DSTR * dstr,UDM_CHARSET * cset,size_t ofs)376 UdmDSTRRemoveHighlightWithOffset(UDM_DSTR *dstr, UDM_CHARSET *cset, size_t ofs)
377 {
378 dstr->Val.length= UdmRemoveHl(cset, dstr->Val.str, ofs, dstr->Val.length);
379 }
380
381
382 udm_rc_t
UdmDSTRAppendInflate(UDM_DSTR * dstr,const char * src,size_t length)383 UdmDSTRAppendInflate(UDM_DSTR *dstr, const char *src, size_t length)
384 {
385 size_t i, mul[4]= {10, 100, 1000, 10000};
386 for (i= 0; i < 4; i++)
387 {
388 size_t reslen, nbytes= length * mul[i];
389 udm_rc_t dummy;
390 /* fprintf(stderr, "allocating %d bytes\n", nbytes); */
391 if (UdmDSTRReserve(dstr, nbytes))
392 return UDM_ERROR;
393 reslen= UdmInflate(dstr->Val.str + dstr->Val.length, nbytes,
394 src, length, &dummy);
395 /* fprintf(stderr, "reslen=%d site_total=%d\n", reslen, buf->size_total);*/
396 if (reslen < nbytes)
397 {
398 dstr->Val.length+= reslen;
399 return UDM_OK;
400 }
401 }
402 return UDM_ERROR;
403 }
404
405
406 udm_rc_t
UdmDSTRAppendDeflate(UDM_DSTR * dstr,const char * src,size_t length)407 UdmDSTRAppendDeflate(UDM_DSTR *dstr, const char *src, size_t length)
408 {
409 udm_rc_t dummy;
410 if (UDM_OK != UdmDSTRReserve(dstr, length))
411 return UDM_ERROR;
412 dstr->Val.length+= UdmDeflate(dstr->Val.str + dstr->Val.length, length,
413 src, length, &dummy);
414 return UDM_OK;
415 }
416
417
UdmDSTRPCase(UDM_DSTR * dstr)418 void UdmDSTRPCase(UDM_DSTR *dstr)
419 {
420 size_t i;
421 for (i= 0; i < dstr->Val.length; i++)
422 {
423 int ch= dstr->Val.str[i];
424 /* This will probably need full Unicode support in the future */
425 dstr->Val.str[i]= (i == 0) ? toupper(ch) : tolower(ch);
426 }
427
428 }
429
430
UdmDSTRLCase(UDM_DSTR * dstr)431 void UdmDSTRLCase(UDM_DSTR *dstr)
432 {
433 size_t i;
434 for (i= 0; i < dstr->Val.length; i++)
435 {
436 dstr->Val.str[i]= tolower(dstr->Val.str[i]);
437 }
438 }
439
440
UdmDSTRUCase(UDM_DSTR * dstr)441 void UdmDSTRUCase(UDM_DSTR *dstr)
442 {
443 size_t i;
444 for (i= 0; i < dstr->Val.length; i++)
445 {
446 dstr->Val.str[i]= toupper(dstr->Val.str[i]);
447 }
448 }
449
450
UdmDSTRBCut(UDM_DSTR * dstr)451 void UdmDSTRBCut(UDM_DSTR *dstr)
452 {
453 if (UdmDSTRLength(dstr) > 1)
454 {
455 memmove(dstr->Val.str, dstr->Val.str + 1, dstr->Val.length - 1);
456 dstr->Val.length--;
457 dstr->Val.str[dstr->Val.length]= '\0';
458 }
459 else
460 dstr->Val.str[0]= '\0';
461 }
462
463
UdmDSTRGiveValue(UDM_DSTR * dstr,UDM_STR * to)464 void UdmDSTRGiveValue(UDM_DSTR *dstr, UDM_STR *to)
465 {
466 *to= dstr->Val;
467 UDM_BZERO(dstr, sizeof(UDM_DSTR));
468 }
469
470
471 udm_rc_t
UdmDSTRURLDecode(UDM_DSTR * dstr)472 UdmDSTRURLDecode(UDM_DSTR *dstr)
473 {
474 UDM_DSTR dstr2;
475 UdmDSTRInit(&dstr2, 256);
476 UdmDSTRAppendURLDecode(&dstr2, UdmDSTRPtr(dstr), UdmDSTRLength(dstr));
477 UdmDSTRFree(dstr);
478 dstr[0]= dstr2;
479 return UDM_OK;
480 }
481
482
483 udm_rc_t
UdmDSTRAppendHTMLEncode(UDM_DSTR * dstr,const char * str,size_t length)484 UdmDSTRAppendHTMLEncode(UDM_DSTR *dstr, const char *str, size_t length)
485 {
486 size_t reslen, enclen= length * 6 + 1;
487 if (UDM_OK != UdmDSTRReserve(dstr, enclen))
488 return UDM_ERROR;
489 reslen= UdmHTMLEncode(dstr->Val.str + dstr->Val.length, enclen, str, length);
490 dstr->Val.length+= reslen;
491 return UDM_OK;
492 }
493
494
495 udm_rc_t
UdmDSTRAppendURLEncode(UDM_DSTR * dstr,const char * str,size_t length)496 UdmDSTRAppendURLEncode(UDM_DSTR *dstr, const char *str, size_t length)
497 {
498 size_t reslen, enclen= length * 3 + 1;
499 if (UDM_OK != UdmDSTRReserve(dstr, enclen))
500 return UDM_ERROR;
501 reslen= UdmURLEncode(dstr->Val.str + dstr->Val.length, str, length);
502 dstr->Val.length+= reslen;
503 return UDM_OK;
504 }
505
506
507 udm_rc_t
UdmDSTRHTMLEncode(UDM_DSTR * dstr)508 UdmDSTRHTMLEncode(UDM_DSTR *dstr)
509 {
510 size_t enclen= UdmDSTRLength(dstr) * 6 + 1;
511 char *vurl_encoded= (char*) UdmMalloc(enclen);
512 size_t reslen= UdmHTMLEncode(vurl_encoded, enclen,
513 UdmDSTRPtr(dstr), UdmDSTRLength(dstr));
514 UdmDSTRReset(dstr);
515 UdmDSTRAppend(dstr, vurl_encoded, reslen);
516 UdmFree(vurl_encoded);
517 return UDM_OK;
518 }
519
520
521 udm_rc_t
UdmDSTRAppendRegexReplace(UDM_DSTR * dst,const char * src,size_t srclen,const char * pattern,size_t patternlen,const char * replacement,size_t replacementlen)522 UdmDSTRAppendRegexReplace(UDM_DSTR *dst, const char *src, size_t srclen,
523 const char *pattern, size_t patternlen,
524 const char *replacement, size_t replacementlen)
525 {
526 char errstr[128];
527 UDM_MATCH M;
528 UDM_MATCH_PART P[10];
529 size_t len= (srclen + patternlen + replacementlen) * 10;
530 UDM_ASSERT(src[srclen] == '\0'); /* Must be NULL-terminated */
531 UDM_ASSERT(pattern[patternlen] == '\0'); /* Must be NULL-terminated */
532 UdmMatchInit(&M);
533 if (!UdmMatchCompSpecificRegex(&M, pattern, errstr, sizeof(errstr)) &&
534 !UdmMatchExec(&M, src, srclen, NULL, 10, P))
535 {
536 char *res= (char*) UdmMalloc(len);
537 size_t reslen;
538 res[0]= '\0';
539 reslen= UdmMatchApply(res, len, src, replacement, replacementlen,
540 &M, 10, P);
541 UdmDSTRAppend(dst, res, reslen);
542 UdmFree(res);
543 }
544 UdmMatchFree(&M);
545 return UDM_OK;
546 }
547
548
549 static udm_rc_t
UdmDSTRCopySubpatterns(UDM_DSTR * dst,const UDM_CONST_STR * src,const UDM_MATCH_PART * P,int nparts)550 UdmDSTRCopySubpatterns(UDM_DSTR *dst,
551 const UDM_CONST_STR *src,
552 const UDM_MATCH_PART *P, int nparts)
553 {
554 int i;
555 /* Copy the part before the first match */
556 UdmDSTRAppend(dst, src->str, (size_t) P[1].beg);
557 UDM_ASSERT(P[1].beg >= 0 && P[1].end >= 0);
558 /* Copy the middle */
559 for (i= 2; i < nparts && P[i].beg >= 0 && P[i].end >= 0; i++)
560 {
561 UDM_ASSERT(P[i - 1].end <= P[i].beg);
562 UdmDSTRAppend(dst, src->str + P[i - 1].end, P[i].beg - P[i - 1].end);
563 }
564 /*
565 Copy the part after the last subpattern: P[i-1].end
566 until the end of the entire matched pattern: P[0].end
567 */
568 UDM_ASSERT(P[0].end >= P[i-1].end);
569 UdmDSTRAppend(dst, src->str + P[i-1].end, P[0].end - P[i-1].end);
570 return UDM_OK;
571 }
572
573
574 udm_rc_t
UdmDSTRAppendRegexCut(UDM_DSTR * dst,const char * src,size_t srclen,const char * pattern,size_t patternlen)575 UdmDSTRAppendRegexCut(UDM_DSTR *dst,
576 const char *src, size_t srclen,
577 const char *pattern, size_t patternlen)
578 {
579 UDM_CONST_STR tmp;
580 UDM_MATCH M;
581 UDM_MATCH_PART P[10];
582 char errstr[128];
583
584 UDM_ASSERT(src[srclen] == '\0');
585 UDM_ASSERT(pattern[patternlen] == '\0');
586
587 UdmConstStrSet(&tmp, src, srclen);
588
589 UdmMatchInit(&M);
590 if (UdmMatchCompSpecificRegex(&M, pattern, errstr, sizeof(errstr)))
591 goto ret;
592
593 for ( ; ; )
594 {
595 UDM_ASSERT(tmp.str[tmp.length] == '\0');
596 if (UdmMatchExec(&M, tmp.str, tmp.length, NULL, 10, P))
597 break;
598 UDM_ASSERT(P[0].beg >= 0);
599 UDM_ASSERT(P[0].end <= (int) tmp.length);
600 if (P[1].beg < 0) /* No subpatterns */
601 {
602 /*
603 Copy the part before the match.
604 It can be empty if matched at the beginning.
605 */
606 UdmDSTRAppend(dst, tmp.str, (size_t) P[0].beg);
607 }
608 else
609 {
610 size_t oldlen= UdmDSTRLength(dst);
611 UdmDSTRCopySubpatterns(dst, &tmp, P, 10);
612 if (UdmDSTRLength(dst) == oldlen)
613 {
614 /*
615 The entire string matched with subpatterns,
616 but subpatterns were empty, e.g.:
617 subject='http://site0/' pattern='^[a-z]+://[^/]+/(.*)'
618 Nothing was actually cut.
619 */
620 break;
621 }
622 }
623 if (!P[0].end) /* Matched empty pattern at the beginning. */
624 break;
625 tmp.str+= P[0].end;
626 tmp.length-= P[0].end;
627 }
628
629 ret:
630 UdmMatchFree(&M);
631 /* Append the trailing unmatched part */
632 UdmDSTRAppend(dst, tmp.str, tmp.length);
633 return UDM_OK;
634 }
635
636
637 udm_rc_t
UdmDSTRAppendBase64Encode(UDM_DSTR * dstr,const char * str,size_t length)638 UdmDSTRAppendBase64Encode(UDM_DSTR *dstr, const char *str, size_t length)
639 {
640 if (UdmDSTRReserve(dstr, BASE64_LEN(length)))
641 return UDM_ERROR;
642 length= udm_base64_encode(str, dstr->Val.str + dstr->Val.length, length);
643 dstr->Val.length+= length;
644 return UDM_OK;
645 }
646
647
648 udm_rc_t
UdmDSTRAppendHighlight(UDM_DSTR * dstr,const char * src,size_t srclen,const char * beg,size_t blen,const char * end,size_t elen)649 UdmDSTRAppendHighlight(UDM_DSTR *dstr,
650 const char *src, size_t srclen,
651 const char *beg, size_t blen,
652 const char *end, size_t elen)
653 {
654 size_t len=1;
655 const char *s, *srcend= src + srclen;
656 char *d;
657
658 for (s= src; s < srcend; s++)
659 {
660 switch(*s)
661 {
662 case '\2':
663 len+=blen;
664 break;
665 case '\3':
666 len+=elen;
667 break;
668 default:
669 len++;
670 }
671 }
672 if (UdmDSTRReserve(dstr, len))
673 return UDM_ERROR;
674 for (s= src, d= dstr->Val.str; s < srcend; s++)
675 {
676 switch (*s)
677 {
678 case '\2':
679 memcpy(d, beg, blen);
680 d+= blen;
681 break;
682 case '\3':
683 memcpy(d, end, elen);
684 d+= elen;
685 break;
686 default:
687 *d++= *s;
688 }
689 }
690 *d= '\0';
691 dstr->Val.length= d - dstr->Val.str;
692 return UDM_OK;
693 }
694