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