xref: /minix3/tests/lib/libc/regex/main.c (revision 11be35a165022172ed3cea20f2b5df0307540b0e)
1*11be35a1SLionel Sambuc /*	$NetBSD: main.c,v 1.2 2011/09/16 16:13:18 plunky Exp $	*/
2*11be35a1SLionel Sambuc 
3*11be35a1SLionel Sambuc /*-
4*11be35a1SLionel Sambuc  * Copyright (c) 1993 The NetBSD Foundation, Inc.
5*11be35a1SLionel Sambuc  * All rights reserved.
6*11be35a1SLionel Sambuc  *
7*11be35a1SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
8*11be35a1SLionel Sambuc  * modification, are permitted provided that the following conditions
9*11be35a1SLionel Sambuc  * are met:
10*11be35a1SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
11*11be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
12*11be35a1SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
13*11be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
14*11be35a1SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
15*11be35a1SLionel Sambuc  *
16*11be35a1SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17*11be35a1SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18*11be35a1SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19*11be35a1SLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20*11be35a1SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*11be35a1SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*11be35a1SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*11be35a1SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*11be35a1SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*11be35a1SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*11be35a1SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
27*11be35a1SLionel Sambuc  */
28*11be35a1SLionel Sambuc 
29*11be35a1SLionel Sambuc #include <assert.h>
30*11be35a1SLionel Sambuc #include <regex.h>
31*11be35a1SLionel Sambuc #include <stdio.h>
32*11be35a1SLionel Sambuc #include <stdlib.h>
33*11be35a1SLionel Sambuc #include <string.h>
34*11be35a1SLionel Sambuc #include <unistd.h>
35*11be35a1SLionel Sambuc 
36*11be35a1SLionel Sambuc #include <sys/types.h>
37*11be35a1SLionel Sambuc 
38*11be35a1SLionel Sambuc #include "test_regex.h"
39*11be35a1SLionel Sambuc 
40*11be35a1SLionel Sambuc char *progname;
41*11be35a1SLionel Sambuc int debug = 0;
42*11be35a1SLionel Sambuc int line = 0;
43*11be35a1SLionel Sambuc int status = 0;
44*11be35a1SLionel Sambuc 
45*11be35a1SLionel Sambuc int copts = REG_EXTENDED;
46*11be35a1SLionel Sambuc int eopts = 0;
47*11be35a1SLionel Sambuc regoff_t startoff = 0;
48*11be35a1SLionel Sambuc regoff_t endoff = 0;
49*11be35a1SLionel Sambuc 
50*11be35a1SLionel Sambuc static char empty = '\0';
51*11be35a1SLionel Sambuc 
52*11be35a1SLionel Sambuc static char *eprint(int);
53*11be35a1SLionel Sambuc static int efind(char *);
54*11be35a1SLionel Sambuc 
55*11be35a1SLionel Sambuc /*
56*11be35a1SLionel Sambuc  * main - do the simple case, hand off to regress() for regression
57*11be35a1SLionel Sambuc  */
58*11be35a1SLionel Sambuc int
main(int argc,char * argv[])59*11be35a1SLionel Sambuc main(int argc, char *argv[])
60*11be35a1SLionel Sambuc {
61*11be35a1SLionel Sambuc 	regex_t re;
62*11be35a1SLionel Sambuc #	define	NS	10
63*11be35a1SLionel Sambuc 	regmatch_t subs[NS];
64*11be35a1SLionel Sambuc 	char erbuf[100];
65*11be35a1SLionel Sambuc 	int err;
66*11be35a1SLionel Sambuc 	size_t len;
67*11be35a1SLionel Sambuc 	int c;
68*11be35a1SLionel Sambuc 	int errflg = 0;
69*11be35a1SLionel Sambuc 	int i;
70*11be35a1SLionel Sambuc 	extern int optind;
71*11be35a1SLionel Sambuc 	extern char *optarg;
72*11be35a1SLionel Sambuc 
73*11be35a1SLionel Sambuc 	progname = argv[0];
74*11be35a1SLionel Sambuc 
75*11be35a1SLionel Sambuc 	while ((c = getopt(argc, argv, "c:e:S:E:x")) != -1)
76*11be35a1SLionel Sambuc 		switch (c) {
77*11be35a1SLionel Sambuc 		case 'c':	/* compile options */
78*11be35a1SLionel Sambuc 			copts = options('c', optarg);
79*11be35a1SLionel Sambuc 			break;
80*11be35a1SLionel Sambuc 		case 'e':	/* execute options */
81*11be35a1SLionel Sambuc 			eopts = options('e', optarg);
82*11be35a1SLionel Sambuc 			break;
83*11be35a1SLionel Sambuc 		case 'S':	/* start offset */
84*11be35a1SLionel Sambuc 			startoff = (regoff_t)atoi(optarg);
85*11be35a1SLionel Sambuc 			break;
86*11be35a1SLionel Sambuc 		case 'E':	/* end offset */
87*11be35a1SLionel Sambuc 			endoff = (regoff_t)atoi(optarg);
88*11be35a1SLionel Sambuc 			break;
89*11be35a1SLionel Sambuc 		case 'x':	/* Debugging. */
90*11be35a1SLionel Sambuc 			debug++;
91*11be35a1SLionel Sambuc 			break;
92*11be35a1SLionel Sambuc 		case '?':
93*11be35a1SLionel Sambuc 		default:
94*11be35a1SLionel Sambuc 			errflg++;
95*11be35a1SLionel Sambuc 			break;
96*11be35a1SLionel Sambuc 		}
97*11be35a1SLionel Sambuc 	if (errflg) {
98*11be35a1SLionel Sambuc 		fprintf(stderr, "usage: %s ", progname);
99*11be35a1SLionel Sambuc 		fprintf(stderr, "[-c copt][-C][-d] [re]\n");
100*11be35a1SLionel Sambuc 		exit(2);
101*11be35a1SLionel Sambuc 	}
102*11be35a1SLionel Sambuc 
103*11be35a1SLionel Sambuc 	if (optind >= argc) {
104*11be35a1SLionel Sambuc 		regress(stdin);
105*11be35a1SLionel Sambuc 		exit(status);
106*11be35a1SLionel Sambuc 	}
107*11be35a1SLionel Sambuc 
108*11be35a1SLionel Sambuc 	err = regcomp(&re, argv[optind++], copts);
109*11be35a1SLionel Sambuc 	if (err) {
110*11be35a1SLionel Sambuc 		len = regerror(err, &re, erbuf, sizeof(erbuf));
111*11be35a1SLionel Sambuc 		fprintf(stderr, "error %s, %zd/%zd `%s'\n",
112*11be35a1SLionel Sambuc 			eprint(err), len, (size_t)sizeof(erbuf), erbuf);
113*11be35a1SLionel Sambuc 		exit(status);
114*11be35a1SLionel Sambuc 	}
115*11be35a1SLionel Sambuc 	regprint(&re, stdout);
116*11be35a1SLionel Sambuc 
117*11be35a1SLionel Sambuc 	if (optind >= argc) {
118*11be35a1SLionel Sambuc 		regfree(&re);
119*11be35a1SLionel Sambuc 		exit(status);
120*11be35a1SLionel Sambuc 	}
121*11be35a1SLionel Sambuc 
122*11be35a1SLionel Sambuc 	if (eopts&REG_STARTEND) {
123*11be35a1SLionel Sambuc 		subs[0].rm_so = startoff;
124*11be35a1SLionel Sambuc 		subs[0].rm_eo = strlen(argv[optind]) - endoff;
125*11be35a1SLionel Sambuc 	}
126*11be35a1SLionel Sambuc 	err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
127*11be35a1SLionel Sambuc 	if (err) {
128*11be35a1SLionel Sambuc 		len = regerror(err, &re, erbuf, sizeof(erbuf));
129*11be35a1SLionel Sambuc 		fprintf(stderr, "error %s, %zd/%zd `%s'\n",
130*11be35a1SLionel Sambuc 			eprint(err), len, (size_t)sizeof(erbuf), erbuf);
131*11be35a1SLionel Sambuc 		exit(status);
132*11be35a1SLionel Sambuc 	}
133*11be35a1SLionel Sambuc 	if (!(copts&REG_NOSUB)) {
134*11be35a1SLionel Sambuc 		len = (int)(subs[0].rm_eo - subs[0].rm_so);
135*11be35a1SLionel Sambuc 		if (subs[0].rm_so != -1) {
136*11be35a1SLionel Sambuc 			if (len != 0)
137*11be35a1SLionel Sambuc 				printf("match `%.*s'\n", (int)len,
138*11be35a1SLionel Sambuc 					argv[optind] + subs[0].rm_so);
139*11be35a1SLionel Sambuc 			else
140*11be35a1SLionel Sambuc 				printf("match `'@%.1s\n",
141*11be35a1SLionel Sambuc 					argv[optind] + subs[0].rm_so);
142*11be35a1SLionel Sambuc 		}
143*11be35a1SLionel Sambuc 		for (i = 1; i < NS; i++)
144*11be35a1SLionel Sambuc 			if (subs[i].rm_so != -1)
145*11be35a1SLionel Sambuc 				printf("(%d) `%.*s'\n", i,
146*11be35a1SLionel Sambuc 					(int)(subs[i].rm_eo - subs[i].rm_so),
147*11be35a1SLionel Sambuc 					argv[optind] + subs[i].rm_so);
148*11be35a1SLionel Sambuc 	}
149*11be35a1SLionel Sambuc 	exit(status);
150*11be35a1SLionel Sambuc }
151*11be35a1SLionel Sambuc 
152*11be35a1SLionel Sambuc /*
153*11be35a1SLionel Sambuc  * regress - main loop of regression test
154*11be35a1SLionel Sambuc  */
155*11be35a1SLionel Sambuc void
regress(FILE * in)156*11be35a1SLionel Sambuc regress(FILE *in)
157*11be35a1SLionel Sambuc {
158*11be35a1SLionel Sambuc 	char inbuf[1000];
159*11be35a1SLionel Sambuc #	define	MAXF	10
160*11be35a1SLionel Sambuc 	char *f[MAXF];
161*11be35a1SLionel Sambuc 	int nf;
162*11be35a1SLionel Sambuc 	int i;
163*11be35a1SLionel Sambuc 	char erbuf[100];
164*11be35a1SLionel Sambuc 	size_t ne;
165*11be35a1SLionel Sambuc 	const char *badpat = "invalid regular expression";
166*11be35a1SLionel Sambuc #	define	SHORT	10
167*11be35a1SLionel Sambuc 	const char *bpname = "REG_BADPAT";
168*11be35a1SLionel Sambuc 	regex_t re;
169*11be35a1SLionel Sambuc 
170*11be35a1SLionel Sambuc 	while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
171*11be35a1SLionel Sambuc 		line++;
172*11be35a1SLionel Sambuc 		if (inbuf[0] == '#' || inbuf[0] == '\n')
173*11be35a1SLionel Sambuc 			continue;			/* NOTE CONTINUE */
174*11be35a1SLionel Sambuc 		inbuf[strlen(inbuf)-1] = '\0';	/* get rid of stupid \n */
175*11be35a1SLionel Sambuc 		if (debug)
176*11be35a1SLionel Sambuc 			fprintf(stdout, "%d:\n", line);
177*11be35a1SLionel Sambuc 		nf = split(inbuf, f, MAXF, "\t\t");
178*11be35a1SLionel Sambuc 		if (nf < 3) {
179*11be35a1SLionel Sambuc 			fprintf(stderr, "bad input, line %d\n", line);
180*11be35a1SLionel Sambuc 			exit(1);
181*11be35a1SLionel Sambuc 		}
182*11be35a1SLionel Sambuc 		for (i = 0; i < nf; i++)
183*11be35a1SLionel Sambuc 			if (strcmp(f[i], "\"\"") == 0)
184*11be35a1SLionel Sambuc 				f[i] = &empty;
185*11be35a1SLionel Sambuc 		if (nf <= 3)
186*11be35a1SLionel Sambuc 			f[3] = NULL;
187*11be35a1SLionel Sambuc 		if (nf <= 4)
188*11be35a1SLionel Sambuc 			f[4] = NULL;
189*11be35a1SLionel Sambuc 		try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
190*11be35a1SLionel Sambuc 		if (opt('&', f[1]))	/* try with either type of RE */
191*11be35a1SLionel Sambuc 			try(f[0], f[1], f[2], f[3], f[4],
192*11be35a1SLionel Sambuc 					options('c', f[1]) &~ REG_EXTENDED);
193*11be35a1SLionel Sambuc 	}
194*11be35a1SLionel Sambuc 
195*11be35a1SLionel Sambuc 	ne = regerror(REG_BADPAT, NULL, erbuf, sizeof(erbuf));
196*11be35a1SLionel Sambuc 	if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
197*11be35a1SLionel Sambuc 		fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
198*11be35a1SLionel Sambuc 							erbuf, badpat);
199*11be35a1SLionel Sambuc 		status = 1;
200*11be35a1SLionel Sambuc 	}
201*11be35a1SLionel Sambuc 	ne = regerror(REG_BADPAT, NULL, erbuf, (size_t)SHORT);
202*11be35a1SLionel Sambuc 	if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
203*11be35a1SLionel Sambuc 						ne != strlen(badpat)+1) {
204*11be35a1SLionel Sambuc 		fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
205*11be35a1SLionel Sambuc 						erbuf, SHORT-1, badpat);
206*11be35a1SLionel Sambuc 		status = 1;
207*11be35a1SLionel Sambuc 	}
208*11be35a1SLionel Sambuc 	ne = regerror(REG_ITOA|REG_BADPAT, NULL, erbuf, sizeof(erbuf));
209*11be35a1SLionel Sambuc 	if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
210*11be35a1SLionel Sambuc 		fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
211*11be35a1SLionel Sambuc 						erbuf, bpname);
212*11be35a1SLionel Sambuc 		status = 1;
213*11be35a1SLionel Sambuc 	}
214*11be35a1SLionel Sambuc 	re.re_endp = bpname;
215*11be35a1SLionel Sambuc 	ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
216*11be35a1SLionel Sambuc 	if (atoi(erbuf) != (int)REG_BADPAT) {
217*11be35a1SLionel Sambuc 		fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
218*11be35a1SLionel Sambuc 						erbuf, (long)REG_BADPAT);
219*11be35a1SLionel Sambuc 		status = 1;
220*11be35a1SLionel Sambuc 	} else if (ne != strlen(erbuf)+1) {
221*11be35a1SLionel Sambuc 		fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
222*11be35a1SLionel Sambuc 						erbuf, (long)REG_BADPAT);
223*11be35a1SLionel Sambuc 		status = 1;
224*11be35a1SLionel Sambuc 	}
225*11be35a1SLionel Sambuc }
226*11be35a1SLionel Sambuc 
227*11be35a1SLionel Sambuc /*
228*11be35a1SLionel Sambuc  - try - try it, and report on problems
229*11be35a1SLionel Sambuc  == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
230*11be35a1SLionel Sambuc  */
231*11be35a1SLionel Sambuc void
try(char * f0,char * f1,char * f2,char * f3,char * f4,int opts)232*11be35a1SLionel Sambuc try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts)
233*11be35a1SLionel Sambuc {
234*11be35a1SLionel Sambuc 	regex_t re;
235*11be35a1SLionel Sambuc #	define	NSUBS	10
236*11be35a1SLionel Sambuc 	regmatch_t subs[NSUBS];
237*11be35a1SLionel Sambuc #	define	NSHOULD	15
238*11be35a1SLionel Sambuc 	char *should[NSHOULD];
239*11be35a1SLionel Sambuc 	int nshould;
240*11be35a1SLionel Sambuc 	char erbuf[100];
241*11be35a1SLionel Sambuc 	int err;
242*11be35a1SLionel Sambuc 	int len;
243*11be35a1SLionel Sambuc 	const char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
244*11be35a1SLionel Sambuc 	int i;
245*11be35a1SLionel Sambuc 	char *grump;
246*11be35a1SLionel Sambuc 	char f0copy[1000];
247*11be35a1SLionel Sambuc 	char f2copy[1000];
248*11be35a1SLionel Sambuc 
249*11be35a1SLionel Sambuc 	strcpy(f0copy, f0);
250*11be35a1SLionel Sambuc 	re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
251*11be35a1SLionel Sambuc 	fixstr(f0copy);
252*11be35a1SLionel Sambuc 	err = regcomp(&re, f0copy, opts);
253*11be35a1SLionel Sambuc 	if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
254*11be35a1SLionel Sambuc 		/* unexpected error or wrong error */
255*11be35a1SLionel Sambuc 		len = regerror(err, &re, erbuf, sizeof(erbuf));
256*11be35a1SLionel Sambuc 		fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
257*11be35a1SLionel Sambuc 					line, type, eprint(err), len,
258*11be35a1SLionel Sambuc 					(int)sizeof(erbuf), erbuf);
259*11be35a1SLionel Sambuc 		status = 1;
260*11be35a1SLionel Sambuc 	} else if (err == 0 && opt('C', f1)) {
261*11be35a1SLionel Sambuc 		/* unexpected success */
262*11be35a1SLionel Sambuc 		fprintf(stderr, "%d: %s should have given REG_%s\n",
263*11be35a1SLionel Sambuc 						line, type, f2);
264*11be35a1SLionel Sambuc 		status = 1;
265*11be35a1SLionel Sambuc 		err = 1;	/* so we won't try regexec */
266*11be35a1SLionel Sambuc 	}
267*11be35a1SLionel Sambuc 
268*11be35a1SLionel Sambuc 	if (err != 0) {
269*11be35a1SLionel Sambuc 		regfree(&re);
270*11be35a1SLionel Sambuc 		return;
271*11be35a1SLionel Sambuc 	}
272*11be35a1SLionel Sambuc 
273*11be35a1SLionel Sambuc 	strcpy(f2copy, f2);
274*11be35a1SLionel Sambuc 	fixstr(f2copy);
275*11be35a1SLionel Sambuc 
276*11be35a1SLionel Sambuc 	if (options('e', f1)&REG_STARTEND) {
277*11be35a1SLionel Sambuc 		if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
278*11be35a1SLionel Sambuc 			fprintf(stderr, "%d: bad STARTEND syntax\n", line);
279*11be35a1SLionel Sambuc 		subs[0].rm_so = strchr(f2, '(') - f2 + 1;
280*11be35a1SLionel Sambuc 		subs[0].rm_eo = strchr(f2, ')') - f2;
281*11be35a1SLionel Sambuc 	}
282*11be35a1SLionel Sambuc 	err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
283*11be35a1SLionel Sambuc 
284*11be35a1SLionel Sambuc 	if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
285*11be35a1SLionel Sambuc 		/* unexpected error or wrong error */
286*11be35a1SLionel Sambuc 		len = regerror(err, &re, erbuf, sizeof(erbuf));
287*11be35a1SLionel Sambuc 		fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
288*11be35a1SLionel Sambuc 					line, type, eprint(err), len,
289*11be35a1SLionel Sambuc 					(int)sizeof(erbuf), erbuf);
290*11be35a1SLionel Sambuc 		status = 1;
291*11be35a1SLionel Sambuc 	} else if (err != 0) {
292*11be35a1SLionel Sambuc 		/* nothing more to check */
293*11be35a1SLionel Sambuc 	} else if (f3 == NULL) {
294*11be35a1SLionel Sambuc 		/* unexpected success */
295*11be35a1SLionel Sambuc 		fprintf(stderr, "%d: %s exec should have failed\n",
296*11be35a1SLionel Sambuc 						line, type);
297*11be35a1SLionel Sambuc 		status = 1;
298*11be35a1SLionel Sambuc 		err = 1;		/* just on principle */
299*11be35a1SLionel Sambuc 	} else if (opts&REG_NOSUB) {
300*11be35a1SLionel Sambuc 		/* nothing more to check */
301*11be35a1SLionel Sambuc 	} else if ((grump = check(f2, subs[0], f3)) != NULL) {
302*11be35a1SLionel Sambuc 		fprintf(stderr, "%d: %s %s\n", line, type, grump);
303*11be35a1SLionel Sambuc 		status = 1;
304*11be35a1SLionel Sambuc 		err = 1;
305*11be35a1SLionel Sambuc 	}
306*11be35a1SLionel Sambuc 
307*11be35a1SLionel Sambuc 	if (err != 0 || f4 == NULL) {
308*11be35a1SLionel Sambuc 		regfree(&re);
309*11be35a1SLionel Sambuc 		return;
310*11be35a1SLionel Sambuc 	}
311*11be35a1SLionel Sambuc 
312*11be35a1SLionel Sambuc 	for (i = 1; i < NSHOULD; i++)
313*11be35a1SLionel Sambuc 		should[i] = NULL;
314*11be35a1SLionel Sambuc 	nshould = split(f4, &should[1], NSHOULD-1, ",");
315*11be35a1SLionel Sambuc 	if (nshould == 0) {
316*11be35a1SLionel Sambuc 		nshould = 1;
317*11be35a1SLionel Sambuc 		should[1] = &empty;
318*11be35a1SLionel Sambuc 	}
319*11be35a1SLionel Sambuc 	for (i = 1; i < NSUBS; i++) {
320*11be35a1SLionel Sambuc 		grump = check(f2, subs[i], should[i]);
321*11be35a1SLionel Sambuc 		if (grump != NULL) {
322*11be35a1SLionel Sambuc 			fprintf(stderr, "%d: %s $%d %s\n", line,
323*11be35a1SLionel Sambuc 							type, i, grump);
324*11be35a1SLionel Sambuc 			status = 1;
325*11be35a1SLionel Sambuc 			err = 1;
326*11be35a1SLionel Sambuc 		}
327*11be35a1SLionel Sambuc 	}
328*11be35a1SLionel Sambuc 
329*11be35a1SLionel Sambuc 	regfree(&re);
330*11be35a1SLionel Sambuc }
331*11be35a1SLionel Sambuc 
332*11be35a1SLionel Sambuc /*
333*11be35a1SLionel Sambuc  - options - pick options out of a regression-test string
334*11be35a1SLionel Sambuc  == int options(int type, char *s);
335*11be35a1SLionel Sambuc  */
336*11be35a1SLionel Sambuc int
options(int type,char * s)337*11be35a1SLionel Sambuc options(int type, char *s)
338*11be35a1SLionel Sambuc {
339*11be35a1SLionel Sambuc 	char *p;
340*11be35a1SLionel Sambuc 	int o = (type == 'c') ? copts : eopts;
341*11be35a1SLionel Sambuc 	const char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
342*11be35a1SLionel Sambuc 
343*11be35a1SLionel Sambuc 	for (p = s; *p != '\0'; p++)
344*11be35a1SLionel Sambuc 		if (strchr(legal, *p) != NULL)
345*11be35a1SLionel Sambuc 			switch (*p) {
346*11be35a1SLionel Sambuc 			case 'b':
347*11be35a1SLionel Sambuc 				o &= ~REG_EXTENDED;
348*11be35a1SLionel Sambuc 				break;
349*11be35a1SLionel Sambuc 			case 'i':
350*11be35a1SLionel Sambuc 				o |= REG_ICASE;
351*11be35a1SLionel Sambuc 				break;
352*11be35a1SLionel Sambuc 			case 's':
353*11be35a1SLionel Sambuc 				o |= REG_NOSUB;
354*11be35a1SLionel Sambuc 				break;
355*11be35a1SLionel Sambuc 			case 'n':
356*11be35a1SLionel Sambuc 				o |= REG_NEWLINE;
357*11be35a1SLionel Sambuc 				break;
358*11be35a1SLionel Sambuc 			case 'm':
359*11be35a1SLionel Sambuc 				o &= ~REG_EXTENDED;
360*11be35a1SLionel Sambuc 				o |= REG_NOSPEC;
361*11be35a1SLionel Sambuc 				break;
362*11be35a1SLionel Sambuc 			case 'p':
363*11be35a1SLionel Sambuc 				o |= REG_PEND;
364*11be35a1SLionel Sambuc 				break;
365*11be35a1SLionel Sambuc 			case '^':
366*11be35a1SLionel Sambuc 				o |= REG_NOTBOL;
367*11be35a1SLionel Sambuc 				break;
368*11be35a1SLionel Sambuc 			case '$':
369*11be35a1SLionel Sambuc 				o |= REG_NOTEOL;
370*11be35a1SLionel Sambuc 				break;
371*11be35a1SLionel Sambuc 			case '#':
372*11be35a1SLionel Sambuc 				o |= REG_STARTEND;
373*11be35a1SLionel Sambuc 				break;
374*11be35a1SLionel Sambuc 			case 't':	/* trace */
375*11be35a1SLionel Sambuc 				o |= REG_TRACE;
376*11be35a1SLionel Sambuc 				break;
377*11be35a1SLionel Sambuc 			case 'l':	/* force long representation */
378*11be35a1SLionel Sambuc 				o |= REG_LARGE;
379*11be35a1SLionel Sambuc 				break;
380*11be35a1SLionel Sambuc 			case 'r':	/* force backref use */
381*11be35a1SLionel Sambuc 				o |= REG_BACKR;
382*11be35a1SLionel Sambuc 				break;
383*11be35a1SLionel Sambuc 			}
384*11be35a1SLionel Sambuc 	return(o);
385*11be35a1SLionel Sambuc }
386*11be35a1SLionel Sambuc 
387*11be35a1SLionel Sambuc /*
388*11be35a1SLionel Sambuc  - opt - is a particular option in a regression string?
389*11be35a1SLionel Sambuc  == int opt(int c, char *s);
390*11be35a1SLionel Sambuc  */
391*11be35a1SLionel Sambuc int				/* predicate */
opt(int c,char * s)392*11be35a1SLionel Sambuc opt(int c, char *s)
393*11be35a1SLionel Sambuc {
394*11be35a1SLionel Sambuc 	return(strchr(s, c) != NULL);
395*11be35a1SLionel Sambuc }
396*11be35a1SLionel Sambuc 
397*11be35a1SLionel Sambuc /*
398*11be35a1SLionel Sambuc  - fixstr - transform magic characters in strings
399*11be35a1SLionel Sambuc  == void fixstr(char *p);
400*11be35a1SLionel Sambuc  */
401*11be35a1SLionel Sambuc void
fixstr(char * p)402*11be35a1SLionel Sambuc fixstr(char *p)
403*11be35a1SLionel Sambuc {
404*11be35a1SLionel Sambuc 	if (p == NULL)
405*11be35a1SLionel Sambuc 		return;
406*11be35a1SLionel Sambuc 
407*11be35a1SLionel Sambuc 	for (; *p != '\0'; p++)
408*11be35a1SLionel Sambuc 		if (*p == 'N')
409*11be35a1SLionel Sambuc 			*p = '\n';
410*11be35a1SLionel Sambuc 		else if (*p == 'T')
411*11be35a1SLionel Sambuc 			*p = '\t';
412*11be35a1SLionel Sambuc 		else if (*p == 'S')
413*11be35a1SLionel Sambuc 			*p = ' ';
414*11be35a1SLionel Sambuc 		else if (*p == 'Z')
415*11be35a1SLionel Sambuc 			*p = '\0';
416*11be35a1SLionel Sambuc }
417*11be35a1SLionel Sambuc 
418*11be35a1SLionel Sambuc /*
419*11be35a1SLionel Sambuc  * check - check a substring match
420*11be35a1SLionel Sambuc  */
421*11be35a1SLionel Sambuc char *				/* NULL or complaint */
check(char * str,regmatch_t sub,char * should)422*11be35a1SLionel Sambuc check(char *str, regmatch_t sub, char *should)
423*11be35a1SLionel Sambuc {
424*11be35a1SLionel Sambuc 	int len;
425*11be35a1SLionel Sambuc 	int shlen;
426*11be35a1SLionel Sambuc 	char *p;
427*11be35a1SLionel Sambuc 	static char grump[500];
428*11be35a1SLionel Sambuc 	char *at = NULL;
429*11be35a1SLionel Sambuc 
430*11be35a1SLionel Sambuc 	if (should != NULL && strcmp(should, "-") == 0)
431*11be35a1SLionel Sambuc 		should = NULL;
432*11be35a1SLionel Sambuc 	if (should != NULL && should[0] == '@') {
433*11be35a1SLionel Sambuc 		at = should + 1;
434*11be35a1SLionel Sambuc 		should = &empty;
435*11be35a1SLionel Sambuc 	}
436*11be35a1SLionel Sambuc 
437*11be35a1SLionel Sambuc 	/* check rm_so and rm_eo for consistency */
438*11be35a1SLionel Sambuc 	if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
439*11be35a1SLionel Sambuc 				(sub.rm_so != -1 && sub.rm_eo == -1) ||
440*11be35a1SLionel Sambuc 				(sub.rm_so != -1 && sub.rm_so < 0) ||
441*11be35a1SLionel Sambuc 				(sub.rm_eo != -1 && sub.rm_eo < 0) ) {
442*11be35a1SLionel Sambuc 		sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
443*11be35a1SLionel Sambuc 							(long)sub.rm_eo);
444*11be35a1SLionel Sambuc 		return(grump);
445*11be35a1SLionel Sambuc 	}
446*11be35a1SLionel Sambuc 
447*11be35a1SLionel Sambuc 	/* check for no match */
448*11be35a1SLionel Sambuc 	if (sub.rm_so == -1) {
449*11be35a1SLionel Sambuc 		if (should == NULL)
450*11be35a1SLionel Sambuc 			return(NULL);
451*11be35a1SLionel Sambuc 		else {
452*11be35a1SLionel Sambuc 			sprintf(grump, "did not match");
453*11be35a1SLionel Sambuc 			return(grump);
454*11be35a1SLionel Sambuc 		}
455*11be35a1SLionel Sambuc 	}
456*11be35a1SLionel Sambuc 
457*11be35a1SLionel Sambuc 	/* check for in range */
458*11be35a1SLionel Sambuc 	if (sub.rm_eo > (ssize_t)strlen(str)) {
459*11be35a1SLionel Sambuc 		sprintf(grump, "start %ld end %ld, past end of string",
460*11be35a1SLionel Sambuc 					(long)sub.rm_so, (long)sub.rm_eo);
461*11be35a1SLionel Sambuc 		return(grump);
462*11be35a1SLionel Sambuc 	}
463*11be35a1SLionel Sambuc 
464*11be35a1SLionel Sambuc 	len = (int)(sub.rm_eo - sub.rm_so);
465*11be35a1SLionel Sambuc 	p = str + sub.rm_so;
466*11be35a1SLionel Sambuc 
467*11be35a1SLionel Sambuc 	/* check for not supposed to match */
468*11be35a1SLionel Sambuc 	if (should == NULL) {
469*11be35a1SLionel Sambuc 		sprintf(grump, "matched `%.*s'", len, p);
470*11be35a1SLionel Sambuc 		return(grump);
471*11be35a1SLionel Sambuc 	}
472*11be35a1SLionel Sambuc 
473*11be35a1SLionel Sambuc 	/* check for wrong match */
474*11be35a1SLionel Sambuc 	shlen = (int)strlen(should);
475*11be35a1SLionel Sambuc 	if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
476*11be35a1SLionel Sambuc 		sprintf(grump, "matched `%.*s' instead", len, p);
477*11be35a1SLionel Sambuc 		return(grump);
478*11be35a1SLionel Sambuc 	}
479*11be35a1SLionel Sambuc 	if (shlen > 0)
480*11be35a1SLionel Sambuc 		return(NULL);
481*11be35a1SLionel Sambuc 
482*11be35a1SLionel Sambuc 	/* check null match in right place */
483*11be35a1SLionel Sambuc 	if (at == NULL)
484*11be35a1SLionel Sambuc 		return(NULL);
485*11be35a1SLionel Sambuc 	shlen = strlen(at);
486*11be35a1SLionel Sambuc 	if (shlen == 0)
487*11be35a1SLionel Sambuc 		shlen = 1;	/* force check for end-of-string */
488*11be35a1SLionel Sambuc 	if (strncmp(p, at, shlen) != 0) {
489*11be35a1SLionel Sambuc 		sprintf(grump, "matched null at `%.20s'", p);
490*11be35a1SLionel Sambuc 		return(grump);
491*11be35a1SLionel Sambuc 	}
492*11be35a1SLionel Sambuc 	return(NULL);
493*11be35a1SLionel Sambuc }
494*11be35a1SLionel Sambuc 
495*11be35a1SLionel Sambuc /*
496*11be35a1SLionel Sambuc  * eprint - convert error number to name
497*11be35a1SLionel Sambuc  */
498*11be35a1SLionel Sambuc static char *
eprint(int err)499*11be35a1SLionel Sambuc eprint(int err)
500*11be35a1SLionel Sambuc {
501*11be35a1SLionel Sambuc 	static char epbuf[100];
502*11be35a1SLionel Sambuc 	size_t len;
503*11be35a1SLionel Sambuc 
504*11be35a1SLionel Sambuc 	len = regerror(REG_ITOA|err, NULL, epbuf, sizeof(epbuf));
505*11be35a1SLionel Sambuc 	assert(len <= sizeof(epbuf));
506*11be35a1SLionel Sambuc 	return(epbuf);
507*11be35a1SLionel Sambuc }
508*11be35a1SLionel Sambuc 
509*11be35a1SLionel Sambuc /*
510*11be35a1SLionel Sambuc  * efind - convert error name to number
511*11be35a1SLionel Sambuc  */
512*11be35a1SLionel Sambuc static int
efind(char * name)513*11be35a1SLionel Sambuc efind(char *name)
514*11be35a1SLionel Sambuc {
515*11be35a1SLionel Sambuc 	static char efbuf[100];
516*11be35a1SLionel Sambuc 	regex_t re;
517*11be35a1SLionel Sambuc 
518*11be35a1SLionel Sambuc 	sprintf(efbuf, "REG_%s", name);
519*11be35a1SLionel Sambuc 	assert(strlen(efbuf) < sizeof(efbuf));
520*11be35a1SLionel Sambuc 	re.re_endp = efbuf;
521*11be35a1SLionel Sambuc 	(void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
522*11be35a1SLionel Sambuc 	return(atoi(efbuf));
523*11be35a1SLionel Sambuc }
524