root/trunk/ARBDB/admatch.cxx

Revision 8736, 30.4 KB (checked in by westram, 11 days ago)
  • add pointers to regexpr format
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
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     * for regexpression format see http://dev.mikro.biologie.tu-muenchen.de/help_nightly/reg.html#Syntax_of_POSIX_extended_regular_expressions_as_used_in_ARB
200     *
201     * returns
202     * - pointer to start of first match in 'str' and
203     *   length of match in 'matchlen' ('matchlen' may be NULL, then no len is reported)
204     *                                            or
205     * - NULL if nothing matched (in this case 'matchlen' is undefined)
206     *
207     * 'error' will be set if sth is wrong
208     *
209     * Note: Only use this function if you do exactly ONE match.
210     *       Use GBS_regmatch_compiled if you use the regexpr twice or more!
211     */
212    const char *firstMatch     = NULL;
213    GB_CASE     case_flag;
214    const char *unwrapped_expr = GBS_unwrap_regexpr(regExpr, &case_flag, error);
215
216    if (unwrapped_expr) {
217        GBS_regex *comreg = GBS_compile_regexpr(unwrapped_expr, case_flag, error);
218        if (comreg) {
219            firstMatch = GBS_regmatch_compiled(str, comreg, matchlen);
220            GBS_free_regexpr(comreg);
221        }
222    }
223
224    return firstMatch;
225}
226
227char *GBS_regreplace(const char *str, const char *regReplExpr, GB_ERROR *error) {
228    /* search and replace all matches in 'str' using POSIX extended regular expression
229     * 'regReplExpr' has to be in format '/regexpr/replace/[i]'
230     *
231     * returns
232     * - a heap copy of the modified string or
233     * - NULL if something went wrong (in this case 'error' contains the reason)
234     *
235     * 'replace' may contain several special substrings:
236     *
237     *     "\n" gets replaced by '\n'
238     *     "\t" -------''------- '\t'
239     *     "\\" -------''------- '\\'
240     *     "\0" -------''------- the complete match to regexpr
241     *     "\1" -------''------- the match to the first subexpression
242     *     "\2" -------''------- the match to the second subexpression
243     *     ...
244     *     "\9" -------''------- the match to the ninth subexpression
245     */
246
247    GB_CASE     case_flag;
248    const char *unwrapped_expr = GBS_unwrap_regexpr(regReplExpr, &case_flag, error);
249    char       *result         = NULL;
250
251    if (unwrapped_expr) {
252        const char *sep = unwrapped_expr;
253        while (sep) {
254            sep = strchr(sep, '/');
255            if (!sep) break;
256            if (sep>unwrapped_expr && sep[-1] != '\\') break;
257        }
258
259        if (!sep) {
260            // Warning: GB_command_interpreter() tests for this error message - don't change
261            *error = "Missing '/' between search and replace string";
262        }
263        else {
264            char      *regexpr  = GB_strpartdup(unwrapped_expr, sep-1);
265            char      *replexpr = GB_strpartdup(sep+1, NULL);
266            GBS_regex *comreg   = GBS_compile_regexpr(regexpr, case_flag, error);
267
268            if (comreg) {
269                GBS_strstruct *out    = GBS_stropen(1000);
270                int            eflags = 0;
271
272                while (str) {
273                    regmatch_t match[10];
274                    int        res = regexec(&comreg->compiled, str, 10, match, eflags);
275
276                    if (res == REG_NOMATCH) {
277                        GBS_strcat(out, str);
278                        str = 0;
279                    }
280                    else {      // found match
281                        size_t p;
282                        char   c;
283
284                        GBS_strncat(out, str, match[0].rm_so);
285
286                        for (p = 0; (c = replexpr[p]); ++p) {
287                            if (c == '\\') {
288                                c = replexpr[++p];
289                                if (!c) break;
290                                if (c >= '0' && c <= '9') {
291                                    regoff_t start = match[c-'0'].rm_so;
292                                    GBS_strncat(out, str+start, match[c-'0'].rm_eo-start);
293                                }
294                                else {
295                                    switch (c) {
296                                        case 'n': c = '\n'; break;
297                                        case 't': c = '\t'; break;
298                                        default: break;
299                                    }
300                                    GBS_chrcat(out, c);
301                                }
302                            }
303                            else {
304                                GBS_chrcat(out, c);
305                            }
306                        }
307
308                        str    = str+match[0].rm_eo; // continue behind match
309                        eflags = REG_NOTBOL; // for futher matches, do not regard 'str' as "beginning of line"
310                    }
311                }
312
313                GBS_free_regexpr(comreg);
314                result = GBS_strclose(out);
315            }
316            free(replexpr);
317            free(regexpr);
318        }
319    }
320
321    return result;
322}
323
324// -------------------------
325//      wildcard search
326
327GB_CSTR GBS_find_string(GB_CSTR cont, GB_CSTR substr, int match_mode) {
328    /* search a substring in another string
329     * match_mode == 0     -> exact match
330     * match_mode == 1     -> a==A
331     * match_mode == 2     -> a==a && a==?
332     * match_mode == else  -> a==A && a==?
333     */
334    const char *p1, *p2;
335    char        b;
336
337    switch (match_mode) {
338
339        case 0: // exact match
340            for (p1 = cont, p2 = substr; *p1;) {
341                if (!(b = *p2)) {
342                    return (char *)cont;
343                }
344                else {
345                    if (b == *p1) {
346                        p1++;
347                        p2++;
348                    }
349                    else {
350                        p2 = substr;
351                        p1 = (++cont);
352                    }
353                }
354            }
355            if (!*p2)   return (char *)cont;
356            break;
357
358        case 1: // a==A
359            for (p1 = cont, p2 = substr; *p1;) {
360                if (!(b = *p2)) {
361                    return (char *)cont;
362                }
363                else {
364                    if (toupper(*p1) == toupper(b)) {
365                        p1++;
366                        p2++;
367                    }
368                    else {
369                        p2 = substr;
370                        p1 = (++cont);
371                    }
372                }
373            }
374            if (!*p2) return (char *)cont;
375            break;
376        case 2: // a==a && a==?
377            for (p1 = cont, p2 = substr; *p1;) {
378                if (!(b = *p2)) {
379                    return (char *)cont;
380                }
381                else {
382                    if (b == *p1 || (b=='?')) {
383                        p1++;
384                        p2++;
385                    }
386                    else {
387                        p2 = substr;
388                        p1 = (++cont);
389                    }
390                }
391            }
392            if (!*p2) return (char *)cont;
393            break;
394
395        default: // a==A && a==?
396            for (p1 = cont, p2 = substr; *p1;) {
397                if (!(b = *p2)) {
398                    return (char *)cont;
399                }
400                else {
401                    if (toupper(*p1) == toupper(b) || (b=='?')) {
402                        p1++;
403                        p2++;
404                    }
405                    else {
406                        p2 = substr;
407                        p1 = (++cont);
408                    }
409                }
410            }
411            if (!*p2) return (char *)cont;
412            break;
413    }
414    return 0;
415}
416
417bool GBS_string_matches(const char *str, const char *search, GB_CASE case_sens)
418/* Wildcards in 'search' string:
419 *      ?   one character
420 *      *   several characters
421 *
422 * if 'case_sens' == GB_IGNORE_CASE -> change all letters to uppercase
423 *
424 * returns true if strings are equal, false otherwise
425 */
426{
427    const char *p1, *p2;
428    char        a, b, *d;
429    long        i;
430    char        fsbuf[256];
431
432    p1 = str;
433    p2 = search;
434    while (1) {
435        a = *p1;
436        b = *p2;
437        if (b == '*') {
438            if (!p2[1]) break; // '*' also matches nothing
439            i = 0;
440            d = fsbuf;
441            for (p2++; (b=*p2)&&(b!='*');) {
442                *(d++) = b;
443                p2++;
444                i++;
445                if (i > 250) break;
446            }
447            if (*p2 != '*') {
448                p1 += strlen(p1)-i;     // check the end of the string
449                if (p1 < str) return false;
450                p2 -= i;
451            }
452            else {
453                *= 0;
454                p1  = GBS_find_string(p1, fsbuf, 2+(case_sens == GB_IGNORE_CASE)); // match with '?' wildcard
455                if (!p1) return false;
456                p1 += i;
457            }
458            continue;
459        }
460
461        if (!a) return !b;
462        if (a != b) {
463            if (b != '?') {
464                if (!b) return !a;
465                if (case_sens == GB_IGNORE_CASE) {
466                    a = toupper(a);
467                    b = toupper(b);
468                    if (a != b) return false;
469                }
470                else {
471                    return false;
472                }
473            }
474        }
475        p1++;
476        p2++;
477    }
478    return true;
479}
480
481bool GBS_string_matches_regexp(const char *str, const GBS_string_matcher *expr) {
482    /* Wildcard or regular expression match
483     * Returns true if match
484     *
485     * Use GBS_compile_matcher() and GBS_free_matcher() to maintain 'expr'
486     */
487    bool matches = false;
488
489    switch (expr->type) {
490        case SM_ANY: {
491            matches = true;
492            break;
493        }
494        case SM_WILDCARDED: {
495            matches = GBS_string_matches(str, expr->wildexpr, expr->case_flag);
496            break;
497        }
498        case SM_REGEXPR: {
499            matches = GBS_regmatch_compiled(str, expr->regexpr, NULL) != NULL;
500            break;
501        }
502        case SM_INVALID: {
503            gb_assert(0);
504            break;
505        }
506    }
507
508    return matches;
509}
510
511// -----------------------------------
512//      Search replace tool (SRT)
513
514#define GBS_SET   ((char)1)
515#define GBS_SEP   ((char)2)
516#define GBS_MWILD ((char)3)
517#define GBS_WILD  ((char)4)
518
519static int GBS_reference_not_found;
520
521STATIC_ATTRIBUTED(__ATTR__USERESULT_TODO,
522                  GB_ERROR gbs_build_replace_string(GBS_strstruct *strstruct,
523                                                    char *bar, char *wildcards, long max_wildcard,
524                                                    char **mwildcards, long max_mwildcard, GBDATA *gb_container))
525{
526    char *p, c, d;
527    int   wildcardcnt  = 0;
528    int   mwildcardcnt = 0;
529    int   wildcard_num;
530    char *entry;
531
532    p = bar;
533
534    wildcardcnt  = 0;
535    mwildcardcnt = 0;
536
537    p = bar;
538    while ((c=*(p++))) {
539        switch (c) {
540            case GBS_MWILD: case GBS_WILD:
541                d = *(p++);
542                if (gb_container && (d=='(')) { // if a gbcont then replace till ')'
543                    GBDATA *gb_entry;
544                    char    *klz;
545                    char    *psym;
546                    klz = gbs_search_second_bracket(p);
547                    if (klz) {          // reference found: $(gbd)
548                        int separator = 0;
549                        *klz = 0;
550                        psym = strpbrk(p, "#|:");
551                        if (psym) {
552                            separator = *psym;
553                            *psym = 0;
554                        }
555                        if (*p) {
556                            gb_entry = GB_search(gb_container, p, GB_FIND);
557                        }
558                        else {
559                            gb_entry = gb_container;
560                        }
561                        if (psym) *psym = separator;
562
563                        if (!gb_entry || gb_entry == gb_container) {
564                            GBS_reference_not_found = 1;
565                            entry = strdup("");
566                        }
567                        else {
568                            entry = GB_read_as_string(gb_entry);
569                        }
570                        if (entry) {
571                            char *h;
572                            switch (separator) {
573                                case ':':
574                                    h = GBS_string_eval(entry, psym+1, gb_container);
575                                    if (!h) return GB_await_error();
576
577                                    GBS_strcat(strstruct, h);
578                                    free(h);
579                                    break;
580
581                                case '|':
582                                    h = GB_command_interpreter(GB_get_root(gb_container), entry, psym+1, gb_container, 0);
583                                    if (!h) return GB_await_error();
584
585                                    GBS_strcat(strstruct, h);
586                                    free(h);
587                                    break;
588
589                                case '#':
590                                    if (!gb_entry) {
591                                        GBS_strcat(strstruct, psym+1);
592                                        break;
593                                    }
594                                    // fall-through
595                                default:
596                                    GBS_strcat(strstruct, entry);
597                                    break;
598                            }
599                            free(entry);
600                        }
601                        *klz = ')';
602                        p = klz+1;
603                        break;
604                    }
605                    c = '*';
606                    GBS_chrcat(strstruct, c);
607                    GBS_chrcat(strstruct, d);
608                }
609                else {
610                    wildcard_num = d - '1';
611                    if (c == GBS_WILD) {
612                        c = '?';
613                        if ((wildcard_num<0)||(wildcard_num>9)) {
614                            p--;            // use this character
615                            wildcard_num = wildcardcnt++;
616                        }
617                        if (wildcard_num>=max_wildcard) {
618                            GBS_chrcat(strstruct, c);
619                        }
620                        else {
621                            GBS_chrcat(strstruct, wildcards[wildcard_num]);
622                        }
623                    }
624                    else {
625                        c = '*';
626                        if ((wildcard_num<0)||(wildcard_num>9)) {
627                            p--;            // use this character
628                            wildcard_num = mwildcardcnt++;
629                        }
630                        if (wildcard_num>=max_mwildcard) {
631                            GBS_chrcat(strstruct, c);
632                        }
633                        else {
634                            GBS_strcat(strstruct, mwildcards[wildcard_num]);
635                        }
636                    }
637                }
638                break;
639            default:
640                GBS_chrcat(strstruct, c);
641                break;
642        }
643    }
644    return 0;
645}
646
647static char *gbs_compress_command(const char *com) {
648    /* Prepare SRT.
649     *
650     * Replaces all
651     *   '=' by GBS_SET
652     *   ':' by GBS_SEP
653     *   '?' by GBS_WILD if followed by a number or '?'
654     *   '*' by GBS_MWILD  or '('
655     * \ is the escape character
656     */
657    char *result, *s, *d;
658    int   ch;
659
660    s = d = result = strdup(com);
661    while ((ch = *(s++))) {
662        switch (ch) {
663            case '=':   *(d++) = GBS_SET; break;
664            case ':':   *(d++) = GBS_SEP; break;
665            case '?':
666                ch = *s;
667                *(d++) = GBS_WILD;
668                break;
669            case '*':
670                ch = *s;
671                *(d++) = GBS_MWILD;
672                break;
673            case '\\':
674                ch = *(s++); if (!ch) { s--; break; };
675                switch (ch) {
676                    case 'n':   *(d++) = '\n'; break;
677                    case 't':   *(d++) = '\t'; break;
678                    case '0':   *(d++) = '\0'; break;
679                    default:    *(d++) = ch; break;
680                }
681                break;
682            default:
683                *(d++) = ch;
684        }
685    }
686    *d = 0;
687    return result;
688}
689
690
691char *GBS_string_eval(const char *insource, const char *icommand, GBDATA *gb_container)
692     /* GBS_string_eval replaces substrings in source
693      * Syntax: command = "oliver=olli:peter=peti"
694      *
695      * Returns a heapcopy of result of replacement.
696      *
697      *         * is a wildcard for any number of character
698      *         ? is a wildcard for exactly one character
699      *
700      * To reference to the wildcards on the left side of the '='
701      * use ? and *, to reference in a different order use:
702      *         *0 to reference to the first occurrence of *
703      *         *1          second
704      *         ...
705      *         *9
706      *
707      * if the last and first characters of the search string are no '*' wildcards then
708      * the replace is repeated as many times as possible
709      * '\' is the escape character: e.g. \n is newline; '\\' is '\'; '\=' is '='; ....
710      *
711      * eg:
712      * print first three characters of first word and the whole second word:
713      *
714      *         *(arb_key)          is the value of the a database entry arb key
715      *         *(arb_key#string)   value of the database entry or 'string' if the entry does not exist
716      *         *(arb_key\:SRT)     runs SRT recursively on the value of the database entry
717      *         *([arb_key]|ACI)    runs the ACI command interpreter on the value of the database entry (or on an empty string)
718      *
719      * If an error occurs it returns NULL - in this case the error was exported.
720      */
721{
722    GB_CSTR  source;            // pointer into the current string when parsed
723    char    *search;            // pointer into the current command when parsed
724    GB_CSTR  p;                 // short live pointer
725    char     c;
726    GB_CSTR  already_transferred; // point into 'in' string to non parsed position
727
728    char      wildcard[40];
729    char     *mwildcard[10];
730    GB_ERROR  error;
731
732    long i;
733    long max_wildcard;
734    long max_mwildcard;
735
736    char *start_of_wildcard;
737    char  what_wild_card;
738
739    GB_CSTR start_match;
740
741    char *doppelpunkt;
742
743    char *bar;
744    char *in;
745    char *nextdp;
746    GBS_strstruct *strstruct;
747    char *command;
748
749    if (!icommand || !icommand[0]) return strdup(insource);
750
751    command = gbs_compress_command(icommand);
752    in = strdup(insource);               // copy insource to allow to destroy it
753
754    for (doppelpunkt = command; doppelpunkt; doppelpunkt = nextdp) {    // loop over command string
755        // in is in , strstruct is out
756        max_wildcard = 0;
757        max_mwildcard = 0;
758        nextdp = strchr(doppelpunkt, GBS_SEP);
759        if (nextdp) {
760            *(nextdp++) = 0;
761        }
762        if (!doppelpunkt[0]) {                      // empty command -> search next
763            continue;
764        }
765
766        bar = strchr(doppelpunkt+1, GBS_SET);               // Parse the command string !!!!
767        if (bar) {
768            *(bar++) = 0;
769        }
770        else {
771            GB_export_errorf("SRT ERROR: no '=' found in command '%s' (position > %zi)", icommand, doppelpunkt-command+1);
772            free(command);
773            free(in);
774            return 0;
775        }
776
777        already_transferred = in;
778        strstruct = GBS_stropen(1000);          // create output stream
779
780        if ((!*in) && doppelpunkt[0] == GBS_MWILD && doppelpunkt[1] == 0) {     // empty string -> pars myself
781            // * matches empty string !!!!
782            mwildcard[max_mwildcard++] = strdup("");
783            gbs_build_replace_string(strstruct, bar, wildcard, max_wildcard, mwildcard, max_mwildcard, gb_container);
784            goto gbs_pars_unsuccessfull;    // successfull search
785        }
786
787        for (source = in; *source;) {               // loop over string
788            search = doppelpunkt;
789
790            start_match = 0;                // match string for '*'
791            while ((c = *(search++))) {             // search matching command
792                switch (c) {
793                    case GBS_MWILD:
794                        if (!start_match) start_match = source;
795
796                        start_of_wildcard = search;
797                        if (!(c = *(search++))) {       // last character is a wildcard -> that was it
798                            mwildcard[max_mwildcard++] = strdup(source);
799                            source += strlen(source);
800                            goto gbs_pars_successfull;      // successfull search and end wildcard
801                        }
802                        while ((c=*(search++)) && c!=GBS_MWILD && c!=GBS_WILD) ;     // search the next wildcardstring
803                        search--;                   // back one character
804                        *search = 0;
805                        what_wild_card = c;
806                        p = GBS_find_string(source, start_of_wildcard, 0);
807                        if (!p) {                   // string not found -> unsuccessful search
808                            goto gbs_pars_unsuccessfull;
809                        }
810                        c = *p;                     // set wildcard
811                        mwildcard[max_mwildcard++] = GB_strpartdup(source, p-1);
812                        source = p + strlen(start_of_wildcard);         // we parsed it
813                        *search = what_wild_card;
814                        break;
815
816                    case GBS_WILD:
817                        if (!source[0]) {
818                            goto gbs_pars_unsuccessfull;
819                        }
820                        if (!start_match) start_match = source;
821                        wildcard[max_wildcard++] = *(source++);
822                        break;
823                    default:
824                        if (start_match) {
825                            if (c != *(source++)) {
826                                goto gbs_pars_unsuccessfull;
827                            }
828                            break;
829                        }
830                        else {
831                            char *buf1;
832                            buf1 = search-1;
833                            while ((c=*(search++)) && c!=GBS_MWILD && c!=GBS_WILD) ;     // search the next wildcardstring
834                            search--;                   // back one character
835                            *search = 0;
836                            what_wild_card = c;
837                            p = GBS_find_string(source, buf1, 0);
838                            if (!p) {                   // string not found -> unsuccessful search
839                                goto gbs_pars_unsuccessfull;
840                            }
841                            start_match = p;
842                            source = p + strlen(buf1);          // we parsed it
843                            *search = what_wild_card;
844                        }
845                        break;
846                }
847            }
848
849        gbs_pars_successfull :
850            /* now we got
851             * source:                  pointer to end of match
852             * start_match:             pointer to start of match
853             * in:                      pointer to the entire string
854             * already_transferred:     pointer to the start of the unparsed string
855             * bar:                     the replace string
856             */
857
858            // now look for the replace string
859            GBS_strncat(strstruct, already_transferred, start_match-already_transferred); // cat old data
860            error               = gbs_build_replace_string(strstruct, bar, wildcard, max_wildcard, // do the command
861                                             mwildcard, max_mwildcard, gb_container);
862            already_transferred = source;
863
864            for (i = 0; i < max_mwildcard; i++) {
865                freenull(mwildcard[i]);
866            }
867            max_wildcard  = 0;
868            max_mwildcard = 0;
869
870            if (error) {
871                free(GBS_strclose(strstruct));
872                free(command);
873                free(in);
874                GB_export_error(error);
875                return 0;
876            }
877        }
878    gbs_pars_unsuccessfull :
879        GBS_strcat(strstruct, already_transferred); // cat the rest data
880
881        for (i = 0; i < max_mwildcard; i++) {
882            freenull(mwildcard[i]);
883        }
884        max_wildcard  = 0;
885        max_mwildcard = 0;
886
887        freeset(in, GBS_strclose(strstruct));
888    }
889    free(command);
890    return in;
891}
Note: See TracBrowser for help on using the browser.