MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
main.c
1 #include <my_global.h>
2 #include <m_string.h>
3 #include <sys/types.h>
4 #include <assert.h>
5 
6 #include "my_regex.h"
7 #include "main.ih"
8 #include "tests_include.h"
9 
10 char *progname;
11 int debug = 0;
12 int line = 0;
13 int status = 0;
14 
15 int copts = MY_REG_EXTENDED;
16 int eopts = 0;
17 my_regoff_t startoff = 0;
18 my_regoff_t endoff = 0;
19 
20 
21 extern int split(char *string, char *fields[], int nfields, char *sep);
22 extern void regprint(my_regex_t *r, FILE *d);
23 
24 
25 #ifdef __WIN__
26 char *optarg= "";
27 int optind= 1;
28 int opterr;
29 
30 /* A (very) simplified version of getopt, enough to run the registered tests. */
31 int getopt(int argc, char *argv[], const char *optstring)
32 {
33  char *opt= NULL;
34  int retval= -1;
35  if (optind >= argc)
36  return retval;
37 
38  opt= argv[optind];
39  if (*opt != '-')
40  return retval;
41 
42  retval= *(opt+1);
43  if (*(opt+1) && *(opt+2))
44  optarg= opt + 2;
45  else
46  optarg= "";
47 
48  ++optind;
49  return retval;
50 }
51 #endif
52 
53 
54 /*
55  - main - do the simple case, hand off to regress() for regression
56  */
57 int main(argc, argv)
58 int argc;
59 char *argv[];
60 {
61  my_regex_t re;
62 # define NS 10
63  my_regmatch_t subs[NS];
64  char erbuf[100];
65  int err;
66  size_t len;
67  int c;
68  int errflg = 0;
69  int opt_inline = 0;
70  register int i;
71  char *input_file_name= NULL;
72  extern int optind;
73  extern char *optarg;
74 
75  progname = argv[0];
76 
77  while ((c = getopt(argc, argv, "c:e:i:S:E:xI")) != EOF)
78  switch (c) {
79  case 'c': /* compile options */
80  copts = options('c', optarg);
81  break;
82  case 'e': /* execute options */
83  eopts = options('e', optarg);
84  break;
85  case 'i':
86  input_file_name= optarg;
87  break;
88  case 'S': /* start offset */
89  startoff = (my_regoff_t)atoi(optarg);
90  break;
91  case 'E': /* end offset */
92  endoff = (my_regoff_t)atoi(optarg);
93  break;
94  case 'x': /* Debugging. */
95  debug++;
96  break;
97  case 'I': /* Inline. */
98  opt_inline= 1;
99  break;
100  case '?':
101  default:
102  errflg++;
103  break;
104  }
105  if (errflg) {
106  fprintf(stderr, "usage: %s ", progname);
107  fprintf(stderr,
108  "[-c copt][-e eopt][-i filename][-S][-E][-x][-I] [re]\n");
109  exit(2);
110  }
111 
112  if (opt_inline) {
113  regress(NULL);
114  exit(status);
115  }
116 
117  if (optind >= argc && !input_file_name) {
118  regress(stdin);
119  exit(status);
120  }
121 
122  if (input_file_name) {
123  FILE *input_file= fopen(input_file_name, "r");
124  if (!input_file) {
125  fprintf(stderr, "Could not open '%s' : ", input_file_name);
126  perror(NULL);
127  exit(EXIT_FAILURE);
128  }
129  regress(input_file);
130  fclose(input_file);
131  exit(status);
132  }
133 
134  err = my_regcomp(&re, argv[optind++], copts, &my_charset_latin1);
135  if (err) {
136  len = my_regerror(err, &re, erbuf, sizeof(erbuf));
137  fprintf(stderr, "error %s, %d/%d `%s'\n",
138  eprint(err), (int) len, (int) sizeof(erbuf), erbuf);
139  exit(status);
140  }
141  regprint(&re, stdout);
142 
143  if (optind >= argc) {
144  my_regfree(&re);
145  exit(status);
146  }
147 
148  if (eopts&MY_REG_STARTEND) {
149  subs[0].rm_so = startoff;
150  subs[0].rm_eo = strlen(argv[optind]) - endoff;
151  }
152  err = my_regexec(&re, argv[optind], (size_t)NS, subs, eopts);
153  if (err) {
154  len = my_regerror(err, &re, erbuf, sizeof(erbuf));
155  fprintf(stderr, "error %s, %d/%d `%s'\n",
156  eprint(err), (int) len, (int) sizeof(erbuf), erbuf);
157  exit(status);
158  }
159  if (!(copts&MY_REG_NOSUB)) {
160  len = (int)(subs[0].rm_eo - subs[0].rm_so);
161  if (subs[0].rm_so != -1) {
162  if (len != 0)
163  printf("match `%.*s'\n", (int)len,
164  argv[optind] + subs[0].rm_so);
165  else
166  printf("match `'@%.1s\n",
167  argv[optind] + subs[0].rm_so);
168  }
169  for (i = 1; i < NS; i++)
170  if (subs[i].rm_so != -1)
171  printf("(%d) `%.*s'\n", i,
172  (int)(subs[i].rm_eo - subs[i].rm_so),
173  argv[optind] + subs[i].rm_so);
174  }
175  exit(status);
176 }
177 
178 char*
179 get_next_line(s, size, stream)
180 char *s;
181 int size;
182 FILE *stream;
183 {
184  if (stream)
185  return fgets(s, size, stream);
186  if (test_array[line])
187  return strncpy(s, test_array[line], size);
188  return NULL;
189 }
190 
191 /*
192  - regress - main loop of regression test
193  == void regress(FILE *in);
194  Reads file, line-by-line.
195  If in == NULL, we read data from test_array instead.
196  */
197 void
198 regress(in)
199 FILE *in;
200 {
201  char inbuf[1000];
202 # define MAXF 10
203  char *f[MAXF];
204  int nf;
205  int i;
206  char erbuf[100];
207  size_t ne;
208  const char *badpat = "invalid regular expression";
209 # define SHORT 10
210  const char *bpname = "MY_REG_BADPAT";
211  my_regex_t re;
212 
213  while (get_next_line(inbuf, sizeof(inbuf), in) != NULL) {
214  line++;
215  if (inbuf[0] == '#' || inbuf[0] == '\n' || inbuf[0] == '\0')
216  continue; /* NOTE CONTINUE */
217  if (inbuf[strlen(inbuf)-1] == '\n')
218  inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
219  if (debug)
220  fprintf(stdout, "%d: <%s>\n", line, inbuf);
221  nf = split(inbuf, f, MAXF, (char*) "\t\t");
222  if (nf < 3) {
223  fprintf(stderr, "bad input, line %d\n", line);
224  exit(1);
225  }
226  for (i = 0; i < nf; i++)
227  if (strcmp(f[i], "\"\"") == 0)
228  f[i] = (char*) "";
229  if (nf <= 3)
230  f[3] = NULL;
231  if (nf <= 4)
232  f[4] = NULL;
233  rx_try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
234  if (opt('&', f[1])) /* try with either type of RE */
235  rx_try(f[0], f[1], f[2], f[3], f[4],
236  options('c', f[1]) &~ MY_REG_EXTENDED);
237  }
238 
239  ne = my_regerror(MY_REG_BADPAT, (my_regex_t *)NULL, erbuf, sizeof(erbuf));
240  if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
241  fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
242  erbuf, badpat);
243  status = 1;
244  }
245  ne = my_regerror(MY_REG_BADPAT, (my_regex_t *)NULL, erbuf, (size_t)SHORT);
246  if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
247  ne != strlen(badpat)+1) {
248  fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
249  erbuf, SHORT-1, badpat);
250  status = 1;
251  }
252  ne = my_regerror(MY_REG_ITOA|MY_REG_BADPAT, (my_regex_t *)NULL, erbuf, sizeof(erbuf));
253  if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
254  fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
255  erbuf, bpname);
256  status = 1;
257  }
258  re.re_endp = bpname;
259  ne = my_regerror(MY_REG_ATOI, &re, erbuf, sizeof(erbuf));
260  if (atoi(erbuf) != (int)MY_REG_BADPAT) {
261  fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
262  erbuf, (long)MY_REG_BADPAT);
263  status = 1;
264  } else if (ne != strlen(erbuf)+1) {
265  fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
266  erbuf, (long)MY_REG_BADPAT);
267  status = 1;
268  }
269 }
270 
271 /*
272  - rx_try - try it, and report on problems
273  == void rx_try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
274  */
275 void
276 rx_try(f0, f1, f2, f3, f4, opts)
277 char *f0;
278 char *f1;
279 char *f2;
280 char *f3;
281 char *f4;
282 int opts; /* may not match f1 */
283 {
284  my_regex_t re;
285 # define NSUBS 10
286  my_regmatch_t subs[NSUBS];
287 # define NSHOULD 15
288  char *should[NSHOULD];
289  int nshould;
290  char erbuf[100];
291  int err;
292  int len;
293  const char *type = (opts & MY_REG_EXTENDED) ? "ERE" : "BRE";
294  register int i;
295  char *grump;
296  char f0copy[1000];
297  char f2copy[1000];
298 
299  strcpy(f0copy, f0);
300  re.re_endp = (opts&MY_REG_PEND) ? f0copy + strlen(f0copy) : NULL;
301  fixstr(f0copy);
302  err = my_regcomp(&re, f0copy, opts, &my_charset_latin1);
303  if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
304  /* unexpected error or wrong error */
305  len = my_regerror(err, &re, erbuf, sizeof(erbuf));
306  fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
307  line, type, eprint(err), len,
308  (int) sizeof(erbuf), erbuf);
309  status = 1;
310  } else if (err == 0 && opt('C', f1)) {
311  /* unexpected success */
312  fprintf(stderr, "%d: %s should have given MY_REG_%s\n",
313  line, type, f2);
314  status = 1;
315  err = 1; /* so we won't try regexec */
316  }
317 
318  if (err != 0) {
319  my_regfree(&re);
320  return;
321  }
322 
323  strcpy(f2copy, f2);
324  fixstr(f2copy);
325 
326  if (options('e', f1)&MY_REG_STARTEND) {
327  if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
328  fprintf(stderr, "%d: bad STARTEND syntax\n", line);
329  subs[0].rm_so = strchr(f2, '(') - f2 + 1;
330  subs[0].rm_eo = strchr(f2, ')') - f2;
331  }
332  err = my_regexec(&re, f2copy, NSUBS, subs, options('e', f1));
333 
334  if (err != 0 && (f3 != NULL || err != MY_REG_NOMATCH)) {
335  /* unexpected error or wrong error */
336  len = my_regerror(err, &re, erbuf, sizeof(erbuf));
337  fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
338  line, type, eprint(err), len,
339  (int) sizeof(erbuf), erbuf);
340  status = 1;
341  } else if (err != 0) {
342  /* nothing more to check */
343  } else if (f3 == NULL) {
344  /* unexpected success */
345  fprintf(stderr, "%d: %s exec should have failed\n",
346  line, type);
347  status = 1;
348  err = 1; /* just on principle */
349  } else if (opts&MY_REG_NOSUB) {
350  /* nothing more to check */
351  } else if ((grump = check(f2, subs[0], f3)) != NULL) {
352  fprintf(stderr, "%d: %s %s\n", line, type, grump);
353  status = 1;
354  err = 1;
355  }
356 
357  if (err != 0 || f4 == NULL) {
358  my_regfree(&re);
359  return;
360  }
361 
362  for (i = 1; i < NSHOULD; i++)
363  should[i] = NULL;
364  nshould = split(f4, should+1, NSHOULD-1, (char*) ",");
365  if (nshould == 0) {
366  nshould = 1;
367  should[1] = (char*) "";
368  }
369  for (i = 1; i < NSUBS; i++) {
370  grump = check(f2, subs[i], should[i]);
371  if (grump != NULL) {
372  fprintf(stderr, "%d: %s $%d %s\n", line,
373  type, i, grump);
374  status = 1;
375  err = 1;
376  }
377  }
378 
379  my_regfree(&re);
380 }
381 
382 /*
383  - options - pick options out of a regression-test string
384  == int options(int type, char *s);
385  */
386 int
387 options(type, s)
388 int type; /* 'c' compile, 'e' exec */
389 char *s;
390 {
391  register char *p;
392  register int o = (type == 'c') ? copts : eopts;
393  register const char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
394 
395  for (p = s; *p != '\0'; p++)
396  if (strchr(legal, *p) != NULL)
397  switch (*p) {
398  case 'b':
399  o &= ~MY_REG_EXTENDED;
400  break;
401  case 'i':
402  o |= MY_REG_ICASE;
403  break;
404  case 's':
405  o |= MY_REG_NOSUB;
406  break;
407  case 'n':
408  o |= MY_REG_NEWLINE;
409  break;
410  case 'm':
411  o &= ~MY_REG_EXTENDED;
412  o |= MY_REG_NOSPEC;
413  break;
414  case 'p':
415  o |= MY_REG_PEND;
416  break;
417  case '^':
418  o |= MY_REG_NOTBOL;
419  break;
420  case '$':
421  o |= MY_REG_NOTEOL;
422  break;
423  case '#':
424  o |= MY_REG_STARTEND;
425  break;
426  case 't': /* trace */
427  o |= MY_REG_TRACE;
428  break;
429  case 'l': /* force long representation */
430  o |= MY_REG_LARGE;
431  break;
432  case 'r': /* force backref use */
433  o |= MY_REG_BACKR;
434  break;
435  }
436  return(o);
437 }
438 
439 /*
440  - opt - is a particular option in a regression string?
441  == int opt(int c, char *s);
442  */
443 int /* predicate */
444 opt(c, s)
445 int c;
446 char *s;
447 {
448  return(strchr(s, c) != NULL);
449 }
450 
451 /*
452  - fixstr - transform magic characters in strings
453  == void fixstr(register char *p);
454  */
455 void
456 fixstr(p)
457 register char *p;
458 {
459  if (p == NULL)
460  return;
461 
462  for (; *p != '\0'; p++)
463  if (*p == 'N')
464  *p = '\n';
465  else if (*p == 'T')
466  *p = '\t';
467  else if (*p == 'S')
468  *p = ' ';
469  else if (*p == 'Z')
470  *p = '\0';
471 }
472 
473 /*
474  - check - check a substring match
475  == char *check(char *str, regmatch_t sub, char *should);
476  */
477 char * /* NULL or complaint */
478 check(str, sub, should)
479 char *str;
480 my_regmatch_t sub;
481 char *should;
482 {
483  register int len;
484  register int shlen;
485  register char *p;
486  static char grump[500];
487  register char *at = NULL;
488 
489  if (should != NULL && strcmp(should, "-") == 0)
490  should = NULL;
491  if (should != NULL && should[0] == '@') {
492  at = should + 1;
493  should = (char*) "";
494  }
495 
496  /* check rm_so and rm_eo for consistency */
497  if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
498  (sub.rm_so != -1 && sub.rm_eo == -1) ||
499  (sub.rm_so != -1 && sub.rm_so < 0) ||
500  (sub.rm_eo != -1 && sub.rm_eo < 0) ) {
501  sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
502  (long)sub.rm_eo);
503  return(grump);
504  }
505 
506  /* check for no match */
507  if (sub.rm_so == -1 && should == NULL)
508  return(NULL);
509  if (sub.rm_so == -1)
510  return((char*) "did not match");
511 
512  /* check for in range */
513  if ((int) sub.rm_eo > (int) strlen(str)) {
514  sprintf(grump, "start %ld end %ld, past end of string",
515  (long)sub.rm_so, (long)sub.rm_eo);
516  return(grump);
517  }
518 
519  len = (int)(sub.rm_eo - sub.rm_so);
520  shlen = (int)strlen(should);
521  p = str + sub.rm_so;
522 
523  /* check for not supposed to match */
524  if (should == NULL) {
525  sprintf(grump, "matched `%.*s'", len, p);
526  return(grump);
527  }
528 
529  /* check for wrong match */
530  if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
531  sprintf(grump, "matched `%.*s' instead", len, p);
532  return(grump);
533  }
534  if (shlen > 0)
535  return(NULL);
536 
537  /* check null match in right place */
538  if (at == NULL)
539  return(NULL);
540  shlen = strlen(at);
541  if (shlen == 0)
542  shlen = 1; /* force check for end-of-string */
543  if (strncmp(p, at, shlen) != 0) {
544  sprintf(grump, "matched null at `%.20s'", p);
545  return(grump);
546  }
547  return(NULL);
548 }
549 
550 /*
551  - eprint - convert error number to name
552  == static char *eprint(int err);
553  */
554 static char *
555 eprint(err)
556 int err;
557 {
558  static char epbuf[100];
559  size_t len;
560 
561  len = my_regerror(MY_REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf));
562  assert(len <= sizeof(epbuf));
563  return(epbuf);
564 }
565 
566 /*
567  - efind - convert error name to number
568  == static int efind(char *name);
569  */
570 static int
571 efind(name)
572 char *name;
573 {
574  static char efbuf[100];
575  my_regex_t re;
576 
577  sprintf(efbuf, "MY_REG_%s", name);
578  assert(strlen(efbuf) < sizeof(efbuf));
579  re.re_endp = efbuf;
580  (void) my_regerror(MY_REG_ATOI, &re, efbuf, sizeof(efbuf));
581  return(atoi(efbuf));
582 }