1 /*
2 ** Copyright (c) 2016, Cyrille Lefevre <cyrille.lefevre-regs@laposte.net>.
3 ** All rights reserved.
4 **
5 ** Redistribution and use in source and binary forms, with or without
6 ** modification, are permitted provided that the following conditions
7 ** are met:
8 **
9 ** 1. Redistributions of source code must retain the above copyright
10 ** notice, this list of conditions and the following disclaimer.
11 ** 2. Redistributions in binary form must reproduce the above copyright
12 ** notice, this list of conditions and the following disclaimer in the
13 ** documentation and/or other materials provided with the distribution.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
19 ** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
20 ** OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21 ** OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22 ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24 ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25 ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 **/
27
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "rplregex.h"
35
36 #ifndef HAVE_REGEX
37 static char *_regerrorstr;
38
regerror(char * s)39 void regerror(char *s)
40 {
41 _regerrorstr = s;
42 }
43 #endif
44
rpl_regfree(REGEXP_T ** _prog)45 void rpl_regfree(REGEXP_T **_prog)
46 {
47 REGEXP_T *prog = *_prog;
48 #ifdef HAVE_REGEX
49 if (prog->preg.re_nsub)
50 free(prog->pmatch);
51 regfree(&prog->preg);
52 #endif
53 free(prog);
54 *_prog = (REGEXP_T *) NULL;
55 }
56
rpl_regcomp(REGEXP_T ** _prog,const char * regex,int cflags)57 int rpl_regcomp(REGEXP_T **_prog, const char *regex, int cflags)
58 {
59 #ifdef HAVE_REGEX
60 int rc;
61 REGEXP_T *prog = *_prog = (REGEXP_T *) malloc(sizeof(REGEXP_T));
62 if (prog == NULL)
63 return REG_ESPACE;
64 prog->cflags = cflags;
65 prog->pmatch = NULL;
66 rc = regcomp(&prog->preg, regex, cflags|REG_EXTENDED);
67 if (rc || cflags & REG_NOSUB || prog->preg.re_nsub == 0)
68 return rc;
69 prog->pmatch = calloc(prog->preg.re_nsub + 1, sizeof(regmatch_t));
70 if (prog->pmatch == NULL) {
71 prog->preg.re_nsub = 0;
72 rpl_regfree(&prog);
73 return REG_ESPACE;
74 }
75 return 0;
76 #else
77 *_prog = regcomp((char *)regex);
78 return *_prog == NULL;
79 #endif
80 }
81
rpl_regexec(REGEXP_T * const * _prog,const char * string)82 int rpl_regexec(REGEXP_T * const *_prog, const char *string)
83 {
84 REGEXP_T *prog = *_prog;
85 #ifdef HAVE_REGEX
86 if (!(prog->cflags & REG_NOSUB))
87 prog->string = string;
88 return regexec(&prog->preg, string, prog->preg.re_nsub + 1, prog->pmatch, 0);
89 #else
90 int rc = !regexec(prog, (char *)string);
91 return rc && _regerrorstr ? REG_ESPACE : rc;
92 #endif
93 }
94
rpl_regsub(REGEXP_T * const * _prog,const char * source,char * dest,size_t size)95 int rpl_regsub(REGEXP_T * const *_prog, const char *source, char *dest, size_t size)
96 {
97 REGEXP_T *prog = *_prog;
98 const char *src;
99 char *dst, c;
100 int no;
101 size_t len;
102
103 if (prog == NULL || source == NULL || dest == NULL || size == 0)
104 return REG_ESPACE;
105
106 src = source;
107 dst = dest;
108 while ((c = *src++) != '\0') {
109 if (c == '&')
110 no = 0;
111 else if (c == '\\' && '0' <= *src && *src <= '9')
112 no = *src++ - '0';
113 else
114 no = -1;
115 if (no < 0) { /* Ordinary character. */
116 if (c == '\\' && (*src == '\\' || *src == '&'))
117 c = *src++;
118 if ((size_t) (dst - dest) + 1 >= size)
119 return REG_ESPACE;
120 *dst++ = c;
121 #ifdef HAVE_REGEX
122 } else if (prog->preg.re_nsub &&
123 (size_t) no <= prog->preg.re_nsub &&
124 prog->pmatch[no].rm_so >= 0 &&
125 prog->pmatch[no].rm_eo > prog->pmatch[no].rm_so) {
126 len = (size_t) (prog->pmatch[no].rm_eo - prog->pmatch[no].rm_so);
127 if ((size_t) (dst - dest) + len >= size)
128 return REG_ESPACE;
129 /* Flawfinder: ignore (strncpy) */
130 strncpy(dst, prog->string + prog->pmatch[no].rm_so, len);
131 #else
132 } else if (prog->startp[no] != NULL && prog->endp[no] != NULL &&
133 prog->endp[no] > prog->startp[no]) {
134 len = (size_t) (prog->endp[no] - prog->startp[no]);
135 if ((size_t) (dst - dest) + len >= size)
136 return REG_ESPACE;
137 /* Flawfinder: ignore (strncpy) */
138 strncpy(dst, prog->startp[no], len);
139 #endif
140 dst += len;
141 if (len != 0 && *(dst - 1) == '\0') /* strncpy hit NUL. */
142 return REG_ESUBREG;
143 }
144 }
145 *dst = '\0';
146 return 0;
147 }
148
rpl_regerror(int error,REGEXP_T * const * _prog)149 char *rpl_regerror(int error, REGEXP_T * const *_prog)
150 {
151 char *buf;
152 #ifdef HAVE_REGEX
153 REGEXP_T *prog = *_prog;
154 size_t len = regerror(error, &prog->preg, NULL, 0);
155
156 buf = malloc(len);
157 if (buf)
158 regerror(error, &prog->preg, buf, len);
159 #else
160 if (_regerrorstr) {
161 buf = strdup(_regerrorstr);
162 _regerrorstr = NULL;
163 } else {
164 size_t len = 16;
165
166 buf = malloc(len);
167 if (buf)
168 snprintf(buf, sizeof(buf), "Error %d\n", error);
169 }
170 #endif
171 return buf;
172 }
173
174 #ifdef WANT_REGMAIN
main(int argc,char ** argv)175 int main(int argc, char **argv)
176 {
177 REGEXP_T *prog;
178 int rc, no;
179 char *str = argv[1];
180 char *re = argv[2];
181 char *sub = argv[3];
182 char dst[1024];
183
184 rc = rpl_regcomp(&prog, re, 0);
185 if (rc == 0)
186 rc = rpl_regexec(&prog, str);
187 if (rc == 0) {
188 fprintf(stderr, "match\n");
189 #ifdef HAVE_REGEX
190 if (prog->preg.re_nsub)
191 for (no = 0; no <= prog->preg.re_nsub; no++)
192 fprintf(stderr, "[%d]:%2d-%2d %-.*s\n", no,
193 prog->pmatch[no].rm_so, prog->pmatch[no].rm_eo,
194 prog->pmatch[no].rm_eo - prog->pmatch[no].rm_so,
195 str+prog->pmatch[no].rm_so);
196 #else
197 for (no = 0; no <= NSUBEXP; no++)
198 if (prog->startp[no] && prog->endp[no])
199 fprintf(stderr, "[%d]:%2ld-%2ld %-.*s\n", no,
200 prog->startp[no] - str, prog->endp[no] - str,
201 (int)(prog->endp[no] - prog->startp[no]),
202 prog->startp[no]);
203 #endif
204 rc = rpl_regsub(&prog, sub, dst, sizeof(dst));
205 }
206 if (rc == 0)
207 printf("%s\n", dst);
208 else if (rc == REG_NOMATCH)
209 fprintf(stderr, "nomatch\n");
210 else {
211 char *buf = rpl_regerror(rc, &prog);
212 fprintf(stderr, "regerror: %s\n", buf);
213 free(buf);
214 }
215 rpl_regfree(&prog);
216 return rc;
217 }
218 #endif
219