Back to index

php5  5.3.10
main.c
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <string.h>
00003 #include <sys/types.h>
00004 #include <regex.h>
00005 #include <assert.h>
00006 #include <stdlib.h>
00007 
00008 #include "main.ih"
00009 
00010 char *progname;
00011 int debug = 0;
00012 int line = 0;
00013 int status = 0;
00014 
00015 int copts = REG_EXTENDED;
00016 int eopts = 0;
00017 regoff_t startoff = 0;
00018 regoff_t endoff = 0;
00019 
00020 
00021 extern int split();
00022 extern void regprint();
00023 
00024 /*
00025  - main - do the simple case, hand off to regress() for regression
00026  */
00027 int main(argc, argv)
00028 int argc;
00029 char *argv[];
00030 {
00031        regex_t re;
00032 #      define NS     10
00033        regmatch_t subs[NS];
00034        char erbuf[100];
00035        int err;
00036        size_t len;
00037        int c;
00038        int errflg = 0;
00039        register int i;
00040        extern int optind;
00041        extern char *optarg;
00042 
00043        progname = argv[0];
00044 
00045        while ((c = getopt(argc, argv, "c:e:S:E:x")) != EOF)
00046               switch (c) {
00047               case 'c':     /* compile options */
00048                      copts = options('c', optarg);
00049                      break;
00050               case 'e':     /* execute options */
00051                      eopts = options('e', optarg);
00052                      break;
00053               case 'S':     /* start offset */
00054                      startoff = (regoff_t)atoi(optarg);
00055                      break;
00056               case 'E':     /* end offset */
00057                      endoff = (regoff_t)atoi(optarg);
00058                      break;
00059               case 'x':     /* Debugging. */
00060                      debug++;
00061                      break;
00062               case '?':
00063               default:
00064                      errflg++;
00065                      break;
00066               }
00067        if (errflg) {
00068               fprintf(stderr, "usage: %s ", progname);
00069               fprintf(stderr, "[-c copt][-C][-d] [re]\n");
00070               exit(2);
00071        }
00072 
00073        if (optind >= argc) {
00074               regress(stdin);
00075               exit(status);
00076        }
00077 
00078        err = regcomp(&re, argv[optind++], copts);
00079        if (err) {
00080               len = regerror(err, &re, erbuf, sizeof(erbuf));
00081               fprintf(stderr, "error %s, %d/%d `%s'\n",
00082                      eprint(err), len, sizeof(erbuf), erbuf);
00083               exit(status);
00084        }
00085        regprint(&re, stdout);      
00086 
00087        if (optind >= argc) {
00088               regfree(&re);
00089               exit(status);
00090        }
00091 
00092        if (eopts&REG_STARTEND) {
00093               subs[0].rm_so = startoff;
00094               subs[0].rm_eo = strlen(argv[optind]) - endoff;
00095        }
00096        err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
00097        if (err) {
00098               len = regerror(err, &re, erbuf, sizeof(erbuf));
00099               fprintf(stderr, "error %s, %d/%d `%s'\n",
00100                      eprint(err), len, sizeof(erbuf), erbuf);
00101               exit(status);
00102        }
00103        if (!(copts&REG_NOSUB)) {
00104               len = (int)(subs[0].rm_eo - subs[0].rm_so);
00105               if (subs[0].rm_so != -1) {
00106                      if (len != 0)
00107                             printf("match `%.*s'\n", (int)len,
00108                                    argv[optind] + subs[0].rm_so);
00109                      else
00110                             printf("match `'@%.1s\n",
00111                                    argv[optind] + subs[0].rm_so);
00112               }
00113               for (i = 1; i < NS; i++)
00114                      if (subs[i].rm_so != -1)
00115                             printf("(%d) `%.*s'\n", i,
00116                                    (int)(subs[i].rm_eo - subs[i].rm_so),
00117                                    argv[optind] + subs[i].rm_so);
00118        }
00119        exit(status);
00120 }
00121 
00122 /*
00123  - regress - main loop of regression test
00124  == void regress(FILE *in);
00125  */
00126 void
00127 regress(in)
00128 FILE *in;
00129 {
00130        char inbuf[1000];
00131 #      define MAXF   10
00132        char *f[MAXF];
00133        int nf;
00134        int i;
00135        char erbuf[100];
00136        size_t ne;
00137        char *badpat = "invalid regular expression";
00138 #      define SHORT  10
00139        char *bpname = "REG_BADPAT";
00140        regex_t re;
00141 
00142        while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
00143               line++;
00144               if (inbuf[0] == '#' || inbuf[0] == '\n')
00145                      continue;                   /* NOTE CONTINUE */
00146               inbuf[strlen(inbuf)-1] = '\0';     /* get rid of stupid \n */
00147               if (debug)
00148                      fprintf(stdout, "%d:\n", line);
00149               nf = split(inbuf, f, MAXF, "\t\t");
00150               if (nf < 3) {
00151                      fprintf(stderr, "bad input, line %d\n", line);
00152                      exit(1);
00153               }
00154               for (i = 0; i < nf; i++)
00155                      if (strcmp(f[i], "\"\"") == 0)
00156                             f[i] = "";
00157               if (nf <= 3)
00158                      f[3] = NULL;
00159               if (nf <= 4)
00160                      f[4] = NULL;
00161               try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
00162               if (opt('&', f[1]))  /* try with either type of RE */
00163                      try(f[0], f[1], f[2], f[3], f[4],
00164                                    options('c', f[1]) &~ REG_EXTENDED);
00165        }
00166 
00167        ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
00168        if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
00169               fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
00170                                                  erbuf, badpat);
00171               status = 1;
00172        }
00173        ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT);
00174        if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
00175                                           ne != strlen(badpat)+1) {
00176               fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
00177                                           erbuf, SHORT-1, badpat);
00178               status = 1;
00179        }
00180        ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
00181        if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
00182               fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
00183                                           erbuf, bpname);
00184               status = 1;
00185        }
00186        re.re_endp = bpname;
00187        ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
00188        if (atoi(erbuf) != (int)REG_BADPAT) {
00189               fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
00190                                           erbuf, (long)REG_BADPAT);
00191               status = 1;
00192        } else if (ne != strlen(erbuf)+1) {
00193               fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
00194                                           erbuf, (long)REG_BADPAT);
00195               status = 1;
00196        }
00197 }
00198 
00199 /*
00200  - try - try it, and report on problems
00201  == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
00202  */
00203 void
00204 try(f0, f1, f2, f3, f4, opts)
00205 char *f0;
00206 char *f1;
00207 char *f2;
00208 char *f3;
00209 char *f4;
00210 int opts;                   /* may not match f1 */
00211 {
00212        regex_t re;
00213 #      define NSUBS  10
00214        regmatch_t subs[NSUBS];
00215 #      define NSHOULD       15
00216        char *should[NSHOULD];
00217        int nshould;
00218        char erbuf[100];
00219        int err;
00220        int len;
00221        char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
00222        register int i;
00223        char *grump;
00224        char f0copy[1000];
00225        char f2copy[1000];
00226 
00227        strcpy(f0copy, f0);
00228        re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
00229        fixstr(f0copy);
00230        err = regcomp(&re, f0copy, opts);
00231        if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
00232               /* unexpected error or wrong error */
00233               len = regerror(err, &re, erbuf, sizeof(erbuf));
00234               fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
00235                                    line, type, eprint(err), len,
00236                                    sizeof(erbuf), erbuf);
00237               status = 1;
00238        } else if (err == 0 && opt('C', f1)) {
00239               /* unexpected success */
00240               fprintf(stderr, "%d: %s should have given REG_%s\n",
00241                                           line, type, f2);
00242               status = 1;
00243               err = 1;      /* so we won't try regexec */
00244        }
00245 
00246        if (err != 0) {
00247               regfree(&re);
00248               return;
00249        }
00250 
00251        strcpy(f2copy, f2);
00252        fixstr(f2copy);
00253 
00254        if (options('e', f1)&REG_STARTEND) {
00255               if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
00256                      fprintf(stderr, "%d: bad STARTEND syntax\n", line);
00257               subs[0].rm_so = strchr(f2, '(') - f2 + 1;
00258               subs[0].rm_eo = strchr(f2, ')') - f2;
00259        }
00260        err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
00261 
00262        if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
00263               /* unexpected error or wrong error */
00264               len = regerror(err, &re, erbuf, sizeof(erbuf));
00265               fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
00266                                    line, type, eprint(err), len,
00267                                    sizeof(erbuf), erbuf);
00268               status = 1;
00269        } else if (err != 0) {
00270               /* nothing more to check */
00271        } else if (f3 == NULL) {
00272               /* unexpected success */
00273               fprintf(stderr, "%d: %s exec should have failed\n",
00274                                           line, type);
00275               status = 1;
00276               err = 1;             /* just on principle */
00277        } else if (opts&REG_NOSUB) {
00278               /* nothing more to check */
00279        } else if ((grump = check(f2, subs[0], f3)) != NULL) {
00280               fprintf(stderr, "%d: %s %s\n", line, type, grump);
00281               status = 1;
00282               err = 1;
00283        }
00284 
00285        if (err != 0 || f4 == NULL) {
00286               regfree(&re);
00287               return;
00288        }
00289 
00290        for (i = 1; i < NSHOULD; i++)
00291               should[i] = NULL;
00292        nshould = split(f4, should+1, NSHOULD-1, ",");
00293        if (nshould == 0) {
00294               nshould = 1;
00295               should[1] = "";
00296        }
00297        for (i = 1; i < NSUBS; i++) {
00298               grump = check(f2, subs[i], should[i]);
00299               if (grump != NULL) {
00300                      fprintf(stderr, "%d: %s $%d %s\n", line,
00301                                                  type, i, grump);
00302                      status = 1;
00303                      err = 1;
00304               }
00305        }
00306 
00307        regfree(&re);
00308 }
00309 
00310 /*
00311  - options - pick options out of a regression-test string
00312  == int options(int type, char *s);
00313  */
00314 int
00315 options(type, s)
00316 int type;                   /* 'c' compile, 'e' exec */
00317 char *s;
00318 {
00319        register char *p;
00320        register int o = (type == 'c') ? copts : eopts;
00321        register char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
00322 
00323        for (p = s; *p != '\0'; p++)
00324               if (strchr(legal, *p) != NULL)
00325                      switch (*p) {
00326                      case 'b':
00327                             o &= ~REG_EXTENDED;
00328                             break;
00329                      case 'i':
00330                             o |= REG_ICASE;
00331                             break;
00332                      case 's':
00333                             o |= REG_NOSUB;
00334                             break;
00335                      case 'n':
00336                             o |= REG_NEWLINE;
00337                             break;
00338                      case 'm':
00339                             o &= ~REG_EXTENDED;
00340                             o |= REG_NOSPEC;
00341                             break;
00342                      case 'p':
00343                             o |= REG_PEND;
00344                             break;
00345                      case '^':
00346                             o |= REG_NOTBOL;
00347                             break;
00348                      case '$':
00349                             o |= REG_NOTEOL;
00350                             break;
00351                      case '#':
00352                             o |= REG_STARTEND;
00353                             break;
00354                      case 't':     /* trace */
00355                             o |= REG_TRACE;
00356                             break;
00357                      case 'l':     /* force long representation */
00358                             o |= REG_LARGE;
00359                             break;
00360                      case 'r':     /* force backref use */
00361                             o |= REG_BACKR;
00362                             break;
00363                      }
00364        return(o);
00365 }
00366 
00367 /*
00368  - opt - is a particular option in a regression string?
00369  == int opt(int c, char *s);
00370  */
00371 int                         /* predicate */
00372 opt(c, s)
00373 int c;
00374 char *s;
00375 {
00376        return(strchr(s, c) != NULL);
00377 }
00378 
00379 /*
00380  - fixstr - transform magic characters in strings
00381  == void fixstr(register char *p);
00382  */
00383 void
00384 fixstr(p)
00385 register char *p;
00386 {
00387        if (p == NULL)
00388               return;
00389 
00390        for (; *p != '\0'; p++)
00391               if (*p == 'N')
00392                      *p = '\n';
00393               else if (*p == 'T')
00394                      *p = '\t';
00395               else if (*p == 'S')
00396                      *p = ' ';
00397               else if (*p == 'Z')
00398                      *p = '\0';
00399 }
00400 
00401 /*
00402  - check - check a substring match
00403  == char *check(char *str, regmatch_t sub, char *should);
00404  */
00405 char *                      /* NULL or complaint */
00406 check(str, sub, should)
00407 char *str;
00408 regmatch_t sub;
00409 char *should;
00410 {
00411        register int len;
00412        register int shlen;
00413        register char *p;
00414        static char grump[500];
00415        register char *at = NULL;
00416 
00417        if (should != NULL && strcmp(should, "-") == 0)
00418               should = NULL;
00419        if (should != NULL && should[0] == '@') {
00420               at = should + 1;
00421               should = "";
00422        }
00423 
00424        /* check rm_so and rm_eo for consistency */
00425        if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
00426                             (sub.rm_so != -1 && sub.rm_eo == -1) ||
00427                             (sub.rm_so != -1 && sub.rm_so < 0) ||
00428                             (sub.rm_eo != -1 && sub.rm_eo < 0) ) {
00429               sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
00430                                                  (long)sub.rm_eo);
00431               return(grump);
00432        }
00433 
00434        /* check for no match */
00435        if (sub.rm_so == -1 && should == NULL)
00436               return(NULL);
00437        if (sub.rm_so == -1)
00438               return("did not match");
00439 
00440        /* check for in range */
00441        if (sub.rm_eo > strlen(str)) {
00442               sprintf(grump, "start %ld end %ld, past end of string",
00443                                    (long)sub.rm_so, (long)sub.rm_eo);
00444               return(grump);
00445        }
00446 
00447        len = (int)(sub.rm_eo - sub.rm_so);
00448        shlen = (int)strlen(should);
00449        p = str + sub.rm_so;
00450 
00451        /* check for not supposed to match */
00452        if (should == NULL) {
00453               sprintf(grump, "matched `%.*s'", len, p);
00454               return(grump);
00455        }
00456 
00457        /* check for wrong match */
00458        if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
00459               sprintf(grump, "matched `%.*s' instead", len, p);
00460               return(grump);
00461        }
00462        if (shlen > 0)
00463               return(NULL);
00464 
00465        /* check null match in right place */
00466        if (at == NULL)
00467               return(NULL);
00468        shlen = strlen(at);
00469        if (shlen == 0)
00470               shlen = 1;    /* force check for end-of-string */
00471        if (strncmp(p, at, shlen) != 0) {
00472               sprintf(grump, "matched null at `%.20s'", p);
00473               return(grump);
00474        }
00475        return(NULL);
00476 }
00477 
00478 /*
00479  - eprint - convert error number to name
00480  == static char *eprint(int err);
00481  */
00482 static char *
00483 eprint(err)
00484 int err;
00485 {
00486        static char epbuf[100];
00487        size_t len;
00488 
00489        len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf));
00490        assert(len <= sizeof(epbuf));
00491        return(epbuf);
00492 }
00493 
00494 /*
00495  - efind - convert error name to number
00496  == static int efind(char *name);
00497  */
00498 static int
00499 efind(name)
00500 char *name;
00501 {
00502        static char efbuf[100];
00503        regex_t re;
00504 
00505        sprintf(efbuf, "REG_%s", name);
00506        assert(strlen(efbuf) < sizeof(efbuf));
00507        re.re_endp = efbuf;
00508        (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
00509        return(atoi(efbuf));
00510 }