~ubuntu-branches/ubuntu/lucid/w3m/lucid-proposed

« back to all changes in this revision

Viewing changes to regex.c

  • Committer: Bazaar Package Importer
  • Author(s): Fumitoshi UKAI
  • Date: 2004-04-29 03:28:41 UTC
  • Revision ID: james.westby@ubuntu.com-20040429032841-uo4mu7a813aqrua8
Tags: upstream-0.5.1
ImportĀ upstreamĀ versionĀ 0.5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: regex.c,v 1.22 2003/09/24 18:49:00 ukai Exp $ */
 
2
/* 
 
3
 * regex: Regular expression pattern match library
 
4
 * 
 
5
 * by A.ITO, December 1989
 
6
 * Revised by A.ITO, January 2002
 
7
 */
 
8
 
 
9
#ifdef REGEX_DEBUG
 
10
#include <sys/types.h>
 
11
#include <malloc.h>
 
12
#endif                          /* REGEX_DEBUG */
 
13
#include <stdio.h>
 
14
#include <stdlib.h>
 
15
#include <string.h>
 
16
#include <gc.h>
 
17
#include "config.h"
 
18
#ifdef USE_M17N
 
19
#include "wc.h"
 
20
#include "wtf.h"
 
21
#ifdef USE_UNICODE
 
22
#include "ucs.h"
 
23
#endif
 
24
#endif
 
25
#include "regex.h"
 
26
#include "config.h"
 
27
#include "myctype.h"
 
28
 
 
29
#ifndef NULL
 
30
#define NULL    0
 
31
#endif                          /* not NULL */
 
32
 
 
33
#define RE_ITER_LIMIT   65535
 
34
 
 
35
#define RE_MATCHMODE    0x07
 
36
#define RE_NORMAL       0x00
 
37
#define RE_ANY          0x01
 
38
#define RE_WHICH        0x02
 
39
#define RE_EXCEPT       0x03
 
40
#define RE_SUBREGEX     0x04
 
41
#define RE_BEGIN        0x05
 
42
#define RE_END          0x06
 
43
#define RE_ENDMARK      0x07
 
44
 
 
45
#define RE_OPT          0x08
 
46
#define RE_ANYTIME      0x10
 
47
#define RE_IGNCASE      0x40
 
48
 
 
49
#define RE_MODE(x)      ((x)->mode&RE_MATCHMODE)
 
50
#define RE_SET_MODE(x,v) ((x)->mode = (((x)->mode&~RE_MATCHMODE)|((v)&RE_MATCHMODE)))
 
51
 
 
52
#ifdef REGEX_DEBUG
 
53
void debugre(regexchar *);
 
54
char *lc2c(longchar *, int);
 
55
int verbose;
 
56
#endif                          /* REGEX_DEBUG */
 
57
 
 
58
#ifdef USE_M17N
 
59
#define get_mclen(c) wtf_len1((wc_uchar *)(c))
 
60
#else
 
61
#define get_mclen(c) 1
 
62
#endif
 
63
 
 
64
#ifndef TOLOWER
 
65
#include <ctype.h>
 
66
#define TOLOWER(x) tolower(x)
 
67
#define TOUPPER(x) toupper(x)
 
68
#endif
 
69
 
 
70
#define RE_TYPE_END     0
 
71
#define RE_TYPE_CHAR    1
 
72
#define RE_TYPE_WCHAR_T 2
 
73
#define RE_WHICH_RANGE  3
 
74
#define RE_TYPE_SYMBOL  4
 
75
 
 
76
static longchar
 
77
set_longchar(char *str)
 
78
{
 
79
    unsigned char *p = (unsigned char *)str;
 
80
    longchar r;
 
81
 
 
82
#ifdef USE_M17N
 
83
    if (*p & 0x80) {
 
84
        r.wch = wtf_parse1(&p);
 
85
        if (r.wch.ccs == WC_CCS_SPECIAL || r.wch.ccs == WC_CCS_SPECIAL_W) {
 
86
            r.type = RE_TYPE_SYMBOL;
 
87
            return r;
 
88
        }
 
89
#ifdef USE_UNICODE
 
90
        if (WC_CCS_IS_UNICODE(r.wch.ccs)) {
 
91
            if (WC_CCS_SET(r.wch.ccs) == WC_CCS_UCS_TAG)
 
92
                r.wch.code = wc_ucs_tag_to_ucs(r.wch.code);
 
93
            r.wch.ccs = WC_CCS_UCS4;
 
94
        }
 
95
        else
 
96
#endif
 
97
            r.wch.ccs = WC_CCS_SET(r.wch.ccs);
 
98
        r.type = RE_TYPE_WCHAR_T;
 
99
        return r;
 
100
    }
 
101
#endif
 
102
    r.ch = *p;
 
103
    r.type = RE_TYPE_CHAR;
 
104
    return r;
 
105
}
 
106
 
 
107
static Regex DefaultRegex;
 
108
#define CompiledRegex DefaultRegex.re
 
109
#define Cstorage DefaultRegex.storage
 
110
 
 
111
static int regmatch(regexchar *, char *, char *, int, char **);
 
112
static int regmatch1(regexchar *, longchar *);
 
113
static int matchWhich(longchar *, longchar *, int);
 
114
static int match_longchar(longchar *, longchar *, int);
 
115
static int match_range_longchar(longchar *, longchar *, longchar *, int);
 
116
 
 
117
/* 
 
118
 * regexCompile: compile regular expression
 
119
 */
 
120
char *
 
121
regexCompile(char *ex, int igncase)
 
122
{
 
123
    char *msg;
 
124
    newRegex(ex, igncase, &DefaultRegex, &msg);
 
125
    return msg;
 
126
}
 
127
 
 
128
static Regex *
 
129
newRegex0(char **ex, int igncase, Regex *regex, char **msg, int level)
 
130
{
 
131
    char *p;
 
132
    longchar *r;
 
133
    regexchar *re;
 
134
    int m;
 
135
    longchar *st_ptr;
 
136
 
 
137
    if (regex == NULL)
 
138
        regex = (Regex *)GC_malloc(sizeof(Regex));
 
139
    regex->alt_regex = NULL;
 
140
    re = regex->re;
 
141
    st_ptr = regex->storage;
 
142
    for (p = *ex; *p != '\0'; p++) {
 
143
        re->mode = 0;
 
144
        switch (*p) {
 
145
        case '.':
 
146
            re->p.pattern = NULL;
 
147
            RE_SET_MODE(re, RE_ANY);
 
148
            re++;
 
149
            break;
 
150
        case '$':
 
151
            re->p.pattern = NULL;
 
152
            RE_SET_MODE(re, RE_END);
 
153
            re++;
 
154
            break;
 
155
        case '^':
 
156
            re->p.pattern = NULL;
 
157
            RE_SET_MODE(re, RE_BEGIN);
 
158
            re++;
 
159
            break;
 
160
        case '+':
 
161
            if (re == regex->re ||
 
162
                (RE_MODE(re - 1) != RE_ANY && (re - 1)->p.pattern == NULL)) {
 
163
                if (msg)
 
164
                    *msg = "Invalid regular expression";
 
165
                return NULL;
 
166
            }
 
167
            *re = *(re - 1);
 
168
            re->mode |= RE_ANYTIME;
 
169
            re++;
 
170
            break;
 
171
        case '*':
 
172
            if (re == regex->re ||
 
173
                (RE_MODE(re - 1) != RE_ANY && (re - 1)->p.pattern == NULL)) {
 
174
                if (msg)
 
175
                    *msg = "Invalid regular expression";
 
176
                return NULL;
 
177
            }
 
178
            (re - 1)->mode |= RE_ANYTIME;
 
179
            break;
 
180
        case '?':
 
181
            if (re == regex->re ||
 
182
                (RE_MODE(re - 1) != RE_ANY && (re - 1)->p.pattern == NULL)) {
 
183
                if (msg)
 
184
                    *msg = "Invalid regular expression";
 
185
                return NULL;
 
186
            }
 
187
            (re - 1)->mode |= RE_OPT;
 
188
            break;
 
189
        case '[':
 
190
            r = st_ptr;
 
191
            if (*++p == '^') {
 
192
                p++;
 
193
                m = RE_EXCEPT;
 
194
            }
 
195
            else
 
196
                m = RE_WHICH;
 
197
            if (*p == '-' || *p == ']')
 
198
                *(st_ptr++) = set_longchar(p);
 
199
            while (*p != ']') {
 
200
                if (*p == '\\') {
 
201
                    p++;
 
202
                    *(st_ptr++) = set_longchar(p);
 
203
                    p += get_mclen(p);
 
204
                }
 
205
                else if (*p == '-' && *(p + 1) != ']') {
 
206
                    (st_ptr++)->type = RE_WHICH_RANGE;
 
207
                    p++;
 
208
                }
 
209
                else if (*p == '\0') {
 
210
                    if (msg)
 
211
                        *msg = "Missing ]";
 
212
                    return NULL;
 
213
                }
 
214
                else {
 
215
                    *(st_ptr++) = set_longchar(p);
 
216
                    p += get_mclen(p);
 
217
                }
 
218
                if (st_ptr >= &regex->storage[STORAGE_MAX]) {
 
219
                    if (msg)
 
220
                        *msg = "Regular expression too long";
 
221
                    return NULL;
 
222
                }
 
223
            }
 
224
            (st_ptr++)->type = RE_TYPE_END;
 
225
            re->p.pattern = r;
 
226
            RE_SET_MODE(re, m);
 
227
            if (igncase)
 
228
                re->mode |= RE_IGNCASE;
 
229
            re++;
 
230
            break;
 
231
        case '|':
 
232
            RE_SET_MODE(re, RE_ENDMARK);
 
233
            re++;
 
234
            p++;
 
235
            regex->alt_regex = newRegex0(&p, igncase, NULL, msg, level);
 
236
            if (regex->alt_regex == NULL)
 
237
                return NULL;
 
238
            *ex = p;
 
239
            return regex;
 
240
        case '(':
 
241
            RE_SET_MODE(re, RE_SUBREGEX);
 
242
            p++;
 
243
            re->p.sub = newRegex0(&p, igncase, NULL, msg, level + 1);
 
244
            if (re->p.sub == NULL)
 
245
                return NULL;
 
246
            re++;
 
247
            break;
 
248
        case ')':
 
249
            if (level == 0) {
 
250
                if (msg)
 
251
                    *msg = "Too many ')'";
 
252
                return NULL;
 
253
            }
 
254
            RE_SET_MODE(re, RE_ENDMARK);
 
255
            re++;
 
256
            *ex = p;
 
257
            return regex;
 
258
        case '\\':
 
259
            p++;
 
260
        default:
 
261
            *(st_ptr) = set_longchar(p);
 
262
            p += get_mclen(p) - 1;
 
263
            re->p.pattern = st_ptr;
 
264
            st_ptr++;
 
265
            RE_SET_MODE(re, RE_NORMAL);
 
266
            if (igncase)
 
267
                re->mode |= RE_IGNCASE;
 
268
            re++;
 
269
        }
 
270
        if (st_ptr >= &regex->storage[STORAGE_MAX] ||
 
271
            re >= &regex->re[REGEX_MAX]) {
 
272
            if (msg)
 
273
                *msg = "Regular expression too long";
 
274
            return NULL;
 
275
        }
 
276
    }
 
277
    RE_SET_MODE(re, RE_ENDMARK);
 
278
    if (msg)
 
279
        *msg = NULL;
 
280
    *ex = p;
 
281
    return regex;
 
282
}
 
283
 
 
284
Regex *
 
285
newRegex(char *ex, int igncase, Regex *regex, char **msg)
 
286
{
 
287
    return newRegex0(&ex, igncase, regex, msg, 0);
 
288
}
 
289
 
 
290
/* 
 
291
 * regexMatch: match regular expression
 
292
 */
 
293
int
 
294
regexMatch(char *str, int len, int firstp)
 
295
{
 
296
    return RegexMatch(&DefaultRegex, str, len, firstp);
 
297
}
 
298
 
 
299
int
 
300
RegexMatch(Regex *re, char *str, int len, int firstp)
 
301
{
 
302
    char *p, *ep;
 
303
    char *lpos;
 
304
    Regex *r;
 
305
 
 
306
    if (str == NULL)
 
307
        return 0;
 
308
    if (len < 0)
 
309
        len = strlen(str);
 
310
    re->position = NULL;
 
311
    ep = str + len;
 
312
    for (p = str; p <= ep; p++) {
 
313
        lpos = NULL;
 
314
        re->lposition = NULL;
 
315
        for (r = re; r != NULL; r = r->alt_regex) {
 
316
            switch (regmatch(r->re, p, ep, firstp && (p == str), &lpos)) {
 
317
            case 1:             /* matched */
 
318
                re->position = p;
 
319
                if (re->lposition == NULL || re->lposition < lpos)
 
320
                    re->lposition = lpos;
 
321
                break;
 
322
            case -1:            /* error */
 
323
                re->position = NULL;
 
324
                return -1;
 
325
            }
 
326
        }
 
327
        if (re->lposition != NULL) {
 
328
            /* matched */
 
329
            return 1;
 
330
        }
 
331
        p += get_mclen(p) - 1;
 
332
    }
 
333
    return 0;
 
334
}
 
335
 
 
336
/* 
 
337
 * matchedPosition: last matched position
 
338
 */
 
339
void
 
340
MatchedPosition(Regex *re, char **first, char **last)
 
341
{
 
342
    *first = re->position;
 
343
    *last = re->lposition;
 
344
}
 
345
 
 
346
void
 
347
matchedPosition(char **first, char **last)
 
348
{
 
349
    *first = DefaultRegex.position;
 
350
    *last = DefaultRegex.lposition;
 
351
}
 
352
 
 
353
/* 
 
354
 * Intermal routines
 
355
 */
 
356
 
 
357
struct MatchingContext1 {
 
358
    int label;
 
359
    regexchar *re;
 
360
    char *lastpos;
 
361
    char *str;
 
362
    int iter_limit;
 
363
    int n_any;
 
364
    int firstp;
 
365
    char *end_p;
 
366
    Regex *sub_regex;
 
367
    struct MatchingContext1 *sub_ctx;
 
368
    struct MatchingContext2 *ctx2;
 
369
};
 
370
 
 
371
struct MatchingContext2 {
 
372
    int label;
 
373
    Regex *regex;
 
374
    char *lastpos;
 
375
    struct MatchingContext1 *ctx;
 
376
    struct MatchingContext2 *ctx2;
 
377
    char *str;
 
378
    int n_any;
 
379
    int firstp;
 
380
};
 
381
 
 
382
 
 
383
#define YIELD(retval,context,lnum) (context)->label = lnum; return (retval); label##lnum:
 
384
 
 
385
static int regmatch_iter(struct MatchingContext1 *,
 
386
                         regexchar *, char *, char *, int);
 
387
 
 
388
static int
 
389
regmatch_sub_anytime(struct MatchingContext2 *c, Regex *regex,
 
390
                     regexchar * pat2,
 
391
                     char *str, char *end_p, int iter_limit, int firstp)
 
392
{
 
393
    switch (c->label) {
 
394
    case 1:
 
395
        goto label1;
 
396
    case 2:
 
397
        goto label2;
 
398
    case 3:
 
399
        goto label3;
 
400
    }
 
401
    c->ctx = GC_malloc(sizeof(struct MatchingContext1));
 
402
    c->ctx2 = GC_malloc(sizeof(struct MatchingContext2));
 
403
    c->ctx->label = 0;
 
404
    c->regex = regex;
 
405
    c->n_any = 0;
 
406
    c->str = str;
 
407
    c->firstp = firstp;
 
408
    for (;;) {
 
409
        c->ctx->label = 0;
 
410
        while (regmatch_iter(c->ctx, c->regex->re, c->str, end_p, c->firstp)) {
 
411
            c->n_any = c->ctx->lastpos - c->str;
 
412
            if (c->n_any <= 0)
 
413
                continue;
 
414
            c->firstp = 0;
 
415
            if (RE_MODE(pat2) == RE_ENDMARK) {
 
416
                c->lastpos = c->str + c->n_any;
 
417
                YIELD(1, c, 1);
 
418
            }
 
419
            else if (regmatch(pat2, c->str + c->n_any, end_p,
 
420
                              c->firstp, &c->lastpos) == 1) {
 
421
                YIELD(1, c, 2);
 
422
            }
 
423
            if (iter_limit == 1)
 
424
                continue;
 
425
            c->ctx2->label = 0;
 
426
            while (regmatch_sub_anytime(c->ctx2, regex, pat2,
 
427
                                        c->str + c->n_any, end_p,
 
428
                                        iter_limit - 1, c->firstp)) {
 
429
 
 
430
                c->lastpos = c->ctx2->lastpos;
 
431
                YIELD(1, c, 3);
 
432
            }
 
433
        }
 
434
        if (c->regex->alt_regex == NULL)
 
435
            break;
 
436
        c->regex = c->regex->alt_regex;
 
437
    }
 
438
    return 0;
 
439
}
 
440
 
 
441
static int
 
442
regmatch_iter(struct MatchingContext1 *c,
 
443
              regexchar * re, char *str, char *end_p, int firstp)
 
444
{
 
445
    switch (c->label) {
 
446
    case 1:
 
447
        goto label1;
 
448
    case 2:
 
449
        goto label2;
 
450
    case 3:
 
451
        goto label3;
 
452
    case 4:
 
453
        goto label4;
 
454
    case 5:
 
455
        goto label5;
 
456
    case 6:
 
457
        goto label6;
 
458
    case 7:
 
459
        goto label7;
 
460
    }
 
461
    if (RE_MODE(re) == RE_ENDMARK)
 
462
        return 0;
 
463
    c->re = re;
 
464
    c->firstp = firstp;
 
465
    c->str = str;
 
466
    c->end_p = end_p;
 
467
    c->sub_ctx = NULL;
 
468
    c->lastpos = NULL;
 
469
    while (RE_MODE(c->re) != RE_ENDMARK) {
 
470
        if (c->re->mode & (RE_ANYTIME | RE_OPT)) {
 
471
            if (c->re->mode & RE_ANYTIME)
 
472
                c->iter_limit = RE_ITER_LIMIT;
 
473
            else
 
474
                c->iter_limit = 1;
 
475
            c->n_any = -1;
 
476
            while (c->n_any < c->iter_limit) {
 
477
                if (c->str + c->n_any >= c->end_p) {
 
478
                    return 0;
 
479
                }
 
480
                if (c->n_any >= 0) {
 
481
                    if (RE_MODE(c->re) == RE_SUBREGEX) {
 
482
                        c->ctx2 = GC_malloc(sizeof(struct MatchingContext2));
 
483
                        c->ctx2->label = 0;
 
484
                        while (regmatch_sub_anytime(c->ctx2,
 
485
                                                    c->re->p.sub,
 
486
                                                    c->re + 1,
 
487
                                                    c->str + c->n_any,
 
488
                                                    c->end_p,
 
489
                                                    c->iter_limit,
 
490
                                                    c->firstp)) {
 
491
                            c->n_any = c->ctx2->lastpos - c->str;
 
492
                            c->lastpos = c->ctx2->lastpos;
 
493
                            YIELD(1, c, 1);
 
494
                        }
 
495
                        return 0;
 
496
                    }
 
497
                    else {
 
498
                        longchar k;
 
499
                        k = set_longchar(c->str + c->n_any);
 
500
                        if (regmatch1(c->re, &k)) {
 
501
                            c->n_any += get_mclen(c->str + c->n_any);
 
502
                        }
 
503
                        else {
 
504
                            return 0;
 
505
                        }
 
506
                        c->firstp = 0;
 
507
                    }
 
508
                }
 
509
                else
 
510
                    c->n_any++;
 
511
                if (RE_MODE(c->re + 1) == RE_ENDMARK) {
 
512
                    c->lastpos = c->str + c->n_any;
 
513
                    YIELD(1, c, 2);
 
514
                }
 
515
                else if (regmatch(c->re + 1, c->str + c->n_any, c->end_p,
 
516
                                  c->firstp, &c->lastpos) == 1) {
 
517
                    YIELD(1, c, 3);
 
518
                }
 
519
            }
 
520
            return 0;
 
521
        }
 
522
        /* regexp other than pat*, pat+ and pat? */
 
523
        switch (RE_MODE(c->re)) {
 
524
        case RE_BEGIN:
 
525
            if (!c->firstp)
 
526
                return 0;
 
527
            c->re++;
 
528
            break;
 
529
        case RE_END:
 
530
            if (c->str >= c->end_p) {
 
531
                c->lastpos = c->str;
 
532
                c->re++;
 
533
                YIELD(1, c, 4);
 
534
            }
 
535
            else {
 
536
                c->lastpos = NULL;
 
537
                return 0;
 
538
            }
 
539
            break;
 
540
        case RE_SUBREGEX:
 
541
            if (c->sub_ctx == NULL) {
 
542
                c->sub_ctx = GC_malloc(sizeof(struct MatchingContext1));
 
543
            }
 
544
            c->sub_regex = c->re->p.sub;
 
545
            for (;;) {
 
546
                c->sub_ctx->label = 0;
 
547
                while (regmatch_iter(c->sub_ctx, c->sub_regex->re,
 
548
                                     c->str, c->end_p, c->firstp)) {
 
549
                    if (c->sub_ctx->lastpos != c->str)
 
550
                        c->firstp = 0;
 
551
                    if (RE_MODE(c->re + 1) == RE_ENDMARK) {
 
552
                        c->lastpos = c->sub_ctx->lastpos;
 
553
                        YIELD(1, c, 5);
 
554
                    }
 
555
                    else if (regmatch(c->re + 1, c->sub_ctx->lastpos, c->end_p,
 
556
                                      c->firstp, &c->lastpos) == 1) {
 
557
                        YIELD(1, c, 6);
 
558
                    }
 
559
                }
 
560
                if (c->sub_regex->alt_regex == NULL)
 
561
                    break;
 
562
                c->sub_regex = c->sub_regex->alt_regex;
 
563
            }
 
564
            return 0;
 
565
        default:
 
566
            {
 
567
                longchar k;
 
568
                k = set_longchar(c->str);
 
569
                c->str += get_mclen(c->str);
 
570
                if (!regmatch1(c->re, &k))
 
571
                    return 0;
 
572
            }
 
573
            c->re++;
 
574
            c->firstp = 0;
 
575
        }
 
576
        if (c->str > c->end_p) {
 
577
            return 0;
 
578
        }
 
579
    }
 
580
    c->lastpos = c->str;
 
581
#ifdef REGEX_DEBUG
 
582
    if (verbose)
 
583
        printf("Succeed: %s %d\n", c->str, c->lastpos - c->str);
 
584
#endif
 
585
    YIELD(1, c, 7);
 
586
    return 0;
 
587
}
 
588
 
 
589
static int
 
590
regmatch(regexchar * re, char *str, char *end_p, int firstp, char **lastpos)
 
591
{
 
592
    struct MatchingContext1 contx;
 
593
 
 
594
    *lastpos = NULL;
 
595
 
 
596
    contx.label = 0;
 
597
    while (regmatch_iter(&contx, re, str, end_p, firstp)) {
 
598
#ifdef REGEX_DEBUG
 
599
        char *p;
 
600
        if (verbose) {
 
601
            printf("regmatch: matched <");
 
602
            for (p = str; p < contx.lastpos; p++)
 
603
                putchar(*p);
 
604
            printf(">\n");
 
605
        }
 
606
#endif
 
607
        if (*lastpos == NULL || *lastpos < contx.lastpos)
 
608
            *lastpos = contx.lastpos;
 
609
    }
 
610
    if (*lastpos == NULL)
 
611
        return 0;
 
612
    return 1;
 
613
}
 
614
 
 
615
 
 
616
static int
 
617
regmatch1(regexchar * re, longchar * c)
 
618
{
 
619
    int ans;
 
620
 
 
621
#ifdef USE_M17N
 
622
    if (c->type == RE_TYPE_SYMBOL)
 
623
        return 0;
 
624
#endif
 
625
    switch (RE_MODE(re)) {
 
626
    case RE_ANY:
 
627
#ifdef REGEX_DEBUG
 
628
        if (verbose)
 
629
            printf("%s vs any. -> 1\n", lc2c(c, 1));
 
630
#endif                          /* REGEX_DEBUG */
 
631
        return 1;
 
632
    case RE_NORMAL:
 
633
        ans = match_longchar(re->p.pattern, c, re->mode & RE_IGNCASE);
 
634
#ifdef REGEX_DEBUG
 
635
        if (verbose)
 
636
            printf("RE=%s vs %s -> %d\n", lc2c(re->p.pattern, 1), lc2c(c, 1),
 
637
                   ans);
 
638
#endif                          /* REGEX_DEBUG */
 
639
        return ans;
 
640
    case RE_WHICH:
 
641
        return matchWhich(re->p.pattern, c, re->mode & RE_IGNCASE);
 
642
    case RE_EXCEPT:
 
643
        return !matchWhich(re->p.pattern, c, re->mode & RE_IGNCASE);
 
644
    }
 
645
    return 0;
 
646
}
 
647
 
 
648
static int
 
649
matchWhich(longchar * pattern, longchar * c, int igncase)
 
650
{
 
651
    longchar *p = pattern;
 
652
    int ans = 0;
 
653
 
 
654
#ifdef REGEX_DEBUG
 
655
    if (verbose)
 
656
        printf("RE pattern = %s char=%s", lc2c(pattern, 10000), lc2c(c, 1));
 
657
#endif                          /* REGEX_DEBUG */
 
658
    while (p->type != RE_TYPE_END) {
 
659
        if ((p + 1)->type == RE_WHICH_RANGE && (p + 2)->type != RE_TYPE_END) {
 
660
            if (match_range_longchar(p, p + 2, c, igncase)) {
 
661
                ans = 1;
 
662
                break;
 
663
            }
 
664
            p += 3;
 
665
        }
 
666
        else {
 
667
            if (match_longchar(p, c, igncase)) {
 
668
                ans = 1;
 
669
                break;
 
670
            }
 
671
            p++;
 
672
        }
 
673
    }
 
674
#ifdef REGEX_DEBUG
 
675
    if (verbose)
 
676
        printf(" -> %d\n", ans);
 
677
#endif                          /* REGEX_DEBUG */
 
678
    return ans;
 
679
}
 
680
 
 
681
static int
 
682
match_longchar(longchar * a, longchar * b, int ignore)
 
683
{
 
684
#ifdef USE_M17N
 
685
    if (a->type != b->type)
 
686
        return 0;
 
687
    if (a->type == RE_TYPE_WCHAR_T)
 
688
        return (a->wch.ccs == b->wch.ccs) && (a->wch.code == b->wch.code);
 
689
#endif
 
690
    if (ignore && IS_ALPHA(b->ch))
 
691
        return (a->ch == TOLOWER(b->ch) || a->ch == TOUPPER(b->ch));
 
692
    else
 
693
        return a->ch == b->ch;
 
694
}
 
695
 
 
696
static int
 
697
match_range_longchar(longchar * a, longchar * b, longchar * c, int ignore)
 
698
{
 
699
#ifdef USE_M17N
 
700
    if (a->type != b->type || a->type != c->type)
 
701
        return 0;
 
702
    if (a->type == RE_TYPE_WCHAR_T)
 
703
        return ((a->wch.ccs == c->wch.ccs && c->wch.ccs == b->wch.ccs) &&
 
704
                (a->wch.code <= c->wch.code && c->wch.code <= b->wch.code));
 
705
#endif
 
706
    if (ignore && IS_ALPHA(c->ch))
 
707
        return ((a->ch <= TOLOWER(c->ch) && TOLOWER(c->ch) <= b->ch) ||
 
708
                (a->ch <= TOUPPER(c->ch) && TOUPPER(c->ch) <= b->ch));
 
709
    else
 
710
        return (a->ch <= c->ch && c->ch <= b->ch);
 
711
}
 
712
 
 
713
#ifdef REGEX_DEBUG
 
714
char *
 
715
lc2c(longchar * x, int len)
 
716
{
 
717
    static char y[100];
 
718
    int i = 0, j = 0;
 
719
    char *r;
 
720
 
 
721
    while (x[j].type != RE_TYPE_END && j < len) {
 
722
        if (x[j].type == RE_WHICH_RANGE)
 
723
            y[i++] = '-';
 
724
#ifdef USE_M17N
 
725
        else if (x[j].type == RE_TYPE_WCHAR_T) {
 
726
            char buf[20];
 
727
            sprintf(buf, "[%x-%x]", x[j].wch.ccs, x[j].wch.code);
 
728
            strcpy(&y[i], buf);
 
729
            i += strlen(buf);
 
730
        }
 
731
#endif
 
732
        else
 
733
            y[i++] = x[j].ch;
 
734
        j++;
 
735
    }
 
736
    y[i] = '\0';
 
737
    r = GC_malloc_atomic(i + 1);
 
738
    strcpy(r, y);
 
739
    return r;
 
740
}
 
741
 
 
742
void
 
743
debugre(regexchar * re)
 
744
{
 
745
    for (; RE_MODE(re) != RE_ENDMARK; re++) {
 
746
        switch (RE_MODE(re)) {
 
747
        case RE_BEGIN:
 
748
            printf("Begin ");
 
749
            continue;
 
750
        case RE_END:
 
751
            printf("End ");
 
752
            continue;
 
753
        }
 
754
        if (re->mode & RE_ANYTIME)
 
755
            printf("Anytime-");
 
756
        if (re->mode & RE_OPT)
 
757
            printf("Opt-");
 
758
 
 
759
        switch (RE_MODE(re)) {
 
760
        case RE_ANY:
 
761
            printf("Any ");
 
762
            break;
 
763
        case RE_NORMAL:
 
764
            printf("Match-to'%c' ", *re->p.pattern);
 
765
            break;
 
766
        case RE_WHICH:
 
767
            printf("One-of\"%s\" ", lc2c(re->p.pattern, 10000));
 
768
            break;
 
769
        case RE_EXCEPT:
 
770
            printf("Other-than\"%s\" ", lc2c(re->p.pattern, 10000));
 
771
            break;
 
772
        case RE_SUBREGEX:
 
773
            {
 
774
                Regex *r = re->p.sub;
 
775
                printf("(");
 
776
                while (r) {
 
777
                    debugre(r->re);
 
778
                    if (r->alt_regex)
 
779
                        printf(" | ");
 
780
                    r = r->alt_regex;
 
781
                }
 
782
                printf(")");
 
783
                break;
 
784
            }
 
785
        default:
 
786
            printf("Unknown ");
 
787
        }
 
788
    }
 
789
}
 
790
 
 
791
#endif                          /* REGEX_DEBUG */
 
792
 
 
793
#ifdef REGEXTEST
 
794
int
 
795
main(int argc, char **argv)
 
796
{
 
797
    char buf[128], buf2[128];
 
798
    char *msg;
 
799
    Regex *re;
 
800
    char *fpos, *epos;
 
801
    FILE *f = stdin;
 
802
    int i = 1;
 
803
 
 
804
#ifdef USE_M17N
 
805
    wtf_init(WC_CES_EUC_JP, WC_CES_EUC_JP);
 
806
#endif
 
807
#ifdef REGEX_DEBUG
 
808
    for (i = 1; i < argc; i++) {
 
809
        if (strcmp(argv[i], "-v") == 0)
 
810
            verbose = 1;
 
811
        else
 
812
            break;
 
813
    }
 
814
#endif
 
815
 
 
816
    if (argc > i)
 
817
        f = fopen(argv[i], "r");
 
818
    if (f == NULL) {
 
819
        fprintf(stderr, "Can't open %s\n", argv[i]);
 
820
        exit(1);
 
821
    }
 
822
    while (fscanf(f, "%s%s", buf, buf2) == 2) {
 
823
        re = newRegex(buf, 0, NULL, &msg);
 
824
        if (re == NULL) {
 
825
            printf("Error on regexp /%s/: %s\n", buf, msg);
 
826
            exit(1);
 
827
        }
 
828
        if (RegexMatch(re, buf2, -1, 1)) {
 
829
            printf("/%s/\t\"%s\"\t\"", buf, buf2);
 
830
            MatchedPosition(re, &fpos, &epos);
 
831
            while (fpos < epos)
 
832
                putchar(*(fpos++));
 
833
            putchar('"');
 
834
        }
 
835
        else
 
836
            printf("/%s/\t\"%s\"\tno_match", buf, buf2);
 
837
        putchar('\n');
 
838
    }
 
839
    /* notreatched */
 
840
    return 0;
 
841
}
 
842
#endif