1*57718be8SEnji Cooper /* $NetBSD: t_regex_att.c,v 1.1 2012/08/24 20:24:40 jmmv Exp $ */ 2*57718be8SEnji Cooper 3*57718be8SEnji Cooper /*- 4*57718be8SEnji Cooper * Copyright (c) 2011 The NetBSD Foundation, Inc. 5*57718be8SEnji Cooper * All rights reserved. 6*57718be8SEnji Cooper * 7*57718be8SEnji Cooper * This code is derived from software contributed to The NetBSD Foundation 8*57718be8SEnji Cooper * by Christos Zoulas. 9*57718be8SEnji Cooper * 10*57718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without 11*57718be8SEnji Cooper * modification, are permitted provided that the following conditions 12*57718be8SEnji Cooper * are met: 13*57718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright 14*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer. 15*57718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 16*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the 17*57718be8SEnji Cooper * documentation and/or other materials provided with the distribution. 18*57718be8SEnji Cooper * 3. All advertising materials mentioning features or use of this software 19*57718be8SEnji Cooper * must display the following acknowledgement: 20*57718be8SEnji Cooper * This product includes software developed by the NetBSD 21*57718be8SEnji Cooper * Foundation, Inc. and its contributors. 22*57718be8SEnji Cooper * 4. Neither the name of The NetBSD Foundation nor the names of its 23*57718be8SEnji Cooper * contributors may be used to endorse or promote products derived 24*57718be8SEnji Cooper * from this software without specific prior written permission. 25*57718be8SEnji Cooper * 26*57718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27*57718be8SEnji Cooper * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28*57718be8SEnji Cooper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29*57718be8SEnji Cooper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30*57718be8SEnji Cooper * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31*57718be8SEnji Cooper * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32*57718be8SEnji Cooper * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33*57718be8SEnji Cooper * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34*57718be8SEnji Cooper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35*57718be8SEnji Cooper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36*57718be8SEnji Cooper * POSSIBILITY OF SUCH DAMAGE. 37*57718be8SEnji Cooper */ 38*57718be8SEnji Cooper 39*57718be8SEnji Cooper #include <sys/cdefs.h> 40*57718be8SEnji Cooper __RCSID("$NetBSD: t_regex_att.c,v 1.1 2012/08/24 20:24:40 jmmv Exp $"); 41*57718be8SEnji Cooper 42*57718be8SEnji Cooper #include <sys/param.h> 43*57718be8SEnji Cooper 44*57718be8SEnji Cooper #include <stdio.h> 45*57718be8SEnji Cooper #include <regex.h> 46*57718be8SEnji Cooper #include <string.h> 47*57718be8SEnji Cooper #include <stdlib.h> 48*57718be8SEnji Cooper #include <vis.h> 49*57718be8SEnji Cooper #include <ctype.h> 50*57718be8SEnji Cooper #include <atf-c.h> 51*57718be8SEnji Cooper 52*57718be8SEnji Cooper static const char sep[] = "\r\n\t"; 53*57718be8SEnji Cooper static const char delim[3] = "\\\\\0"; 54*57718be8SEnji Cooper 55*57718be8SEnji Cooper 56*57718be8SEnji Cooper static void 57*57718be8SEnji Cooper fail(const char *pattern, const char *input, size_t lineno) { 58*57718be8SEnji Cooper fprintf(stderr, 59*57718be8SEnji Cooper "skipping failed test at line %zu (pattern=%s, input=%s)\n", 60*57718be8SEnji Cooper lineno, pattern, input); 61*57718be8SEnji Cooper } 62*57718be8SEnji Cooper 63*57718be8SEnji Cooper static int 64*57718be8SEnji Cooper bug(const char *pattern, const char *input, size_t lineno) { 65*57718be8SEnji Cooper static const struct { 66*57718be8SEnji Cooper const char *p; 67*57718be8SEnji Cooper const char *i; 68*57718be8SEnji Cooper } b[] = { 69*57718be8SEnji Cooper #if defined(REGEX_SPENCER) 70*57718be8SEnji Cooper /* 71*57718be8SEnji Cooper * The default libc implementation by Henry Spencer 72*57718be8SEnji Cooper */ 73*57718be8SEnji Cooper { "a[-]?c", "ac" }, // basic.dat 74*57718be8SEnji Cooper { "(a*)*", "a" }, // categorization.dat 75*57718be8SEnji Cooper { "(aba|a*b)*", "ababa" }, // categorization.dat 76*57718be8SEnji Cooper { "\\(a\\(b\\)*\\)*\\2", "abab" }, // categorization.dat 77*57718be8SEnji Cooper { "(a*)*", "aaaaaa" }, // nullsubexpression.dat 78*57718be8SEnji Cooper { "(a*)*", "aaaaaax" }, // nullsubexpression.dat 79*57718be8SEnji Cooper { "(a*)+", "a" }, // nullsubexpression.dat 80*57718be8SEnji Cooper { "(a*)+", "aaaaaa" }, // nullsubexpression.dat 81*57718be8SEnji Cooper { "(a*)+", "aaaaaax" }, // nullsubexpression.dat 82*57718be8SEnji Cooper { "([a]*)*", "a" }, // nullsubexpression.dat 83*57718be8SEnji Cooper { "([a]*)*", "aaaaaa" }, // nullsubexpression.dat 84*57718be8SEnji Cooper { "([a]*)*", "aaaaaax" }, // nullsubexpression.dat 85*57718be8SEnji Cooper { "([a]*)+", "a" }, // nullsubexpression.dat 86*57718be8SEnji Cooper { "([a]*)+", "aaaaaa" }, // nullsubexpression.dat 87*57718be8SEnji Cooper { "([a]*)+", "aaaaaax" }, // nullsubexpression.dat 88*57718be8SEnji Cooper { "([^b]*)*", "a" }, // nullsubexpression.dat 89*57718be8SEnji Cooper { "([^b]*)*", "aaaaaa" }, // nullsubexpression.dat 90*57718be8SEnji Cooper { "([^b]*)*", "aaaaaab" }, // nullsubexpression.dat 91*57718be8SEnji Cooper { "([ab]*)*", "a" }, // nullsubexpression.dat 92*57718be8SEnji Cooper { "([ab]*)*", "aaaaaa" }, // nullsubexpression.dat 93*57718be8SEnji Cooper { "([ab]*)*", "ababab" }, // nullsubexpression.dat 94*57718be8SEnji Cooper { "([ab]*)*", "bababa" }, // nullsubexpression.dat 95*57718be8SEnji Cooper { "([ab]*)*", "b" }, // nullsubexpression.dat 96*57718be8SEnji Cooper { "([ab]*)*", "bbbbbb" }, // nullsubexpression.dat 97*57718be8SEnji Cooper { "([ab]*)*", "aaaabcde" }, // nullsubexpression.dat 98*57718be8SEnji Cooper { "([^a]*)*", "b" }, // nullsubexpression.dat 99*57718be8SEnji Cooper { "([^a]*)*", "bbbbbb" }, // nullsubexpression.dat 100*57718be8SEnji Cooper { "([^ab]*)*", "ccccxx" }, // nullsubexpression.dat 101*57718be8SEnji Cooper { "\\(a*\\)*\\(x\\)", "ax" }, // nullsubexpression.dat 102*57718be8SEnji Cooper { "\\(a*\\)*\\(x\\)", "axa" }, // nullsubexpression.dat 103*57718be8SEnji Cooper { "\\(a*\\)*\\(x\\)\\(\\1\\)", "x" }, // nullsubexpression.dat 104*57718be8SEnji Cooper /* crash! */ { "\\(a*\\)*\\(x\\)\\(\\1\\)", "ax" }, // nullsubexpression.dat 105*57718be8SEnji Cooper /* crash! */ { "\\(a*\\)*\\(x\\)\\(\\1\\)\\(x\\)", "axxa" }, // "" 106*57718be8SEnji Cooper { "(a*)*(x)", "ax" }, // nullsubexpression.dat 107*57718be8SEnji Cooper { "(a*)*(x)", "axa" }, // nullsubexpression.dat 108*57718be8SEnji Cooper { "(a*)+(x)", "ax" }, // nullsubexpression.dat 109*57718be8SEnji Cooper { "(a*)+(x)", "axa" }, // nullsubexpression.dat 110*57718be8SEnji Cooper { "((a|ab)(c|bcd))(d*)", "abcd" }, // forcedassoc.dat 111*57718be8SEnji Cooper { "((a|ab)(bcd|c))(d*)", "abcd" }, // forcedassoc.dat 112*57718be8SEnji Cooper { "((ab|a)(c|bcd))(d*)", "abcd" }, // forcedassoc.dat 113*57718be8SEnji Cooper { "((ab|a)(bcd|c))(d*)", "abcd" }, // forcedassoc.dat 114*57718be8SEnji Cooper { "((a*)(b|abc))(c*)", "abc" }, // forcedassoc.dat 115*57718be8SEnji Cooper { "((a*)(abc|b))(c*)", "abc" }, // forcedassoc.dat 116*57718be8SEnji Cooper { "((..)|(.)){2}", "aaa" }, // repetition.dat 117*57718be8SEnji Cooper { "((..)|(.)){3}", "aaa" }, // repetition.dat 118*57718be8SEnji Cooper { "((..)|(.)){3}", "aaaa" }, // repetition.dat 119*57718be8SEnji Cooper { "((..)|(.)){3}", "aaaaa" }, // repetition.dat 120*57718be8SEnji Cooper { "X(.?){0,}Y", "X1234567Y" }, // repetition.dat 121*57718be8SEnji Cooper { "X(.?){1,}Y", "X1234567Y" }, // repetition.dat 122*57718be8SEnji Cooper { "X(.?){2,}Y", "X1234567Y" }, // repetition.dat 123*57718be8SEnji Cooper { "X(.?){3,}Y", "X1234567Y" }, // repetition.dat 124*57718be8SEnji Cooper { "X(.?){4,}Y", "X1234567Y" }, // repetition.dat 125*57718be8SEnji Cooper { "X(.?){5,}Y", "X1234567Y" }, // repetition.dat 126*57718be8SEnji Cooper { "X(.?){6,}Y", "X1234567Y" }, // repetition.dat 127*57718be8SEnji Cooper { "X(.?){7,}Y", "X1234567Y" }, // repetition.dat 128*57718be8SEnji Cooper { "X(.?){0,8}Y", "X1234567Y" }, // repetition.dat 129*57718be8SEnji Cooper { "X(.?){1,8}Y", "X1234567Y" }, // repetition.dat 130*57718be8SEnji Cooper { "X(.?){2,8}Y", "X1234567Y" }, // repetition.dat 131*57718be8SEnji Cooper { "X(.?){3,8}Y", "X1234567Y" }, // repetition.dat 132*57718be8SEnji Cooper { "X(.?){4,8}Y", "X1234567Y" }, // repetition.dat 133*57718be8SEnji Cooper { "X(.?){5,8}Y", "X1234567Y" }, // repetition.dat 134*57718be8SEnji Cooper { "X(.?){6,8}Y", "X1234567Y" }, // repetition.dat 135*57718be8SEnji Cooper { "X(.?){7,8}Y", "X1234567Y" }, // repetition.dat 136*57718be8SEnji Cooper { "(a|ab|c|bcd){0,}(d*)", "ababcd" }, // repetition.dat 137*57718be8SEnji Cooper { "(a|ab|c|bcd){1,}(d*)", "ababcd" }, // repetition.dat 138*57718be8SEnji Cooper { "(a|ab|c|bcd){2,}(d*)", "ababcd" }, // repetition.dat 139*57718be8SEnji Cooper { "(a|ab|c|bcd){3,}(d*)", "ababcd" }, // repetition.dat 140*57718be8SEnji Cooper { "(a|ab|c|bcd){1,10}(d*)", "ababcd" }, // repetition.dat 141*57718be8SEnji Cooper { "(a|ab|c|bcd){2,10}(d*)", "ababcd" }, // repetition.dat 142*57718be8SEnji Cooper { "(a|ab|c|bcd){3,10}(d*)", "ababcd" }, // repetition.dat 143*57718be8SEnji Cooper { "(a|ab|c|bcd)*(d*)", "ababcd" }, // repetition.dat 144*57718be8SEnji Cooper { "(a|ab|c|bcd)+(d*)", "ababcd" }, // repetition.dat 145*57718be8SEnji Cooper { "(ab|a|c|bcd){0,}(d*)", "ababcd" }, // repetition.dat 146*57718be8SEnji Cooper { "(ab|a|c|bcd){1,}(d*)", "ababcd" }, // repetition.dat 147*57718be8SEnji Cooper { "(ab|a|c|bcd){2,}(d*)", "ababcd" }, // repetition.dat 148*57718be8SEnji Cooper { "(ab|a|c|bcd){3,}(d*)", "ababcd" }, // repetition.dat 149*57718be8SEnji Cooper { "(ab|a|c|bcd){1,10}(d*)", "ababcd" }, // repetition.dat 150*57718be8SEnji Cooper { "(ab|a|c|bcd){2,10}(d*)", "ababcd" }, // repetition.dat 151*57718be8SEnji Cooper { "(ab|a|c|bcd){3,10}(d*)", "ababcd" }, // repetition.dat 152*57718be8SEnji Cooper { "(ab|a|c|bcd)*(d*)", "ababcd" }, // repetition.dat 153*57718be8SEnji Cooper { "(ab|a|c|bcd)+(d*)", "ababcd" }, // repetition.dat 154*57718be8SEnji Cooper #elif defined(REGEX_TRE) 155*57718be8SEnji Cooper { "a[-]?c", "ac" }, // basic.dat 156*57718be8SEnji Cooper { "a\\(b\\)*\\1", "a" }, // categorization.dat 157*57718be8SEnji Cooper { "a\\(b\\)*\\1", "abab" }, // categorization.dat 158*57718be8SEnji Cooper { "\\(a\\(b\\)*\\)*\\2", "abab" }, // categorization.dat 159*57718be8SEnji Cooper { "\\(a*\\)*\\(x\\)\\(\\1\\)", "ax" }, // categorization.dat 160*57718be8SEnji Cooper { "\\(a*\\)*\\(x\\)\\(\\1\\)\\(x\\)", "axxa" }, // "" 161*57718be8SEnji Cooper { "((..)|(.))*", "aa" }, // repetition.dat 162*57718be8SEnji Cooper { "((..)|(.))*", "aaa" }, // repetition.dat 163*57718be8SEnji Cooper { "((..)|(.))*", "aaaaa" }, // repetition.dat 164*57718be8SEnji Cooper { "X(.?){7,}Y", "X1234567Y" }, // repetition.dat 165*57718be8SEnji Cooper #else 166*57718be8SEnji Cooper { "", "" } 167*57718be8SEnji Cooper #endif 168*57718be8SEnji Cooper }; 169*57718be8SEnji Cooper 170*57718be8SEnji Cooper for (size_t i = 0; i < __arraycount(b); i++) { 171*57718be8SEnji Cooper if (strcmp(pattern, b[i].p) == 0 && 172*57718be8SEnji Cooper strcmp(input, b[i].i) == 0) { 173*57718be8SEnji Cooper fail(pattern, input, lineno); 174*57718be8SEnji Cooper return 1; 175*57718be8SEnji Cooper } 176*57718be8SEnji Cooper } 177*57718be8SEnji Cooper return 0; 178*57718be8SEnji Cooper } 179*57718be8SEnji Cooper 180*57718be8SEnji Cooper #ifdef REGEX_SPENCER 181*57718be8SEnji Cooper #define HAVE_BRACES 1 182*57718be8SEnji Cooper #define HAVE_MINIMAL 0 183*57718be8SEnji Cooper #endif 184*57718be8SEnji Cooper #ifndef HAVE_BRACES 185*57718be8SEnji Cooper #define HAVE_BRACES 1 186*57718be8SEnji Cooper #endif 187*57718be8SEnji Cooper #ifndef HAVE_MINIMAL 188*57718be8SEnji Cooper #define HAVE_MINIMAL 1 189*57718be8SEnji Cooper #endif 190*57718be8SEnji Cooper 191*57718be8SEnji Cooper static int 192*57718be8SEnji Cooper optional(const char *s) 193*57718be8SEnji Cooper { 194*57718be8SEnji Cooper static const struct{ 195*57718be8SEnji Cooper const char *n; 196*57718be8SEnji Cooper int v; 197*57718be8SEnji Cooper } nv[]= { 198*57718be8SEnji Cooper { "[[<element>]] not supported", HAVE_BRACES }, 199*57718be8SEnji Cooper { "no *? +? mimimal match ops", HAVE_MINIMAL }, 200*57718be8SEnji Cooper }; 201*57718be8SEnji Cooper 202*57718be8SEnji Cooper for (size_t i = 0; i < __arraycount(nv); i++) 203*57718be8SEnji Cooper if (strcmp(nv[i].n, s) == 0) { 204*57718be8SEnji Cooper if (nv[i].v) 205*57718be8SEnji Cooper return 0; 206*57718be8SEnji Cooper fprintf(stderr, "skipping unsupported [%s] tests\n", s); 207*57718be8SEnji Cooper return 1; 208*57718be8SEnji Cooper } 209*57718be8SEnji Cooper 210*57718be8SEnji Cooper ATF_REQUIRE_MSG(0, "Unknown feature: %s", s); 211*57718be8SEnji Cooper return 0; 212*57718be8SEnji Cooper } 213*57718be8SEnji Cooper 214*57718be8SEnji Cooper static int 215*57718be8SEnji Cooper unsupported(const char *s) 216*57718be8SEnji Cooper { 217*57718be8SEnji Cooper static const char *we[] = { 218*57718be8SEnji Cooper #if defined(REGEX_SPENCER) 219*57718be8SEnji Cooper "ASSOCIATIVITY=left", // have right associativity 220*57718be8SEnji Cooper "SUBEXPRESSION=precedence", // have grouping subexpression 221*57718be8SEnji Cooper "REPEAT_LONGEST=last", // have first repeat longest 222*57718be8SEnji Cooper "BUG=alternation-order", // don't have it 223*57718be8SEnji Cooper "BUG=first-match", // don't have it 224*57718be8SEnji Cooper "BUG=nomatch-match", // don't have it 225*57718be8SEnji Cooper "BUG=repeat-any", // don't have it 226*57718be8SEnji Cooper "BUG=range-null", // don't have it 227*57718be8SEnji Cooper "BUG=repeat-null-unknown", // don't have it 228*57718be8SEnji Cooper "BUG=repeat-null", // don't have it 229*57718be8SEnji Cooper "BUG=repeat-artifact", // don't have it 230*57718be8SEnji Cooper "BUG=subexpression-first", // don't have it 231*57718be8SEnji Cooper #elif defined(REGEX_TRE) 232*57718be8SEnji Cooper "ASSOCIATIVITY=right", // have left associativity 233*57718be8SEnji Cooper "SUBEXPRESSION=grouping", // have precedence subexpression 234*57718be8SEnji Cooper "REPEAT_LONGEST=first", // have last repeat longest 235*57718be8SEnji Cooper "LENGTH=first", // have last length 236*57718be8SEnji Cooper "BUG=alternation-order", // don't have it 237*57718be8SEnji Cooper "BUG=first-match", // don't have it 238*57718be8SEnji Cooper "BUG=range-null", // don't have it 239*57718be8SEnji Cooper "BUG=repeat-null", // don't have it 240*57718be8SEnji Cooper "BUG=repeat-artifact", // don't have it 241*57718be8SEnji Cooper "BUG=subexpression-first", // don't have it 242*57718be8SEnji Cooper "BUG=repeat-short", // don't have it 243*57718be8SEnji Cooper #endif 244*57718be8SEnji Cooper }; 245*57718be8SEnji Cooper 246*57718be8SEnji Cooper if (s == NULL) 247*57718be8SEnji Cooper return 0; 248*57718be8SEnji Cooper 249*57718be8SEnji Cooper while (*s == '#' || isspace((unsigned char)*s)) 250*57718be8SEnji Cooper s++; 251*57718be8SEnji Cooper 252*57718be8SEnji Cooper for (size_t i = 0; i < __arraycount(we); i++) 253*57718be8SEnji Cooper if (strcmp(we[i], s) == 0) 254*57718be8SEnji Cooper return 1; 255*57718be8SEnji Cooper return 0; 256*57718be8SEnji Cooper } 257*57718be8SEnji Cooper 258*57718be8SEnji Cooper static void 259*57718be8SEnji Cooper geterror(const char *s, int *comp, int *exec) 260*57718be8SEnji Cooper { 261*57718be8SEnji Cooper static const struct { 262*57718be8SEnji Cooper const char *n; 263*57718be8SEnji Cooper int v; 264*57718be8SEnji Cooper int ce; 265*57718be8SEnji Cooper } nv[] = { 266*57718be8SEnji Cooper #define COMP 1 267*57718be8SEnji Cooper #define EXEC 2 268*57718be8SEnji Cooper { "OK", 0, COMP|EXEC }, 269*57718be8SEnji Cooper #define _DO(a, b) { # a, REG_ ## a, b }, 270*57718be8SEnji Cooper _DO(NOMATCH, EXEC) 271*57718be8SEnji Cooper _DO(BADPAT, COMP) 272*57718be8SEnji Cooper _DO(ECOLLATE, COMP) 273*57718be8SEnji Cooper _DO(ECTYPE, COMP) 274*57718be8SEnji Cooper _DO(EESCAPE, COMP) 275*57718be8SEnji Cooper _DO(ESUBREG, COMP) 276*57718be8SEnji Cooper _DO(EBRACK, COMP) 277*57718be8SEnji Cooper _DO(EPAREN, COMP) 278*57718be8SEnji Cooper _DO(EBRACE, COMP) 279*57718be8SEnji Cooper _DO(BADBR, COMP) 280*57718be8SEnji Cooper _DO(ERANGE, COMP) 281*57718be8SEnji Cooper _DO(ESPACE, EXEC) 282*57718be8SEnji Cooper _DO(BADRPT, COMP) 283*57718be8SEnji Cooper _DO(EMPTY, COMP) 284*57718be8SEnji Cooper _DO(ASSERT, COMP) 285*57718be8SEnji Cooper _DO(INVARG, COMP) 286*57718be8SEnji Cooper _DO(ENOSYS, COMP) 287*57718be8SEnji Cooper #undef _DO 288*57718be8SEnji Cooper }; 289*57718be8SEnji Cooper *comp = 0; 290*57718be8SEnji Cooper *exec = 0; 291*57718be8SEnji Cooper for (size_t i = 0; i < __arraycount(nv); i++) 292*57718be8SEnji Cooper if (strcmp(s, nv[i].n) == 0) { 293*57718be8SEnji Cooper if (nv[i].ce & COMP) 294*57718be8SEnji Cooper *comp = nv[i].v; 295*57718be8SEnji Cooper if (nv[i].ce & EXEC) 296*57718be8SEnji Cooper *exec = nv[i].v; 297*57718be8SEnji Cooper return; 298*57718be8SEnji Cooper } 299*57718be8SEnji Cooper ATF_REQUIRE_MSG(0, "Unknown error %s", s); 300*57718be8SEnji Cooper return; 301*57718be8SEnji Cooper } 302*57718be8SEnji Cooper 303*57718be8SEnji Cooper static int 304*57718be8SEnji Cooper getflags(char *s) 305*57718be8SEnji Cooper { 306*57718be8SEnji Cooper int flags = 0; 307*57718be8SEnji Cooper 308*57718be8SEnji Cooper for (;; s++) 309*57718be8SEnji Cooper switch (*s) { 310*57718be8SEnji Cooper case '0': case '1': case '2': case '3': case '4': 311*57718be8SEnji Cooper case '5': case '6': case '7': case '8': case '9': 312*57718be8SEnji Cooper *s = '\0'; 313*57718be8SEnji Cooper break; 314*57718be8SEnji Cooper case '\0': 315*57718be8SEnji Cooper return flags; 316*57718be8SEnji Cooper case 'B': 317*57718be8SEnji Cooper case 'E': 318*57718be8SEnji Cooper case 'F': 319*57718be8SEnji Cooper case 'L': 320*57718be8SEnji Cooper break; 321*57718be8SEnji Cooper case 'i': 322*57718be8SEnji Cooper flags |= REG_ICASE; 323*57718be8SEnji Cooper *s = '\0'; 324*57718be8SEnji Cooper break; 325*57718be8SEnji Cooper case '$': 326*57718be8SEnji Cooper *s = '\0'; 327*57718be8SEnji Cooper break; 328*57718be8SEnji Cooper case 'n': 329*57718be8SEnji Cooper *s = '\0'; 330*57718be8SEnji Cooper break; 331*57718be8SEnji Cooper default: 332*57718be8SEnji Cooper ATF_REQUIRE_MSG(0, "Unknown char %c", *s); 333*57718be8SEnji Cooper break; 334*57718be8SEnji Cooper } 335*57718be8SEnji Cooper } 336*57718be8SEnji Cooper 337*57718be8SEnji Cooper static size_t 338*57718be8SEnji Cooper getmatches(const char *s) 339*57718be8SEnji Cooper { 340*57718be8SEnji Cooper size_t i; 341*57718be8SEnji Cooper char *q; 342*57718be8SEnji Cooper for (i = 0; (q = strchr(s, '(')) != NULL; i++, s = q + 1) 343*57718be8SEnji Cooper continue; 344*57718be8SEnji Cooper ATF_REQUIRE_MSG(i != 0, "No parentheses found"); 345*57718be8SEnji Cooper return i; 346*57718be8SEnji Cooper } 347*57718be8SEnji Cooper 348*57718be8SEnji Cooper static void 349*57718be8SEnji Cooper checkcomment(const char *s, size_t lineno) 350*57718be8SEnji Cooper { 351*57718be8SEnji Cooper if (s && strstr(s, "BUG") != NULL) 352*57718be8SEnji Cooper fprintf(stderr, "Expected %s at line %zu\n", s, lineno); 353*57718be8SEnji Cooper } 354*57718be8SEnji Cooper 355*57718be8SEnji Cooper static void 356*57718be8SEnji Cooper checkmatches(const char *matches, size_t nm, const regmatch_t *pm, 357*57718be8SEnji Cooper size_t lineno) 358*57718be8SEnji Cooper { 359*57718be8SEnji Cooper if (nm == 0) 360*57718be8SEnji Cooper return; 361*57718be8SEnji Cooper 362*57718be8SEnji Cooper char *res; 363*57718be8SEnji Cooper size_t len = strlen(matches) + 1, off = 0; 364*57718be8SEnji Cooper 365*57718be8SEnji Cooper ATF_REQUIRE((res = strdup(matches)) != NULL); 366*57718be8SEnji Cooper for (size_t i = 0; i < nm; i++) { 367*57718be8SEnji Cooper int l; 368*57718be8SEnji Cooper if (pm[i].rm_so == -1 && pm[i].rm_eo == -1) 369*57718be8SEnji Cooper l = snprintf(res + off, len - off, "(?,?)"); 370*57718be8SEnji Cooper else 371*57718be8SEnji Cooper l = snprintf(res + off, len - off, "(%lld,%lld)", 372*57718be8SEnji Cooper (long long)pm[i].rm_so, (long long)pm[i].rm_eo); 373*57718be8SEnji Cooper ATF_REQUIRE_MSG((size_t) l < len - off, "String too long %s" 374*57718be8SEnji Cooper " cur=%d, max=%zu", res, l, len - off); 375*57718be8SEnji Cooper off += l; 376*57718be8SEnji Cooper } 377*57718be8SEnji Cooper ATF_REQUIRE_STREQ_MSG(res, matches, " at line %zu", lineno); 378*57718be8SEnji Cooper free(res); 379*57718be8SEnji Cooper } 380*57718be8SEnji Cooper 381*57718be8SEnji Cooper static void 382*57718be8SEnji Cooper att_test(const struct atf_tc *tc, const char *data_name) 383*57718be8SEnji Cooper { 384*57718be8SEnji Cooper regex_t re; 385*57718be8SEnji Cooper char *line, *lastpattern = NULL, data_path[MAXPATHLEN]; 386*57718be8SEnji Cooper size_t len, lineno = 0; 387*57718be8SEnji Cooper int skipping = 0; 388*57718be8SEnji Cooper FILE *input_file; 389*57718be8SEnji Cooper 390*57718be8SEnji Cooper snprintf(data_path, sizeof(data_path), "%s/data/%s.dat", 391*57718be8SEnji Cooper atf_tc_get_config_var(tc, "srcdir"), data_name); 392*57718be8SEnji Cooper 393*57718be8SEnji Cooper input_file = fopen(data_path, "r"); 394*57718be8SEnji Cooper if (input_file == NULL) 395*57718be8SEnji Cooper atf_tc_fail("Failed to open input file %s", data_path); 396*57718be8SEnji Cooper 397*57718be8SEnji Cooper for (; (line = fparseln(input_file, &len, &lineno, delim, 0)) 398*57718be8SEnji Cooper != NULL; free(line)) { 399*57718be8SEnji Cooper char *name, *pattern, *input, *matches, *comment; 400*57718be8SEnji Cooper regmatch_t *pm; 401*57718be8SEnji Cooper size_t nm; 402*57718be8SEnji Cooper #ifdef DEBUG 403*57718be8SEnji Cooper fprintf(stderr, "[%s]\n", line); 404*57718be8SEnji Cooper #endif 405*57718be8SEnji Cooper if ((name = strtok(line, sep)) == NULL) 406*57718be8SEnji Cooper continue; 407*57718be8SEnji Cooper 408*57718be8SEnji Cooper /* 409*57718be8SEnji Cooper * We check these early so that we skip the lines quickly 410*57718be8SEnji Cooper * in order to do more strict testing on the other arguments 411*57718be8SEnji Cooper * The same characters are also tested in the switch below 412*57718be8SEnji Cooper */ 413*57718be8SEnji Cooper if (*name == '}') { 414*57718be8SEnji Cooper skipping = 0; 415*57718be8SEnji Cooper continue; 416*57718be8SEnji Cooper } 417*57718be8SEnji Cooper if (skipping) 418*57718be8SEnji Cooper continue; 419*57718be8SEnji Cooper if (*name == ';' || *name == '#' || strcmp(name, "NOTE") == 0) 420*57718be8SEnji Cooper continue; 421*57718be8SEnji Cooper if (*name == ':') { 422*57718be8SEnji Cooper /* Skip ":HA#???:" prefix */ 423*57718be8SEnji Cooper while (*++name && *name != ':') 424*57718be8SEnji Cooper continue; 425*57718be8SEnji Cooper if (*name) 426*57718be8SEnji Cooper name++; 427*57718be8SEnji Cooper } 428*57718be8SEnji Cooper 429*57718be8SEnji Cooper ATF_REQUIRE_MSG((pattern = strtok(NULL, sep)) != NULL, 430*57718be8SEnji Cooper "Missing pattern at line %zu", lineno); 431*57718be8SEnji Cooper ATF_REQUIRE_MSG((input = strtok(NULL, sep)) != NULL, 432*57718be8SEnji Cooper "Missing input at line %zu", lineno); 433*57718be8SEnji Cooper 434*57718be8SEnji Cooper if (strchr(name, '$')) { 435*57718be8SEnji Cooper ATF_REQUIRE(strunvis(pattern, pattern) != -1); 436*57718be8SEnji Cooper ATF_REQUIRE(strunvis(input, input) != -1); 437*57718be8SEnji Cooper } 438*57718be8SEnji Cooper 439*57718be8SEnji Cooper 440*57718be8SEnji Cooper if (strcmp(input, "NULL") == 0) 441*57718be8SEnji Cooper *input = '\0'; 442*57718be8SEnji Cooper 443*57718be8SEnji Cooper if (strcmp(pattern, "SAME") == 0) { 444*57718be8SEnji Cooper ATF_REQUIRE(lastpattern != NULL); 445*57718be8SEnji Cooper pattern = lastpattern; 446*57718be8SEnji Cooper } else { 447*57718be8SEnji Cooper free(lastpattern); 448*57718be8SEnji Cooper ATF_REQUIRE((lastpattern = strdup(pattern)) != NULL); 449*57718be8SEnji Cooper } 450*57718be8SEnji Cooper 451*57718be8SEnji Cooper ATF_REQUIRE_MSG((matches = strtok(NULL, sep)) != NULL, 452*57718be8SEnji Cooper "Missing matches at line %zu", lineno); 453*57718be8SEnji Cooper 454*57718be8SEnji Cooper comment = strtok(NULL, sep); 455*57718be8SEnji Cooper switch (*name) { 456*57718be8SEnji Cooper case '{': /* Begin optional implementation */ 457*57718be8SEnji Cooper if (optional(comment)) { 458*57718be8SEnji Cooper skipping++; 459*57718be8SEnji Cooper continue; 460*57718be8SEnji Cooper } 461*57718be8SEnji Cooper name++; /* We have it, so ignore */ 462*57718be8SEnji Cooper break; 463*57718be8SEnji Cooper case '}': /* End optional implementation */ 464*57718be8SEnji Cooper skipping = 0; 465*57718be8SEnji Cooper continue; 466*57718be8SEnji Cooper case '?': /* Optional */ 467*57718be8SEnji Cooper case '|': /* Alternative */ 468*57718be8SEnji Cooper if (unsupported(comment)) 469*57718be8SEnji Cooper continue; 470*57718be8SEnji Cooper name++; /* We have it, so ignore */ 471*57718be8SEnji Cooper break; 472*57718be8SEnji Cooper case '#': /* Comment */ 473*57718be8SEnji Cooper case ';': /* Skip */ 474*57718be8SEnji Cooper continue; 475*57718be8SEnji Cooper default: 476*57718be8SEnji Cooper break; 477*57718be8SEnji Cooper } 478*57718be8SEnji Cooper 479*57718be8SEnji Cooper /* XXX: Our bug */ 480*57718be8SEnji Cooper if (bug(pattern, input, lineno)) 481*57718be8SEnji Cooper continue; 482*57718be8SEnji Cooper 483*57718be8SEnji Cooper int comp, exec; 484*57718be8SEnji Cooper if (*matches != '(') { 485*57718be8SEnji Cooper geterror(matches, &comp, &exec); 486*57718be8SEnji Cooper pm = NULL; 487*57718be8SEnji Cooper nm = 0; 488*57718be8SEnji Cooper } else { 489*57718be8SEnji Cooper comp = exec = 0; 490*57718be8SEnji Cooper nm = getmatches(matches); 491*57718be8SEnji Cooper ATF_REQUIRE((pm = calloc(nm, sizeof(*pm))) != NULL); 492*57718be8SEnji Cooper } 493*57718be8SEnji Cooper 494*57718be8SEnji Cooper 495*57718be8SEnji Cooper 496*57718be8SEnji Cooper int iflags = getflags(name); 497*57718be8SEnji Cooper for (; *name; name++) { 498*57718be8SEnji Cooper int flags; 499*57718be8SEnji Cooper switch (*name) { 500*57718be8SEnji Cooper case 'B': 501*57718be8SEnji Cooper flags = REG_BASIC; 502*57718be8SEnji Cooper break; 503*57718be8SEnji Cooper case 'E': 504*57718be8SEnji Cooper flags = REG_EXTENDED; 505*57718be8SEnji Cooper break; 506*57718be8SEnji Cooper case 'L': 507*57718be8SEnji Cooper flags = REG_NOSPEC; 508*57718be8SEnji Cooper break; 509*57718be8SEnji Cooper default: 510*57718be8SEnji Cooper ATF_REQUIRE_MSG(0, "Bad name %c", *name); 511*57718be8SEnji Cooper continue; 512*57718be8SEnji Cooper } 513*57718be8SEnji Cooper int c = regcomp(&re, pattern, flags | iflags); 514*57718be8SEnji Cooper ATF_REQUIRE_MSG(c == comp, 515*57718be8SEnji Cooper "regcomp returned %d for pattern %s at line %zu", 516*57718be8SEnji Cooper c, pattern, lineno); 517*57718be8SEnji Cooper if (c) 518*57718be8SEnji Cooper continue; 519*57718be8SEnji Cooper int e = regexec(&re, input, nm, pm, 0); 520*57718be8SEnji Cooper ATF_REQUIRE_MSG(e == exec, "Expected error %d," 521*57718be8SEnji Cooper " got %d at line %zu", exec, e, lineno); 522*57718be8SEnji Cooper checkmatches(matches, nm, pm, lineno); 523*57718be8SEnji Cooper checkcomment(comment, lineno); 524*57718be8SEnji Cooper regfree(&re); 525*57718be8SEnji Cooper } 526*57718be8SEnji Cooper free(pm); 527*57718be8SEnji Cooper } 528*57718be8SEnji Cooper 529*57718be8SEnji Cooper fclose(input_file); 530*57718be8SEnji Cooper } 531*57718be8SEnji Cooper 532*57718be8SEnji Cooper ATF_TC(basic); 533*57718be8SEnji Cooper ATF_TC_HEAD(basic, tc) 534*57718be8SEnji Cooper { 535*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests basic functionality"); 536*57718be8SEnji Cooper } 537*57718be8SEnji Cooper ATF_TC_BODY(basic, tc) 538*57718be8SEnji Cooper { 539*57718be8SEnji Cooper att_test(tc, "basic"); 540*57718be8SEnji Cooper } 541*57718be8SEnji Cooper 542*57718be8SEnji Cooper ATF_TC(categorization); 543*57718be8SEnji Cooper ATF_TC_HEAD(categorization, tc) 544*57718be8SEnji Cooper { 545*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests implementation categorization"); 546*57718be8SEnji Cooper } 547*57718be8SEnji Cooper ATF_TC_BODY(categorization, tc) 548*57718be8SEnji Cooper { 549*57718be8SEnji Cooper att_test(tc, "categorization"); 550*57718be8SEnji Cooper } 551*57718be8SEnji Cooper 552*57718be8SEnji Cooper ATF_TC(nullsubexpr); 553*57718be8SEnji Cooper ATF_TC_HEAD(nullsubexpr, tc) 554*57718be8SEnji Cooper { 555*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests (...)*"); 556*57718be8SEnji Cooper } 557*57718be8SEnji Cooper ATF_TC_BODY(nullsubexpr, tc) 558*57718be8SEnji Cooper { 559*57718be8SEnji Cooper att_test(tc, "nullsubexpr"); 560*57718be8SEnji Cooper } 561*57718be8SEnji Cooper 562*57718be8SEnji Cooper ATF_TC(leftassoc); 563*57718be8SEnji Cooper ATF_TC_HEAD(leftassoc, tc) 564*57718be8SEnji Cooper { 565*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests left-associative " 566*57718be8SEnji Cooper "implementations"); 567*57718be8SEnji Cooper } 568*57718be8SEnji Cooper ATF_TC_BODY(leftassoc, tc) 569*57718be8SEnji Cooper { 570*57718be8SEnji Cooper #if SKIP_LEFTASSOC 571*57718be8SEnji Cooper /* jmmv: I converted the original shell-based tests to C and they 572*57718be8SEnji Cooper * disabled this test in a very unconventional way without giving 573*57718be8SEnji Cooper * any explation. Mark as broken here, but I don't know why. */ 574*57718be8SEnji Cooper atf_tc_expect_fail("Reason for breakage unknown"); 575*57718be8SEnji Cooper #endif 576*57718be8SEnji Cooper att_test(tc, "leftassoc"); 577*57718be8SEnji Cooper } 578*57718be8SEnji Cooper 579*57718be8SEnji Cooper ATF_TC(rightassoc); 580*57718be8SEnji Cooper ATF_TC_HEAD(rightassoc, tc) 581*57718be8SEnji Cooper { 582*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests right-associative " 583*57718be8SEnji Cooper "implementations"); 584*57718be8SEnji Cooper } 585*57718be8SEnji Cooper ATF_TC_BODY(rightassoc, tc) 586*57718be8SEnji Cooper { 587*57718be8SEnji Cooper #if SKIP_RIGHTASSOC 588*57718be8SEnji Cooper /* jmmv: I converted the original shell-based tests to C and they 589*57718be8SEnji Cooper * disabled this test in a very unconventional way without giving 590*57718be8SEnji Cooper * any explation. Mark as broken here, but I don't know why. */ 591*57718be8SEnji Cooper atf_tc_expect_fail("Reason for breakage unknown"); 592*57718be8SEnji Cooper #endif 593*57718be8SEnji Cooper att_test(tc, "rightassoc"); 594*57718be8SEnji Cooper } 595*57718be8SEnji Cooper 596*57718be8SEnji Cooper ATF_TC(forcedassoc); 597*57718be8SEnji Cooper ATF_TC_HEAD(forcedassoc, tc) 598*57718be8SEnji Cooper { 599*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests subexpression grouping to " 600*57718be8SEnji Cooper "force association"); 601*57718be8SEnji Cooper } 602*57718be8SEnji Cooper ATF_TC_BODY(forcedassoc, tc) 603*57718be8SEnji Cooper { 604*57718be8SEnji Cooper att_test(tc, "forcedassoc"); 605*57718be8SEnji Cooper } 606*57718be8SEnji Cooper 607*57718be8SEnji Cooper ATF_TC(repetition); 608*57718be8SEnji Cooper ATF_TC_HEAD(repetition, tc) 609*57718be8SEnji Cooper { 610*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Tests implicit vs. explicit " 611*57718be8SEnji Cooper "repetition"); 612*57718be8SEnji Cooper } 613*57718be8SEnji Cooper ATF_TC_BODY(repetition, tc) 614*57718be8SEnji Cooper { 615*57718be8SEnji Cooper att_test(tc, "repetition"); 616*57718be8SEnji Cooper } 617*57718be8SEnji Cooper 618*57718be8SEnji Cooper ATF_TP_ADD_TCS(tp) 619*57718be8SEnji Cooper { 620*57718be8SEnji Cooper 621*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, basic); 622*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, categorization); 623*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, nullsubexpr); 624*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, leftassoc); 625*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, rightassoc); 626*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, forcedassoc); 627*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, repetition); 628*57718be8SEnji Cooper return atf_no_error(); 629*57718be8SEnji Cooper } 630