123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145 |
- /*
- * regex(3) test harness
- *
- * build: cc -o testregex testregex.c
- * help: testregex --man
- * note: REG_* features are detected by #ifdef; if REG_* are enums
- * then supply #define REG_foo REG_foo for each enum REG_foo
- *
- * Glenn Fowler <gsf@research.att.com>
- * AT&T Labs Research
- *
- * PLEASE: publish your tests so everyone can benefit
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, and/or sell copies of the
- * Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following disclaimer:
- *
- * THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- static const char id[] = "\n@(#)$Id: testregex (AT&T Research) 2005-05-20 $\0\n";
- #if _PACKAGE_ast
- #include <ast.h>
- #else
- #include <sys/types.h>
- #endif
- #include <stdio.h>
- #include <regex.h>
- #include <ctype.h>
- #include <setjmp.h>
- #include <signal.h>
- #include <string.h>
- #include <unistd.h>
- #ifdef __STDC__
- #include <stdlib.h>
- #include <locale.h>
- #endif
- #if !_PACKAGE_ast
- #undef REG_DISCIPLINE
- #endif
- #ifndef REG_DELIMITED
- #undef _REG_subcomp
- #endif
- #define TEST_ARE 0x00000001
- #define TEST_BRE 0x00000002
- #define TEST_ERE 0x00000004
- #define TEST_KRE 0x00000008
- #define TEST_LRE 0x00000010
- #define TEST_SRE 0x00000020
- #define TEST_EXPAND 0x00000040
- #define TEST_LENIENT 0x00000080
- #define TEST_QUERY 0x00000100
- #define TEST_SUB 0x00000200
- #define TEST_UNSPECIFIED 0x00000400
- #define TEST_VERIFY 0x00000800
- #define TEST_AND 0x00001000
- #define TEST_OR 0x00002000
- #define TEST_DELIMIT 0x00010000
- #define TEST_OK 0x00020000
- #define TEST_SAME 0x00040000
- #define TEST_ACTUAL 0x00100000
- #define TEST_BASELINE 0x00200000
- #define TEST_FAIL 0x00400000
- #define TEST_PASS 0x00800000
- #define TEST_SUMMARY 0x01000000
- #define TEST_IGNORE_ERROR 0x02000000
- #define TEST_IGNORE_OVER 0x04000000
- #define TEST_IGNORE_POSITION 0x08000000
- #define TEST_CATCH 0x10000000
- #define TEST_VERBOSE 0x20000000
- #define TEST_GLOBAL (TEST_ACTUAL|TEST_AND|TEST_BASELINE|TEST_CATCH|TEST_FAIL|TEST_IGNORE_ERROR|TEST_IGNORE_OVER|TEST_IGNORE_POSITION|TEST_OR|TEST_PASS|TEST_SUMMARY|TEST_VERBOSE)
- #ifdef REG_DISCIPLINE
- #include <stk.h>
- typedef struct Disc_s
- {
- regdisc_t disc;
- int ordinal;
- Sfio_t* sp;
- } Disc_t;
- static void*
- compf(const regex_t* re, const char* xstr, size_t xlen, regdisc_t* disc)
- {
- Disc_t* dp = (Disc_t*)disc;
- return (void*)++dp->ordinal;
- }
- static int
- execf(const regex_t* re, void* data, const char* xstr, size_t xlen, const char* sstr, size_t slen, char** snxt, regdisc_t* disc)
- {
- Disc_t* dp = (Disc_t*)disc;
- sfprintf(dp->sp, "{%-.*s}(%d:%d)", xlen, xstr, (int)data, slen);
- return atoi(xstr);
- }
- static void*
- resizef(void* handle, void* data, size_t size)
- {
- if (!size)
- return 0;
- return stkalloc((Sfio_t*)handle, size);
- }
- #endif
- #ifndef NiL
- #ifdef __STDC__
- #define NiL 0
- #else
- #define NiL (char*)0
- #endif
- #endif
- #define H(x) do{if(html)fprintf(stderr,x);}while(0)
- #define T(x) fprintf(stderr,x)
- static void
- help(int html)
- {
- H("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n");
- H("<HTML>\n");
- H("<HEAD>\n");
- H("<TITLE>testregex man document</TITLE>\n");
- H("</HEAD>\n");
- H("<BODY bgcolor=white>\n");
- H("<PRE>\n");
- T("NAME\n");
- T(" testregex - regex(3) test harness\n");
- T("\n");
- T("SYNOPSIS\n");
- T(" testregex [ options ]\n");
- T("\n");
- T("DESCRIPTION\n");
- T(" testregex reads regex(3) test specifications, one per line, from the\n");
- T(" standard input and writes one output line for each failed test. A\n");
- T(" summary line is written after all tests are done. Each successful\n");
- T(" test is run again with REG_NOSUB. Unsupported features are noted\n");
- T(" before the first test, and tests requiring these features are\n");
- T(" silently ignored.\n");
- T("\n");
- T("OPTIONS\n");
- T(" -c catch signals and non-terminating calls\n");
- T(" -e ignore error return mismatches\n");
- T(" -h list help on standard error\n");
- T(" -n do not repeat successful tests with regnexec()\n");
- T(" -o ignore match[] overrun errors\n");
- T(" -p ignore negative position mismatches\n");
- T(" -s use stack instead of malloc\n");
- T(" -x do not repeat successful tests with REG_NOSUB\n");
- T(" -v list each test line\n");
- T(" -A list failed test lines with actual answers\n");
- T(" -B list all test lines with actual answers\n");
- T(" -F list failed test lines\n");
- T(" -P list passed test lines\n");
- T(" -S output one summary line\n");
- T("\n");
- T("INPUT FORMAT\n");
- T(" Input lines may be blank, a comment beginning with #, or a test\n");
- T(" specification. A specification is five fields separated by one\n");
- T(" or more tabs. NULL denotes the empty string and NIL denotes the\n");
- T(" 0 pointer.\n");
- T("\n");
- T(" Field 1: the regex(3) flags to apply, one character per REG_feature\n");
- T(" flag. The test is skipped if REG_feature is not supported by the\n");
- T(" implementation. If the first character is not [BEASKL] then the\n");
- T(" specification is a global control line. One or more of [BEASKL] may be\n");
- T(" specified; the test will be repeated for each mode.\n");
- T("\n");
- T(" B basic BRE (grep, ed, sed)\n");
- T(" E REG_EXTENDED ERE (egrep)\n");
- T(" A REG_AUGMENTED ARE (egrep with negation)\n");
- T(" S REG_SHELL SRE (sh glob)\n");
- T(" K REG_SHELL|REG_AUGMENTED KRE (ksh glob)\n");
- T(" L REG_LITERAL LRE (fgrep)\n");
- T("\n");
- T(" a REG_LEFT|REG_RIGHT implicit ^...$\n");
- T(" b REG_NOTBOL lhs does not match ^\n");
- T(" c REG_COMMENT ignore space and #...\\n\n");
- T(" d REG_SHELL_DOT explicit leading . match\n");
- T(" e REG_NOTEOL rhs does not match $\n");
- T(" f REG_MULTIPLE multiple \\n separated patterns\n");
- T(" g FNM_LEADING_DIR testfnmatch only -- match until /\n");
- T(" h REG_MULTIREF multiple digit backref\n");
- T(" i REG_ICASE ignore case\n");
- T(" j REG_SPAN . matches \\n\n");
- T(" k REG_ESCAPE \\ to ecape [...] delimiter\n");
- T(" l REG_LEFT implicit ^...\n");
- T(" m REG_MINIMAL minimal match\n");
- T(" n REG_NEWLINE explicit \\n match\n");
- T(" o REG_ENCLOSED (|&) magic inside [@|&](...)\n");
- T(" p REG_SHELL_PATH explicit / match\n");
- T(" q REG_DELIMITED delimited pattern\n");
- T(" r REG_RIGHT implicit ...$\n");
- T(" s REG_SHELL_ESCAPED \\ not special\n");
- T(" t REG_MUSTDELIM all delimiters must be specified\n");
- T(" u standard unspecified behavior -- errors not counted\n");
- T(" w REG_NOSUB no subexpression match array\n");
- T(" x REG_LENIENT let some errors slide\n");
- T(" y REG_LEFT regexec() implicit ^...\n");
- T(" z REG_NULL NULL subexpressions ok\n");
- T(" $ expand C \\c escapes in fields 2 and 3\n");
- T(" / field 2 is a regsubcomp() expression\n");
- T("\n");
- T(" Field 1 control lines:\n");
- T("\n");
- T(" C set LC_COLLATE and LC_CTYPE to locale in field 2\n");
- T("\n");
- T(" ?test ... output field 5 if passed and != EXPECTED, silent otherwise\n");
- T(" &test ... output field 5 if current and previous passed\n");
- T(" |test ... output field 5 if current passed and previous failed\n");
- T(" ; ... output field 2 if previous failed\n");
- T(" {test ... skip if failed until }\n");
- T(" } end of skip\n");
- T("\n");
- T(" : comment comment copied as output NOTE\n");
- T(" :comment:test :comment: ignored\n");
- T(" N[OTE] comment comment copied as output NOTE\n");
- T(" T[EST] comment comment\n");
- T("\n");
- T(" number use number for nmatch (20 by default)\n");
- T("\n");
- T(" Field 2: the regular expression pattern; SAME uses the pattern from\n");
- T(" the previous specification.\n");
- T("\n");
- T(" Field 3: the string to match.\n");
- T("\n");
- T(" Field 4: the test outcome. This is either one of the posix error\n");
- T(" codes (with REG_ omitted) or the match array, a list of (m,n)\n");
- T(" entries with m and n being first and last+1 positions in the\n");
- T(" field 3 string, or NULL if REG_NOSUB is in effect and success\n");
- T(" is expected. BADPAT is acceptable in place of any regcomp(3)\n");
- T(" error code. The match[] array is initialized to (-2,-2) before\n");
- T(" each test. All array elements from 0 to nmatch-1 must be specified\n");
- T(" in the outcome. Unspecified endpoints (offset -1) are denoted by ?.\n");
- T(" Unset endpoints (offset -2) are denoted by X. {x}(o:n) denotes a\n");
- T(" matched (?{...}) expression, where x is the text enclosed by {...},\n");
- T(" o is the expression ordinal counting from 1, and n is the length of\n");
- T(" the unmatched portion of the subject string. If x starts with a\n");
- T(" number then that is the return value of re_execf(), otherwise 0 is\n");
- T(" returned.\n");
- T("\n");
- T(" Field 5: optional comment appended to the report.\n");
- T("\n");
- T("CAVEAT\n");
- T(" If a regex implementation misbehaves with memory then all bets are off.\n");
- T("\n");
- T("CONTRIBUTORS\n");
- T(" Glenn Fowler gsf@research.att.com (ksh strmatch, regex extensions)\n");
- T(" David Korn dgk@research.att.com (ksh glob matcher)\n");
- T(" Doug McIlroy mcilroy@dartmouth.edu (ast regex/testre in C++)\n");
- T(" Tom Lord lord@regexps.com (rx tests)\n");
- T(" Henry Spencer henry@zoo.toronto.edu (original public regex)\n");
- T(" Andrew Hume andrew@research.att.com (gre tests)\n");
- T(" John Maddock John_Maddock@compuserve.com (regex++ tests)\n");
- T(" Philip Hazel ph10@cam.ac.uk (pcre tests)\n");
- T(" Ville Laurikari vl@iki.fi (libtre tests)\n");
- H("</PRE>\n");
- H("</BODY>\n");
- H("</HTML>\n");
- }
- #ifndef elementsof
- #define elementsof(x) (sizeof(x)/sizeof(x[0]))
- #endif
- #ifndef streq
- #define streq(a,b) (*(a)==*(b)&&!strcmp(a,b))
- #endif
- #define HUNG 5
- #define NOTEST (~0)
- #ifndef REG_TEST_DEFAULT
- #define REG_TEST_DEFAULT 0
- #endif
- #ifndef REG_EXEC_DEFAULT
- #define REG_EXEC_DEFAULT 0
- #endif
- static const char* unsupported[] =
- {
- "BASIC",
- #ifndef REG_EXTENDED
- "EXTENDED",
- #endif
- #ifndef REG_AUGMENTED
- "AUGMENTED",
- #endif
- #ifndef REG_SHELL
- "SHELL",
- #endif
- #ifndef REG_COMMENT
- "COMMENT",
- #endif
- #ifndef REG_DELIMITED
- "DELIMITED",
- #endif
- #ifndef REG_DISCIPLINE
- "DISCIPLINE",
- #endif
- #ifndef REG_ESCAPE
- "ESCAPE",
- #endif
- #ifndef REG_ICASE
- "ICASE",
- #endif
- #ifndef REG_LEFT
- "LEFT",
- #endif
- #ifndef REG_LENIENT
- "LENIENT",
- #endif
- #ifndef REG_LITERAL
- "LITERAL",
- #endif
- #ifndef REG_MINIMAL
- "MINIMAL",
- #endif
- #ifndef REG_MULTIPLE
- "MULTIPLE",
- #endif
- #ifndef REG_MULTIREF
- "MULTIREF",
- #endif
- #ifndef REG_MUSTDELIM
- "MUSTDELIM",
- #endif
- #ifndef REG_NEWLINE
- "NEWLINE",
- #endif
- #ifndef REG_NOTBOL
- "NOTBOL",
- #endif
- #ifndef REG_NOTEOL
- "NOTEOL",
- #endif
- #ifndef REG_NULL
- "NULL",
- #endif
- #ifndef REG_RIGHT
- "RIGHT",
- #endif
- #ifndef REG_SHELL_DOT
- "SHELL_DOT",
- #endif
- #ifndef REG_SHELL_ESCAPED
- "SHELL_ESCAPED",
- #endif
- #ifndef REG_SHELL_GROUP
- "SHELL_GROUP",
- #endif
- #ifndef REG_SHELL_PATH
- "SHELL_PATH",
- #endif
- #ifndef REG_SPAN
- "SPAN",
- #endif
- #if REG_NOSUB & REG_TEST_DEFAULT
- "SUBMATCH",
- #endif
- #if !_REG_nexec
- "regnexec",
- #endif
- #if !_REG_subcomp
- "regsubcomp",
- #endif
- 0
- };
- #ifndef REG_COMMENT
- #define REG_COMMENT NOTEST
- #endif
- #ifndef REG_DELIMITED
- #define REG_DELIMITED NOTEST
- #endif
- #ifndef REG_ESCAPE
- #define REG_ESCAPE NOTEST
- #endif
- #ifndef REG_ICASE
- #define REG_ICASE NOTEST
- #endif
- #ifndef REG_LEFT
- #define REG_LEFT NOTEST
- #endif
- #ifndef REG_LENIENT
- #define REG_LENIENT 0
- #endif
- #ifndef REG_MINIMAL
- #define REG_MINIMAL NOTEST
- #endif
- #ifndef REG_MULTIPLE
- #define REG_MULTIPLE NOTEST
- #endif
- #ifndef REG_MULTIREF
- #define REG_MULTIREF NOTEST
- #endif
- #ifndef REG_MUSTDELIM
- #define REG_MUSTDELIM NOTEST
- #endif
- #ifndef REG_NEWLINE
- #define REG_NEWLINE NOTEST
- #endif
- #ifndef REG_NOTBOL
- #define REG_NOTBOL NOTEST
- #endif
- #ifndef REG_NOTEOL
- #define REG_NOTEOL NOTEST
- #endif
- #ifndef REG_NULL
- #define REG_NULL NOTEST
- #endif
- #ifndef REG_RIGHT
- #define REG_RIGHT NOTEST
- #endif
- #ifndef REG_SHELL_DOT
- #define REG_SHELL_DOT NOTEST
- #endif
- #ifndef REG_SHELL_ESCAPED
- #define REG_SHELL_ESCAPED NOTEST
- #endif
- #ifndef REG_SHELL_GROUP
- #define REG_SHELL_GROUP NOTEST
- #endif
- #ifndef REG_SHELL_PATH
- #define REG_SHELL_PATH NOTEST
- #endif
- #ifndef REG_SPAN
- #define REG_SPAN NOTEST
- #endif
- #define REG_UNKNOWN (-1)
- #ifndef REG_ENEWLINE
- #define REG_ENEWLINE (REG_UNKNOWN-1)
- #endif
- #ifndef REG_ENULL
- #ifndef REG_EMPTY
- #define REG_ENULL (REG_UNKNOWN-2)
- #else
- #define REG_ENULL REG_EMPTY
- #endif
- #endif
- #ifndef REG_ECOUNT
- #define REG_ECOUNT (REG_UNKNOWN-3)
- #endif
- #ifndef REG_BADESC
- #define REG_BADESC (REG_UNKNOWN-4)
- #endif
- #ifndef REG_EMEM
- #define REG_EMEM (REG_UNKNOWN-5)
- #endif
- #ifndef REG_EHUNG
- #define REG_EHUNG (REG_UNKNOWN-6)
- #endif
- #ifndef REG_EBUS
- #define REG_EBUS (REG_UNKNOWN-7)
- #endif
- #ifndef REG_EFAULT
- #define REG_EFAULT (REG_UNKNOWN-8)
- #endif
- #ifndef REG_EFLAGS
- #define REG_EFLAGS (REG_UNKNOWN-9)
- #endif
- #ifndef REG_EDELIM
- #define REG_EDELIM (REG_UNKNOWN-9)
- #endif
- static const struct { int code; char* name; } codes[] =
- {
- {REG_UNKNOWN, "UNKNOWN"},
- {REG_NOMATCH, "NOMATCH"},
- {REG_BADPAT, "BADPAT"},
- {REG_ECOLLATE, "ECOLLATE"},
- {REG_ECTYPE, "ECTYPE"},
- {REG_EESCAPE, "EESCAPE"},
- {REG_ESUBREG, "ESUBREG"},
- {REG_EBRACK, "EBRACK"},
- {REG_EPAREN, "EPAREN"},
- {REG_EBRACE, "EBRACE"},
- {REG_BADBR, "BADBR"},
- {REG_ERANGE, "ERANGE"},
- {REG_ESPACE, "ESPACE"},
- {REG_BADRPT, "BADRPT"},
- {REG_ENEWLINE, "ENEWLINE"},
- {REG_ENULL, "ENULL"},
- {REG_ECOUNT, "ECOUNT"},
- {REG_BADESC, "BADESC"},
- {REG_EMEM, "EMEM"},
- {REG_EHUNG, "EHUNG"},
- {REG_EBUS, "EBUS"},
- {REG_EFAULT, "EFAULT"},
- {REG_EFLAGS, "EFLAGS"},
- {REG_EDELIM, "EDELIM"},
- };
- static struct
- {
- regmatch_t NOMATCH;
- int errors;
- int extracted;
- int ignored;
- int lineno;
- int passed;
- int signals;
- int unspecified;
- int verify;
- int warnings;
- char* file;
- char* stack;
- char* which;
- jmp_buf gotcha;
- #ifdef REG_DISCIPLINE
- Disc_t disc;
- #endif
- } state;
- static void
- quote(char* s, int len, unsigned long test)
- {
- unsigned char* u = (unsigned char*)s;
- unsigned char* e;
- int c;
- if (!u)
- printf("NIL");
- else if (!*u && len <= 1)
- printf("NULL");
- else if (test & TEST_EXPAND)
- {
- if (len < 0)
- len = strlen((char*)u);
- e = u + len;
- if (test & TEST_DELIMIT)
- printf("\"");
- while (u < e)
- switch (c = *u++)
- {
- case '\\':
- printf("\\\\");
- break;
- case '"':
- if (test & TEST_DELIMIT)
- printf("\\\"");
- else
- printf("\"");
- break;
- case '\a':
- printf("\\a");
- break;
- case '\b':
- printf("\\b");
- break;
- case 033:
- printf("\\e");
- break;
- case '\f':
- printf("\\f");
- break;
- case '\n':
- printf("\\n");
- break;
- case '\r':
- printf("\\r");
- break;
- case '\t':
- printf("\\t");
- break;
- case '\v':
- printf("\\v");
- break;
- default:
- if (!iscntrl(c) && isprint(c))
- putchar(c);
- else
- printf("\\x%02x", c);
- break;
- }
- if (test & TEST_DELIMIT)
- printf("\"");
- }
- else
- printf("%s", s);
- }
- static void
- report(char* comment, char* fun, char* re, char* s, int len, char* msg, int flags, unsigned long test)
- {
- if (state.file)
- printf("%s:", state.file);
- printf("%d:", state.lineno);
- if (re)
- {
- printf(" ");
- quote(re, -1, test|TEST_DELIMIT);
- if (s)
- {
- printf(" versus ");
- quote(s, len, test|TEST_DELIMIT);
- }
- }
- if (test & TEST_UNSPECIFIED)
- {
- state.unspecified++;
- printf(" unspecified behavior");
- }
- else
- state.errors++;
- if (state.which)
- printf(" %s", state.which);
- if (flags & REG_NOSUB)
- printf(" NOSUB");
- if (fun)
- printf(" %s", fun);
- if (comment[strlen(comment)-1] == '\n')
- printf(" %s", comment);
- else
- {
- printf(" %s: ", comment);
- if (msg)
- printf("%s: ", msg);
- }
- }
- static void
- error(regex_t* preg, int code)
- {
- char* msg;
- char buf[256];
- switch (code)
- {
- case REG_EBUS:
- msg = "bus error";
- break;
- case REG_EFAULT:
- msg = "memory fault";
- break;
- case REG_EHUNG:
- msg = "did not terminate";
- break;
- default:
- regerror(code, preg, msg = buf, sizeof buf);
- break;
- }
- printf("%s\n", msg);
- }
- static void
- bad(char* comment, char* re, char* s, int len, unsigned long test)
- {
- printf("bad test case ");
- report(comment, NiL, re, s, len, NiL, 0, test);
- exit(1);
- }
- static int
- escape(char* s)
- {
- char* b;
- char* t;
- char* q;
- char* e;
- int c;
- for (b = t = s; (*t = *s); s++, t++)
- if (*s == '\\')
- switch (*++s)
- {
- case '\\':
- break;
- case 'a':
- *t = '\a';
- break;
- case 'b':
- *t = '\b';
- break;
- case 'c':
- if ((*t = *++s))
- *t &= 037;
- else
- s--;
- break;
- case 'e':
- case 'E':
- *t = 033;
- break;
- case 'f':
- *t = '\f';
- break;
- case 'n':
- *t = '\n';
- break;
- case 'r':
- *t = '\r';
- break;
- case 's':
- *t = ' ';
- break;
- case 't':
- *t = '\t';
- break;
- case 'v':
- *t = '\v';
- break;
- case 'u':
- case 'x':
- c = 0;
- q = c == 'u' ? (s + 5) : (char*)0;
- e = s + 1;
- while (!e || !q || s < q)
- {
- switch (*++s)
- {
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- c = (c << 4) + *s - 'a' + 10;
- continue;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- c = (c << 4) + *s - 'A' + 10;
- continue;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- c = (c << 4) + *s - '0';
- continue;
- case '{':
- case '[':
- if (s != e)
- {
- s--;
- break;
- }
- e = 0;
- continue;
- case '}':
- case ']':
- if (e)
- s--;
- break;
- default:
- s--;
- break;
- }
- break;
- }
- *t = c;
- break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- c = *s - '0';
- q = s + 2;
- while (s < q)
- {
- switch (*++s)
- {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- c = (c << 3) + *s - '0';
- break;
- default:
- q = --s;
- break;
- }
- }
- *t = c;
- break;
- default:
- *(s + 1) = 0;
- bad("invalid C \\ escape\n", s - 1, NiL, 0, 0);
- }
- return t - b;
- }
- static void
- matchoffprint(int off)
- {
- switch (off)
- {
- case -2:
- printf("X");
- break;
- case -1:
- printf("?");
- break;
- default:
- printf("%d", off);
- break;
- }
- }
- static void
- matchprint(regmatch_t* match, int nmatch, int nsub, char* ans, unsigned long test)
- {
- int i;
- for (; nmatch > nsub + 1; nmatch--)
- if ((match[nmatch-1].rm_so != -1 || match[nmatch-1].rm_eo != -1) && (!(test & TEST_IGNORE_POSITION) || (match[nmatch-1].rm_so >= 0 && match[nmatch-1].rm_eo >= 0)))
- break;
- for (i = 0; i < nmatch; i++)
- {
- printf("(");
- matchoffprint(match[i].rm_so);
- printf(",");
- matchoffprint(match[i].rm_eo);
- printf(")");
- }
- if (!(test & (TEST_ACTUAL|TEST_BASELINE)))
- {
- if (ans)
- printf(" expected: %s", ans);
- printf("\n");
- }
- }
- static int
- matchcheck(regmatch_t* match, int nmatch, int nsub, char* ans, char* re, char* s, int len, int flags, unsigned long test)
- {
- char* p;
- int i;
- int m;
- int n;
- if (streq(ans, "OK"))
- return test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY);
- for (i = 0, p = ans; i < nmatch && *p; i++)
- {
- if (*p == '{')
- {
- #ifdef REG_DISCIPLINE
- char* x;
- x = sfstruse(state.disc.sp);
- if (strcmp(p, x))
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- return 0;
- report("callout failed", NiL, re, s, len, NiL, flags, test);
- quote(p, -1, test);
- printf(" expected, ");
- quote(x, -1, test);
- printf(" returned\n");
- }
- #endif
- break;
- }
- if (*p++ != '(')
- bad("improper answer\n", re, s, -1, test);
- if (*p == '?')
- {
- m = -1;
- p++;
- }
- else
- m = strtol(p, &p, 10);
- if (*p++ != ',')
- bad("improper answer\n", re, s, -1, test);
- if (*p == '?')
- {
- n = -1;
- p++;
- }
- else
- n = strtol(p, &p, 10);
- if (*p++ != ')')
- bad("improper answer\n", re, s, -1, test);
- if (m!=match[i].rm_so || n!=match[i].rm_eo)
- {
- if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
- {
- report("failed: match was", NiL, re, s, len, NiL, flags, test);
- matchprint(match, nmatch, nsub, ans, test);
- }
- return 0;
- }
- }
- for (; i < nmatch; i++)
- {
- if (match[i].rm_so!=-1 || match[i].rm_eo!=-1)
- {
- if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_VERIFY)))
- {
- if ((test & TEST_IGNORE_POSITION) && (match[i].rm_so<0 || match[i].rm_eo<0))
- {
- state.ignored++;
- return 0;
- }
- if (!(test & TEST_SUMMARY))
- {
- report("failed: match was", NiL, re, s, len, NiL, flags, test);
- matchprint(match, nmatch, nsub, ans, test);
- }
- }
- return 0;
- }
- }
- if (!(test & TEST_IGNORE_OVER) && match[nmatch].rm_so != state.NOMATCH.rm_so)
- {
- if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
- {
- report("failed: overran match array", NiL, re, s, len, NiL, flags, test);
- matchprint(match, nmatch + 1, nsub, NiL, test);
- }
- return 0;
- }
- return 1;
- }
- static void
- sigunblock(int s)
- {
- #ifdef SIG_SETMASK
- int op;
- sigset_t mask;
- sigemptyset(&mask);
- if (s)
- {
- sigaddset(&mask, s);
- op = SIG_UNBLOCK;
- }
- else op = SIG_SETMASK;
- sigprocmask(op, &mask, NiL);
- #else
- #ifdef sigmask
- sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);
- #endif
- #endif
- }
- static void
- gotcha(int sig)
- {
- int ret;
- signal(sig, gotcha);
- alarm(0);
- state.signals++;
- switch (sig)
- {
- case SIGALRM:
- ret = REG_EHUNG;
- break;
- case SIGBUS:
- ret = REG_EBUS;
- break;
- default:
- ret = REG_EFAULT;
- break;
- }
- sigunblock(sig);
- longjmp(state.gotcha, ret);
- }
- static char*
- my_getline(FILE* fp)
- {
- static char buf[32 * 1024];
- register char* s = buf;
- register char* e = &buf[sizeof(buf)];
- register char* b;
- for (;;)
- {
- if (!(b = fgets(s, e - s, fp)))
- return 0;
- state.lineno++;
- s += strlen(s);
- if (s == b || *--s != '\n' || s == b || *(s - 1) != '\\')
- {
- *s = 0;
- break;
- }
- s--;
- }
- return buf;
- }
- static unsigned long
- note(unsigned long level, char* msg, unsigned long skip, unsigned long test)
- {
- if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)) && !skip)
- {
- printf("NOTE\t");
- if (msg)
- printf("%s: ", msg);
- printf("skipping lines %d", state.lineno);
- }
- return skip | level;
- }
- #define TABS(n) &ts[7-((n)&7)]
- static char ts[] = "\t\t\t\t\t\t\t";
- static unsigned long
- extract(int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_OK|TEST_PASS|TEST_SUMMARY))
- {
- state.extracted = 1;
- if (test & TEST_OK)
- {
- state.passed++;
- if ((test & TEST_VERIFY) && !(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
- {
- if (msg && strcmp(msg, "EXPECTED"))
- printf("NOTE\t%s\n", msg);
- return skip;
- }
- test &= ~(TEST_PASS|TEST_QUERY);
- }
- if (test & (TEST_QUERY|TEST_VERIFY))
- {
- if (test & TEST_BASELINE)
- test &= ~(TEST_BASELINE|TEST_PASS);
- else
- test |= TEST_PASS;
- skip |= level;
- }
- if (!(test & TEST_OK))
- {
- if (test & TEST_UNSPECIFIED)
- state.unspecified++;
- else
- state.errors++;
- }
- if (test & (TEST_PASS|TEST_SUMMARY))
- return skip;
- test &= ~TEST_DELIMIT;
- printf("%s%s", spec, TABS(*tabs++));
- if ((test & (TEST_BASELINE|TEST_SAME)) == (TEST_BASELINE|TEST_SAME))
- printf("SAME");
- else
- quote(re, -1, test);
- printf("%s", TABS(*tabs++));
- quote(s, -1, test);
- printf("%s", TABS(*tabs++));
- if (!(test & (TEST_ACTUAL|TEST_BASELINE)) || (!accept && !match))
- printf("%s", ans);
- else if (accept)
- printf("%s", accept);
- else
- matchprint(match, nmatch, nsub, NiL, test);
- if (msg)
- printf("%s%s", TABS(*tabs++), msg);
- putchar('\n');
- }
- else if (test & TEST_QUERY)
- skip = note(level, msg, skip, test);
- else if (test & TEST_VERIFY)
- state.extracted = 1;
- return skip;
- }
- static int
- catchfree(regex_t* preg, int flags, int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
- {
- int eret;
- if (!(test & TEST_CATCH))
- {
- regfree(preg);
- eret = 0;
- }
- else if (!(eret = setjmp(state.gotcha)))
- {
- alarm(HUNG);
- regfree(preg);
- alarm(0);
- }
- else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- extract(tabs, spec, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
- else
- {
- report("failed", "regfree", re, NiL, -1, msg, flags, test);
- error(preg, eret);
- }
- return eret;
- }
- int
- old_main(int unused_param_argc, char** argv)
- {
- int flags;
- int cflags;
- int eflags;
- int nmatch;
- int nexec;
- int nstr;
- int cret;
- int eret;
- int nsub;
- int i;
- int j;
- int expected;
- int got;
- int locale;
- int subunitlen = 0;
- int testno;
- unsigned long level;
- unsigned long skip;
- char* p;
- char* line;
- char* spec;
- char* re;
- char* s;
- char* ans;
- char* msg;
- char* fun;
- char* ppat = NULL;
- char* subunit = NULL;
- char* version;
- char* field[6];
- char* delim[6];
- FILE* fp;
- int tabs[6];
- char unit[64];
- regmatch_t match[100];
- regex_t preg;
- static char pat[32 * 1024];
- int nonosub = REG_NOSUB == 0;
- int nonexec = 0;
- unsigned long test = 0;
- static char* filter[] = { "-", 0 };
- state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;
- p = unit;
- version = (char*)id + 10;
- while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
- p++;
- *p = 0;
- while ((p = *++argv) && *p == '-')
- for (;;)
- {
- switch (*++p)
- {
- case 0:
- break;
- case 'c':
- test |= TEST_CATCH;
- continue;
- case 'e':
- test |= TEST_IGNORE_ERROR;
- continue;
- case 'h':
- case '?':
- help(0);
- return 2;
- case '-':
- help(p[1] == 'h');
- return 2;
- case 'n':
- nonexec = 1;
- continue;
- case 'o':
- test |= TEST_IGNORE_OVER;
- continue;
- case 'p':
- test |= TEST_IGNORE_POSITION;
- continue;
- case 's':
- #ifdef REG_DISCIPLINE
- if (!(state.stack = stkalloc(stkstd, 0)))
- fprintf(stderr, "%s: out of space [stack]", unit);
- state.disc.disc.re_resizef = resizef;
- state.disc.disc.re_resizehandle = (void*)stkstd;
- #endif
- continue;
- case 'x':
- nonosub = 1;
- continue;
- case 'v':
- test |= TEST_VERBOSE;
- continue;
- case 'A':
- test |= TEST_ACTUAL;
- continue;
- case 'B':
- test |= TEST_BASELINE;
- continue;
- case 'F':
- test |= TEST_FAIL;
- continue;
- case 'P':
- test |= TEST_PASS;
- continue;
- case 'S':
- test |= TEST_SUMMARY;
- continue;
- default:
- fprintf(stderr, "%s: %c: invalid option\n", unit, *p);
- return 2;
- }
- break;
- }
- if (!*argv)
- argv = filter;
- locale = 0;
- while ((state.file = *argv++))
- {
- if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
- {
- state.file = 0;
- fp = stdin;
- }
- else if (!(fp = fopen(state.file, "r")))
- {
- fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
- return 2;
- }
- testno = state.errors = state.ignored = state.lineno = state.passed =
- state.signals = state.unspecified = state.warnings = 0;
- skip = 0;
- level = 1;
- if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
- {
- printf("TEST\t%s ", unit);
- if ((s = state.file))
- {
- subunit = p = 0;
- for (;;)
- {
- switch (*s++)
- {
- case 0:
- break;
- case '/':
- subunit = s;
- continue;
- case '.':
- p = s - 1;
- continue;
- default:
- continue;
- }
- break;
- }
- if (!subunit)
- subunit = state.file;
- if (p < subunit)
- p = s - 1;
- subunitlen = p - subunit;
- printf("%-.*s ", subunitlen, subunit);
- }
- else
- subunit = 0;
- for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)
- putchar(*s);
- if (test & TEST_CATCH)
- printf(", catch");
- if (test & TEST_IGNORE_ERROR)
- printf(", ignore error code mismatches");
- if (test & TEST_IGNORE_POSITION)
- printf(", ignore negative position mismatches");
- #ifdef REG_DISCIPLINE
- if (state.stack)
- printf(", stack");
- #endif
- if (test & TEST_VERBOSE)
- printf(", verbose");
- printf("\n");
- #ifdef REG_VERSIONID
- if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)
- s = pat;
- else
- #endif
- #ifdef REG_TEST_VERSION
- s = REG_TEST_VERSION;
- #else
- s = "regex";
- #endif
- printf("NOTE\t%s\n", s);
- if (elementsof(unsupported) > 1)
- {
- #if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)
- i = 0;
- #else
- i = REG_EXTENDED != 0;
- #endif
- for (got = 0; i < elementsof(unsupported) - 1; i++)
- {
- if (!got)
- {
- got = 1;
- printf("NOTE\tunsupported: %s", unsupported[i]);
- }
- else
- printf(",%s", unsupported[i]);
- }
- if (got)
- printf("\n");
- }
- }
- #ifdef REG_DISCIPLINE
- state.disc.disc.re_version = REG_VERSION;
- state.disc.disc.re_compf = compf;
- state.disc.disc.re_execf = execf;
- if (!(state.disc.sp = sfstropen()))
- bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);
- preg.re_disc = &state.disc.disc;
- #endif
- if (test & TEST_CATCH)
- {
- signal(SIGALRM, gotcha);
- signal(SIGBUS, gotcha);
- signal(SIGSEGV, gotcha);
- }
- while ((p = my_getline(fp)))
- {
- /* parse: */
- line = p;
- if (*p == ':' && !isspace(*(p + 1)))
- {
- while (*++p && *p != ':');
- if (!*p++)
- {
- if (test & TEST_BASELINE)
- printf("%s\n", line);
- continue;
- }
- }
- while (isspace(*p))
- p++;
- if (*p == 0 || *p == '#' || *p == 'T')
- {
- if (test & TEST_BASELINE)
- printf("%s\n", line);
- continue;
- }
- if (*p == ':' || *p == 'N')
- {
- if (test & TEST_BASELINE)
- printf("%s\n", line);
- else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
- {
- while (*++p && !isspace(*p));
- while (isspace(*p))
- p++;
- printf("NOTE %s\n", p);
- }
- continue;
- }
- j = 0;
- i = 0;
- field[i++] = p;
- for (;;)
- {
- switch (*p++)
- {
- case 0:
- p--;
- j = 0;
- goto checkfield;
- case '\t':
- *(delim[i] = p - 1) = 0;
- j = 1;
- checkfield:
- s = field[i - 1];
- if (streq(s, "NIL"))
- field[i - 1] = 0;
- else if (streq(s, "NULL"))
- *s = 0;
- while (*p == '\t')
- {
- p++;
- j++;
- }
- tabs[i - 1] = j;
- if (!*p)
- break;
- if (i >= elementsof(field))
- bad("too many fields\n", NiL, NiL, 0, 0);
- field[i++] = p;
- /*FALLTHROUGH*/
- default:
- continue;
- }
- break;
- }
- if (!(spec = field[0]))
- bad("NIL spec\n", NiL, NiL, 0, 0);
- /* interpret: */
- cflags = REG_TEST_DEFAULT;
- eflags = REG_EXEC_DEFAULT;
- test &= TEST_GLOBAL;
- state.extracted = 0;
- nmatch = 20;
- nsub = -1;
- for (p = spec; *p; p++)
- {
- if (isdigit(*p))
- {
- nmatch = strtol(p, &p, 10);
- if (nmatch >= elementsof(match))
- bad("nmatch must be < 100\n", NiL, NiL, 0, 0);
- p--;
- continue;
- }
- switch (*p)
- {
- case 'A':
- test |= TEST_ARE;
- continue;
- case 'B':
- test |= TEST_BRE;
- continue;
- case 'C':
- if (!(test & TEST_QUERY) && !(skip & level))
- bad("locale must be nested\n", NiL, NiL, 0, 0);
- test &= ~TEST_QUERY;
- if (locale)
- bad("locale nesting not supported\n", NiL, NiL, 0, 0);
- if (i != 2)
- bad("locale field expected\n", NiL, NiL, 0, 0);
- if (!(skip & level))
- {
- #if defined(LC_COLLATE) && defined(LC_CTYPE)
- s = field[1];
- if (!s || streq(s, "POSIX"))
- s = "C";
- if (!(ans = setlocale(LC_COLLATE, s)) || streq(ans, "C") || streq(ans, "POSIX") || !(ans = setlocale(LC_CTYPE, s)) || streq(ans, "C") || streq(ans, "POSIX"))
- skip = note(level, s, skip, test);
- else
- {
- if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
- printf("NOTE \"%s\" locale\n", s);
- locale = level;
- }
- #else
- skip = note(level, skip, test, "locales not supported");
- #endif
- }
- cflags = NOTEST;
- continue;
- case 'E':
- test |= TEST_ERE;
- continue;
- case 'K':
- test |= TEST_KRE;
- continue;
- case 'L':
- test |= TEST_LRE;
- continue;
- case 'S':
- test |= TEST_SRE;
- continue;
- case 'a':
- cflags |= REG_LEFT|REG_RIGHT;
- continue;
- case 'b':
- eflags |= REG_NOTBOL;
- continue;
- case 'c':
- cflags |= REG_COMMENT;
- continue;
- case 'd':
- cflags |= REG_SHELL_DOT;
- continue;
- case 'e':
- eflags |= REG_NOTEOL;
- continue;
- case 'f':
- cflags |= REG_MULTIPLE;
- continue;
- case 'g':
- cflags |= NOTEST;
- continue;
- case 'h':
- cflags |= REG_MULTIREF;
- continue;
- case 'i':
- cflags |= REG_ICASE;
- continue;
- case 'j':
- cflags |= REG_SPAN;
- continue;
- case 'k':
- cflags |= REG_ESCAPE;
- continue;
- case 'l':
- cflags |= REG_LEFT;
- continue;
- case 'm':
- cflags |= REG_MINIMAL;
- continue;
- case 'n':
- cflags |= REG_NEWLINE;
- continue;
- case 'o':
- cflags |= REG_SHELL_GROUP;
- continue;
- case 'p':
- cflags |= REG_SHELL_PATH;
- continue;
- case 'q':
- cflags |= REG_DELIMITED;
- continue;
- case 'r':
- cflags |= REG_RIGHT;
- continue;
- case 's':
- cflags |= REG_SHELL_ESCAPED;
- continue;
- case 't':
- cflags |= REG_MUSTDELIM;
- continue;
- case 'u':
- test |= TEST_UNSPECIFIED;
- continue;
- case 'w':
- cflags |= REG_NOSUB;
- continue;
- case 'x':
- if (REG_LENIENT)
- cflags |= REG_LENIENT;
- else
- test |= TEST_LENIENT;
- continue;
- case 'y':
- eflags |= REG_LEFT;
- continue;
- case 'z':
- cflags |= REG_NULL;
- continue;
- case '$':
- test |= TEST_EXPAND;
- continue;
- case '/':
- test |= TEST_SUB;
- continue;
- case '?':
- test |= TEST_VERIFY;
- test &= ~(TEST_AND|TEST_OR);
- state.verify = state.passed;
- continue;
- case '&':
- test |= TEST_VERIFY|TEST_AND;
- test &= ~TEST_OR;
- continue;
- case '|':
- test |= TEST_VERIFY|TEST_OR;
- test &= ~TEST_AND;
- continue;
- case ';':
- test |= TEST_OR;
- test &= ~TEST_AND;
- continue;
- case '{':
- level <<= 1;
- if (skip & (level >> 1))
- {
- skip |= level;
- cflags = NOTEST;
- }
- else
- {
- skip &= ~level;
- test |= TEST_QUERY;
- }
- continue;
- case '}':
- if (level == 1)
- bad("invalid {...} nesting\n", NiL, NiL, 0, 0);
- if ((skip & level) && !(skip & (level>>1)))
- {
- if (!(test & (TEST_BASELINE|TEST_SUMMARY)))
- {
- if (test & (TEST_ACTUAL|TEST_FAIL))
- printf("}\n");
- else if (!(test & TEST_PASS))
- printf("-%d\n", state.lineno);
- }
- }
- #if defined(LC_COLLATE) && defined(LC_CTYPE)
- else if (locale & level)
- {
- locale = 0;
- if (!(skip & level))
- {
- s = "C";
- setlocale(LC_COLLATE, s);
- setlocale(LC_CTYPE, s);
- if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
- printf("NOTE \"%s\" locale\n", s);
- else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))
- printf("}\n");
- }
- else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))
- printf("}\n");
- }
- #endif
- level >>= 1;
- cflags = NOTEST;
- continue;
- default:
- bad("bad spec\n", spec, NiL, 0, test);
- break;
- }
- break;
- }
- if ((cflags|eflags) == NOTEST || ((skip & level) && (test & TEST_BASELINE)))
- {
- if (test & TEST_BASELINE)
- {
- while (i > 1)
- *delim[--i] = '\t';
- printf("%s\n", line);
- }
- continue;
- }
- if (test & TEST_OR)
- {
- if (!(test & TEST_VERIFY))
- {
- test &= ~TEST_OR;
- if (state.passed == state.verify && i > 1)
- printf("NOTE\t%s\n", field[1]);
- continue;
- }
- else if (state.passed > state.verify)
- continue;
- }
- else if (test & TEST_AND)
- {
- if (state.passed == state.verify)
- continue;
- state.passed = state.verify;
- }
- if (i < 4)
- bad("too few fields\n", NiL, NiL, 0, test);
- while (i < elementsof(field))
- field[i++] = 0;
- if ((re = field[1]))
- {
- if (streq(re, "SAME"))
- {
- re = ppat;
- test |= TEST_SAME;
- }
- else
- {
- if (test & TEST_EXPAND)
- escape(re);
- strcpy(ppat = pat, re);
- }
- }
- else
- ppat = 0;
- nstr = -1;
- if ((s = field[2]) && (test & TEST_EXPAND))
- {
- nstr = escape(s);
- #if _REG_nexec
- if (nstr != strlen(s))
- nexec = nstr;
- #endif
- }
- if (!(ans = field[3]))
- bad("NIL answer\n", NiL, NiL, 0, test);
- msg = field[4];
- fflush(stdout);
- if (test & TEST_SUB)
- #if _REG_subcomp
- cflags |= REG_DELIMITED;
- #else
- continue;
- #endif
- compile:
- if (state.extracted || (skip & level))
- continue;
- #if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))
- #ifdef REG_EXTENDED
- if (REG_EXTENDED != 0 && (test & TEST_BRE))
- #else
- if (test & TEST_BRE)
- #endif
- {
- test &= ~TEST_BRE;
- flags = cflags;
- state.which = "BRE";
- }
- else
- #endif
- #ifdef REG_EXTENDED
- if (test & TEST_ERE)
- {
- test &= ~TEST_ERE;
- flags = cflags | REG_EXTENDED;
- state.which = "ERE";
- }
- else
- #endif
- #ifdef REG_AUGMENTED
- if (test & TEST_ARE)
- {
- test &= ~TEST_ARE;
- flags = cflags | REG_AUGMENTED;
- state.which = "ARE";
- }
- else
- #endif
- #ifdef REG_LITERAL
- if (test & TEST_LRE)
- {
- test &= ~TEST_LRE;
- flags = cflags | REG_LITERAL;
- state.which = "LRE";
- }
- else
- #endif
- #ifdef REG_SHELL
- if (test & TEST_SRE)
- {
- test &= ~TEST_SRE;
- flags = cflags | REG_SHELL;
- state.which = "SRE";
- }
- else
- #ifdef REG_AUGMENTED
- if (test & TEST_KRE)
- {
- test &= ~TEST_KRE;
- flags = cflags | REG_SHELL | REG_AUGMENTED;
- state.which = "KRE";
- }
- else
- #endif
- #endif
- {
- if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
- extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);
- continue;
- }
- if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)
- {
- printf("test %-3d %s ", state.lineno, state.which);
- quote(re, -1, test|TEST_DELIMIT);
- printf(" ");
- quote(s, nstr, test|TEST_DELIMIT);
- printf("\n");
- }
- nosub:
- fun = "regcomp";
- #if _REG_nexec
- if (nstr >= 0 && nstr != strlen(s))
- nexec = nstr;
- else
- #endif
- nexec = -1;
- if (state.extracted || (skip & level))
- continue;
- if (!(test & TEST_QUERY))
- testno++;
- #ifdef REG_DISCIPLINE
- if (state.stack)
- stkset(stkstd, state.stack, 0);
- flags |= REG_DISCIPLINE;
- state.disc.ordinal = 0;
- sfstrseek(state.disc.sp, 0, SEEK_SET);
- #endif
- if (!(test & TEST_CATCH))
- cret = regcomp(&preg, re, flags);
- else if (!(cret = setjmp(state.gotcha)))
- {
- alarm(HUNG);
- cret = regcomp(&preg, re, flags);
- alarm(0);
- }
- #if _REG_subcomp
- if (!cret && (test & TEST_SUB))
- {
- fun = "regsubcomp";
- p = re + preg.re_npat;
- if (!(test & TEST_CATCH))
- cret = regsubcomp(&preg, p, NiL, 0, 0);
- else if (!(cret = setjmp(state.gotcha)))
- {
- alarm(HUNG);
- cret = regsubcomp(&preg, p, NiL, 0, 0);
- alarm(0);
- }
- if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))
- {
- if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
- continue;
- cret = REG_EFLAGS;
- }
- }
- #endif
- if (!cret)
- {
- if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')
- {
- for (p = ans; *p; p++)
- if (*p == '(')
- nsub++;
- else if (*p == '{')
- nsub--;
- if (nsub >= 0)
- {
- if (test & TEST_IGNORE_OVER)
- {
- if (nmatch > nsub)
- nmatch = nsub + 1;
- }
- else if (nsub != preg.re_nsub)
- {
- if (nsub > preg.re_nsub)
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
- else
- {
- report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);
- printf("at least %d expected, %zd returned\n", nsub, preg.re_nsub);
- state.errors++;
- }
- }
- else
- nsub = preg.re_nsub;
- }
- }
- }
- if (!(test & TEST_SUB) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
- else if (!(test & TEST_LENIENT))
- {
- report("failed", fun, re, NiL, -1, msg, flags, test);
- printf("%s expected, OK returned\n", ans);
- }
- catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
- continue;
- }
- }
- else
- {
- if (test & TEST_LENIENT)
- /* we'll let it go this time */;
- else if (!*ans || ans[0]=='(' || (cret == REG_BADPAT && streq(ans, "NOMATCH")))
- {
- got = 0;
- for (i = 1; i < elementsof(codes); i++)
- if (cret==codes[i].code)
- got = i;
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
- else
- {
- report("failed", fun, re, NiL, -1, msg, flags, test);
- printf("%s returned: ", codes[got].name);
- error(&preg, cret);
- }
- }
- else
- {
- expected = got = 0;
- for (i = 1; i < elementsof(codes); i++)
- {
- if (streq(ans, codes[i].name))
- expected = i;
- if (cret==codes[i].code)
- got = i;
- }
- if (!expected)
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
- else
- {
- report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);
- printf("%s expected, %s returned\n", ans, codes[got].name);
- }
- }
- else if (cret != codes[expected].code && cret != REG_BADPAT)
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
- else if (test & TEST_IGNORE_ERROR)
- state.ignored++;
- else
- {
- report("should fail and did", fun, re, NiL, -1, msg, flags, test);
- printf("%s expected, %s returned: ", ans, codes[got].name);
- state.errors--;
- state.warnings++;
- error(&preg, cret);
- }
- }
- }
- goto compile;
- }
- #if _REG_nexec
- execute:
- if (nexec >= 0)
- fun = "regnexec";
- else
- #endif
- fun = "regexec";
- for (i = 0; i < elementsof(match); i++)
- match[i] = state.NOMATCH;
- #if _REG_nexec
- if (nexec >= 0)
- {
- eret = regnexec(&preg, s, nexec, nmatch, match, eflags);
- s[nexec] = 0;
- }
- else
- #endif
- {
- if (!(test & TEST_CATCH))
- eret = regexec(&preg, s, nmatch, match, eflags);
- else if (!(eret = setjmp(state.gotcha)))
- {
- alarm(HUNG);
- eret = regexec(&preg, s, nmatch, match, eflags);
- alarm(0);
- }
- }
- #if _REG_subcomp
- if ((test & TEST_SUB) && !eret)
- {
- fun = "regsubexec";
- if (!(test & TEST_CATCH))
- eret = regsubexec(&preg, s, nmatch, match);
- else if (!(eret = setjmp(state.gotcha)))
- {
- alarm(HUNG);
- eret = regsubexec(&preg, s, nmatch, match);
- alarm(0);
- }
- }
- #endif
- if (flags & REG_NOSUB)
- {
- if (eret)
- {
- if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
- else
- {
- report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);
- error(&preg, eret);
- }
- }
- }
- else if (streq(ans, "NOMATCH"))
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
- else
- {
- report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
- error(&preg, eret);
- }
- }
- }
- else if (eret)
- {
- if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);
- else
- {
- report("failed", fun, re, s, nstr, msg, flags, test);
- if (eret != REG_NOMATCH)
- error(&preg, eret);
- else if (*ans)
- printf("expected: %s\n", ans);
- else
- printf("\n");
- }
- }
- }
- else if (streq(ans, "NOMATCH"))
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
- else
- {
- report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
- matchprint(match, nmatch, nsub, NiL, test);
- }
- }
- #if _REG_subcomp
- else if (test & TEST_SUB)
- {
- p = preg.re_sub->re_buf;
- if (strcmp(p, ans))
- {
- report("failed", fun, re, s, nstr, msg, flags, test);
- quote(ans, -1, test|TEST_DELIMIT);
- printf(" expected, ");
- quote(p, -1, test|TEST_DELIMIT);
- printf(" returned\n");
- }
- }
- #endif
- else if (!*ans)
- {
- if (match[0].rm_so != state.NOMATCH.rm_so)
- {
- if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
- else
- {
- report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);
- matchprint(match, nmatch, nsub, NiL, test);
- }
- }
- }
- else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))
- {
- #if _REG_nexec
- if (nexec < 0 && !nonexec)
- {
- nexec = nstr >= 0 ? nstr : strlen(s);
- s[nexec] = '\n';
- testno++;
- goto execute;
- }
- #endif
- if (!(test & (TEST_SUB|TEST_VERIFY)) && !nonosub)
- {
- if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
- continue;
- flags |= REG_NOSUB;
- goto nosub;
- }
- if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);
- }
- else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
- skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
- if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
- continue;
- goto compile;
- }
- if (test & TEST_SUMMARY)
- printf("tests=%-4d errors=%-4d warnings=%-2d ignored=%-2d unspecified=%-2d signals=%d\n", testno, state.errors, state.warnings, state.ignored, state.unspecified, state.signals);
- else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))
- {
- printf("TEST\t%s", unit);
- if (subunit)
- printf(" %-.*s", subunitlen, subunit);
- printf(", %d test%s", testno, testno == 1 ? "" : "s");
- if (state.ignored)
- printf(", %d ignored mismatch%s", state.ignored, state.ignored == 1 ? "" : "es");
- if (state.warnings)
- printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
- if (state.unspecified)
- printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
- if (state.signals)
- printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
- printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
- }
- if (fp != stdin)
- fclose(fp);
- }
- return state.errors;
- }
- int main(int argc, char **argv)
- {
- static char *param[][4] = {
- { NULL, "basic.dat" , NULL },
- { NULL, "categorize.dat" , NULL },
- { NULL, "forcedassoc.dat" , NULL },
- { NULL, "-c", "interpretation.dat", NULL },
- { NULL, "leftassoc.dat" , NULL },
- { NULL, "-c", "nullsubexpr.dat" , NULL },
- { NULL, "repetition.dat" , NULL },
- { NULL, "rightassoc.dat" , NULL },
- };
- int r, i;
- if (argv[1])
- return old_main(argc, argv);
- r = 0;
- for (i = 0; i < sizeof(param) / sizeof(param[0]); i++) {
- param[i][0] = argv[0];
- printf("Testing %s\n", param[i][1][0] != '-' ? param[i][1] : param[i][2]);
- r |= old_main(3 /* not used */, param[i]);
- }
- return r;
- }
|