xref: /freebsd/contrib/netbsd-tests/lib/libc/regex/main.c (revision 4f1efa309ca48a088595dd57969ae6a397dd49d1)
157718be8SEnji Cooper /*	$NetBSD: main.c,v 1.2 2011/09/16 16:13:18 plunky Exp $	*/
257718be8SEnji Cooper 
357718be8SEnji Cooper /*-
457718be8SEnji Cooper  * Copyright (c) 1993 The NetBSD Foundation, Inc.
557718be8SEnji Cooper  * All rights reserved.
657718be8SEnji Cooper  *
757718be8SEnji Cooper  * Redistribution and use in source and binary forms, with or without
857718be8SEnji Cooper  * modification, are permitted provided that the following conditions
957718be8SEnji Cooper  * are met:
1057718be8SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
1157718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
1257718be8SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
1357718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
1457718be8SEnji Cooper  *    documentation and/or other materials provided with the distribution.
1557718be8SEnji Cooper  *
1657718be8SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1757718be8SEnji Cooper  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1857718be8SEnji Cooper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1957718be8SEnji Cooper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2057718be8SEnji Cooper  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2157718be8SEnji Cooper  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2257718be8SEnji Cooper  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2357718be8SEnji Cooper  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2457718be8SEnji Cooper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2557718be8SEnji Cooper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2657718be8SEnji Cooper  * POSSIBILITY OF SUCH DAMAGE.
2757718be8SEnji Cooper  */
2857718be8SEnji Cooper 
2957718be8SEnji Cooper #include <assert.h>
3057718be8SEnji Cooper #include <regex.h>
3157718be8SEnji Cooper #include <stdio.h>
3257718be8SEnji Cooper #include <stdlib.h>
3357718be8SEnji Cooper #include <string.h>
3457718be8SEnji Cooper #include <unistd.h>
3557718be8SEnji Cooper 
3657718be8SEnji Cooper #include <sys/types.h>
3757718be8SEnji Cooper 
3857718be8SEnji Cooper #include "test_regex.h"
3957718be8SEnji Cooper 
4057718be8SEnji Cooper char *progname;
4157718be8SEnji Cooper int debug = 0;
4257718be8SEnji Cooper int line = 0;
4357718be8SEnji Cooper int status = 0;
4457718be8SEnji Cooper 
4557718be8SEnji Cooper int copts = REG_EXTENDED;
4657718be8SEnji Cooper int eopts = 0;
4757718be8SEnji Cooper regoff_t startoff = 0;
4857718be8SEnji Cooper regoff_t endoff = 0;
4957718be8SEnji Cooper 
5057718be8SEnji Cooper static char empty = '\0';
5157718be8SEnji Cooper 
5257718be8SEnji Cooper static char *eprint(int);
5357718be8SEnji Cooper static int efind(char *);
5457718be8SEnji Cooper 
5557718be8SEnji Cooper /*
5657718be8SEnji Cooper  * main - do the simple case, hand off to regress() for regression
5757718be8SEnji Cooper  */
5857718be8SEnji Cooper int
main(int argc,char * argv[])5957718be8SEnji Cooper main(int argc, char *argv[])
6057718be8SEnji Cooper {
6157718be8SEnji Cooper 	regex_t re;
6257718be8SEnji Cooper #	define	NS	10
6357718be8SEnji Cooper 	regmatch_t subs[NS];
6457718be8SEnji Cooper 	char erbuf[100];
6557718be8SEnji Cooper 	int err;
6657718be8SEnji Cooper 	size_t len;
6757718be8SEnji Cooper 	int c;
6857718be8SEnji Cooper 	int errflg = 0;
6957718be8SEnji Cooper 	int i;
7057718be8SEnji Cooper 	extern int optind;
7157718be8SEnji Cooper 	extern char *optarg;
7257718be8SEnji Cooper 
7357718be8SEnji Cooper 	progname = argv[0];
7457718be8SEnji Cooper 
7557718be8SEnji Cooper 	while ((c = getopt(argc, argv, "c:e:S:E:x")) != -1)
7657718be8SEnji Cooper 		switch (c) {
7757718be8SEnji Cooper 		case 'c':	/* compile options */
7857718be8SEnji Cooper 			copts = options('c', optarg);
7957718be8SEnji Cooper 			break;
8057718be8SEnji Cooper 		case 'e':	/* execute options */
8157718be8SEnji Cooper 			eopts = options('e', optarg);
8257718be8SEnji Cooper 			break;
8357718be8SEnji Cooper 		case 'S':	/* start offset */
8457718be8SEnji Cooper 			startoff = (regoff_t)atoi(optarg);
8557718be8SEnji Cooper 			break;
8657718be8SEnji Cooper 		case 'E':	/* end offset */
8757718be8SEnji Cooper 			endoff = (regoff_t)atoi(optarg);
8857718be8SEnji Cooper 			break;
8957718be8SEnji Cooper 		case 'x':	/* Debugging. */
9057718be8SEnji Cooper 			debug++;
9157718be8SEnji Cooper 			break;
9257718be8SEnji Cooper 		case '?':
9357718be8SEnji Cooper 		default:
9457718be8SEnji Cooper 			errflg++;
9557718be8SEnji Cooper 			break;
9657718be8SEnji Cooper 		}
9757718be8SEnji Cooper 	if (errflg) {
9857718be8SEnji Cooper 		fprintf(stderr, "usage: %s ", progname);
9957718be8SEnji Cooper 		fprintf(stderr, "[-c copt][-C][-d] [re]\n");
10057718be8SEnji Cooper 		exit(2);
10157718be8SEnji Cooper 	}
10257718be8SEnji Cooper 
10357718be8SEnji Cooper 	if (optind >= argc) {
10457718be8SEnji Cooper 		regress(stdin);
10557718be8SEnji Cooper 		exit(status);
10657718be8SEnji Cooper 	}
10757718be8SEnji Cooper 
10857718be8SEnji Cooper 	err = regcomp(&re, argv[optind++], copts);
10957718be8SEnji Cooper 	if (err) {
11057718be8SEnji Cooper 		len = regerror(err, &re, erbuf, sizeof(erbuf));
11157718be8SEnji Cooper 		fprintf(stderr, "error %s, %zd/%zd `%s'\n",
11257718be8SEnji Cooper 			eprint(err), len, (size_t)sizeof(erbuf), erbuf);
11357718be8SEnji Cooper 		exit(status);
11457718be8SEnji Cooper 	}
11557718be8SEnji Cooper 	regprint(&re, stdout);
11657718be8SEnji Cooper 
11757718be8SEnji Cooper 	if (optind >= argc) {
11857718be8SEnji Cooper 		regfree(&re);
11957718be8SEnji Cooper 		exit(status);
12057718be8SEnji Cooper 	}
12157718be8SEnji Cooper 
12257718be8SEnji Cooper 	if (eopts&REG_STARTEND) {
12357718be8SEnji Cooper 		subs[0].rm_so = startoff;
12457718be8SEnji Cooper 		subs[0].rm_eo = strlen(argv[optind]) - endoff;
12557718be8SEnji Cooper 	}
12657718be8SEnji Cooper 	err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
12757718be8SEnji Cooper 	if (err) {
12857718be8SEnji Cooper 		len = regerror(err, &re, erbuf, sizeof(erbuf));
12957718be8SEnji Cooper 		fprintf(stderr, "error %s, %zd/%zd `%s'\n",
13057718be8SEnji Cooper 			eprint(err), len, (size_t)sizeof(erbuf), erbuf);
13157718be8SEnji Cooper 		exit(status);
13257718be8SEnji Cooper 	}
13357718be8SEnji Cooper 	if (!(copts&REG_NOSUB)) {
13457718be8SEnji Cooper 		len = (int)(subs[0].rm_eo - subs[0].rm_so);
13557718be8SEnji Cooper 		if (subs[0].rm_so != -1) {
13657718be8SEnji Cooper 			if (len != 0)
13757718be8SEnji Cooper 				printf("match `%.*s'\n", (int)len,
13857718be8SEnji Cooper 					argv[optind] + subs[0].rm_so);
13957718be8SEnji Cooper 			else
14057718be8SEnji Cooper 				printf("match `'@%.1s\n",
14157718be8SEnji Cooper 					argv[optind] + subs[0].rm_so);
14257718be8SEnji Cooper 		}
14357718be8SEnji Cooper 		for (i = 1; i < NS; i++)
14457718be8SEnji Cooper 			if (subs[i].rm_so != -1)
14557718be8SEnji Cooper 				printf("(%d) `%.*s'\n", i,
14657718be8SEnji Cooper 					(int)(subs[i].rm_eo - subs[i].rm_so),
14757718be8SEnji Cooper 					argv[optind] + subs[i].rm_so);
14857718be8SEnji Cooper 	}
14957718be8SEnji Cooper 	exit(status);
15057718be8SEnji Cooper }
15157718be8SEnji Cooper 
15257718be8SEnji Cooper /*
15357718be8SEnji Cooper  * regress - main loop of regression test
15457718be8SEnji Cooper  */
15557718be8SEnji Cooper void
regress(FILE * in)15657718be8SEnji Cooper regress(FILE *in)
15757718be8SEnji Cooper {
15857718be8SEnji Cooper 	char inbuf[1000];
15957718be8SEnji Cooper #	define	MAXF	10
16057718be8SEnji Cooper 	char *f[MAXF];
16157718be8SEnji Cooper 	int nf;
16257718be8SEnji Cooper 	int i;
16357718be8SEnji Cooper 	char erbuf[100];
16457718be8SEnji Cooper 	size_t ne;
16557718be8SEnji Cooper 	const char *badpat = "invalid regular expression";
16657718be8SEnji Cooper #	define	SHORT	10
16757718be8SEnji Cooper 	const char *bpname = "REG_BADPAT";
16857718be8SEnji Cooper 	regex_t re;
16957718be8SEnji Cooper 
17057718be8SEnji Cooper 	while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
17157718be8SEnji Cooper 		line++;
17257718be8SEnji Cooper 		if (inbuf[0] == '#' || inbuf[0] == '\n')
17357718be8SEnji Cooper 			continue;			/* NOTE CONTINUE */
17457718be8SEnji Cooper 		inbuf[strlen(inbuf)-1] = '\0';	/* get rid of stupid \n */
17557718be8SEnji Cooper 		if (debug)
17657718be8SEnji Cooper 			fprintf(stdout, "%d:\n", line);
17757718be8SEnji Cooper 		nf = split(inbuf, f, MAXF, "\t\t");
17857718be8SEnji Cooper 		if (nf < 3) {
17957718be8SEnji Cooper 			fprintf(stderr, "bad input, line %d\n", line);
18057718be8SEnji Cooper 			exit(1);
18157718be8SEnji Cooper 		}
18257718be8SEnji Cooper 		for (i = 0; i < nf; i++)
18357718be8SEnji Cooper 			if (strcmp(f[i], "\"\"") == 0)
18457718be8SEnji Cooper 				f[i] = &empty;
18557718be8SEnji Cooper 		if (nf <= 3)
18657718be8SEnji Cooper 			f[3] = NULL;
18757718be8SEnji Cooper 		if (nf <= 4)
18857718be8SEnji Cooper 			f[4] = NULL;
18957718be8SEnji Cooper 		try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
19057718be8SEnji Cooper 		if (opt('&', f[1]))	/* try with either type of RE */
19157718be8SEnji Cooper 			try(f[0], f[1], f[2], f[3], f[4],
19257718be8SEnji Cooper 					options('c', f[1]) &~ REG_EXTENDED);
19357718be8SEnji Cooper 	}
19457718be8SEnji Cooper 
19557718be8SEnji Cooper 	ne = regerror(REG_BADPAT, NULL, erbuf, sizeof(erbuf));
19657718be8SEnji Cooper 	if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
19757718be8SEnji Cooper 		fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
19857718be8SEnji Cooper 							erbuf, badpat);
19957718be8SEnji Cooper 		status = 1;
20057718be8SEnji Cooper 	}
20157718be8SEnji Cooper 	ne = regerror(REG_BADPAT, NULL, erbuf, (size_t)SHORT);
20257718be8SEnji Cooper 	if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
20357718be8SEnji Cooper 						ne != strlen(badpat)+1) {
20457718be8SEnji Cooper 		fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
20557718be8SEnji Cooper 						erbuf, SHORT-1, badpat);
20657718be8SEnji Cooper 		status = 1;
20757718be8SEnji Cooper 	}
20857718be8SEnji Cooper 	ne = regerror(REG_ITOA|REG_BADPAT, NULL, erbuf, sizeof(erbuf));
20957718be8SEnji Cooper 	if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
21057718be8SEnji Cooper 		fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
21157718be8SEnji Cooper 						erbuf, bpname);
21257718be8SEnji Cooper 		status = 1;
21357718be8SEnji Cooper 	}
21457718be8SEnji Cooper 	re.re_endp = bpname;
21557718be8SEnji Cooper 	ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
21657718be8SEnji Cooper 	if (atoi(erbuf) != (int)REG_BADPAT) {
21757718be8SEnji Cooper 		fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
21857718be8SEnji Cooper 						erbuf, (long)REG_BADPAT);
21957718be8SEnji Cooper 		status = 1;
22057718be8SEnji Cooper 	} else if (ne != strlen(erbuf)+1) {
22157718be8SEnji Cooper 		fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
22257718be8SEnji Cooper 						erbuf, (long)REG_BADPAT);
22357718be8SEnji Cooper 		status = 1;
22457718be8SEnji Cooper 	}
22557718be8SEnji Cooper }
22657718be8SEnji Cooper 
22757718be8SEnji Cooper /*
22857718be8SEnji Cooper  - try - try it, and report on problems
22957718be8SEnji Cooper  == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
23057718be8SEnji Cooper  */
23157718be8SEnji Cooper void
try(char * f0,char * f1,char * f2,char * f3,char * f4,int opts)23257718be8SEnji Cooper try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts)
23357718be8SEnji Cooper {
23457718be8SEnji Cooper 	regex_t re;
23557718be8SEnji Cooper #	define	NSUBS	10
23657718be8SEnji Cooper 	regmatch_t subs[NSUBS];
23757718be8SEnji Cooper #	define	NSHOULD	15
23857718be8SEnji Cooper 	char *should[NSHOULD];
23957718be8SEnji Cooper 	int nshould;
24057718be8SEnji Cooper 	char erbuf[100];
24157718be8SEnji Cooper 	int err;
24257718be8SEnji Cooper 	int len;
24357718be8SEnji Cooper 	const char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
24457718be8SEnji Cooper 	int i;
24557718be8SEnji Cooper 	char *grump;
24657718be8SEnji Cooper 	char f0copy[1000];
24757718be8SEnji Cooper 	char f2copy[1000];
24857718be8SEnji Cooper 
24957718be8SEnji Cooper 	strcpy(f0copy, f0);
25057718be8SEnji Cooper 	re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
25157718be8SEnji Cooper 	fixstr(f0copy);
25257718be8SEnji Cooper 	err = regcomp(&re, f0copy, opts);
25357718be8SEnji Cooper 	if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
25457718be8SEnji Cooper 		/* unexpected error or wrong error */
25557718be8SEnji Cooper 		len = regerror(err, &re, erbuf, sizeof(erbuf));
25657718be8SEnji Cooper 		fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
25757718be8SEnji Cooper 					line, type, eprint(err), len,
25857718be8SEnji Cooper 					(int)sizeof(erbuf), erbuf);
25957718be8SEnji Cooper 		status = 1;
26057718be8SEnji Cooper 	} else if (err == 0 && opt('C', f1)) {
26157718be8SEnji Cooper 		/* unexpected success */
26257718be8SEnji Cooper 		fprintf(stderr, "%d: %s should have given REG_%s\n",
26357718be8SEnji Cooper 						line, type, f2);
26457718be8SEnji Cooper 		status = 1;
26557718be8SEnji Cooper 		err = 1;	/* so we won't try regexec */
26657718be8SEnji Cooper 	}
26757718be8SEnji Cooper 
26857718be8SEnji Cooper 	if (err != 0) {
26957718be8SEnji Cooper 		regfree(&re);
27057718be8SEnji Cooper 		return;
27157718be8SEnji Cooper 	}
27257718be8SEnji Cooper 
27357718be8SEnji Cooper 	strcpy(f2copy, f2);
27457718be8SEnji Cooper 	fixstr(f2copy);
27557718be8SEnji Cooper 
27657718be8SEnji Cooper 	if (options('e', f1)&REG_STARTEND) {
27757718be8SEnji Cooper 		if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
27857718be8SEnji Cooper 			fprintf(stderr, "%d: bad STARTEND syntax\n", line);
27957718be8SEnji Cooper 		subs[0].rm_so = strchr(f2, '(') - f2 + 1;
28057718be8SEnji Cooper 		subs[0].rm_eo = strchr(f2, ')') - f2;
28157718be8SEnji Cooper 	}
28257718be8SEnji Cooper 	err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
28357718be8SEnji Cooper 
28457718be8SEnji Cooper 	if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
28557718be8SEnji Cooper 		/* unexpected error or wrong error */
28657718be8SEnji Cooper 		len = regerror(err, &re, erbuf, sizeof(erbuf));
28757718be8SEnji Cooper 		fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
28857718be8SEnji Cooper 					line, type, eprint(err), len,
28957718be8SEnji Cooper 					(int)sizeof(erbuf), erbuf);
29057718be8SEnji Cooper 		status = 1;
29157718be8SEnji Cooper 	} else if (err != 0) {
29257718be8SEnji Cooper 		/* nothing more to check */
29357718be8SEnji Cooper 	} else if (f3 == NULL) {
29457718be8SEnji Cooper 		/* unexpected success */
29557718be8SEnji Cooper 		fprintf(stderr, "%d: %s exec should have failed\n",
29657718be8SEnji Cooper 						line, type);
29757718be8SEnji Cooper 		status = 1;
29857718be8SEnji Cooper 		err = 1;		/* just on principle */
29957718be8SEnji Cooper 	} else if (opts&REG_NOSUB) {
30057718be8SEnji Cooper 		/* nothing more to check */
30157718be8SEnji Cooper 	} else if ((grump = check(f2, subs[0], f3)) != NULL) {
30257718be8SEnji Cooper 		fprintf(stderr, "%d: %s %s\n", line, type, grump);
30357718be8SEnji Cooper 		status = 1;
30457718be8SEnji Cooper 		err = 1;
30557718be8SEnji Cooper 	}
30657718be8SEnji Cooper 
30757718be8SEnji Cooper 	if (err != 0 || f4 == NULL) {
30857718be8SEnji Cooper 		regfree(&re);
30957718be8SEnji Cooper 		return;
31057718be8SEnji Cooper 	}
31157718be8SEnji Cooper 
31257718be8SEnji Cooper 	for (i = 1; i < NSHOULD; i++)
31357718be8SEnji Cooper 		should[i] = NULL;
31457718be8SEnji Cooper 	nshould = split(f4, &should[1], NSHOULD-1, ",");
31557718be8SEnji Cooper 	if (nshould == 0) {
31657718be8SEnji Cooper 		nshould = 1;
31757718be8SEnji Cooper 		should[1] = &empty;
31857718be8SEnji Cooper 	}
31957718be8SEnji Cooper 	for (i = 1; i < NSUBS; i++) {
32057718be8SEnji Cooper 		grump = check(f2, subs[i], should[i]);
32157718be8SEnji Cooper 		if (grump != NULL) {
32257718be8SEnji Cooper 			fprintf(stderr, "%d: %s $%d %s\n", line,
32357718be8SEnji Cooper 							type, i, grump);
32457718be8SEnji Cooper 			status = 1;
32557718be8SEnji Cooper 			err = 1;
32657718be8SEnji Cooper 		}
32757718be8SEnji Cooper 	}
32857718be8SEnji Cooper 
32957718be8SEnji Cooper 	regfree(&re);
33057718be8SEnji Cooper }
33157718be8SEnji Cooper 
33257718be8SEnji Cooper /*
33357718be8SEnji Cooper  - options - pick options out of a regression-test string
33457718be8SEnji Cooper  == int options(int type, char *s);
33557718be8SEnji Cooper  */
33657718be8SEnji Cooper int
options(int type,char * s)33757718be8SEnji Cooper options(int type, char *s)
33857718be8SEnji Cooper {
33957718be8SEnji Cooper 	char *p;
34057718be8SEnji Cooper 	int o = (type == 'c') ? copts : eopts;
341*4f1efa30SKyle Evans 	const char *legal = (type == 'c') ? "bisnmpP" : "^$#tl";
34257718be8SEnji Cooper 
34357718be8SEnji Cooper 	for (p = s; *p != '\0'; p++)
34457718be8SEnji Cooper 		if (strchr(legal, *p) != NULL)
34557718be8SEnji Cooper 			switch (*p) {
34657718be8SEnji Cooper 			case 'b':
34757718be8SEnji Cooper 				o &= ~REG_EXTENDED;
34857718be8SEnji Cooper 				break;
34957718be8SEnji Cooper 			case 'i':
35057718be8SEnji Cooper 				o |= REG_ICASE;
35157718be8SEnji Cooper 				break;
35257718be8SEnji Cooper 			case 's':
35357718be8SEnji Cooper 				o |= REG_NOSUB;
35457718be8SEnji Cooper 				break;
35557718be8SEnji Cooper 			case 'n':
35657718be8SEnji Cooper 				o |= REG_NEWLINE;
35757718be8SEnji Cooper 				break;
35857718be8SEnji Cooper 			case 'm':
35957718be8SEnji Cooper 				o &= ~REG_EXTENDED;
36057718be8SEnji Cooper 				o |= REG_NOSPEC;
36157718be8SEnji Cooper 				break;
36257718be8SEnji Cooper 			case 'p':
36357718be8SEnji Cooper 				o |= REG_PEND;
36457718be8SEnji Cooper 				break;
365*4f1efa30SKyle Evans 			case 'P':
366*4f1efa30SKyle Evans 				o |= REG_POSIX;
367*4f1efa30SKyle Evans 				break;
36857718be8SEnji Cooper 			case '^':
36957718be8SEnji Cooper 				o |= REG_NOTBOL;
37057718be8SEnji Cooper 				break;
37157718be8SEnji Cooper 			case '$':
37257718be8SEnji Cooper 				o |= REG_NOTEOL;
37357718be8SEnji Cooper 				break;
37457718be8SEnji Cooper 			case '#':
37557718be8SEnji Cooper 				o |= REG_STARTEND;
37657718be8SEnji Cooper 				break;
37757718be8SEnji Cooper 			case 't':	/* trace */
37857718be8SEnji Cooper 				o |= REG_TRACE;
37957718be8SEnji Cooper 				break;
38057718be8SEnji Cooper 			case 'l':	/* force long representation */
38157718be8SEnji Cooper 				o |= REG_LARGE;
38257718be8SEnji Cooper 				break;
38357718be8SEnji Cooper 			case 'r':	/* force backref use */
38457718be8SEnji Cooper 				o |= REG_BACKR;
38557718be8SEnji Cooper 				break;
38657718be8SEnji Cooper 			}
38757718be8SEnji Cooper 	return(o);
38857718be8SEnji Cooper }
38957718be8SEnji Cooper 
39057718be8SEnji Cooper /*
39157718be8SEnji Cooper  - opt - is a particular option in a regression string?
39257718be8SEnji Cooper  == int opt(int c, char *s);
39357718be8SEnji Cooper  */
39457718be8SEnji Cooper int				/* predicate */
opt(int c,char * s)39557718be8SEnji Cooper opt(int c, char *s)
39657718be8SEnji Cooper {
39757718be8SEnji Cooper 	return(strchr(s, c) != NULL);
39857718be8SEnji Cooper }
39957718be8SEnji Cooper 
40057718be8SEnji Cooper /*
40157718be8SEnji Cooper  - fixstr - transform magic characters in strings
40257718be8SEnji Cooper  == void fixstr(char *p);
40357718be8SEnji Cooper  */
40457718be8SEnji Cooper void
fixstr(char * p)40557718be8SEnji Cooper fixstr(char *p)
40657718be8SEnji Cooper {
40757718be8SEnji Cooper 	if (p == NULL)
40857718be8SEnji Cooper 		return;
40957718be8SEnji Cooper 
41057718be8SEnji Cooper 	for (; *p != '\0'; p++)
41157718be8SEnji Cooper 		if (*p == 'N')
41257718be8SEnji Cooper 			*p = '\n';
41357718be8SEnji Cooper 		else if (*p == 'T')
41457718be8SEnji Cooper 			*p = '\t';
41557718be8SEnji Cooper 		else if (*p == 'S')
41657718be8SEnji Cooper 			*p = ' ';
41757718be8SEnji Cooper 		else if (*p == 'Z')
41857718be8SEnji Cooper 			*p = '\0';
41957718be8SEnji Cooper }
42057718be8SEnji Cooper 
42157718be8SEnji Cooper /*
42257718be8SEnji Cooper  * check - check a substring match
42357718be8SEnji Cooper  */
42457718be8SEnji Cooper char *				/* NULL or complaint */
check(char * str,regmatch_t sub,char * should)42557718be8SEnji Cooper check(char *str, regmatch_t sub, char *should)
42657718be8SEnji Cooper {
42757718be8SEnji Cooper 	int len;
42857718be8SEnji Cooper 	int shlen;
42957718be8SEnji Cooper 	char *p;
43057718be8SEnji Cooper 	static char grump[500];
43157718be8SEnji Cooper 	char *at = NULL;
43257718be8SEnji Cooper 
43357718be8SEnji Cooper 	if (should != NULL && strcmp(should, "-") == 0)
43457718be8SEnji Cooper 		should = NULL;
43557718be8SEnji Cooper 	if (should != NULL && should[0] == '@') {
43657718be8SEnji Cooper 		at = should + 1;
43757718be8SEnji Cooper 		should = &empty;
43857718be8SEnji Cooper 	}
43957718be8SEnji Cooper 
44057718be8SEnji Cooper 	/* check rm_so and rm_eo for consistency */
44157718be8SEnji Cooper 	if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
44257718be8SEnji Cooper 				(sub.rm_so != -1 && sub.rm_eo == -1) ||
44357718be8SEnji Cooper 				(sub.rm_so != -1 && sub.rm_so < 0) ||
44457718be8SEnji Cooper 				(sub.rm_eo != -1 && sub.rm_eo < 0) ) {
44557718be8SEnji Cooper 		sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
44657718be8SEnji Cooper 							(long)sub.rm_eo);
44757718be8SEnji Cooper 		return(grump);
44857718be8SEnji Cooper 	}
44957718be8SEnji Cooper 
45057718be8SEnji Cooper 	/* check for no match */
45157718be8SEnji Cooper 	if (sub.rm_so == -1) {
45257718be8SEnji Cooper 		if (should == NULL)
45357718be8SEnji Cooper 			return(NULL);
45457718be8SEnji Cooper 		else {
45557718be8SEnji Cooper 			sprintf(grump, "did not match");
45657718be8SEnji Cooper 			return(grump);
45757718be8SEnji Cooper 		}
45857718be8SEnji Cooper 	}
45957718be8SEnji Cooper 
46057718be8SEnji Cooper 	/* check for in range */
46157718be8SEnji Cooper 	if (sub.rm_eo > (ssize_t)strlen(str)) {
46257718be8SEnji Cooper 		sprintf(grump, "start %ld end %ld, past end of string",
46357718be8SEnji Cooper 					(long)sub.rm_so, (long)sub.rm_eo);
46457718be8SEnji Cooper 		return(grump);
46557718be8SEnji Cooper 	}
46657718be8SEnji Cooper 
46757718be8SEnji Cooper 	len = (int)(sub.rm_eo - sub.rm_so);
46857718be8SEnji Cooper 	p = str + sub.rm_so;
46957718be8SEnji Cooper 
47057718be8SEnji Cooper 	/* check for not supposed to match */
47157718be8SEnji Cooper 	if (should == NULL) {
47257718be8SEnji Cooper 		sprintf(grump, "matched `%.*s'", len, p);
47357718be8SEnji Cooper 		return(grump);
47457718be8SEnji Cooper 	}
47557718be8SEnji Cooper 
47657718be8SEnji Cooper 	/* check for wrong match */
47757718be8SEnji Cooper 	shlen = (int)strlen(should);
47857718be8SEnji Cooper 	if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
47957718be8SEnji Cooper 		sprintf(grump, "matched `%.*s' instead", len, p);
48057718be8SEnji Cooper 		return(grump);
48157718be8SEnji Cooper 	}
48257718be8SEnji Cooper 	if (shlen > 0)
48357718be8SEnji Cooper 		return(NULL);
48457718be8SEnji Cooper 
48557718be8SEnji Cooper 	/* check null match in right place */
48657718be8SEnji Cooper 	if (at == NULL)
48757718be8SEnji Cooper 		return(NULL);
48857718be8SEnji Cooper 	shlen = strlen(at);
48957718be8SEnji Cooper 	if (shlen == 0)
49057718be8SEnji Cooper 		shlen = 1;	/* force check for end-of-string */
49157718be8SEnji Cooper 	if (strncmp(p, at, shlen) != 0) {
49257718be8SEnji Cooper 		sprintf(grump, "matched null at `%.20s'", p);
49357718be8SEnji Cooper 		return(grump);
49457718be8SEnji Cooper 	}
49557718be8SEnji Cooper 	return(NULL);
49657718be8SEnji Cooper }
49757718be8SEnji Cooper 
49857718be8SEnji Cooper /*
49957718be8SEnji Cooper  * eprint - convert error number to name
50057718be8SEnji Cooper  */
50157718be8SEnji Cooper static char *
eprint(int err)50257718be8SEnji Cooper eprint(int err)
50357718be8SEnji Cooper {
50457718be8SEnji Cooper 	static char epbuf[100];
50557718be8SEnji Cooper 	size_t len;
50657718be8SEnji Cooper 
50757718be8SEnji Cooper 	len = regerror(REG_ITOA|err, NULL, epbuf, sizeof(epbuf));
50857718be8SEnji Cooper 	assert(len <= sizeof(epbuf));
50957718be8SEnji Cooper 	return(epbuf);
51057718be8SEnji Cooper }
51157718be8SEnji Cooper 
51257718be8SEnji Cooper /*
51357718be8SEnji Cooper  * efind - convert error name to number
51457718be8SEnji Cooper  */
51557718be8SEnji Cooper static int
efind(char * name)51657718be8SEnji Cooper efind(char *name)
51757718be8SEnji Cooper {
51857718be8SEnji Cooper 	static char efbuf[100];
51957718be8SEnji Cooper 	regex_t re;
52057718be8SEnji Cooper 
52157718be8SEnji Cooper 	sprintf(efbuf, "REG_%s", name);
52257718be8SEnji Cooper 	assert(strlen(efbuf) < sizeof(efbuf));
52357718be8SEnji Cooper 	re.re_endp = efbuf;
52457718be8SEnji Cooper 	(void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
52557718be8SEnji Cooper 	return(atoi(efbuf));
52657718be8SEnji Cooper }
527