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