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 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 
25 #define UDM_MATCH_PRIV
26 
27 #include "udm_common.h"
28 #include "udm_regex.h"
29 #include "udm_utils.h"
30 #include "udm_wild.h"
31 #include "udm_match.h"
32 #include "udm_vars.h"
33 
34 
UdmMatchPatternConstStr(const UDM_MATCH * Match)35 const char *UdmMatchPatternConstStr(const UDM_MATCH *Match)
36 {
37   return Match->Pattern.str;
38 }
39 
40 
UdmMatchPatternLength(const UDM_MATCH * Match)41 size_t UdmMatchPatternLength(const UDM_MATCH *Match)
42 {
43   return Match->Pattern.length;
44 }
45 
46 
47 udm_bool_t
UdmMatchIsCaseInsensitive(const UDM_MATCH * Match)48 UdmMatchIsCaseInsensitive(const UDM_MATCH *Match)
49 {
50   return UDM_TEST(Match->Param.flags & UDM_MATCH_FLAG_CASE_INSENSITIVE);
51 }
52 
53 
54 udm_bool_t
UdmMatchIsNegative(const UDM_MATCH * Match)55 UdmMatchIsNegative(const UDM_MATCH *Match)
56 {
57   return UDM_TEST(Match->Param.flags & UDM_MATCH_FLAG_NEGATIVE);
58 }
59 
60 
61 void
UdmMatchParamSetCaseInsensitive(UDM_MATCH_PARAM * P,udm_bool_t on)62 UdmMatchParamSetCaseInsensitive(UDM_MATCH_PARAM *P, udm_bool_t on)
63 {
64   if (on)
65     P->flags|= UDM_MATCH_FLAG_CASE_INSENSITIVE;
66   else
67     P->flags&= ~UDM_MATCH_FLAG_CASE_INSENSITIVE;
68 }
69 
70 
71 void
UdmMatchParamSetNegative(UDM_MATCH_PARAM * P,udm_bool_t on)72 UdmMatchParamSetNegative(UDM_MATCH_PARAM *P, udm_bool_t on)
73 {
74   if (on)
75     P->flags|= UDM_MATCH_FLAG_NEGATIVE;
76   else
77     P->flags&= ~UDM_MATCH_FLAG_NEGATIVE;
78 }
79 
80 
81 void
UdmMatchParamSetOptimization(UDM_MATCH_PARAM * P,udm_bool_t on)82 UdmMatchParamSetOptimization(UDM_MATCH_PARAM *P, udm_bool_t on)
83 {
84   if (!on)
85     P->flags|= UDM_MATCH_FLAG_SKIP_OPTIMIZATION;
86   else
87     P->flags&= ~UDM_MATCH_FLAG_SKIP_OPTIMIZATION;
88 }
89 
90 
91 const char *
UdmMatchCaseSensitivityStr(const UDM_MATCH * Match)92 UdmMatchCaseSensitivityStr(const UDM_MATCH *Match)
93 {
94   return UdmMatchIsCaseInsensitive(Match) ? "Insensitive" : "Sensitive";
95 }
96 
97 
98 static int
IsSimpleWildEnding(const char * p)99 IsSimpleWildEnding(const char *p)
100 {
101   if (*p++ != '*' || !*p)
102     return 0;
103   for (; *p; p++)
104   {
105     if (*p == '*' || *p =='?')
106       return 0;
107   }
108   return 1;
109 }
110 
111 
112 static regex_t *
UdmMatchGetRegex(const UDM_MATCH * Match)113 UdmMatchGetRegex(const UDM_MATCH *Match)
114 {
115   return (regex_t *) Match->specific;
116 }
117 
118 
119 /*
120   Compile the given patter to Match->specific.
121   Doesn't touch Match->Pattern.
122 */
123 static udm_rc_t
UdmMatchCompSpecificRegexInternal(UDM_MATCH * Match,const char * pattern,char * errstr,size_t errstrsize)124 UdmMatchCompSpecificRegexInternal(UDM_MATCH *Match, const char *pattern,
125                                   char *errstr, size_t errstrsize)
126 {
127   int err, flag= REG_EXTENDED;
128   errstr[0]= '\0';
129   Match->specific= (regex_t*)UdmRealloc(Match->specific, sizeof(regex_t));
130   bzero((void*)Match->specific, sizeof(regex_t));
131   if (UdmMatchIsCaseInsensitive(Match))
132     flag|= REG_ICASE;
133   if ((err= regcomp(UdmMatchGetRegex(Match), pattern, flag)))
134   {
135     regerror(err, UdmMatchGetRegex(Match), errstr, errstrsize); /* TODO-OVERFLOW */
136     UDM_FREE(Match->specific);
137     return UDM_ERROR;
138   }
139   return UDM_OK;
140 }
141 
142 
143 udm_rc_t
UdmMatchCompSpecificRegex(UDM_MATCH * Match,const char * pattern,char * errstr,size_t errstrsize)144 UdmMatchCompSpecificRegex(UDM_MATCH *Match, const char *pattern,
145                           char *errstr, size_t errstrsize)
146 {
147   Match->Param.match_mode= UDM_MATCH_REGEX;
148   return UdmMatchCompSpecificRegexInternal(Match, pattern, errstr, errstrsize);
149 }
150 
151 
152 udm_rc_t
UdmMatchComp(UDM_MATCH * Match,char * errstr,size_t errstrsize)153 UdmMatchComp(UDM_MATCH *Match,char *errstr,size_t errstrsize)
154 {
155   Match->Pattern.length= strlen(Match->Pattern.str);
156 
157   switch (Match->Param.match_mode)
158   {
159     case UDM_MATCH_REGEX:
160       if (UdmMatchCompSpecificRegex(Match, Match->Pattern.str, errstr, errstrsize))
161         return UDM_ERROR;
162       break;
163     case UDM_MATCH_WILD:
164       errstr[0]= '\0';
165       if (!(Match->Param.flags & UDM_MATCH_FLAG_SKIP_OPTIMIZATION) &&
166           IsSimpleWildEnding(Match->Pattern.str))
167       {
168         /* Convert simple UDM_MATCH_WILD cases to UDM_MATCH_END */
169         memmove(Match->Pattern.str, Match->Pattern.str + 1, Match->Pattern.length);
170         Match->Param.match_mode= UDM_MATCH_END;
171         Match->Pattern.length--;
172       }
173       break;
174     case UDM_MATCH_BEGIN:
175     case UDM_MATCH_END:
176     case UDM_MATCH_SUBSTR:
177     case UDM_MATCH_FULL:
178       errstr[0]= '\0';
179       break;
180     case UDM_MATCH_SUBNET:
181     case UDM_MATCH_NUMERIC_LT:
182     case UDM_MATCH_NUMERIC_GT:
183     case UDM_MATCH_RANGE:
184       udm_snprintf(errstr, errstrsize, "Unknown match type '%d'",
185                    Match->Param.match_mode);
186       return UDM_ERROR;
187   }
188   return UDM_OK;
189 }
190 
191 
192 void
UdmMatchParamInit(UDM_MATCH_PARAM * M)193 UdmMatchParamInit(UDM_MATCH_PARAM *M)
194 {
195   bzero((void*) M, sizeof(*M));
196 }
197 
198 
199 void
UdmMatchInit(UDM_MATCH * M)200 UdmMatchInit(UDM_MATCH *M)
201 {
202   bzero((void*)M, sizeof(*M));
203 }
204 
205 
UdmMatchFree(UDM_MATCH * Match)206 void UdmMatchFree(UDM_MATCH * Match)
207 {
208   UDM_FREE(Match->Pattern.str);
209   Match->Pattern.length= 0;
210   if (Match->specific)
211   {
212     regfree((regex_t*) Match->specific);
213     UDM_FREE(Match->specific);
214   }
215 }
216 
217 
UdmMatchFreeAndInit(UDM_MATCH * Match)218 void UdmMatchFreeAndInit(UDM_MATCH *Match)
219 {
220   UdmMatchFree(Match);
221   UdmMatchInit(Match);
222 }
223 
224 
225 #define UDM_NSUBS 10
226 
227 int
UdmMatchExec(const UDM_MATCH * Match,const char * string,size_t string_length,const char * net_string,size_t nparts,UDM_MATCH_PART * Parts)228 UdmMatchExec(const UDM_MATCH * Match,
229              const char *string, size_t string_length,
230              const char *net_string,
231              size_t nparts,UDM_MATCH_PART * Parts)
232 {
233   size_t    i;
234   int    res=0;
235   regmatch_t  subs[UDM_NSUBS];
236   const char  *se;
237 
238   UdmDebugEnter();
239 
240   switch (Match->Param.match_mode)
241   {
242     case UDM_MATCH_REGEX:
243       if(nparts>UDM_NSUBS)nparts=UDM_NSUBS;
244       res= regexec(UdmMatchGetRegex(Match), string, nparts, subs, 0);
245       if(res)
246       {
247         for(i=0;i<nparts;i++)Parts[i].beg=Parts[i].end=-1;
248       }
249       else
250       {
251         for(i=0;i<nparts;i++)
252         {
253           Parts[i].beg=subs[i].rm_so;
254           Parts[i].end=subs[i].rm_eo;
255         }
256       }
257       break;
258     case UDM_MATCH_WILD:
259       for(i=0;i<nparts;i++)Parts[i].beg=Parts[i].end=-1;
260       if (UdmMatchIsCaseInsensitive(Match))
261       {
262         res= UdmWildCaseCmp(string, Match->Pattern.str);
263       }
264       else
265       {
266         res= UdmWildCmp(string, Match->Pattern.str);
267       }
268       break;
269     case UDM_MATCH_SUBNET:
270       for(i = 0; i < nparts; i++) Parts[i].beg = Parts[i].end = -1;
271       if (UdmMatchIsCaseInsensitive(Match))
272       {
273         res= UdmWildCaseCmp(net_string, Match->Pattern.str);
274       }
275       else
276       {
277         res= UdmWildCmp(net_string, Match->Pattern.str);
278       }
279       break;
280     case UDM_MATCH_BEGIN:
281       for(i=0;i<nparts;i++)Parts[i].beg=Parts[i].end=-1;
282       if (UdmMatchIsCaseInsensitive(Match))
283       {
284         res= strncasecmp(Match->Pattern.str, string, Match->Pattern.length);
285       }
286       else
287       {
288         res= strncmp(Match->Pattern.str, string, Match->Pattern.length);
289       }
290       break;
291     case UDM_MATCH_FULL:
292       for(i=0;i<nparts;i++)Parts[i].beg=Parts[i].end=-1;
293       if (UdmMatchIsCaseInsensitive(Match))
294       {
295         res= strcasecmp(Match->Pattern.str, string);
296       }
297       else
298       {
299         res= strcmp(Match->Pattern.str, string);
300       }
301       break;
302     case UDM_MATCH_END:
303       for(i=0;i<nparts;i++)Parts[i].beg=Parts[i].end=-1;
304       if (string_length < Match->Pattern.length)
305       {
306         res= 1;
307         break;
308       }
309       se= string + string_length - Match->Pattern.length;
310       if (UdmMatchIsCaseInsensitive(Match))
311       {
312         res= strcasecmp(Match->Pattern.str, se);
313       }
314       else
315       {
316         res= strcmp(Match->Pattern.str, se);
317       }
318       break;
319 
320     case UDM_MATCH_SUBSTR:
321     case UDM_MATCH_NUMERIC_LT:
322     case UDM_MATCH_NUMERIC_GT:
323     case UDM_MATCH_RANGE:
324       for(i=0;i<nparts;i++)Parts[i].beg=Parts[i].end=-1;
325       res=0;
326   }
327   if (UdmMatchIsNegative(Match))
328     res= !res;
329   UdmDebugReturn(res);
330 }
331 
332 
333 static int
UdmMatchSubNo(const char * str,const char * end)334 UdmMatchSubNo(const char *str, const char *end)
335 {
336   if (*str == '$' && str + 1 < end && str[1] >= '0' && str[1] <= '9')
337     return str[1] - '0';
338   return -1;
339 }
340 
341 static size_t
UdmMatchPartLength(UDM_MATCH_PART * P)342 UdmMatchPartLength(UDM_MATCH_PART *P)
343 {
344   return ((P->beg > -1) && (P->end > P->beg)) ? P->end - P->beg : 0;
345 }
346 
347 
348 /*
349   Calc length which will be required for UdmMatchRegexApply(),
350   including traling '\0' character.
351 */
352 static size_t
UdmMatchRegexApplyLength(const char * repl,size_t repllen,size_t nparts,UDM_MATCH_PART * Parts)353 UdmMatchRegexApplyLength(const char *repl, size_t repllen,
354                          size_t nparts, UDM_MATCH_PART *Parts)
355 {
356   size_t length;
357   const char *replend= repl + repllen;
358   for (length= 0; repl < replend; repl++)
359   {
360     int sub;
361     if ((sub= UdmMatchSubNo(repl, replend)) >= 0)
362     {
363       size_t part_length= UdmMatchPartLength(&Parts[sub]);
364       length+= part_length;
365       repl++;
366     }
367     else
368     {
369       length++;
370     }
371   }
372   return length + 1;
373 }
374 
375 
376 /*
377   Apply "regex" type of match parts.
378   previously generated by UdmMatchExec result.
379   res    - where to put result to
380   size   - size of res, must be at least 1 byte - for trailing '\0'.
381   string - source string
382   rpl    - replacement pattern, with variables \0, \1, \2, ... \9
383   nparts - how many parts were found by UdmMatchExec
384   Parts  - the parts themself
385 
386   RETURNS - result length.
387 */
388 static size_t
UdmMatchRegexApply(char * res,size_t size,const char * string,const char * rpl,size_t rpllen,size_t nparts,UDM_MATCH_PART * Parts)389 UdmMatchRegexApply(char *res, size_t size,
390                    const char *string,
391                    const char *rpl, size_t rpllen,
392                    size_t nparts, UDM_MATCH_PART *Parts)
393 {
394   char *dst= res, *dstend= res + size - 1;
395   const char *rplend= rpl + rpllen;
396 
397   if (!res)
398     return UdmMatchRegexApplyLength(rpl, rpllen, nparts, Parts);
399 
400   UDM_ASSERT(size>0);
401 
402   while (rpl < rplend && dst < dstend)
403   {
404     int sub;
405     if ((sub= UdmMatchSubNo(rpl, rplend)) >= 0)
406     {
407       size_t part_length;
408       if((part_length= UdmMatchPartLength(&Parts[sub])))
409       {
410         size_t bytes_left= dstend - dst;
411         if (bytes_left <= part_length)
412           part_length= bytes_left;
413         memcpy(dst, string + Parts[sub].beg, part_length);
414         dst+= part_length;
415       }
416       rpl+= 2;
417     }
418     else
419     {
420       *dst++= *rpl++;
421     }
422   }
423   *dst='\0';
424   return dst - res;
425 }
426 
427 
428 size_t
UdmMatchApply(char * res,size_t size,const char * string,const char * rpl,size_t rpllen,const UDM_MATCH * Match,size_t nparts,UDM_MATCH_PART * Parts)429 UdmMatchApply(char *res, size_t size,
430               const char *string,
431               const char *rpl, size_t rpllen,
432               const UDM_MATCH *Match,
433               size_t nparts, UDM_MATCH_PART *Parts)
434 {
435   int    len=0;
436   if(!size)return 0;
437 
438   switch (Match->Param.match_mode)
439   {
440     case UDM_MATCH_REGEX:
441       len= UdmMatchRegexApply(res, size, string, rpl, rpllen, nparts, Parts);
442       break;
443 
444     case UDM_MATCH_BEGIN:
445       len= udm_snprintf(res, size - 1, "%.*s%s",
446                         (int) rpllen, rpl,
447                         string + strlen(Match->Pattern.str));
448       break;
449 
450     case UDM_MATCH_FULL:
451     case UDM_MATCH_SUBSTR:
452     case UDM_MATCH_END:
453     case UDM_MATCH_WILD:
454     case UDM_MATCH_SUBNET:
455     case UDM_MATCH_NUMERIC_LT:
456     case UDM_MATCH_NUMERIC_GT:
457     case UDM_MATCH_RANGE:
458       *res='\0';
459       len=0;
460       break;
461   }
462   return len;
463 }
464 
465 
466 udm_rc_t
UdmMatchSetPattern(UDM_MATCH * Match,const char * pattern)467 UdmMatchSetPattern(UDM_MATCH *Match, const char *pattern)
468 {
469   if (!pattern)
470   {
471     Match->Pattern.str= NULL;
472     Match->Pattern.length= 0;
473     return UDM_OK;
474   }
475   if (!(Match->Pattern.str= UdmStrdup(pattern)))
476   {
477     Match->Pattern.length= 0;
478     return UDM_ERROR;
479   }
480   Match->Pattern.length= strlen(pattern);
481   return UDM_OK;
482 }
483 
484 
485 const char *
UdmMatchModeStr(udm_match_mode_t m)486 UdmMatchModeStr(udm_match_mode_t m)
487 {
488   switch(m)
489   {
490     case UDM_MATCH_REGEX:  return  "Regex";
491     case UDM_MATCH_WILD:  return  "Wild";
492     case UDM_MATCH_BEGIN:  return  "Begin";
493     case UDM_MATCH_END:  return  "End";
494     case UDM_MATCH_SUBSTR:  return  "SubStr";
495     case UDM_MATCH_FULL:  return  "Full";
496     case UDM_MATCH_SUBNET:  return  "Subnet";
497     case UDM_MATCH_NUMERIC_LT: return "LT";
498     case UDM_MATCH_NUMERIC_GT: return "GT";
499     case UDM_MATCH_RANGE: return "Range";
500   }
501   return "<Unknown Match Type>";
502 }
503 
504 
505 void
UdmFilterListInit(UDM_FILTERLIST * L)506 UdmFilterListInit(UDM_FILTERLIST *L)
507 {
508   bzero((void*)L, sizeof(*L));
509 }
510 
511 
512 void
UdmFilterListFree(UDM_FILTERLIST * L)513 UdmFilterListFree(UDM_FILTERLIST *L)
514 {
515   size_t i;
516   for (i= 0; i < L->nitems; i++)
517   {
518     UdmMatchFree(&L->Item[i].Match);
519   }
520   L->nitems= L->mitems= 0;
521   UDM_FREE(L->Item);
522 }
523 
524 
525 udm_rc_t
UdmFilterListAdd(UDM_FILTERLIST * L,const UDM_MATCH_PARAM * MatchParam,udm_method_t method,const UDM_CONST_STR * Pattern,char * err,size_t errsize)526 UdmFilterListAdd(UDM_FILTERLIST *L,
527                  const UDM_MATCH_PARAM *MatchParam, udm_method_t method,
528                  const UDM_CONST_STR *Pattern,
529                  char *err, size_t errsize)
530 {
531   UDM_FILTER  *N;
532   udm_rc_t rc;
533 
534   if (L->nitems >= L->mitems)
535   {
536     L->mitems= L->nitems + 32;
537     L->Item= (UDM_FILTER*) UdmRealloc(L->Item, L->mitems * sizeof(UDM_FILTER));
538   }
539 
540   N= &L->Item[L->nitems];
541   UdmMatchInit(&N->Match);
542   UdmMatchSetPattern(&N->Match, Pattern->str);
543   N->Match.Param= *MatchParam;
544   N->method= method;
545 
546   if (UDM_OK != (rc= UdmMatchComp(&N->Match, err, errsize)))
547     return rc;
548 
549   L->nitems++;
550   return UDM_OK;
551 }
552 
553 
554 const UDM_FILTER *
UdmFilterListFind(const UDM_FILTERLIST * L,const char * str)555 UdmFilterListFind(const UDM_FILTERLIST *L, const char *str)
556 {
557   size_t i, slen= strlen(str);
558   for (i= 0; i < L->nitems; i++)
559   {
560     UDM_FILTER *F= &L->Item[i];
561     if (!UdmMatchExec(&F->Match, str, slen, str, 0, NULL))
562       return F;
563   }
564   return NULL;
565 }
566 
567 
568 void
UdmReplaceListInit(UDM_REPLACELIST * L)569 UdmReplaceListInit(UDM_REPLACELIST *L)
570 {
571   bzero((void*)L, sizeof(*L));
572 }
573 
574 
575 void
UdmReplaceListFree(UDM_REPLACELIST * L)576 UdmReplaceListFree(UDM_REPLACELIST *L)
577 {
578   size_t i;
579   for (i= 0; i < L->nitems; i++)
580   {
581     UDM_REPLACE *Replace= &L->Item[i];
582     UdmMatchFree(&Replace->Match);
583     UdmFree(Replace->Replace.str);
584   }
585   L->nitems= L->mitems= 0;
586   UDM_FREE(L->Item);
587 }
588 
589 
590 udm_rc_t
UdmReplaceListAdd(UDM_REPLACELIST * L,const UDM_MATCH_PARAM * MatchParam,const UDM_CONST_STR * Pattern,const UDM_CONST_STR * Replace,char * err,size_t errsize)591 UdmReplaceListAdd(UDM_REPLACELIST *L,
592                   const UDM_MATCH_PARAM *MatchParam,
593                   const UDM_CONST_STR *Pattern,
594                   const UDM_CONST_STR *Replace,
595                   char *err, size_t errsize)
596 {
597   UDM_REPLACE *N;
598   udm_rc_t rc;
599 
600   if (L->nitems >= L->mitems)
601   {
602     L->mitems= L->nitems + 32;
603     L->Item= (UDM_REPLACE*) UdmRealloc(L->Item, L->mitems * sizeof(UDM_REPLACE));
604   }
605 
606   N= &L->Item[L->nitems];
607   UdmMatchInit(&N->Match);
608   UdmMatchSetPattern(&N->Match, Pattern->str);
609   N->Match.Param= *MatchParam;
610   N->Replace.str= Replace->str ? udm_strndup(Replace->str, Replace->length) : NULL;
611   N->Replace.length= Replace->str ? Replace->length : 0;
612 
613   if (UDM_OK != (rc= UdmMatchComp(&N->Match, err, errsize)))
614     return rc;
615 
616   L->nitems++;
617   return UDM_OK;
618 }
619 
620 
621 const UDM_REPLACE *
UdmReplaceListFind(const UDM_REPLACELIST * L,const char * str,size_t nparts,UDM_MATCH_PART * Parts)622 UdmReplaceListFind(const UDM_REPLACELIST *L, const char *str,
623                    size_t nparts, UDM_MATCH_PART *Parts)
624 {
625   size_t i, slen= strlen(str);
626   for (i= 0; i < L->nitems; i++)
627   {
628     UDM_REPLACE *F= &L->Item[i];
629     if (!UdmMatchExec(&F->Match, str, slen, str, nparts, Parts))
630       return F;
631   }
632   return NULL;
633 }
634 
635 
636 void
UdmSectionFilterListInit(UDM_SECTIONFILTERLIST * L)637 UdmSectionFilterListInit(UDM_SECTIONFILTERLIST *L)
638 {
639   bzero((void*)L, sizeof(*L));
640 }
641 
642 
643 void
UdmSectionFilterListFree(UDM_SECTIONFILTERLIST * L)644 UdmSectionFilterListFree(UDM_SECTIONFILTERLIST *L)
645 {
646   size_t i;
647   for (i= 0; i < L->nitems; i++)
648   {
649     UdmMatchFree(&L->Item[i].Filter.Match);
650     UdmFree(L->Item[i].section);
651   }
652   L->nitems= L->mitems= 0;
653   UDM_FREE(L->Item);
654 }
655 
656 
657 udm_rc_t
UdmSectionFilterListAdd(UDM_SECTIONFILTERLIST * L,const UDM_MATCH_PARAM * MatchParam,udm_method_t method,const UDM_CONST_STR * Pattern,const char * section,char * err,size_t errsize)658 UdmSectionFilterListAdd(UDM_SECTIONFILTERLIST *L,
659                         const UDM_MATCH_PARAM *MatchParam, udm_method_t method,
660                         const UDM_CONST_STR *Pattern, const char *section,
661                         char *err, size_t errsize)
662 {
663   UDM_SECTIONFILTER *N;
664   udm_rc_t rc;
665 
666   if (L->nitems >= L->mitems)
667   {
668     L->mitems= L->nitems + 32;
669     L->Item= (UDM_SECTIONFILTER*) UdmRealloc(L->Item, L->mitems * sizeof(UDM_SECTIONFILTER));
670   }
671 
672   N= &L->Item[L->nitems];
673   UdmMatchInit(&N->Filter.Match);
674   UdmMatchSetPattern(&N->Filter.Match, Pattern->str);
675   N->Filter.Match.Param= *MatchParam;
676   N->Filter.method= method;
677   N->section= section ? UdmStrdup(section) : NULL;
678 
679   if (UDM_OK != (rc= UdmMatchComp(&N->Filter.Match, err, errsize)))
680     return rc;
681 
682   L->nitems++;
683   return UDM_OK;
684 }
685 
686 
687 const UDM_SECTIONFILTER *
UdmSectionFilterListFind(const UDM_SECTIONFILTERLIST * L,const char * str)688 UdmSectionFilterListFind(const UDM_SECTIONFILTERLIST *L, const char *str)
689 {
690   size_t i, slen= strlen(str);
691   for (i= 0; i < L->nitems; i++)
692   {
693     UDM_SECTIONFILTER *F= &L->Item[i];
694     if (!UdmMatchExec(&F->Filter.Match, str, slen, str, 0, NULL))
695       return F;
696   }
697   return NULL;
698 }
699 
700 
UdmExcerptFragmentInit(UDM_EXCERPT_FRAGMENT * dst)701 void UdmExcerptFragmentInit(UDM_EXCERPT_FRAGMENT *dst)
702 {
703   UdmMatchInit(&dst->Match);
704   dst->quality= 0;
705 }
706 
707 
UdmExcerptFragmentFree(UDM_EXCERPT_FRAGMENT * dst)708 void UdmExcerptFragmentFree(UDM_EXCERPT_FRAGMENT *dst)
709 {
710   UdmMatchFree(&dst->Match);
711 }
712 
713