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