source: tags/arb_5.1/ARBDB/admatch.c

Last change on this file was 6100, checked in by westram, 15 years ago
  • fix warning "format not a string literal and no format arguments"
    • GB_export_error → GB_export_error/GB_export_errorf
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.2 KB
Line 
1/* ============================================================= */
2/*                                                               */
3/*   File      : admatch.c                                       */
4/*   Purpose   : functions related to string match/replace       */
5/*                                                               */
6/*   ReCoded for POSIX ERE by Ralf Westram (coder@reallysoft.de) */
7/*                         in April 2009                         */
8/*   Institute of Microbiology (Technical University Munich)     */
9/*   http://www.arb-home.de/                                     */
10/*                                                               */
11/* ============================================================= */
12
13#include "adlocal.h"
14 
15#include <stdlib.h>
16#include <string.h>
17#include <ctype.h>
18#include <regex.h>
19
20 /* ------------------------ */
21 /*      string matcher      */
22
23struct GBS_string_matcher {
24    enum {
25        SM_ANY,                 // matches any string
26        SM_WILDCARDED,          // match with wildcards (GBS_string_matches)
27        SM_REGEXPR,             // match using regexpr
28    } type;
29
30    GB_CASE    case_flag;
31    char      *wildexpr;
32    GBS_REGEX *regexpr;
33};
34
35GBS_MATCHER *GBS_compile_matcher(const char *search_expr, GB_CASE case_flag) {
36    /* returns a valid string matcher (to be used with GBS_string_matches_regexp)
37     * or NULL (in which case an error was exported)
38     */
39
40    GBS_MATCHER *matcher = malloc(sizeof(*matcher));
41    GB_ERROR     error   = 0;
42
43    matcher->type      = -1;
44    matcher->case_flag = case_flag;
45    matcher->wildexpr  = NULL;
46    matcher->regexpr   = NULL;
47
48    if (search_expr[0] == '/') {
49        const char *end = strchr(search_expr, 0)-1;
50        if (end>search_expr && end[0] == '/') {
51            GB_CASE     expr_attached_case;
52            const char *unwrapped_expr = GBS_unwrap_regexpr(search_expr, &expr_attached_case, &error);
53
54            if (unwrapped_expr) {
55                if (expr_attached_case != GB_MIND_CASE) error = "format '/../i' not allowed here";
56                else {
57                    matcher->regexpr = GBS_compile_regexpr(unwrapped_expr, case_flag, &error);
58                    if (matcher->regexpr) {
59                        matcher->type = SM_REGEXPR;;
60                    }
61                }
62            }
63        }
64    }
65
66    if (matcher->regexpr == NULL && !error) {
67        if (strcmp(search_expr, "*") == 0) {
68            matcher->type = SM_ANY;
69        }
70        else {
71            matcher->type     = SM_WILDCARDED;
72            matcher->wildexpr = strdup(search_expr);
73        }
74    }
75
76    if (error) {
77        GBS_free_matcher(matcher);
78        matcher = 0;
79        GB_export_error(error);
80    }
81    return matcher;
82}
83
84void GBS_free_matcher(GBS_MATCHER *matcher) {
85    free(matcher->wildexpr);
86    if (matcher->regexpr) GBS_free_regexpr(matcher->regexpr);
87    free(matcher);
88}
89
90/* --------------------------------------------- */
91/*      Regular Expressions search/replace       */
92
93struct GBS_regex { regex_t compiled; }; // definition exists twice (see ../SL/REGEXPR/RegExpr.cxx)
94
95GBS_REGEX *GBS_compile_regexpr(const char *regexpr, GB_CASE case_flag, GB_ERROR *error) {
96    GBS_REGEX *comreg  = malloc(sizeof(*comreg));
97    int        cflags  = REG_EXTENDED|(case_flag == GB_IGNORE_CASE ? REG_ICASE : 0)|REG_NEWLINE;
98    int        errcode = regcomp(&comreg->compiled, regexpr, cflags);
99
100    if (errcode != 0) {          // error compiling regexpr
101        size_t    size = regerror(errcode, &comreg->compiled, NULL, 0);
102        GB_BUFFER buf  = GB_give_buffer(size);
103
104        regerror(errcode, &comreg->compiled, buf, size);
105        *error = buf;
106       
107        free(comreg);
108        comreg = NULL;
109    }
110    else {
111        *error = NULL;
112    }
113
114    return comreg;
115}
116
117void GBS_free_regexpr(GBS_REGEX *toFree) {
118    if (toFree) {
119        regfree(&toFree->compiled);
120        free(toFree);
121    }
122}
123
124const char *GBS_unwrap_regexpr(const char *regexpr_in_slashes, GB_CASE *case_flag, GB_ERROR *error) {
125    /* unwraps 'expr' from '/expr/[i]'
126     * if slashes are not present, 'error' is set
127     * 'case_flag' is set to GB_MIND_CASE   if format is '/expr/' or
128     *                    to GB_IGNORE_CASE if format is '/expr/i'
129     *
130     * returns a pointer to a static buffer (containing the unwrapped expression)
131     * (Note: The content is invalidated by the next call to GBS_unwrap_regexpr)
132     */
133
134    const char *result = NULL;
135    const char *end    = strchr(regexpr_in_slashes, 0);
136
137    if (end >= (regexpr_in_slashes+3)) {
138        *case_flag = GB_MIND_CASE;
139        if (end[-1] == 'i') {
140            *case_flag = GB_IGNORE_CASE;
141            end--;
142        }
143        if (regexpr_in_slashes[0] == '/' && end[-1] == '/') {
144            ad_assert(*error == NULL);
145
146            static char   *result_buffer = 0;
147            static size_t  max_len    = 0;
148
149            size_t len = end-regexpr_in_slashes-2;
150            ad_assert(len>0); // don't accept empty expression
151
152            if (len>max_len) {
153                max_len = len*3/2;
154                freeset(result_buffer, malloc(max_len+1));
155            }
156
157            memcpy(result_buffer, regexpr_in_slashes+1, len);
158            result_buffer[len] = 0;
159
160            result = result_buffer;
161        }
162    }
163
164    if (!result) {
165        *error = GBS_global_string("Regular expression format is '/expr/' or '/expr/i', not '%s'",
166                                   regexpr_in_slashes);
167    }
168    return result;
169}
170
171const char *GBS_regmatch_compiled(const char *str, GBS_REGEX *comreg, size_t *matchlen) {
172    /* like GBS_regmatch,
173     * - but uses a precompiled regular expression
174     * - no errors can occur here (beside out of memory, which is not handled)
175     */
176
177    regmatch_t  match;
178    int         res      = regexec(&comreg->compiled, str, 1, &match, 0);
179    const char *matchpos = NULL;
180
181    if (res == 0) { // matched
182        matchpos = str+match.rm_so;
183        if (matchlen) *matchlen = match.rm_eo-match.rm_so;
184    }
185
186    return matchpos;
187}
188
189const char *GBS_regmatch(const char *str, const char *regExpr, size_t *matchlen, GB_ERROR *error) {
190    /* searches 'str' for first occurrence of 'regExpr'
191     * 'regExpr' has to be in format "/expr/[i]", where 'expr' is a POSIX extended regular expression
192     *
193     * returns
194     * - pointer to start of first match in 'str' and
195     *   length of match in 'matchlen' ('matchlen' may be NULL, then no len is reported)
196     *                                            or
197     * - NULL if nothing matched (in this case 'matchlen' is undefined)
198     *
199     * 'error' will be set if sth is wrong
200     *
201     * Note: Only use this function if you do exactly ONE match.
202     *       Use GBS_regmatch_compiled if you use the regexpr twice or more!
203     */
204    const char *firstMatch     = NULL;
205    GB_CASE     case_flag;
206    const char *unwrapped_expr = GBS_unwrap_regexpr(regExpr, &case_flag, error);
207
208    if (unwrapped_expr) {
209        GBS_REGEX *comreg = GBS_compile_regexpr(unwrapped_expr, case_flag, error);
210        if (comreg) {
211            firstMatch = GBS_regmatch_compiled(str, comreg, matchlen);
212            GBS_free_regexpr(comreg);
213        }
214    }
215
216    return firstMatch;
217}
218
219char *GBS_regreplace(const char *str, const char *regReplExpr, GB_ERROR *error) {
220    /* search and replace all matches in 'str' using POSIX extended regular expression
221     * 'regReplExpr' has to be in format '/regexpr/replace/[i]'
222     *
223     * returns
224     * - a heap copy of the modified string or
225     * - NULL if something went wrong (in this case 'error' contains the reason)
226     *
227     * 'replace' may contain several special substrings:
228     *
229     *     "\n" gets replaced by '\n'
230     *     "\t" -------''------- '\t'
231     *     "\\" -------''------- '\\'
232     *     "\0" -------''------- the complete match to regexpr
233     *     "\1" -------''------- the match to the first subexpression
234     *     "\2" -------''------- the match to the second subexpression
235     *     ...
236     *     "\9" -------''------- the match to the ninth subexpression
237     */
238
239    GB_CASE     case_flag;
240    const char *unwrapped_expr = GBS_unwrap_regexpr(regReplExpr, &case_flag, error);
241    char       *result         = NULL;
242
243    if (unwrapped_expr) {
244        const char *sep = unwrapped_expr;
245        while (sep) {
246            sep = strchr(sep, '/');
247            if (!sep) break;
248            if (sep>unwrapped_expr && sep[-1] != '\\') break;
249        }
250
251        if (!sep) {
252            // Warning: GB_command_interpreter() tests for this error message - don't change
253            *error = "Missing '/' between search and replace string";
254        }
255        else {
256            char      *regexpr  = GB_strpartdup(unwrapped_expr, sep-1);
257            char      *replexpr = GB_strpartdup(sep+1, NULL);
258            GBS_REGEX *comreg   = GBS_compile_regexpr(regexpr, case_flag, error);
259
260            if (comreg) {
261                struct GBS_strstruct *out    = GBS_stropen(1000);
262                int                   eflags = 0;
263
264                while (str) {
265                    regmatch_t match[10];
266                    int        res = regexec(&comreg->compiled, str, 10, match, eflags);
267
268                    if (res == REG_NOMATCH) {
269                        GBS_strcat(out, str);
270                        str = 0;
271                    }
272                    else {      // found match
273                        size_t p;
274                        char   c;
275                       
276                        GBS_strncat(out, str, match[0].rm_so);
277
278                        for (p = 0; (c = replexpr[p]); ++p) {
279                            if (c == '\\') {
280                                c = replexpr[++p];
281                                if (!c) break; 
282                                if (c >= '0' && c <= '9') {
283                                    regoff_t start = match[c-'0'].rm_so;
284                                    GBS_strncat(out, str+start, match[c-'0'].rm_eo-start);
285                                }
286                                else {
287                                    switch (c) {
288                                        case 'n': c = '\n'; break;
289                                        case 't': c = '\t'; break;
290                                        default: break;
291                                    }
292                                    GBS_chrcat(out, c);
293                                }
294                            }
295                            else {
296                                GBS_chrcat(out, c);
297                            }
298                        }
299
300                        str    = str+match[0].rm_eo; // continue behind match
301                        eflags = REG_NOTBOL; // for futher matches, do not regard 'str' as "beginning of line"
302                    }
303                }
304
305                GBS_free_regexpr(comreg);
306                result = GBS_strclose(out);
307            }
308            free(replexpr);
309            free(regexpr);
310        }
311    }
312
313    return result;
314}
315
316/* ------------------------- */
317/*      wildcard search      */
318
319GB_CSTR GBS_find_string(GB_CSTR str, GB_CSTR substr, int match_mode) {
320    /* search a substring in another string
321       match_mode == 0     -> exact match
322       match_mode == 1     -> a==A
323       match_mode == 2     -> a==a && a==?
324       match_mode == else  -> a==A && a==?
325    */
326    const char *p1, *p2;
327    char        b;
328   
329    switch (match_mode) {
330
331        case 0: /* exact match */
332            for (p1 = str, p2 = substr; *p1;) {
333                if (!(b = *p2)) {
334                    return (char *)str;
335                } else {
336                    if (b == *p1) {
337                        p1++;
338                        p2++;
339                    } else {
340                        p2 = substr;
341                        p1 = (++str);
342                    }
343                }
344            }
345            if (!*p2)   return (char *)str;
346            break;
347
348        case 1: /* a==A */
349            for (p1 = str, p2 = substr; *p1;) {
350                if (!(b = *p2)) {
351                    return (char *)str;
352                } else {
353                    if (toupper(*p1) == toupper(b)) {
354                        p1++;
355                        p2++;
356                    } else {
357                        p2 = substr;
358                        p1 = (++str);
359                    }
360                }
361            }
362            if (!*p2) return (char *)str;
363            break;
364        case 2: /* a==a && a==? */
365            for (p1 = str, p2 = substr; *p1;) {
366                if (!(b = *p2)) {
367                    return (char *)str;
368                } else {
369                    if (b == *p1 || (b=='?')) {
370                        p1++;
371                        p2++;
372                    } else {
373                        p2 = substr;
374                        p1 = (++str);
375                    }
376                }
377            }
378            if (!*p2) return (char *)str;
379            break;
380
381        default: /* a==A && a==? */
382            for (p1 = str, p2 = substr; *p1;) {
383                if (!(b = *p2)) {
384                    return (char *)str;
385                } else {
386                    if (toupper(*p1) == toupper(b) || (b=='?') ) {
387                        p1++;
388                        p2++;
389                    } else {
390                        p2 = substr;
391                        p1 = (++str);
392                    }
393                }
394            }
395            if (!*p2) return (char *)str;
396            break;
397    }
398    return 0;
399}
400
401GB_BOOL GBS_string_matches(const char *str, const char *search, GB_CASE case_sens)
402/* Wildcards in 'search' string:
403 *      ?   one character
404 *      *   serveral characters
405 *
406 * if 'case_sens' == GB_IGNORE_CASE -> change all letters to uppercase
407 *
408 * returns GB_TRUE if strings are equal, GB_FALSE otherwise
409 */
410{
411    const char *p1,*p2;
412    char        a,b,*d;
413    long        i;
414    char        fsbuf[256];
415
416    p1 = str;
417    p2 = search;
418    while (1) {
419        a = *p1;
420        b = *p2;
421        if (b == '*')   {
422            if (!p2[1]) break; /* '*' also matches nothing */
423            i = 0;
424            d = fsbuf;
425            for (p2++; (b=*p2)&&(b!='*'); ) {
426                *(d++) = b;
427                p2++;
428                i++;
429                if (i > 250) break;
430            }
431            if (*p2 != '*' ) {
432                p1 += strlen(p1)-i;     /* check the end of the string */
433                if (p1 < str) return GB_FALSE;
434                p2 -= i;
435            }
436            else {
437                *= 0;
438                p1  = GBS_find_string(p1,fsbuf,2+(case_sens == GB_IGNORE_CASE)); // match with '?' wildcard
439                if (!p1) return GB_FALSE;
440                p1 += i;
441            }
442            continue;
443        }
444
445        if (!a) return b ? GB_FALSE : GB_TRUE;
446        if (a != b) {
447            if (b != '?') {
448                if (!b) return a ? GB_FALSE : GB_TRUE;
449                if (case_sens == GB_IGNORE_CASE) {
450                    a = toupper(a);
451                    b = toupper(b);
452                    if (a != b) return GB_FALSE;
453                }
454                else {
455                    return GB_FALSE;
456                }
457            }
458        }
459        p1++;
460        p2++;
461    }
462    return GB_TRUE;
463}
464
465GB_BOOL GBS_string_matches_regexp(const char *str, const GBS_MATCHER *expr) {
466    /* Wildcard or regular expression match
467     * Returns GB_TRUE if match
468     *
469     * Use GBS_compile_matcher() and GBS_free_matcher() to maintain 'expr'
470     */
471    GB_BOOL matches = GB_FALSE;
472
473    switch (expr->type) {
474        case SM_ANY: {
475            matches = GB_TRUE;
476            break;
477        }
478        case SM_WILDCARDED: {
479            matches = GBS_string_matches(str, expr->wildexpr, expr->case_flag);
480            break;
481        }
482        case SM_REGEXPR: {
483            matches = GBS_regmatch_compiled(str, expr->regexpr, NULL) != NULL;
484            break;
485        }
486        default: {
487            ad_assert(0);
488            break;
489        }
490    }
491
492    return matches;
493}
494
495/* ----------------------------------- */
496/*      Search replace tool (SRT)      */
497
498#define GBS_SET   ((char)1)
499#define GBS_SEP   ((char)2)
500#define GBS_MWILD ((char)3)
501#define GBS_WILD  ((char)4)
502
503int GBS_reference_not_found;
504
505ATTRIBUTED(__ATTR__USERESULT,
506           static GB_ERROR gbs_build_replace_string(void *strstruct,
507                                                    char *bar,char *wildcards, long max_wildcard,
508                                                    char **mwildcards, long max_mwildcard, GBDATA *gb_container))
509{
510    char *p,c,d;
511    int   wildcardcnt  = 0;
512    int   mwildcardcnt = 0;
513    int   wildcard_num;
514    char *entry;
515
516    p = bar;
517
518    wildcardcnt  = 0;
519    mwildcardcnt = 0;
520
521    p = bar;
522    while ( (c=*(p++)) ) {
523        switch (c){
524            case GBS_MWILD: case GBS_WILD:
525                d = *(p++);
526                if (gb_container && (d=='(')) { /* if a gbcont then replace till ')' */
527                    GBDATA *gb_entry;
528                    char    *klz;
529                    char    *psym;
530                    klz = gbs_search_second_bracket(p);
531                    if (klz) {          /* reference found: $(gbd) */
532                        int seperator = 0;
533                        *klz = 0;
534                        psym = strpbrk(p,"#|:");
535                        if (psym) {
536                            seperator = *psym;
537                            *psym =0;
538                        }
539                        if (*p){
540                            gb_entry = GB_search(gb_container,p,GB_FIND);
541                        }else{
542                            gb_entry = gb_container;
543                        }
544                        if (psym) *psym = seperator;
545
546                        if (!gb_entry || gb_entry == gb_container) {
547                            GBS_reference_not_found = 1;
548                            entry = strdup("");
549                        }else{
550                            entry = GB_read_as_string(gb_entry);
551                        }
552                        if (entry) {
553                            char *h;
554                            switch(seperator) {
555                                case ':':
556                                    h = GBS_string_eval(entry,psym+1,gb_container);
557                                    if (!h) return GB_await_error();
558
559                                    GBS_strcat(strstruct,h);
560                                    free(h);
561                                    break;
562                                   
563                                case '|':
564                                    h = GB_command_interpreter(GB_get_root(gb_container), entry,psym+1,gb_container, 0);
565                                    if (!h) return GB_await_error();
566
567                                    GBS_strcat(strstruct,h);
568                                    free(h);
569                                    break;
570                                   
571                                case '#':
572                                    if (!gb_entry){
573                                        GBS_strcat(strstruct,psym+1);
574                                        break;
575                                    }
576                                    // fall-through
577                                default:
578                                    GBS_strcat(strstruct,entry);
579                                    break;
580                            }
581                            free(entry);
582                        }
583                        *klz = ')';
584                        p = klz+1;
585                        break;
586                    }
587                    c = '*';
588                    GBS_chrcat(strstruct,c);
589                    GBS_chrcat(strstruct,d);
590                }
591                else {
592                    wildcard_num = d - '1';
593                    if (c == GBS_WILD) {
594                        c = '?';
595                        if ( (wildcard_num<0)||(wildcard_num>9) ) {
596                            p--;            /* use this character */
597                            wildcard_num = wildcardcnt++;
598                        }
599                        if (wildcard_num>=max_wildcard) {
600                            GBS_chrcat(strstruct,c);
601                        }
602                        else {
603                            GBS_chrcat(strstruct,wildcards[wildcard_num]);
604                        }
605                    }
606                    else {
607                        c = '*';
608                        if ( (wildcard_num<0)||(wildcard_num>9) ) {
609                            p--;            /* use this character */
610                            wildcard_num = mwildcardcnt++;
611                        }
612                        if (wildcard_num>=max_mwildcard) {
613                            GBS_chrcat(strstruct,c);
614                        }else{
615                            GBS_strcat(strstruct,mwildcards[wildcard_num]);
616                        }
617                    }
618                }
619                break;
620            default:
621                GBS_chrcat(strstruct,c);
622                break;
623        }       /* switch c */
624    }
625    return 0;
626}
627
628static char *gbs_compress_command(const char *com) {
629    /* Prepare SRT.
630     *
631     * Replaces all
632     *   '=' by GBS_SET
633     *   ':' by GBS_SEP
634     *   '?' by GBS_WILD if followed by a number or '?'
635     *   '*' by GBS_MWILD  or '('
636     * \ is the escape charakter
637     */
638    char *result,*s,*d;
639    int   ch;
640
641    s = d = result = strdup(com);
642    while ( (ch = *(s++)) ){
643        switch (ch) {
644            case '=':   *(d++) = GBS_SET;break;
645            case ':':   *(d++) = GBS_SEP;break;
646            case '?':
647                ch = *s;
648                /*if ( (ch>='0' && ch <='9') || ch=='?'){   *(d++) = GBS_WILD;break;}*/
649                *(d++) = GBS_WILD; break;
650            case '*':
651                ch = *s;
652                /* if ( (ch>='0' && ch <='9') || ch=='('){  *(d++) = GBS_MWILD;break;}*/
653                *(d++) = GBS_MWILD; break;
654            case '\\':
655                ch = *(s++); if (!ch) { s--; break; };
656                switch (ch) {
657                    case 'n':   *(d++) = '\n';break;
658                    case 't':   *(d++) = '\t';break;
659                    case '0':   *(d++) = '\0';break;
660                    default:    *(d++) = ch;break;
661                }
662                break;
663            default:
664                *(d++) = ch;
665        }
666    }
667    *d = 0;
668    return result;
669}
670
671
672char *GBS_string_eval(const char *insource, const char *icommand, GBDATA *gb_container)
673     /* GBS_string_eval replaces substrings in source
674      * Syntax: command = "oliver=olli:peter=peti"
675      *
676      * Returns a heapcopy of result of replacement.
677      *
678      *         * is a wildcard for any number of character
679      *         ? is a wildcard for exactly one character
680      *
681      * To reference to the wildcards on the left side of the '='
682      * use ? and *, to reference in a different order use:
683      *         *0 to reference to the first occurrence of *
684      *         *1          second
685      *         ...
686      *         *9
687      *
688      * if the last and first characters of the search string are no '*' wildcards then
689      * the replace is repeated as many times as possible
690      * '\' is the escape character: e.g. \n is newline; '\\' is '\'; '\=' is '='; ....
691      *
692      * eg:
693      * print first three characters of first word and the whole second word:
694      *
695      *         *(arb_key)          is the value of the a database entry arb key
696      *         *(arb_key#string)   value of the database entry or 'string' if the entry does not exist
697      *         *(arb_key\:SRT)     runs SRT recursively on the value of the database entry
698      *         *([arb_key]|ACI)    runs the ACI command interpreter on the value of the database entry (or on an empty string)
699      *
700      * If an error occurs it returns NULL - in this case the error was exported.
701      */
702{
703    GB_CSTR  source;            /* pointer into the current string when parsed */
704    char    *search;            /* pointer into the current command when parsed */
705    GB_CSTR  p;                 /* short live pointer */
706    char     c;
707    GB_CSTR  already_transferred; /* point into 'in' string to non parsed position */
708
709    char      wildcard[40];
710    char     *mwildcard[10];
711    GB_ERROR  error;
712
713    long i;
714    long max_wildcard;
715    long max_mwildcard;
716
717    char *start_of_wildcard;
718    char  what_wild_card;
719
720    GB_CSTR start_match;
721
722    char *doppelpunkt;
723
724    char *bar;
725    char *in;
726    char *nextdp;
727    void *strstruct;
728    char *command;
729
730    if (!icommand || !icommand[0]) return strdup(insource);
731
732    command = gbs_compress_command(icommand);
733    in = strdup(insource);               /* copy insource to allow to destroy it */
734
735    for (doppelpunkt = command; doppelpunkt; doppelpunkt = nextdp) {    /* loop over command string */
736        /* in is in , strstruct is out */
737        max_wildcard = 0;
738        max_mwildcard = 0;
739        nextdp = strchr(doppelpunkt, GBS_SEP);
740        if (nextdp){
741            *(nextdp++) = 0;
742        }
743        if (!doppelpunkt[0]) {                      /* empty command -> search next */
744            continue;
745        }
746
747        bar = strchr(doppelpunkt+1, GBS_SET);               /* Parse the command string !!!! */
748        if (bar) {
749            *(bar++) = 0;
750        } else {
751            GB_export_errorf("SRT ERROR: no '=' found in command '%s' (position > %zi)", icommand, doppelpunkt-command+1);
752            free(command);
753            free(in);
754            return 0;
755        }
756
757        already_transferred = in;
758        strstruct = GBS_stropen(1000);          /* create output stream */
759
760        if ( (!*in) && doppelpunkt[0] == GBS_MWILD && doppelpunkt[1] == 0) {    /* empty string -> pars myself */
761            /* * matches empty string !!!!  */
762            mwildcard[max_mwildcard++] = strdup("");
763            gbs_build_replace_string(strstruct,bar,wildcard, max_wildcard, mwildcard, max_mwildcard,gb_container);
764            goto gbs_pars_unsuccessfull;    /* successfull search*/
765        }
766
767        for (source = in;*source; ) {               /* loop over string */
768            search = doppelpunkt;
769
770            start_match = 0;                /* match string for '*' */
771            while ( (c = *(search++))  ) {          /* search matching command */
772                switch (c) {
773                    case GBS_MWILD:
774                        if (!start_match) start_match = source;
775
776                        start_of_wildcard = search;
777                        if ( !(c = *(search++) ) ) {    /* last character is a wildcard -> that was it */
778                            mwildcard[max_mwildcard++] = strdup(source);
779                            source += strlen(source);
780                            goto gbs_pars_successfull;      /* successfull search and end wildcard*/
781                        }
782                        while ( (c=*(search++)) && c!=GBS_MWILD && c!=GBS_WILD );   /* search the next wildcardstring */
783                        search--;                   /* back one character */
784                        *search = 0;
785                        what_wild_card = c;
786                        p = GBS_find_string(source,start_of_wildcard,0);
787                        if (!p){                    /* string not found -> unsuccessful search */
788                            goto gbs_pars_unsuccessfull;
789                        }
790                        c = *p;                     /* set wildcard */
791                        mwildcard[max_mwildcard++] = GB_strpartdup(source, p-1);
792                        source = p + strlen(start_of_wildcard);         /* we parsed it */
793                        *search = what_wild_card;
794                        break;
795
796                    case GBS_WILD:
797                        if ( !source[0] ) {
798                            goto gbs_pars_unsuccessfull;
799                        }
800                        if (!start_match) start_match = source;
801                        wildcard[max_wildcard++] = *(source++);
802                        break;
803                    default:
804                        if (start_match) {
805                            if (c != *(source++)) {
806                                goto gbs_pars_unsuccessfull;
807                            }
808                            break;
809                        }else{
810                            char *buf1;
811                            buf1 = search-1;
812                            while ( (c=*(search++)) && c!=GBS_MWILD && c!=GBS_WILD );   /* search the next wildcardstring */
813                            search--;                   /* back one character */
814                            *search = 0;
815                            what_wild_card = c;
816                            p = GBS_find_string(source,buf1,0);
817                            if (!p){                    /* string not found -> unsuccessful search */
818                                goto gbs_pars_unsuccessfull;
819                            }
820                            start_match = p;
821                            source = p + strlen(buf1);          /* we parsed it */
822                            *search = what_wild_card;
823                        }
824                        break;
825                } /* switch */
826            } /* while */           /* search matching command */
827
828        gbs_pars_successfull:   /* now we got   source: pointer to end of match
829                                   start_match: pointer to start of match
830                                   in:  pointer to the entire string
831                                   already_transferred: pointer to the start of the unparsed string
832                                   bar: the replace string
833                                */
834            /* now look for the replace string */
835            GBS_strncat(strstruct,already_transferred,start_match-already_transferred); /* cat old data */
836            error = gbs_build_replace_string(strstruct,bar,wildcard, max_wildcard,      /* do the command */
837                                             mwildcard, max_mwildcard,gb_container);
838            already_transferred = source;
839
840            for (i = 0; i < max_mwildcard; i++) {
841                freeset(mwildcard[i], 0);
842            }
843            max_wildcard  = 0;
844            max_mwildcard = 0;
845
846            if (error) {
847                free(GBS_strclose(strstruct));
848                free(command);
849                free(in);
850                GB_export_error(error);
851                return 0;
852            }
853        }       /* while parsing */
854    gbs_pars_unsuccessfull:
855        GBS_strcat(strstruct,already_transferred);  /* cat the rest data */
856
857        for (i = 0; i < max_mwildcard; i++){
858            freeset(mwildcard[i], 0);
859        }
860        max_wildcard  = 0;
861        max_mwildcard = 0;
862
863        freeset(in, GBS_strclose(strstruct));
864    }
865    free(command);
866    return in;
867}
868
Note: See TracBrowser for help on using the repository browser.