]> mj.ucw.cz Git - libucw.git/blob - lib/regex.c
e1e2df608370b722675db4a2e187cdeeb885cc91
[libucw.git] / lib / regex.c
1 /*
2  *      Sherlock Library -- Regular Expressions
3  *
4  *      (c) 1997 Martin Mares <mj@ucw.cz>
5  *      (c) 2001 Robert Spalek <robert@ucw.cz>
6  */
7
8 #include "lib/lib.h"
9 #include "lib/chartype.h"
10
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <regex.h>
16
17 #define INITIAL_MEM 1024                /* Initial space allocated for each pattern */
18 #define CHAR_SET_SIZE 256               /* How many characters in the character set.  */
19
20 struct regex {
21   struct re_pattern_buffer buf;
22   struct re_registers regs;             /* Must not change between re_match() calls */
23   int len_cache;
24 };
25
26 regex *
27 rx_compile(byte *p, int icase)
28 {
29   regex *r = xmalloc_zero(sizeof(regex));
30   const char *msg;
31
32   r->buf.buffer = xmalloc(INITIAL_MEM);
33   r->buf.allocated = INITIAL_MEM;
34   if (icase)
35     {
36       unsigned i;
37       r->buf.translate = xmalloc (CHAR_SET_SIZE);
38       /* Map uppercase characters to corresponding lowercase ones.  */
39       for (i = 0; i < CHAR_SET_SIZE; i++)
40         r->buf.translate[i] = Cupper(i) ? tolower (i) : i;
41     }
42   else
43     r->buf.translate = NULL;
44   re_set_syntax(RE_SYNTAX_POSIX_EXTENDED);
45   msg = re_compile_pattern(p, strlen(p), &r->buf);
46   if (!msg)
47     return r;
48   die("Error parsing pattern `%s': %s", p, msg);
49 }
50
51 void
52 rx_free(regex *r)
53 {
54   xfree(r->buf.buffer);
55   xfree(r);
56 }
57
58 int
59 rx_match(regex *r, byte *s)
60 {
61   int len = strlen(s);
62
63   r->len_cache = len;
64   if (re_match(&r->buf, s, len, 0, &r->regs) < 0)
65     return 0;
66   if (r->regs.start[0] || r->regs.end[0] != len) /* XXX: Why regex doesn't enforce implicit "^...$" ? */
67     return 0;
68   return 1;
69 }
70
71 int
72 rx_subst(regex *r, byte *by, byte *src, byte *dest, uns destlen)
73 {
74   byte *end = dest + destlen - 1;
75
76   if (!rx_match(r, src))
77     return 0;
78
79   while (*by)
80     {
81       if (*by == '\\')
82         {
83           by++;
84           if (*by >= '0' && *by <= '9') /* \0 gets replaced by entire pattern */
85             {
86               uns j = *by++ - '0';
87               if (j < r->regs.num_regs)
88                 {
89                   byte *s = src + r->regs.start[j];
90                   uns i = r->regs.end[j] - r->regs.start[j];
91                   if (r->regs.start[j] > r->len_cache || r->regs.end[j] > r->len_cache)
92                     return -1;
93                   if (dest + i >= end)
94                     return -1;
95                   memcpy(dest, s, i);
96                   dest += i;
97                   continue;
98                 }
99             }
100         }
101       if (dest < end)
102         *dest++ = *by++;
103       else
104         return -1;
105     }
106   *dest = 0;
107   return 1;
108 }
109
110 #ifdef TEST
111
112 void main(int argc, char **argv)
113 {
114   regex *r;
115   byte buf1[256], buf2[256];
116
117   r = rx_compile(argv[1]);
118   while (fgets(buf1, sizeof(buf1), stdin))
119     {
120       char *p = strchr(buf1, '\n');
121       if (p)
122         *p = 0;
123       if (argc == 2)
124         {
125           if (rx_match(r, buf1))
126             puts("MATCH");
127           else
128             puts("NO MATCH");
129         }
130       else
131         {
132           int i = rx_subst(r, argv[2], buf1, buf2, sizeof(buf2));
133           if (i < 0)
134             puts("OVERFLOW");
135           else if (!i)
136             puts("NO MATCH");
137           else
138             puts(buf2);
139         }
140     }
141   rx_free(r);
142 }
143
144 #endif