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