source: tags/svn.1.5.4/ARBDB/admatch.cxx

Last change on this file was 8309, checked in by westram, 14 years ago
  • moved much code into static scope

(partly reverted by [8310])

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