1*8621598aSchristos /* $NetBSD: main.c,v 1.4 2021/02/23 17:13:44 christos Exp $ */
217f9a364Spgoyette
317f9a364Spgoyette /*-
417f9a364Spgoyette * Copyright (c) 1993 The NetBSD Foundation, Inc.
517f9a364Spgoyette * All rights reserved.
617f9a364Spgoyette *
717f9a364Spgoyette * Redistribution and use in source and binary forms, with or without
817f9a364Spgoyette * modification, are permitted provided that the following conditions
917f9a364Spgoyette * are met:
1017f9a364Spgoyette * 1. Redistributions of source code must retain the above copyright
1117f9a364Spgoyette * notice, this list of conditions and the following disclaimer.
1217f9a364Spgoyette * 2. Redistributions in binary form must reproduce the above copyright
1317f9a364Spgoyette * notice, this list of conditions and the following disclaimer in the
1417f9a364Spgoyette * documentation and/or other materials provided with the distribution.
1517f9a364Spgoyette *
1617f9a364Spgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1717f9a364Spgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1817f9a364Spgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1917f9a364Spgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2017f9a364Spgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2117f9a364Spgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2217f9a364Spgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2317f9a364Spgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2417f9a364Spgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2517f9a364Spgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2617f9a364Spgoyette * POSSIBILITY OF SUCH DAMAGE.
2717f9a364Spgoyette */
2817f9a364Spgoyette
2917f9a364Spgoyette #include <assert.h>
3017f9a364Spgoyette #include <regex.h>
3117f9a364Spgoyette #include <stdio.h>
3217f9a364Spgoyette #include <stdlib.h>
3317f9a364Spgoyette #include <string.h>
3417f9a364Spgoyette #include <unistd.h>
3517f9a364Spgoyette
3617f9a364Spgoyette #include <sys/types.h>
3717f9a364Spgoyette
3817f9a364Spgoyette #include "test_regex.h"
3917f9a364Spgoyette
4017f9a364Spgoyette char *progname;
4117f9a364Spgoyette int debug = 0;
4217f9a364Spgoyette int line = 0;
4317f9a364Spgoyette int status = 0;
4417f9a364Spgoyette
4517f9a364Spgoyette int copts = REG_EXTENDED;
4617f9a364Spgoyette int eopts = 0;
4717f9a364Spgoyette regoff_t startoff = 0;
4817f9a364Spgoyette regoff_t endoff = 0;
4917f9a364Spgoyette
5017f9a364Spgoyette static char empty = '\0';
5117f9a364Spgoyette
5217f9a364Spgoyette static char *eprint(int);
5317f9a364Spgoyette static int efind(char *);
5417f9a364Spgoyette
553d2aab13Schristos #ifndef REG_ATOI
563d2aab13Schristos #define REG_ATOI 0
573d2aab13Schristos #define REG_ITOA 0
583d2aab13Schristos #define REG_PEND 0
593d2aab13Schristos #define REG_TRACE 0
603d2aab13Schristos #define REG_BACKR 0
613d2aab13Schristos #define REG_NOSPEC 0
623d2aab13Schristos #define REG_LARGE 0
633d2aab13Schristos #endif
643d2aab13Schristos
6517f9a364Spgoyette /*
6617f9a364Spgoyette * main - do the simple case, hand off to regress() for regression
6717f9a364Spgoyette */
6817f9a364Spgoyette int
main(int argc,char * argv[])6917f9a364Spgoyette main(int argc, char *argv[])
7017f9a364Spgoyette {
7117f9a364Spgoyette regex_t re;
7217f9a364Spgoyette # define NS 10
7317f9a364Spgoyette regmatch_t subs[NS];
7417f9a364Spgoyette char erbuf[100];
7517f9a364Spgoyette int err;
7617f9a364Spgoyette size_t len;
7717f9a364Spgoyette int c;
7817f9a364Spgoyette int errflg = 0;
7917f9a364Spgoyette int i;
8017f9a364Spgoyette extern int optind;
8117f9a364Spgoyette extern char *optarg;
8217f9a364Spgoyette
8317f9a364Spgoyette progname = argv[0];
8417f9a364Spgoyette
853d2aab13Schristos while ((c = getopt(argc, argv, "c:E:e:S:x")) != -1)
8617f9a364Spgoyette switch (c) {
8717f9a364Spgoyette case 'c': /* compile options */
8817f9a364Spgoyette copts = options('c', optarg);
8917f9a364Spgoyette break;
9017f9a364Spgoyette case 'e': /* execute options */
9117f9a364Spgoyette eopts = options('e', optarg);
9217f9a364Spgoyette break;
9317f9a364Spgoyette case 'E': /* end offset */
9417f9a364Spgoyette endoff = (regoff_t)atoi(optarg);
9517f9a364Spgoyette break;
963d2aab13Schristos case 'S': /* start offset */
973d2aab13Schristos startoff = (regoff_t)atoi(optarg);
983d2aab13Schristos break;
9917f9a364Spgoyette case 'x': /* Debugging. */
10017f9a364Spgoyette debug++;
10117f9a364Spgoyette break;
10217f9a364Spgoyette case '?':
10317f9a364Spgoyette default:
10417f9a364Spgoyette errflg++;
10517f9a364Spgoyette break;
10617f9a364Spgoyette }
10717f9a364Spgoyette if (errflg) {
10817f9a364Spgoyette fprintf(stderr, "usage: %s ", progname);
10917f9a364Spgoyette fprintf(stderr, "[-c copt][-C][-d] [re]\n");
11017f9a364Spgoyette exit(2);
11117f9a364Spgoyette }
11217f9a364Spgoyette
11317f9a364Spgoyette if (optind >= argc) {
11417f9a364Spgoyette regress(stdin);
11517f9a364Spgoyette exit(status);
11617f9a364Spgoyette }
11717f9a364Spgoyette
11817f9a364Spgoyette err = regcomp(&re, argv[optind++], copts);
11917f9a364Spgoyette if (err) {
12017f9a364Spgoyette len = regerror(err, &re, erbuf, sizeof(erbuf));
12117f9a364Spgoyette fprintf(stderr, "error %s, %zd/%zd `%s'\n",
12217f9a364Spgoyette eprint(err), len, (size_t)sizeof(erbuf), erbuf);
12317f9a364Spgoyette exit(status);
12417f9a364Spgoyette }
12517f9a364Spgoyette regprint(&re, stdout);
12617f9a364Spgoyette
12717f9a364Spgoyette if (optind >= argc) {
12817f9a364Spgoyette regfree(&re);
12917f9a364Spgoyette exit(status);
13017f9a364Spgoyette }
13117f9a364Spgoyette
13217f9a364Spgoyette if (eopts®_STARTEND) {
13317f9a364Spgoyette subs[0].rm_so = startoff;
13417f9a364Spgoyette subs[0].rm_eo = strlen(argv[optind]) - endoff;
13517f9a364Spgoyette }
13617f9a364Spgoyette err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
13717f9a364Spgoyette if (err) {
13817f9a364Spgoyette len = regerror(err, &re, erbuf, sizeof(erbuf));
13917f9a364Spgoyette fprintf(stderr, "error %s, %zd/%zd `%s'\n",
14017f9a364Spgoyette eprint(err), len, (size_t)sizeof(erbuf), erbuf);
14117f9a364Spgoyette exit(status);
14217f9a364Spgoyette }
14317f9a364Spgoyette if (!(copts®_NOSUB)) {
14417f9a364Spgoyette len = (int)(subs[0].rm_eo - subs[0].rm_so);
14517f9a364Spgoyette if (subs[0].rm_so != -1) {
14617f9a364Spgoyette if (len != 0)
14717f9a364Spgoyette printf("match `%.*s'\n", (int)len,
14817f9a364Spgoyette argv[optind] + subs[0].rm_so);
14917f9a364Spgoyette else
15017f9a364Spgoyette printf("match `'@%.1s\n",
15117f9a364Spgoyette argv[optind] + subs[0].rm_so);
15217f9a364Spgoyette }
15317f9a364Spgoyette for (i = 1; i < NS; i++)
15417f9a364Spgoyette if (subs[i].rm_so != -1)
15517f9a364Spgoyette printf("(%d) `%.*s'\n", i,
15617f9a364Spgoyette (int)(subs[i].rm_eo - subs[i].rm_so),
15717f9a364Spgoyette argv[optind] + subs[i].rm_so);
15817f9a364Spgoyette }
15917f9a364Spgoyette exit(status);
16017f9a364Spgoyette }
16117f9a364Spgoyette
16217f9a364Spgoyette /*
16317f9a364Spgoyette * regress - main loop of regression test
16417f9a364Spgoyette */
16517f9a364Spgoyette void
regress(FILE * in)16617f9a364Spgoyette regress(FILE *in)
16717f9a364Spgoyette {
16817f9a364Spgoyette char inbuf[1000];
16917f9a364Spgoyette # define MAXF 10
17017f9a364Spgoyette char *f[MAXF];
17117f9a364Spgoyette int nf;
17217f9a364Spgoyette int i;
17317f9a364Spgoyette char erbuf[100];
17417f9a364Spgoyette size_t ne;
17517f9a364Spgoyette const char *badpat = "invalid regular expression";
17617f9a364Spgoyette # define SHORT 10
17717f9a364Spgoyette const char *bpname = "REG_BADPAT";
17817f9a364Spgoyette regex_t re;
17917f9a364Spgoyette
18017f9a364Spgoyette while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
18117f9a364Spgoyette line++;
18217f9a364Spgoyette if (inbuf[0] == '#' || inbuf[0] == '\n')
18317f9a364Spgoyette continue; /* NOTE CONTINUE */
18417f9a364Spgoyette inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
18517f9a364Spgoyette if (debug)
18617f9a364Spgoyette fprintf(stdout, "%d:\n", line);
18717f9a364Spgoyette nf = split(inbuf, f, MAXF, "\t\t");
18817f9a364Spgoyette if (nf < 3) {
18917f9a364Spgoyette fprintf(stderr, "bad input, line %d\n", line);
19017f9a364Spgoyette exit(1);
19117f9a364Spgoyette }
19217f9a364Spgoyette for (i = 0; i < nf; i++)
19317f9a364Spgoyette if (strcmp(f[i], "\"\"") == 0)
19417f9a364Spgoyette f[i] = ∅
19517f9a364Spgoyette if (nf <= 3)
19617f9a364Spgoyette f[3] = NULL;
19717f9a364Spgoyette if (nf <= 4)
19817f9a364Spgoyette f[4] = NULL;
19917f9a364Spgoyette try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
20017f9a364Spgoyette if (opt('&', f[1])) /* try with either type of RE */
20117f9a364Spgoyette try(f[0], f[1], f[2], f[3], f[4],
20217f9a364Spgoyette options('c', f[1]) &~ REG_EXTENDED);
20317f9a364Spgoyette }
20417f9a364Spgoyette
2052b8aaed8Splunky ne = regerror(REG_BADPAT, NULL, erbuf, sizeof(erbuf));
20617f9a364Spgoyette if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
20717f9a364Spgoyette fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
20817f9a364Spgoyette erbuf, badpat);
20917f9a364Spgoyette status = 1;
21017f9a364Spgoyette }
2112b8aaed8Splunky ne = regerror(REG_BADPAT, NULL, erbuf, (size_t)SHORT);
21217f9a364Spgoyette if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
21317f9a364Spgoyette ne != strlen(badpat)+1) {
21417f9a364Spgoyette fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
21517f9a364Spgoyette erbuf, SHORT-1, badpat);
21617f9a364Spgoyette status = 1;
21717f9a364Spgoyette }
2182b8aaed8Splunky ne = regerror(REG_ITOA|REG_BADPAT, NULL, erbuf, sizeof(erbuf));
21917f9a364Spgoyette if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
22017f9a364Spgoyette fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
22117f9a364Spgoyette erbuf, bpname);
22217f9a364Spgoyette status = 1;
22317f9a364Spgoyette }
2243d2aab13Schristos #if REG_ATOI
22517f9a364Spgoyette re.re_endp = bpname;
2263d2aab13Schristos #endif
22717f9a364Spgoyette ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
22817f9a364Spgoyette if (atoi(erbuf) != (int)REG_BADPAT) {
22917f9a364Spgoyette fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
23017f9a364Spgoyette erbuf, (long)REG_BADPAT);
23117f9a364Spgoyette status = 1;
23217f9a364Spgoyette } else if (ne != strlen(erbuf)+1) {
23317f9a364Spgoyette fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
23417f9a364Spgoyette erbuf, (long)REG_BADPAT);
23517f9a364Spgoyette status = 1;
23617f9a364Spgoyette }
23717f9a364Spgoyette }
23817f9a364Spgoyette
23917f9a364Spgoyette /*
24017f9a364Spgoyette - try - try it, and report on problems
24117f9a364Spgoyette == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
24217f9a364Spgoyette */
24317f9a364Spgoyette void
try(char * f0,char * f1,char * f2,char * f3,char * f4,int opts)24417f9a364Spgoyette try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts)
24517f9a364Spgoyette {
24617f9a364Spgoyette regex_t re;
24717f9a364Spgoyette # define NSUBS 10
24817f9a364Spgoyette regmatch_t subs[NSUBS];
24917f9a364Spgoyette # define NSHOULD 15
25017f9a364Spgoyette char *should[NSHOULD];
25117f9a364Spgoyette int nshould;
25217f9a364Spgoyette char erbuf[100];
25317f9a364Spgoyette int err;
25417f9a364Spgoyette int len;
25517f9a364Spgoyette const char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
25617f9a364Spgoyette int i;
25717f9a364Spgoyette char *grump;
25817f9a364Spgoyette char f0copy[1000];
25917f9a364Spgoyette char f2copy[1000];
26017f9a364Spgoyette
26117f9a364Spgoyette strcpy(f0copy, f0);
2623d2aab13Schristos #if REG_ATOI
26317f9a364Spgoyette re.re_endp = (opts®_PEND) ? f0copy + strlen(f0copy) : NULL;
2643d2aab13Schristos #endif
26517f9a364Spgoyette fixstr(f0copy);
26617f9a364Spgoyette err = regcomp(&re, f0copy, opts);
26717f9a364Spgoyette if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
26817f9a364Spgoyette /* unexpected error or wrong error */
26917f9a364Spgoyette len = regerror(err, &re, erbuf, sizeof(erbuf));
27017f9a364Spgoyette fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
27117f9a364Spgoyette line, type, eprint(err), len,
27217f9a364Spgoyette (int)sizeof(erbuf), erbuf);
27317f9a364Spgoyette status = 1;
27417f9a364Spgoyette } else if (err == 0 && opt('C', f1)) {
27517f9a364Spgoyette /* unexpected success */
27617f9a364Spgoyette fprintf(stderr, "%d: %s should have given REG_%s\n",
27717f9a364Spgoyette line, type, f2);
27817f9a364Spgoyette status = 1;
27917f9a364Spgoyette err = 1; /* so we won't try regexec */
28017f9a364Spgoyette }
28117f9a364Spgoyette
28217f9a364Spgoyette if (err != 0) {
28317f9a364Spgoyette regfree(&re);
28417f9a364Spgoyette return;
28517f9a364Spgoyette }
28617f9a364Spgoyette
28717f9a364Spgoyette strcpy(f2copy, f2);
28817f9a364Spgoyette fixstr(f2copy);
28917f9a364Spgoyette
29017f9a364Spgoyette if (options('e', f1)®_STARTEND) {
29117f9a364Spgoyette if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
29217f9a364Spgoyette fprintf(stderr, "%d: bad STARTEND syntax\n", line);
29317f9a364Spgoyette subs[0].rm_so = strchr(f2, '(') - f2 + 1;
29417f9a364Spgoyette subs[0].rm_eo = strchr(f2, ')') - f2;
29517f9a364Spgoyette }
29617f9a364Spgoyette err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
29717f9a364Spgoyette
29817f9a364Spgoyette if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
29917f9a364Spgoyette /* unexpected error or wrong error */
30017f9a364Spgoyette len = regerror(err, &re, erbuf, sizeof(erbuf));
30117f9a364Spgoyette fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
30217f9a364Spgoyette line, type, eprint(err), len,
30317f9a364Spgoyette (int)sizeof(erbuf), erbuf);
30417f9a364Spgoyette status = 1;
30517f9a364Spgoyette } else if (err != 0) {
30617f9a364Spgoyette /* nothing more to check */
30717f9a364Spgoyette } else if (f3 == NULL) {
30817f9a364Spgoyette /* unexpected success */
30917f9a364Spgoyette fprintf(stderr, "%d: %s exec should have failed\n",
31017f9a364Spgoyette line, type);
31117f9a364Spgoyette status = 1;
31217f9a364Spgoyette err = 1; /* just on principle */
31317f9a364Spgoyette } else if (opts®_NOSUB) {
31417f9a364Spgoyette /* nothing more to check */
31517f9a364Spgoyette } else if ((grump = check(f2, subs[0], f3)) != NULL) {
31617f9a364Spgoyette fprintf(stderr, "%d: %s %s\n", line, type, grump);
31717f9a364Spgoyette status = 1;
31817f9a364Spgoyette err = 1;
31917f9a364Spgoyette }
32017f9a364Spgoyette
32117f9a364Spgoyette if (err != 0 || f4 == NULL) {
32217f9a364Spgoyette regfree(&re);
32317f9a364Spgoyette return;
32417f9a364Spgoyette }
32517f9a364Spgoyette
32617f9a364Spgoyette for (i = 1; i < NSHOULD; i++)
32717f9a364Spgoyette should[i] = NULL;
32817f9a364Spgoyette nshould = split(f4, &should[1], NSHOULD-1, ",");
32917f9a364Spgoyette if (nshould == 0) {
33017f9a364Spgoyette nshould = 1;
33117f9a364Spgoyette should[1] = ∅
33217f9a364Spgoyette }
33317f9a364Spgoyette for (i = 1; i < NSUBS; i++) {
33417f9a364Spgoyette grump = check(f2, subs[i], should[i]);
33517f9a364Spgoyette if (grump != NULL) {
33617f9a364Spgoyette fprintf(stderr, "%d: %s $%d %s\n", line,
33717f9a364Spgoyette type, i, grump);
33817f9a364Spgoyette status = 1;
33917f9a364Spgoyette err = 1;
34017f9a364Spgoyette }
34117f9a364Spgoyette }
34217f9a364Spgoyette
34317f9a364Spgoyette regfree(&re);
34417f9a364Spgoyette }
34517f9a364Spgoyette
34617f9a364Spgoyette /*
34717f9a364Spgoyette - options - pick options out of a regression-test string
34817f9a364Spgoyette == int options(int type, char *s);
34917f9a364Spgoyette */
35017f9a364Spgoyette int
options(int type,char * s)35117f9a364Spgoyette options(int type, char *s)
35217f9a364Spgoyette {
35317f9a364Spgoyette char *p;
35417f9a364Spgoyette int o = (type == 'c') ? copts : eopts;
355*8621598aSchristos const char *legal = (type == 'c') ? "bisnmpg" : "^$#tl";
35617f9a364Spgoyette
35717f9a364Spgoyette for (p = s; *p != '\0'; p++)
35817f9a364Spgoyette if (strchr(legal, *p) != NULL)
35917f9a364Spgoyette switch (*p) {
36017f9a364Spgoyette case 'b':
36117f9a364Spgoyette o &= ~REG_EXTENDED;
36217f9a364Spgoyette break;
36317f9a364Spgoyette case 'i':
36417f9a364Spgoyette o |= REG_ICASE;
36517f9a364Spgoyette break;
36617f9a364Spgoyette case 's':
36717f9a364Spgoyette o |= REG_NOSUB;
36817f9a364Spgoyette break;
36917f9a364Spgoyette case 'n':
37017f9a364Spgoyette o |= REG_NEWLINE;
37117f9a364Spgoyette break;
37217f9a364Spgoyette case 'm':
37317f9a364Spgoyette o &= ~REG_EXTENDED;
37417f9a364Spgoyette o |= REG_NOSPEC;
37517f9a364Spgoyette break;
37617f9a364Spgoyette case 'p':
37717f9a364Spgoyette o |= REG_PEND;
37817f9a364Spgoyette break;
379*8621598aSchristos case 'g':
380*8621598aSchristos o |= REG_GNU;
3813d2aab13Schristos break;
38217f9a364Spgoyette case '^':
38317f9a364Spgoyette o |= REG_NOTBOL;
38417f9a364Spgoyette break;
38517f9a364Spgoyette case '$':
38617f9a364Spgoyette o |= REG_NOTEOL;
38717f9a364Spgoyette break;
38817f9a364Spgoyette case '#':
38917f9a364Spgoyette o |= REG_STARTEND;
39017f9a364Spgoyette break;
39117f9a364Spgoyette case 't': /* trace */
39217f9a364Spgoyette o |= REG_TRACE;
39317f9a364Spgoyette break;
39417f9a364Spgoyette case 'l': /* force long representation */
39517f9a364Spgoyette o |= REG_LARGE;
39617f9a364Spgoyette break;
39717f9a364Spgoyette case 'r': /* force backref use */
39817f9a364Spgoyette o |= REG_BACKR;
39917f9a364Spgoyette break;
40017f9a364Spgoyette }
40117f9a364Spgoyette return(o);
40217f9a364Spgoyette }
40317f9a364Spgoyette
40417f9a364Spgoyette /*
40517f9a364Spgoyette - opt - is a particular option in a regression string?
40617f9a364Spgoyette == int opt(int c, char *s);
40717f9a364Spgoyette */
40817f9a364Spgoyette int /* predicate */
opt(int c,char * s)40917f9a364Spgoyette opt(int c, char *s)
41017f9a364Spgoyette {
41117f9a364Spgoyette return(strchr(s, c) != NULL);
41217f9a364Spgoyette }
41317f9a364Spgoyette
41417f9a364Spgoyette /*
41517f9a364Spgoyette - fixstr - transform magic characters in strings
41617f9a364Spgoyette == void fixstr(char *p);
41717f9a364Spgoyette */
41817f9a364Spgoyette void
fixstr(char * p)41917f9a364Spgoyette fixstr(char *p)
42017f9a364Spgoyette {
42117f9a364Spgoyette if (p == NULL)
42217f9a364Spgoyette return;
42317f9a364Spgoyette
42417f9a364Spgoyette for (; *p != '\0'; p++)
42517f9a364Spgoyette if (*p == 'N')
42617f9a364Spgoyette *p = '\n';
42717f9a364Spgoyette else if (*p == 'T')
42817f9a364Spgoyette *p = '\t';
42917f9a364Spgoyette else if (*p == 'S')
43017f9a364Spgoyette *p = ' ';
43117f9a364Spgoyette else if (*p == 'Z')
43217f9a364Spgoyette *p = '\0';
43317f9a364Spgoyette }
43417f9a364Spgoyette
43517f9a364Spgoyette /*
43617f9a364Spgoyette * check - check a substring match
43717f9a364Spgoyette */
43817f9a364Spgoyette char * /* NULL or complaint */
check(char * str,regmatch_t sub,char * should)43917f9a364Spgoyette check(char *str, regmatch_t sub, char *should)
44017f9a364Spgoyette {
44117f9a364Spgoyette int len;
44217f9a364Spgoyette int shlen;
44317f9a364Spgoyette char *p;
44417f9a364Spgoyette static char grump[500];
44517f9a364Spgoyette char *at = NULL;
44617f9a364Spgoyette
44717f9a364Spgoyette if (should != NULL && strcmp(should, "-") == 0)
44817f9a364Spgoyette should = NULL;
44917f9a364Spgoyette if (should != NULL && should[0] == '@') {
45017f9a364Spgoyette at = should + 1;
45117f9a364Spgoyette should = ∅
45217f9a364Spgoyette }
45317f9a364Spgoyette
45417f9a364Spgoyette /* check rm_so and rm_eo for consistency */
45517f9a364Spgoyette if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
45617f9a364Spgoyette (sub.rm_so != -1 && sub.rm_eo == -1) ||
45717f9a364Spgoyette (sub.rm_so != -1 && sub.rm_so < 0) ||
45817f9a364Spgoyette (sub.rm_eo != -1 && sub.rm_eo < 0) ) {
45917f9a364Spgoyette sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
46017f9a364Spgoyette (long)sub.rm_eo);
46117f9a364Spgoyette return(grump);
46217f9a364Spgoyette }
46317f9a364Spgoyette
46417f9a364Spgoyette /* check for no match */
46517f9a364Spgoyette if (sub.rm_so == -1) {
46617f9a364Spgoyette if (should == NULL)
46717f9a364Spgoyette return(NULL);
46817f9a364Spgoyette else {
46917f9a364Spgoyette sprintf(grump, "did not match");
47017f9a364Spgoyette return(grump);
47117f9a364Spgoyette }
47217f9a364Spgoyette }
47317f9a364Spgoyette
47417f9a364Spgoyette /* check for in range */
47517f9a364Spgoyette if (sub.rm_eo > (ssize_t)strlen(str)) {
47617f9a364Spgoyette sprintf(grump, "start %ld end %ld, past end of string",
47717f9a364Spgoyette (long)sub.rm_so, (long)sub.rm_eo);
47817f9a364Spgoyette return(grump);
47917f9a364Spgoyette }
48017f9a364Spgoyette
48117f9a364Spgoyette len = (int)(sub.rm_eo - sub.rm_so);
48217f9a364Spgoyette p = str + sub.rm_so;
48317f9a364Spgoyette
48417f9a364Spgoyette /* check for not supposed to match */
48517f9a364Spgoyette if (should == NULL) {
48617f9a364Spgoyette sprintf(grump, "matched `%.*s'", len, p);
48717f9a364Spgoyette return(grump);
48817f9a364Spgoyette }
48917f9a364Spgoyette
49017f9a364Spgoyette /* check for wrong match */
49117f9a364Spgoyette shlen = (int)strlen(should);
49217f9a364Spgoyette if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
49317f9a364Spgoyette sprintf(grump, "matched `%.*s' instead", len, p);
49417f9a364Spgoyette return(grump);
49517f9a364Spgoyette }
49617f9a364Spgoyette if (shlen > 0)
49717f9a364Spgoyette return(NULL);
49817f9a364Spgoyette
49917f9a364Spgoyette /* check null match in right place */
50017f9a364Spgoyette if (at == NULL)
50117f9a364Spgoyette return(NULL);
50217f9a364Spgoyette shlen = strlen(at);
50317f9a364Spgoyette if (shlen == 0)
50417f9a364Spgoyette shlen = 1; /* force check for end-of-string */
50517f9a364Spgoyette if (strncmp(p, at, shlen) != 0) {
50617f9a364Spgoyette sprintf(grump, "matched null at `%.20s'", p);
50717f9a364Spgoyette return(grump);
50817f9a364Spgoyette }
50917f9a364Spgoyette return(NULL);
51017f9a364Spgoyette }
51117f9a364Spgoyette
51217f9a364Spgoyette /*
51317f9a364Spgoyette * eprint - convert error number to name
51417f9a364Spgoyette */
51517f9a364Spgoyette static char *
eprint(int err)51617f9a364Spgoyette eprint(int err)
51717f9a364Spgoyette {
51817f9a364Spgoyette static char epbuf[100];
51917f9a364Spgoyette size_t len;
52017f9a364Spgoyette
5212b8aaed8Splunky len = regerror(REG_ITOA|err, NULL, epbuf, sizeof(epbuf));
52217f9a364Spgoyette assert(len <= sizeof(epbuf));
52317f9a364Spgoyette return(epbuf);
52417f9a364Spgoyette }
52517f9a364Spgoyette
52617f9a364Spgoyette /*
52717f9a364Spgoyette * efind - convert error name to number
52817f9a364Spgoyette */
52917f9a364Spgoyette static int
efind(char * name)53017f9a364Spgoyette efind(char *name)
53117f9a364Spgoyette {
53217f9a364Spgoyette static char efbuf[100];
53317f9a364Spgoyette regex_t re;
53417f9a364Spgoyette
53517f9a364Spgoyette sprintf(efbuf, "REG_%s", name);
53617f9a364Spgoyette assert(strlen(efbuf) < sizeof(efbuf));
5373d2aab13Schristos #if REG_ATOI
53817f9a364Spgoyette re.re_endp = efbuf;
5393d2aab13Schristos #endif
54017f9a364Spgoyette (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
54117f9a364Spgoyette return(atoi(efbuf));
54217f9a364Spgoyette }
543