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