1*f40f3adcSEnji Cooper /* $NetBSD: t_regex_att.c,v 1.3 2017/01/14 20:59:23 christos Exp $ */
257718be8SEnji Cooper
357718be8SEnji Cooper /*-
457718be8SEnji Cooper * Copyright (c) 2011 The NetBSD Foundation, Inc.
557718be8SEnji Cooper * All rights reserved.
657718be8SEnji Cooper *
757718be8SEnji Cooper * This code is derived from software contributed to The NetBSD Foundation
857718be8SEnji Cooper * by Christos Zoulas.
957718be8SEnji Cooper *
1057718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without
1157718be8SEnji Cooper * modification, are permitted provided that the following conditions
1257718be8SEnji Cooper * are met:
1357718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright
1457718be8SEnji Cooper * notice, this list of conditions and the following disclaimer.
1557718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright
1657718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the
1757718be8SEnji Cooper * documentation and/or other materials provided with the distribution.
1857718be8SEnji Cooper * 3. All advertising materials mentioning features or use of this software
1957718be8SEnji Cooper * must display the following acknowledgement:
2057718be8SEnji Cooper * This product includes software developed by the NetBSD
2157718be8SEnji Cooper * Foundation, Inc. and its contributors.
2257718be8SEnji Cooper * 4. Neither the name of The NetBSD Foundation nor the names of its
2357718be8SEnji Cooper * contributors may be used to endorse or promote products derived
2457718be8SEnji Cooper * from this software without specific prior written permission.
2557718be8SEnji Cooper *
2657718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2757718be8SEnji Cooper * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2857718be8SEnji Cooper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2957718be8SEnji Cooper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
3057718be8SEnji Cooper * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3157718be8SEnji Cooper * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3257718be8SEnji Cooper * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3357718be8SEnji Cooper * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3457718be8SEnji Cooper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3557718be8SEnji Cooper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3657718be8SEnji Cooper * POSSIBILITY OF SUCH DAMAGE.
3757718be8SEnji Cooper */
3857718be8SEnji Cooper
3957718be8SEnji Cooper #include <sys/cdefs.h>
40*f40f3adcSEnji Cooper __RCSID("$NetBSD: t_regex_att.c,v 1.3 2017/01/14 20:59:23 christos Exp $");
4157718be8SEnji Cooper
4257718be8SEnji Cooper #include <sys/param.h>
4357718be8SEnji Cooper
4457718be8SEnji Cooper #include <atf-c.h>
45*f40f3adcSEnji Cooper #include <ctype.h>
46*f40f3adcSEnji Cooper #include <regex.h>
47*f40f3adcSEnji Cooper #include <stdio.h>
48*f40f3adcSEnji Cooper #include <stdlib.h>
49*f40f3adcSEnji Cooper #include <string.h>
50*f40f3adcSEnji Cooper #include <util.h>
51*f40f3adcSEnji Cooper #include <vis.h>
5257718be8SEnji Cooper
5357718be8SEnji Cooper static const char sep[] = "\r\n\t";
5457718be8SEnji Cooper static const char delim[3] = "\\\\\0";
5557718be8SEnji Cooper
5657718be8SEnji Cooper
5757718be8SEnji Cooper static void
fail(const char * pattern,const char * input,size_t lineno)5857718be8SEnji Cooper fail(const char *pattern, const char *input, size_t lineno) {
5957718be8SEnji Cooper fprintf(stderr,
6057718be8SEnji Cooper "skipping failed test at line %zu (pattern=%s, input=%s)\n",
6157718be8SEnji Cooper lineno, pattern, input);
6257718be8SEnji Cooper }
6357718be8SEnji Cooper
6457718be8SEnji Cooper static int
bug(const char * pattern,const char * input,size_t lineno)6557718be8SEnji Cooper bug(const char *pattern, const char *input, size_t lineno) {
6657718be8SEnji Cooper static const struct {
6757718be8SEnji Cooper const char *p;
6857718be8SEnji Cooper const char *i;
6957718be8SEnji Cooper } b[] = {
7057718be8SEnji Cooper #if defined(REGEX_SPENCER)
7157718be8SEnji Cooper /*
7257718be8SEnji Cooper * The default libc implementation by Henry Spencer
7357718be8SEnji Cooper */
7457718be8SEnji Cooper { "a[-]?c", "ac" }, // basic.dat
7557718be8SEnji Cooper { "(a*)*", "a" }, // categorization.dat
7657718be8SEnji Cooper { "(aba|a*b)*", "ababa" }, // categorization.dat
7757718be8SEnji Cooper { "\\(a\\(b\\)*\\)*\\2", "abab" }, // categorization.dat
7857718be8SEnji Cooper { "(a*)*", "aaaaaa" }, // nullsubexpression.dat
7957718be8SEnji Cooper { "(a*)*", "aaaaaax" }, // nullsubexpression.dat
8057718be8SEnji Cooper { "(a*)+", "a" }, // nullsubexpression.dat
8157718be8SEnji Cooper { "(a*)+", "aaaaaa" }, // nullsubexpression.dat
8257718be8SEnji Cooper { "(a*)+", "aaaaaax" }, // nullsubexpression.dat
8357718be8SEnji Cooper { "([a]*)*", "a" }, // nullsubexpression.dat
8457718be8SEnji Cooper { "([a]*)*", "aaaaaa" }, // nullsubexpression.dat
8557718be8SEnji Cooper { "([a]*)*", "aaaaaax" }, // nullsubexpression.dat
8657718be8SEnji Cooper { "([a]*)+", "a" }, // nullsubexpression.dat
8757718be8SEnji Cooper { "([a]*)+", "aaaaaa" }, // nullsubexpression.dat
8857718be8SEnji Cooper { "([a]*)+", "aaaaaax" }, // nullsubexpression.dat
8957718be8SEnji Cooper { "([^b]*)*", "a" }, // nullsubexpression.dat
9057718be8SEnji Cooper { "([^b]*)*", "aaaaaa" }, // nullsubexpression.dat
9157718be8SEnji Cooper { "([^b]*)*", "aaaaaab" }, // nullsubexpression.dat
9257718be8SEnji Cooper { "([ab]*)*", "a" }, // nullsubexpression.dat
9357718be8SEnji Cooper { "([ab]*)*", "aaaaaa" }, // nullsubexpression.dat
9457718be8SEnji Cooper { "([ab]*)*", "ababab" }, // nullsubexpression.dat
9557718be8SEnji Cooper { "([ab]*)*", "bababa" }, // nullsubexpression.dat
9657718be8SEnji Cooper { "([ab]*)*", "b" }, // nullsubexpression.dat
9757718be8SEnji Cooper { "([ab]*)*", "bbbbbb" }, // nullsubexpression.dat
9857718be8SEnji Cooper { "([ab]*)*", "aaaabcde" }, // nullsubexpression.dat
9957718be8SEnji Cooper { "([^a]*)*", "b" }, // nullsubexpression.dat
10057718be8SEnji Cooper { "([^a]*)*", "bbbbbb" }, // nullsubexpression.dat
10157718be8SEnji Cooper { "([^ab]*)*", "ccccxx" }, // nullsubexpression.dat
10257718be8SEnji Cooper { "\\(a*\\)*\\(x\\)", "ax" }, // nullsubexpression.dat
10357718be8SEnji Cooper { "\\(a*\\)*\\(x\\)", "axa" }, // nullsubexpression.dat
10457718be8SEnji Cooper { "\\(a*\\)*\\(x\\)\\(\\1\\)", "x" }, // nullsubexpression.dat
10557718be8SEnji Cooper /* crash! */ { "\\(a*\\)*\\(x\\)\\(\\1\\)", "ax" }, // nullsubexpression.dat
10657718be8SEnji Cooper /* crash! */ { "\\(a*\\)*\\(x\\)\\(\\1\\)\\(x\\)", "axxa" }, // ""
10757718be8SEnji Cooper { "(a*)*(x)", "ax" }, // nullsubexpression.dat
10857718be8SEnji Cooper { "(a*)*(x)", "axa" }, // nullsubexpression.dat
10957718be8SEnji Cooper { "(a*)+(x)", "ax" }, // nullsubexpression.dat
11057718be8SEnji Cooper { "(a*)+(x)", "axa" }, // nullsubexpression.dat
11157718be8SEnji Cooper { "((a|ab)(c|bcd))(d*)", "abcd" }, // forcedassoc.dat
11257718be8SEnji Cooper { "((a|ab)(bcd|c))(d*)", "abcd" }, // forcedassoc.dat
11357718be8SEnji Cooper { "((ab|a)(c|bcd))(d*)", "abcd" }, // forcedassoc.dat
11457718be8SEnji Cooper { "((ab|a)(bcd|c))(d*)", "abcd" }, // forcedassoc.dat
11557718be8SEnji Cooper { "((a*)(b|abc))(c*)", "abc" }, // forcedassoc.dat
11657718be8SEnji Cooper { "((a*)(abc|b))(c*)", "abc" }, // forcedassoc.dat
11757718be8SEnji Cooper { "((..)|(.)){2}", "aaa" }, // repetition.dat
11857718be8SEnji Cooper { "((..)|(.)){3}", "aaa" }, // repetition.dat
11957718be8SEnji Cooper { "((..)|(.)){3}", "aaaa" }, // repetition.dat
12057718be8SEnji Cooper { "((..)|(.)){3}", "aaaaa" }, // repetition.dat
12157718be8SEnji Cooper { "X(.?){0,}Y", "X1234567Y" }, // repetition.dat
12257718be8SEnji Cooper { "X(.?){1,}Y", "X1234567Y" }, // repetition.dat
12357718be8SEnji Cooper { "X(.?){2,}Y", "X1234567Y" }, // repetition.dat
12457718be8SEnji Cooper { "X(.?){3,}Y", "X1234567Y" }, // repetition.dat
12557718be8SEnji Cooper { "X(.?){4,}Y", "X1234567Y" }, // repetition.dat
12657718be8SEnji Cooper { "X(.?){5,}Y", "X1234567Y" }, // repetition.dat
12757718be8SEnji Cooper { "X(.?){6,}Y", "X1234567Y" }, // repetition.dat
12857718be8SEnji Cooper { "X(.?){7,}Y", "X1234567Y" }, // repetition.dat
12957718be8SEnji Cooper { "X(.?){0,8}Y", "X1234567Y" }, // repetition.dat
13057718be8SEnji Cooper { "X(.?){1,8}Y", "X1234567Y" }, // repetition.dat
13157718be8SEnji Cooper { "X(.?){2,8}Y", "X1234567Y" }, // repetition.dat
13257718be8SEnji Cooper { "X(.?){3,8}Y", "X1234567Y" }, // repetition.dat
13357718be8SEnji Cooper { "X(.?){4,8}Y", "X1234567Y" }, // repetition.dat
13457718be8SEnji Cooper { "X(.?){5,8}Y", "X1234567Y" }, // repetition.dat
13557718be8SEnji Cooper { "X(.?){6,8}Y", "X1234567Y" }, // repetition.dat
13657718be8SEnji Cooper { "X(.?){7,8}Y", "X1234567Y" }, // repetition.dat
13757718be8SEnji Cooper { "(a|ab|c|bcd){0,}(d*)", "ababcd" }, // repetition.dat
13857718be8SEnji Cooper { "(a|ab|c|bcd){1,}(d*)", "ababcd" }, // repetition.dat
13957718be8SEnji Cooper { "(a|ab|c|bcd){2,}(d*)", "ababcd" }, // repetition.dat
14057718be8SEnji Cooper { "(a|ab|c|bcd){3,}(d*)", "ababcd" }, // repetition.dat
14157718be8SEnji Cooper { "(a|ab|c|bcd){1,10}(d*)", "ababcd" }, // repetition.dat
14257718be8SEnji Cooper { "(a|ab|c|bcd){2,10}(d*)", "ababcd" }, // repetition.dat
14357718be8SEnji Cooper { "(a|ab|c|bcd){3,10}(d*)", "ababcd" }, // repetition.dat
14457718be8SEnji Cooper { "(a|ab|c|bcd)*(d*)", "ababcd" }, // repetition.dat
14557718be8SEnji Cooper { "(a|ab|c|bcd)+(d*)", "ababcd" }, // repetition.dat
14657718be8SEnji Cooper { "(ab|a|c|bcd){0,}(d*)", "ababcd" }, // repetition.dat
14757718be8SEnji Cooper { "(ab|a|c|bcd){1,}(d*)", "ababcd" }, // repetition.dat
14857718be8SEnji Cooper { "(ab|a|c|bcd){2,}(d*)", "ababcd" }, // repetition.dat
14957718be8SEnji Cooper { "(ab|a|c|bcd){3,}(d*)", "ababcd" }, // repetition.dat
15057718be8SEnji Cooper { "(ab|a|c|bcd){1,10}(d*)", "ababcd" }, // repetition.dat
15157718be8SEnji Cooper { "(ab|a|c|bcd){2,10}(d*)", "ababcd" }, // repetition.dat
15257718be8SEnji Cooper { "(ab|a|c|bcd){3,10}(d*)", "ababcd" }, // repetition.dat
15357718be8SEnji Cooper { "(ab|a|c|bcd)*(d*)", "ababcd" }, // repetition.dat
15457718be8SEnji Cooper { "(ab|a|c|bcd)+(d*)", "ababcd" }, // repetition.dat
15557718be8SEnji Cooper #elif defined(REGEX_TRE)
15657718be8SEnji Cooper { "a[-]?c", "ac" }, // basic.dat
15757718be8SEnji Cooper { "a\\(b\\)*\\1", "a" }, // categorization.dat
15857718be8SEnji Cooper { "a\\(b\\)*\\1", "abab" }, // categorization.dat
15957718be8SEnji Cooper { "\\(a\\(b\\)*\\)*\\2", "abab" }, // categorization.dat
16057718be8SEnji Cooper { "\\(a*\\)*\\(x\\)\\(\\1\\)", "ax" }, // categorization.dat
16157718be8SEnji Cooper { "\\(a*\\)*\\(x\\)\\(\\1\\)\\(x\\)", "axxa" }, // ""
16257718be8SEnji Cooper { "((..)|(.))*", "aa" }, // repetition.dat
16357718be8SEnji Cooper { "((..)|(.))*", "aaa" }, // repetition.dat
16457718be8SEnji Cooper { "((..)|(.))*", "aaaaa" }, // repetition.dat
16557718be8SEnji Cooper { "X(.?){7,}Y", "X1234567Y" }, // repetition.dat
16657718be8SEnji Cooper #else
16757718be8SEnji Cooper { "", "" }
16857718be8SEnji Cooper #endif
16957718be8SEnji Cooper };
17057718be8SEnji Cooper
17157718be8SEnji Cooper for (size_t i = 0; i < __arraycount(b); i++) {
17257718be8SEnji Cooper if (strcmp(pattern, b[i].p) == 0 &&
17357718be8SEnji Cooper strcmp(input, b[i].i) == 0) {
17457718be8SEnji Cooper fail(pattern, input, lineno);
17557718be8SEnji Cooper return 1;
17657718be8SEnji Cooper }
17757718be8SEnji Cooper }
17857718be8SEnji Cooper return 0;
17957718be8SEnji Cooper }
18057718be8SEnji Cooper
18157718be8SEnji Cooper #ifdef REGEX_SPENCER
18257718be8SEnji Cooper #define HAVE_BRACES 1
18357718be8SEnji Cooper #define HAVE_MINIMAL 0
18457718be8SEnji Cooper #endif
18557718be8SEnji Cooper #ifndef HAVE_BRACES
18657718be8SEnji Cooper #define HAVE_BRACES 1
18757718be8SEnji Cooper #endif
18857718be8SEnji Cooper #ifndef HAVE_MINIMAL
18957718be8SEnji Cooper #define HAVE_MINIMAL 1
19057718be8SEnji Cooper #endif
19157718be8SEnji Cooper
19257718be8SEnji Cooper static int
optional(const char * s)19357718be8SEnji Cooper optional(const char *s)
19457718be8SEnji Cooper {
19557718be8SEnji Cooper static const struct{
19657718be8SEnji Cooper const char *n;
19757718be8SEnji Cooper int v;
19857718be8SEnji Cooper } nv[]= {
19957718be8SEnji Cooper { "[[<element>]] not supported", HAVE_BRACES },
20057718be8SEnji Cooper { "no *? +? mimimal match ops", HAVE_MINIMAL },
20157718be8SEnji Cooper };
20257718be8SEnji Cooper
20357718be8SEnji Cooper for (size_t i = 0; i < __arraycount(nv); i++)
20457718be8SEnji Cooper if (strcmp(nv[i].n, s) == 0) {
20557718be8SEnji Cooper if (nv[i].v)
20657718be8SEnji Cooper return 0;
20757718be8SEnji Cooper fprintf(stderr, "skipping unsupported [%s] tests\n", s);
20857718be8SEnji Cooper return 1;
20957718be8SEnji Cooper }
21057718be8SEnji Cooper
21157718be8SEnji Cooper ATF_REQUIRE_MSG(0, "Unknown feature: %s", s);
21257718be8SEnji Cooper return 0;
21357718be8SEnji Cooper }
21457718be8SEnji Cooper
21557718be8SEnji Cooper static int
unsupported(const char * s)21657718be8SEnji Cooper unsupported(const char *s)
21757718be8SEnji Cooper {
21857718be8SEnji Cooper static const char *we[] = {
21957718be8SEnji Cooper #if defined(REGEX_SPENCER)
22057718be8SEnji Cooper "ASSOCIATIVITY=left", // have right associativity
22157718be8SEnji Cooper "SUBEXPRESSION=precedence", // have grouping subexpression
22257718be8SEnji Cooper "REPEAT_LONGEST=last", // have first repeat longest
22357718be8SEnji Cooper "BUG=alternation-order", // don't have it
22457718be8SEnji Cooper "BUG=first-match", // don't have it
22557718be8SEnji Cooper "BUG=nomatch-match", // don't have it
22657718be8SEnji Cooper "BUG=repeat-any", // don't have it
22757718be8SEnji Cooper "BUG=range-null", // don't have it
22857718be8SEnji Cooper "BUG=repeat-null-unknown", // don't have it
22957718be8SEnji Cooper "BUG=repeat-null", // don't have it
23057718be8SEnji Cooper "BUG=repeat-artifact", // don't have it
23157718be8SEnji Cooper "BUG=subexpression-first", // don't have it
23257718be8SEnji Cooper #elif defined(REGEX_TRE)
23357718be8SEnji Cooper "ASSOCIATIVITY=right", // have left associativity
23457718be8SEnji Cooper "SUBEXPRESSION=grouping", // have precedence subexpression
23557718be8SEnji Cooper "REPEAT_LONGEST=first", // have last repeat longest
23657718be8SEnji Cooper "LENGTH=first", // have last length
23757718be8SEnji Cooper "BUG=alternation-order", // don't have it
23857718be8SEnji Cooper "BUG=first-match", // don't have it
23957718be8SEnji Cooper "BUG=range-null", // don't have it
24057718be8SEnji Cooper "BUG=repeat-null", // don't have it
24157718be8SEnji Cooper "BUG=repeat-artifact", // don't have it
24257718be8SEnji Cooper "BUG=subexpression-first", // don't have it
24357718be8SEnji Cooper "BUG=repeat-short", // don't have it
24457718be8SEnji Cooper #endif
24557718be8SEnji Cooper };
24657718be8SEnji Cooper
24757718be8SEnji Cooper if (s == NULL)
24857718be8SEnji Cooper return 0;
24957718be8SEnji Cooper
25057718be8SEnji Cooper while (*s == '#' || isspace((unsigned char)*s))
25157718be8SEnji Cooper s++;
25257718be8SEnji Cooper
25357718be8SEnji Cooper for (size_t i = 0; i < __arraycount(we); i++)
25457718be8SEnji Cooper if (strcmp(we[i], s) == 0)
25557718be8SEnji Cooper return 1;
25657718be8SEnji Cooper return 0;
25757718be8SEnji Cooper }
25857718be8SEnji Cooper
25957718be8SEnji Cooper static void
geterror(const char * s,int * comp,int * exec)26057718be8SEnji Cooper geterror(const char *s, int *comp, int *exec)
26157718be8SEnji Cooper {
26257718be8SEnji Cooper static const struct {
26357718be8SEnji Cooper const char *n;
26457718be8SEnji Cooper int v;
26557718be8SEnji Cooper int ce;
26657718be8SEnji Cooper } nv[] = {
26757718be8SEnji Cooper #define COMP 1
26857718be8SEnji Cooper #define EXEC 2
26957718be8SEnji Cooper { "OK", 0, COMP|EXEC },
27057718be8SEnji Cooper #define _DO(a, b) { # a, REG_ ## a, b },
27157718be8SEnji Cooper _DO(NOMATCH, EXEC)
27257718be8SEnji Cooper _DO(BADPAT, COMP)
27357718be8SEnji Cooper _DO(ECOLLATE, COMP)
27457718be8SEnji Cooper _DO(ECTYPE, COMP)
27557718be8SEnji Cooper _DO(EESCAPE, COMP)
27657718be8SEnji Cooper _DO(ESUBREG, COMP)
27757718be8SEnji Cooper _DO(EBRACK, COMP)
27857718be8SEnji Cooper _DO(EPAREN, COMP)
27957718be8SEnji Cooper _DO(EBRACE, COMP)
28057718be8SEnji Cooper _DO(BADBR, COMP)
28157718be8SEnji Cooper _DO(ERANGE, COMP)
28257718be8SEnji Cooper _DO(ESPACE, EXEC)
28357718be8SEnji Cooper _DO(BADRPT, COMP)
28457718be8SEnji Cooper _DO(EMPTY, COMP)
28557718be8SEnji Cooper _DO(ASSERT, COMP)
28657718be8SEnji Cooper _DO(INVARG, COMP)
28757718be8SEnji Cooper _DO(ENOSYS, COMP)
28857718be8SEnji Cooper #undef _DO
28957718be8SEnji Cooper };
29057718be8SEnji Cooper *comp = 0;
29157718be8SEnji Cooper *exec = 0;
29257718be8SEnji Cooper for (size_t i = 0; i < __arraycount(nv); i++)
29357718be8SEnji Cooper if (strcmp(s, nv[i].n) == 0) {
29457718be8SEnji Cooper if (nv[i].ce & COMP)
29557718be8SEnji Cooper *comp = nv[i].v;
29657718be8SEnji Cooper if (nv[i].ce & EXEC)
29757718be8SEnji Cooper *exec = nv[i].v;
29857718be8SEnji Cooper return;
29957718be8SEnji Cooper }
30057718be8SEnji Cooper ATF_REQUIRE_MSG(0, "Unknown error %s", s);
30157718be8SEnji Cooper return;
30257718be8SEnji Cooper }
30357718be8SEnji Cooper
30457718be8SEnji Cooper static int
getflags(char * s)30557718be8SEnji Cooper getflags(char *s)
30657718be8SEnji Cooper {
30757718be8SEnji Cooper int flags = 0;
30857718be8SEnji Cooper
30957718be8SEnji Cooper for (;; s++)
31057718be8SEnji Cooper switch (*s) {
31157718be8SEnji Cooper case '0': case '1': case '2': case '3': case '4':
31257718be8SEnji Cooper case '5': case '6': case '7': case '8': case '9':
31357718be8SEnji Cooper *s = '\0';
31457718be8SEnji Cooper break;
31557718be8SEnji Cooper case '\0':
31657718be8SEnji Cooper return flags;
31757718be8SEnji Cooper case 'B':
31857718be8SEnji Cooper case 'E':
31957718be8SEnji Cooper case 'F':
32057718be8SEnji Cooper case 'L':
32157718be8SEnji Cooper break;
32257718be8SEnji Cooper case 'i':
32357718be8SEnji Cooper flags |= REG_ICASE;
32457718be8SEnji Cooper *s = '\0';
32557718be8SEnji Cooper break;
32657718be8SEnji Cooper case '$':
32757718be8SEnji Cooper *s = '\0';
32857718be8SEnji Cooper break;
32957718be8SEnji Cooper case 'n':
33057718be8SEnji Cooper *s = '\0';
33157718be8SEnji Cooper break;
33257718be8SEnji Cooper default:
33357718be8SEnji Cooper ATF_REQUIRE_MSG(0, "Unknown char %c", *s);
33457718be8SEnji Cooper break;
33557718be8SEnji Cooper }
33657718be8SEnji Cooper }
33757718be8SEnji Cooper
33857718be8SEnji Cooper static size_t
getmatches(const char * s)33957718be8SEnji Cooper getmatches(const char *s)
34057718be8SEnji Cooper {
34157718be8SEnji Cooper size_t i;
34257718be8SEnji Cooper char *q;
34357718be8SEnji Cooper for (i = 0; (q = strchr(s, '(')) != NULL; i++, s = q + 1)
34457718be8SEnji Cooper continue;
34557718be8SEnji Cooper ATF_REQUIRE_MSG(i != 0, "No parentheses found");
34657718be8SEnji Cooper return i;
34757718be8SEnji Cooper }
34857718be8SEnji Cooper
34957718be8SEnji Cooper static void
checkcomment(const char * s,size_t lineno)35057718be8SEnji Cooper checkcomment(const char *s, size_t lineno)
35157718be8SEnji Cooper {
35257718be8SEnji Cooper if (s && strstr(s, "BUG") != NULL)
35357718be8SEnji Cooper fprintf(stderr, "Expected %s at line %zu\n", s, lineno);
35457718be8SEnji Cooper }
35557718be8SEnji Cooper
35657718be8SEnji Cooper static void
checkmatches(const char * matches,size_t nm,const regmatch_t * pm,size_t lineno)35757718be8SEnji Cooper checkmatches(const char *matches, size_t nm, const regmatch_t *pm,
35857718be8SEnji Cooper size_t lineno)
35957718be8SEnji Cooper {
36057718be8SEnji Cooper if (nm == 0)
36157718be8SEnji Cooper return;
36257718be8SEnji Cooper
36357718be8SEnji Cooper char *res;
36457718be8SEnji Cooper size_t len = strlen(matches) + 1, off = 0;
36557718be8SEnji Cooper
36657718be8SEnji Cooper ATF_REQUIRE((res = strdup(matches)) != NULL);
36757718be8SEnji Cooper for (size_t i = 0; i < nm; i++) {
36857718be8SEnji Cooper int l;
36957718be8SEnji Cooper if (pm[i].rm_so == -1 && pm[i].rm_eo == -1)
37057718be8SEnji Cooper l = snprintf(res + off, len - off, "(?,?)");
37157718be8SEnji Cooper else
37257718be8SEnji Cooper l = snprintf(res + off, len - off, "(%lld,%lld)",
37357718be8SEnji Cooper (long long)pm[i].rm_so, (long long)pm[i].rm_eo);
37457718be8SEnji Cooper ATF_REQUIRE_MSG((size_t) l < len - off, "String too long %s"
37557718be8SEnji Cooper " cur=%d, max=%zu", res, l, len - off);
37657718be8SEnji Cooper off += l;
37757718be8SEnji Cooper }
37827d2e83dSEnji Cooper ATF_CHECK_STREQ_MSG(res, matches, " at line %zu", lineno);
37957718be8SEnji Cooper free(res);
38057718be8SEnji Cooper }
38157718be8SEnji Cooper
38257718be8SEnji Cooper static void
att_test(const struct atf_tc * tc,const char * data_name)38357718be8SEnji Cooper att_test(const struct atf_tc *tc, const char *data_name)
38457718be8SEnji Cooper {
38557718be8SEnji Cooper regex_t re;
38657718be8SEnji Cooper char *line, *lastpattern = NULL, data_path[MAXPATHLEN];
38757718be8SEnji Cooper size_t len, lineno = 0;
38857718be8SEnji Cooper int skipping = 0;
38957718be8SEnji Cooper FILE *input_file;
39057718be8SEnji Cooper
39157718be8SEnji Cooper snprintf(data_path, sizeof(data_path), "%s/data/%s.dat",
39257718be8SEnji Cooper atf_tc_get_config_var(tc, "srcdir"), data_name);
39357718be8SEnji Cooper
39457718be8SEnji Cooper input_file = fopen(data_path, "r");
39557718be8SEnji Cooper if (input_file == NULL)
39657718be8SEnji Cooper atf_tc_fail("Failed to open input file %s", data_path);
39757718be8SEnji Cooper
39857718be8SEnji Cooper for (; (line = fparseln(input_file, &len, &lineno, delim, 0))
39957718be8SEnji Cooper != NULL; free(line)) {
40057718be8SEnji Cooper char *name, *pattern, *input, *matches, *comment;
40157718be8SEnji Cooper regmatch_t *pm;
40257718be8SEnji Cooper size_t nm;
40357718be8SEnji Cooper #ifdef DEBUG
40457718be8SEnji Cooper fprintf(stderr, "[%s]\n", line);
40557718be8SEnji Cooper #endif
40657718be8SEnji Cooper if ((name = strtok(line, sep)) == NULL)
40757718be8SEnji Cooper continue;
40857718be8SEnji Cooper
40957718be8SEnji Cooper /*
41057718be8SEnji Cooper * We check these early so that we skip the lines quickly
41157718be8SEnji Cooper * in order to do more strict testing on the other arguments
41257718be8SEnji Cooper * The same characters are also tested in the switch below
41357718be8SEnji Cooper */
41457718be8SEnji Cooper if (*name == '}') {
41557718be8SEnji Cooper skipping = 0;
41657718be8SEnji Cooper continue;
41757718be8SEnji Cooper }
41857718be8SEnji Cooper if (skipping)
41957718be8SEnji Cooper continue;
42057718be8SEnji Cooper if (*name == ';' || *name == '#' || strcmp(name, "NOTE") == 0)
42157718be8SEnji Cooper continue;
42257718be8SEnji Cooper if (*name == ':') {
42357718be8SEnji Cooper /* Skip ":HA#???:" prefix */
42457718be8SEnji Cooper while (*++name && *name != ':')
42557718be8SEnji Cooper continue;
42657718be8SEnji Cooper if (*name)
42757718be8SEnji Cooper name++;
42857718be8SEnji Cooper }
42957718be8SEnji Cooper
43057718be8SEnji Cooper ATF_REQUIRE_MSG((pattern = strtok(NULL, sep)) != NULL,
43157718be8SEnji Cooper "Missing pattern at line %zu", lineno);
43257718be8SEnji Cooper ATF_REQUIRE_MSG((input = strtok(NULL, sep)) != NULL,
43357718be8SEnji Cooper "Missing input at line %zu", lineno);
43457718be8SEnji Cooper
43557718be8SEnji Cooper if (strchr(name, '$')) {
43657718be8SEnji Cooper ATF_REQUIRE(strunvis(pattern, pattern) != -1);
43757718be8SEnji Cooper ATF_REQUIRE(strunvis(input, input) != -1);
43857718be8SEnji Cooper }
43957718be8SEnji Cooper
44057718be8SEnji Cooper
44157718be8SEnji Cooper if (strcmp(input, "NULL") == 0)
44257718be8SEnji Cooper *input = '\0';
44357718be8SEnji Cooper
44457718be8SEnji Cooper if (strcmp(pattern, "SAME") == 0) {
44557718be8SEnji Cooper ATF_REQUIRE(lastpattern != NULL);
44657718be8SEnji Cooper pattern = lastpattern;
44757718be8SEnji Cooper } else {
44857718be8SEnji Cooper free(lastpattern);
44957718be8SEnji Cooper ATF_REQUIRE((lastpattern = strdup(pattern)) != NULL);
45057718be8SEnji Cooper }
45157718be8SEnji Cooper
45257718be8SEnji Cooper ATF_REQUIRE_MSG((matches = strtok(NULL, sep)) != NULL,
45357718be8SEnji Cooper "Missing matches at line %zu", lineno);
45457718be8SEnji Cooper
45557718be8SEnji Cooper comment = strtok(NULL, sep);
45657718be8SEnji Cooper switch (*name) {
45757718be8SEnji Cooper case '{': /* Begin optional implementation */
45857718be8SEnji Cooper if (optional(comment)) {
45957718be8SEnji Cooper skipping++;
46057718be8SEnji Cooper continue;
46157718be8SEnji Cooper }
46257718be8SEnji Cooper name++; /* We have it, so ignore */
46357718be8SEnji Cooper break;
46457718be8SEnji Cooper case '}': /* End optional implementation */
46557718be8SEnji Cooper skipping = 0;
46657718be8SEnji Cooper continue;
46757718be8SEnji Cooper case '?': /* Optional */
46857718be8SEnji Cooper case '|': /* Alternative */
46957718be8SEnji Cooper if (unsupported(comment))
47057718be8SEnji Cooper continue;
47157718be8SEnji Cooper name++; /* We have it, so ignore */
47257718be8SEnji Cooper break;
47357718be8SEnji Cooper case '#': /* Comment */
47457718be8SEnji Cooper case ';': /* Skip */
47557718be8SEnji Cooper continue;
47657718be8SEnji Cooper default:
47757718be8SEnji Cooper break;
47857718be8SEnji Cooper }
47957718be8SEnji Cooper
48057718be8SEnji Cooper /* XXX: Our bug */
48157718be8SEnji Cooper if (bug(pattern, input, lineno))
48257718be8SEnji Cooper continue;
48357718be8SEnji Cooper
48457718be8SEnji Cooper int comp, exec;
48557718be8SEnji Cooper if (*matches != '(') {
48657718be8SEnji Cooper geterror(matches, &comp, &exec);
48757718be8SEnji Cooper pm = NULL;
48857718be8SEnji Cooper nm = 0;
48957718be8SEnji Cooper } else {
49057718be8SEnji Cooper comp = exec = 0;
49157718be8SEnji Cooper nm = getmatches(matches);
49257718be8SEnji Cooper ATF_REQUIRE((pm = calloc(nm, sizeof(*pm))) != NULL);
49357718be8SEnji Cooper }
49457718be8SEnji Cooper
49557718be8SEnji Cooper
49657718be8SEnji Cooper
49757718be8SEnji Cooper int iflags = getflags(name);
49857718be8SEnji Cooper for (; *name; name++) {
49957718be8SEnji Cooper int flags;
50057718be8SEnji Cooper switch (*name) {
50157718be8SEnji Cooper case 'B':
50257718be8SEnji Cooper flags = REG_BASIC;
50357718be8SEnji Cooper break;
50457718be8SEnji Cooper case 'E':
50557718be8SEnji Cooper flags = REG_EXTENDED;
50657718be8SEnji Cooper break;
50757718be8SEnji Cooper case 'L':
50857718be8SEnji Cooper flags = REG_NOSPEC;
50957718be8SEnji Cooper break;
51057718be8SEnji Cooper default:
51157718be8SEnji Cooper ATF_REQUIRE_MSG(0, "Bad name %c", *name);
51257718be8SEnji Cooper continue;
51357718be8SEnji Cooper }
51457718be8SEnji Cooper int c = regcomp(&re, pattern, flags | iflags);
51557718be8SEnji Cooper ATF_REQUIRE_MSG(c == comp,
51657718be8SEnji Cooper "regcomp returned %d for pattern %s at line %zu",
51757718be8SEnji Cooper c, pattern, lineno);
51857718be8SEnji Cooper if (c)
51957718be8SEnji Cooper continue;
52057718be8SEnji Cooper int e = regexec(&re, input, nm, pm, 0);
52157718be8SEnji Cooper ATF_REQUIRE_MSG(e == exec, "Expected error %d,"
52257718be8SEnji Cooper " got %d at line %zu", exec, e, lineno);
52357718be8SEnji Cooper checkmatches(matches, nm, pm, lineno);
52457718be8SEnji Cooper checkcomment(comment, lineno);
52557718be8SEnji Cooper regfree(&re);
52657718be8SEnji Cooper }
52757718be8SEnji Cooper free(pm);
52857718be8SEnji Cooper }
52957718be8SEnji Cooper
53057718be8SEnji Cooper fclose(input_file);
53157718be8SEnji Cooper }
53257718be8SEnji Cooper
53357718be8SEnji Cooper ATF_TC(basic);
ATF_TC_HEAD(basic,tc)53457718be8SEnji Cooper ATF_TC_HEAD(basic, tc)
53557718be8SEnji Cooper {
53657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests basic functionality");
53757718be8SEnji Cooper }
ATF_TC_BODY(basic,tc)53857718be8SEnji Cooper ATF_TC_BODY(basic, tc)
53957718be8SEnji Cooper {
54057718be8SEnji Cooper att_test(tc, "basic");
54157718be8SEnji Cooper }
54257718be8SEnji Cooper
54357718be8SEnji Cooper ATF_TC(categorization);
ATF_TC_HEAD(categorization,tc)54457718be8SEnji Cooper ATF_TC_HEAD(categorization, tc)
54557718be8SEnji Cooper {
54657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests implementation categorization");
54757718be8SEnji Cooper }
ATF_TC_BODY(categorization,tc)54857718be8SEnji Cooper ATF_TC_BODY(categorization, tc)
54957718be8SEnji Cooper {
55057718be8SEnji Cooper att_test(tc, "categorization");
55157718be8SEnji Cooper }
55257718be8SEnji Cooper
55357718be8SEnji Cooper ATF_TC(nullsubexpr);
ATF_TC_HEAD(nullsubexpr,tc)55457718be8SEnji Cooper ATF_TC_HEAD(nullsubexpr, tc)
55557718be8SEnji Cooper {
55657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests (...)*");
55757718be8SEnji Cooper }
ATF_TC_BODY(nullsubexpr,tc)55857718be8SEnji Cooper ATF_TC_BODY(nullsubexpr, tc)
55957718be8SEnji Cooper {
56057718be8SEnji Cooper att_test(tc, "nullsubexpr");
56157718be8SEnji Cooper }
56257718be8SEnji Cooper
56357718be8SEnji Cooper ATF_TC(leftassoc);
ATF_TC_HEAD(leftassoc,tc)56457718be8SEnji Cooper ATF_TC_HEAD(leftassoc, tc)
56557718be8SEnji Cooper {
56657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests left-associative "
56757718be8SEnji Cooper "implementations");
56857718be8SEnji Cooper }
ATF_TC_BODY(leftassoc,tc)56957718be8SEnji Cooper ATF_TC_BODY(leftassoc, tc)
57057718be8SEnji Cooper {
57157718be8SEnji Cooper #if SKIP_LEFTASSOC
57257718be8SEnji Cooper /* jmmv: I converted the original shell-based tests to C and they
57357718be8SEnji Cooper * disabled this test in a very unconventional way without giving
57457718be8SEnji Cooper * any explation. Mark as broken here, but I don't know why. */
57557718be8SEnji Cooper atf_tc_expect_fail("Reason for breakage unknown");
57657718be8SEnji Cooper #endif
57757718be8SEnji Cooper att_test(tc, "leftassoc");
57857718be8SEnji Cooper }
57957718be8SEnji Cooper
58057718be8SEnji Cooper ATF_TC(rightassoc);
ATF_TC_HEAD(rightassoc,tc)58157718be8SEnji Cooper ATF_TC_HEAD(rightassoc, tc)
58257718be8SEnji Cooper {
58357718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests right-associative "
58457718be8SEnji Cooper "implementations");
58557718be8SEnji Cooper }
ATF_TC_BODY(rightassoc,tc)58657718be8SEnji Cooper ATF_TC_BODY(rightassoc, tc)
58757718be8SEnji Cooper {
58857718be8SEnji Cooper #if SKIP_RIGHTASSOC
58957718be8SEnji Cooper /* jmmv: I converted the original shell-based tests to C and they
59057718be8SEnji Cooper * disabled this test in a very unconventional way without giving
59157718be8SEnji Cooper * any explation. Mark as broken here, but I don't know why. */
59257718be8SEnji Cooper atf_tc_expect_fail("Reason for breakage unknown");
59357718be8SEnji Cooper #endif
59457718be8SEnji Cooper att_test(tc, "rightassoc");
59557718be8SEnji Cooper }
59657718be8SEnji Cooper
59757718be8SEnji Cooper ATF_TC(forcedassoc);
ATF_TC_HEAD(forcedassoc,tc)59857718be8SEnji Cooper ATF_TC_HEAD(forcedassoc, tc)
59957718be8SEnji Cooper {
60057718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests subexpression grouping to "
60157718be8SEnji Cooper "force association");
60257718be8SEnji Cooper }
ATF_TC_BODY(forcedassoc,tc)60357718be8SEnji Cooper ATF_TC_BODY(forcedassoc, tc)
60457718be8SEnji Cooper {
60557718be8SEnji Cooper att_test(tc, "forcedassoc");
60657718be8SEnji Cooper }
60757718be8SEnji Cooper
60857718be8SEnji Cooper ATF_TC(repetition);
ATF_TC_HEAD(repetition,tc)60957718be8SEnji Cooper ATF_TC_HEAD(repetition, tc)
61057718be8SEnji Cooper {
61157718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests implicit vs. explicit "
61257718be8SEnji Cooper "repetition");
61357718be8SEnji Cooper }
ATF_TC_BODY(repetition,tc)61457718be8SEnji Cooper ATF_TC_BODY(repetition, tc)
61557718be8SEnji Cooper {
61657718be8SEnji Cooper att_test(tc, "repetition");
61757718be8SEnji Cooper }
61857718be8SEnji Cooper
ATF_TP_ADD_TCS(tp)61957718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
62057718be8SEnji Cooper {
62157718be8SEnji Cooper
62257718be8SEnji Cooper ATF_TP_ADD_TC(tp, basic);
62357718be8SEnji Cooper ATF_TP_ADD_TC(tp, categorization);
62457718be8SEnji Cooper ATF_TP_ADD_TC(tp, nullsubexpr);
625e4799c2cSBaptiste Daroussin ATF_TP_ADD_TC(tp, leftassoc);
62657718be8SEnji Cooper ATF_TP_ADD_TC(tp, rightassoc);
62757718be8SEnji Cooper ATF_TP_ADD_TC(tp, forcedassoc);
62857718be8SEnji Cooper ATF_TP_ADD_TC(tp, repetition);
62957718be8SEnji Cooper return atf_no_error();
63057718be8SEnji Cooper }
631