1 /*************************************************
2 *             PCRE testing program               *
3 *************************************************/
4 
5 #include <ctype.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <time.h>
10 #include <locale.h>
11 
12 #ifdef HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15 
16 /* Use the internal info for displaying the results of pcre_study(). */
17 
18 #include "config.h"
19 #include "pcre.h"
20 #include "internal.h"
21 
22 /* It is possible to compile this test program without including support for
23 testing the POSIX interface, though this is not available via the standard
24 Makefile. */
25 
26 #include "regexp.h"
27 
28 #ifndef CLOCKS_PER_SEC
29 #ifdef CLK_TCK
30 #define CLOCKS_PER_SEC CLK_TCK
31 #else
32 #define CLOCKS_PER_SEC 100
33 #endif
34 #endif
35 
36 #define LOOPREPEAT 20000
37 
38 #include "getopt.h"
39 
40 static int log_store = 0;
41 static size_t gotten_store;
42 static FILE *infile, *outfile;
43 
44 
45 
46 /* Character string printing function.  */
47 
48 static void
pchars(unsigned char * p,int length)49 pchars (unsigned char *p, int length)
50 {
51   int c;
52   while (length-- > 0)
53     {
54       if (isprint (c = *(p++)))
55 	fprintf (outfile, "%c", c);
56       else
57 	fprintf (outfile, "\\x%02x", c);
58     }
59 }
60 
61 
62 
63 /* Alternative malloc function, to test functionality and show the size of the
64 compiled re. */
65 
66 static void *
new_malloc(size_t size)67 new_malloc (size_t size)
68 {
69   gotten_store = size;
70   if (log_store)
71     fprintf (outfile, "Memory allocation (code space): %d\n",
72 	     (int) ((int) size - offsetof (pcre, code[0])));
73   return malloc (size);
74 }
75 
76 
77 
78 
79 /* Get one piece of information from the pcre_info() function */
80 
81 static void
new_info(pcre * re,pcre_extra * study,int option,void * ptr)82 new_info (pcre * re, pcre_extra * study, int option, void *ptr)
83 {
84   int rc;
85   if ((rc = pcre_info (re, study, option, ptr)) < 0)
86     fprintf (outfile, "Error %d from pcre_fullinfo(%d)\n", rc, option);
87 }
88 
89 
90 
91 
92 /* Read lines from named file or stdin and write to named file or stdout; lines
93 consist of a regular expression, in delimiters and optionally followed by
94 options, followed by a set of test data, terminated by an empty line. */
95 
96 int
main(int argc,char ** argv)97 main (int argc, char **argv)
98 {
99   int options = 0;
100   int study_options = 0;
101   int timeit = 0;
102   int showinfo = 0;
103   int showstore = 0;
104   int size_offsets = 45;
105   int size_offsets_max;
106   int *offsets;
107   int posix = 0;
108   int perl = 1;
109   int study = 0;
110   int debug = 0;
111   int done = 0;
112   unsigned char buffer[30000];
113   unsigned char dbuffer[1024];
114   char *endptr;
115 
116 /* Scan options */
117 #define SHORTOPTS "dimo:pPSst"
118   for (;;)
119     {
120       static struct option longopts[] = {
121 	{"debug", 0, NULL, 'd'},
122 	{"showinfo", 0, NULL, 'i'},
123 	{"offsets-size", 0, NULL, 'o'},
124 	{"regexec", 0, NULL, 'p'},
125 	{"posix", 0, NULL, 'P'},
126 	{"study", 0, NULL, 'S'},
127 	{"showstore", 0, NULL, 's'},
128 	{"time", 0, NULL, 't'},
129 	{NULL, 0, NULL, 0}
130       };
131 
132       char c = getopt_long (argc, argv, SHORTOPTS,
133 			    longopts, NULL);
134 
135       /* Detect the end of the options. */
136       if (c == -1)
137 	break;
138 
139       switch (c)
140 	{
141 	case 's':
142 	case 'm':
143 	  showstore = 1;
144 	  break;
145 	case 't':
146 	  timeit = 1;
147 	  break;
148 	case 'i':
149 	  showinfo = 1;
150 	  break;
151 	case 'd':
152 	  showinfo = debug = 1;
153 	  break;
154 	case 'p':
155 	  posix = 1;
156 	  break;
157 	case 'P':
158 	  perl = 0;
159 	  break;
160 	case 'S':
161 	  study = 1;
162 	  break;
163 	case 'o':
164 	  if ((size_offsets = strtoul (optarg, &endptr, 10)) && *endptr == 0)
165 	    break;
166 
167 	default:
168 	  printf
169 	    ("Usage:   pcretest [options...] [<input> [<output>]]\n");
170 	  printf ("  -d   --debug          debug: show compiled code; implies -i\n");
171 	  printf ("  -i   --showinfo       show information about compiled pattern\n");
172 	  printf ("  -o N --offsets-size=N set size of offsets vector to <n>\n");
173 	  printf ("  -p   --regexec        use POSIX interface\n");
174 	  printf ("  -P   --posix          use POSIX regular expressions\n");
175 	  printf ("  -S   --study          study regular expressions\n");
176 	  printf ("  -s   --showstore      output store information\n");
177 	  printf ("  -t   --time           time compilation and execution\n");
178 	  return 1;
179 	}
180     }
181 
182 /* Sort out the input and output files */
183 
184   if (optind < argc && strcmp (argv[optind], "-") != 0)
185     {
186       infile = fopen (argv[optind], "r");
187 
188       if (infile == NULL)
189 	{
190 	  fprintf (stderr, "** Failed to open %s\n", argv[optind]);
191 	  return 1;
192 	}
193     }
194   else
195     infile = stdin;
196 
197   if (++optind < argc && strcmp (argv[optind], "-") != 0)
198     {
199       outfile = fopen (argv[optind], "w");
200       if (outfile == NULL)
201 	{
202 	  fprintf (stderr, "** Failed to open %s\n", argv[optind]);
203 	  return 1;
204 	}
205     }
206   else
207     outfile = stdout;
208 
209 /* Get the store for the offsets vector, and remember what it was */
210 
211   size_offsets_max = size_offsets;
212   offsets = malloc (size_offsets_max * sizeof (int));
213   if (offsets == NULL)
214     {
215       fprintf (stderr, "** Failed to get %d bytes of memory for offsets vector\n",
216 	      size_offsets_max * sizeof (int));
217       return 1;
218     }
219 
220 /* Set alternative malloc function */
221 
222   pcre_malloc = new_malloc;
223 
224 /* Main loop */
225 
226   while (!done)
227     {
228       pcre *re = NULL;
229       pcre_extra *extra = NULL;
230 
231       regex_t preg;
232       const char *error;
233       unsigned char *p, *pp, *ppp;
234       const unsigned char *tables = NULL;
235       int do_posix = posix;
236       int do_study = study;
237       int do_debug = debug;
238       int do_showinfo = showinfo;
239       int do_G = 0;
240       int do_g = 0;
241       int do_showrest = 0;
242       int erroroffset, len, delimiter;
243 
244 #ifdef HAVE_ISATTY
245       if (isatty (fileno (infile)))
246 	fprintf (outfile, "  re> ");
247 #endif
248       if (fgets ((char *) buffer, sizeof (buffer), infile) == NULL)
249 	break;
250 #ifdef HAVE_ISATTY
251       if (!isatty (fileno (infile)) || !isatty (fileno (outfile)))
252 #endif
253 	fprintf (outfile, "%s", (char *) buffer);
254 
255       p = buffer;
256       while (isspace (*p))
257 	p++;
258       if (*p == 0 || *p == '#')
259 	continue;
260 
261       /* Get the delimiter and seek the end of the pattern; if is isn't
262          complete, read more. */
263 
264       delimiter = *p++;
265 
266       if (isalnum (delimiter) || delimiter == '\\')
267 	{
268 	  fprintf (stderr, "** Delimiter must not be alphameric or \\\n");
269 	  goto SKIP_DATA;
270 	}
271 
272       pp = p;
273 
274       for (;;)
275 	{
276 	  while (*pp != 0)
277 	    {
278 	      if (*pp == '\\' && pp[1] != 0)
279 		pp++;
280 	      else if (*pp == delimiter)
281 		break;
282 	      pp++;
283 	    }
284 	  if (*pp != 0)
285 	    break;
286 
287 	  len = sizeof (buffer) - (pp - buffer);
288 	  if (len < 256)
289 	    {
290 	      fprintf (stderr,
291 		       "** Expression too long - missing delimiter?\n");
292 	      goto SKIP_DATA;
293 	    }
294 
295 #ifdef HAVE_ISATTY
296 	  if (isatty(fileno(infile)))
297 	    fprintf (outfile, "    > ");
298 #endif
299 	  if (fgets ((char *) pp, len, infile) == NULL)
300 	    {
301 	      fprintf (stderr, "** Unexpected EOF\n");
302 	      done = 1;
303 	      goto CONTINUE;
304 	    }
305 #ifdef HAVE_ISATTY
306 	  if (!isatty (fileno (infile)) || !isatty (fileno (outfile)))
307 #endif
308 	    fprintf (outfile, "%s", (char *) pp);
309 	}
310 
311       /* If the first character after the delimiter is backslash, make
312          the pattern end with backslash. This is purely to provide a way
313          of testing for the error message when a pattern ends with backslash. */
314 
315       if (pp[1] == '\\')
316 	*pp++ = '\\';
317 
318       /* Terminate the pattern at the delimiter */
319 
320       *pp++ = 0;
321 
322       /* Look for options after final delimiter */
323 
324       options = 0;
325       study_options = 0;
326       log_store = showstore;	/* default from command line */
327 
328       while (*pp != 0)
329 	{
330 	  switch (*pp++)
331 	    {
332 	    case 'g':
333 	      do_g = 1;
334 	      break;
335 	    case 'i':
336 	      options |= PCRE_CASELESS;
337 	      break;
338 	    case 'm':
339 	      options |= PCRE_MULTILINE;
340 	      break;
341 	    case 's':
342 	      options |= PCRE_DOTALL;
343 	      break;
344 	    case 'x':
345 	      options |= PCRE_EXTENDED;
346 	      break;
347 
348 	    case '+':
349 	      do_showrest = 1;
350 	      break;
351 	    case 'A':
352 	      options |= PCRE_ANCHORED;
353 	      break;
354 	    case 'D':
355 	      do_debug = do_showinfo = 1;
356 	      break;
357 	    case 'E':
358 	      options |= PCRE_DOLLAR_ENDONLY;
359 	      break;
360 	    case 'G':
361 	      do_G = 1;
362 	      break;
363 	    case 'I':
364 	      do_showinfo = 1;
365 	      break;
366 	    case 'M':
367 	      log_store = 1;
368 	      break;
369 
370 	    case 'P':
371 	      do_posix = 1;
372 	      break;
373 
374 	    case 'S':
375 	      do_study = 1;
376 	      break;
377 	    case 'U':
378 	      options |= PCRE_UNGREEDY;
379 	      break;
380 	    case 'X':
381 	      options |= PCRE_EXTRA;
382 	      break;
383 
384 	    case 'L':
385 	      ppp = pp;
386 	      while (*ppp != '\n' && *ppp != ' ')
387 		ppp++;
388 	      *ppp = 0;
389 	      if (setlocale (LC_CTYPE, (const char *) pp) == NULL)
390 		{
391 		  fprintf (stderr, "** Failed to set locale \"%s\"\n", pp);
392 		  goto SKIP_DATA;
393 		}
394 	      tables = pcre_maketables ();
395 	      pp = ppp;
396 	      break;
397 
398 	    case '\n':
399 	    case ' ':
400 	      break;
401 	    default:
402 	      fprintf (stderr, "** Unknown option '%c'\n", pp[-1]);
403 	      goto SKIP_DATA;
404 	    }
405 	}
406 
407       /* Handle compiling via the POSIX interface, which doesn't support the
408          timing, showing, or debugging options, nor the ability to pass over
409          local character tables. */
410 
411       if (do_posix)
412 	{
413 	  int rc;
414 	  int cflags = 0;
415 	  if ((options & PCRE_CASELESS) != 0)
416 	    cflags |= REG_ICASE;
417 	  if ((options & PCRE_MULTILINE) != 0)
418 	    cflags |= REG_NEWLINE;
419 	  if ((options & PCRE_DOTALL) != 0)
420 	    cflags |= REG_DOTALL;
421 	  if ((options & PCRE_EXTENDED) != 0)
422 	    cflags |= REG_EXTENDED;
423 
424 	  rc = regcomp (&preg, (char *) p, perl ? cflags | REG_PERL : cflags);
425 
426 	  /* Compilation failed; go back for another re, skipping to blank line
427 	     if non-interactive. */
428 
429 	  if (rc != 0)
430 	    {
431 	      (void) regerror (rc, &preg, (char *) buffer, sizeof (buffer));
432 	      fprintf (outfile, "Failed: POSIX code %d: %s\n", rc, buffer);
433 	      goto SKIP_DATA;
434 	    }
435 	}
436 
437       /* Handle compiling via the native interface */
438 
439       else
440 	{
441 	  if (timeit)
442 	    {
443 	      register int i;
444 	      clock_t time_taken;
445 	      clock_t start_time = clock ();
446 	      for (i = 0; i < LOOPREPEAT; i++)
447 		{
448 		  re = perl
449 		    ? pcre_compile ((char *) p, options, &error, &erroroffset,
450 				    tables)
451 		    : pcre_posix_compile ((char *) p, options, &error,
452 					  &erroroffset, tables);
453 		  if (re != NULL)
454 		    free (re);
455 		}
456 	      time_taken = clock () - start_time;
457 	      fprintf (outfile, "Compile time %.3f milliseconds\n",
458 		       ((double) time_taken * 1000.0) /
459 		       ((double) LOOPREPEAT * (double) CLOCKS_PER_SEC));
460 	    }
461 
462 	  re = perl
463 	    ? pcre_compile ((char *) p, options, &error, &erroroffset, tables)
464 	    : pcre_posix_compile ((char *) p, options, &error, &erroroffset,
465 				  tables);
466 
467 	  /* Compilation failed; go back for another re, skipping to blank line
468 	     if non-interactive. */
469 
470 	  if (re == NULL)
471 	    {
472 	      fprintf (outfile, "Failed: %s at offset %d\n", error,
473 		       erroroffset);
474 	    SKIP_DATA:
475 #ifdef HAVE_ISATTY
476 	      if (!isatty (fileno (infile)))
477 #endif
478 		{
479 		  for (;;)
480 		    {
481 		      if (fgets ((char *) buffer, sizeof (buffer), infile) ==
482 			  NULL)
483 			{
484 			  done = 1;
485 			  goto CONTINUE;
486 			}
487 		      len = (int) strlen ((char *) buffer);
488 		      while (len > 0 && isspace (buffer[len - 1]))
489 			len--;
490 		      if (len == 0)
491 			break;
492 		    }
493 		  fprintf (outfile, "\n");
494 		}
495 	      goto CONTINUE;
496 	    }
497 
498 	  /* If /S was present, study the regexp to generate additional info to
499 	         help with the matching. */
500 
501 	  if (do_study)
502 	    {
503 	      if (timeit)
504 		{
505 		  register int i;
506 		  clock_t time_taken;
507 		  clock_t start_time = clock ();
508 		  for (i = 0; i < LOOPREPEAT; i++)
509 		    extra = pcre_study (re, study_options, &error);
510 		  time_taken = clock () - start_time;
511 		  if (extra != NULL)
512 		    free (extra);
513 		  fprintf (outfile, "  Study time %.3f milliseconds\n",
514 			   ((double) time_taken * 1000.0) /
515 			   ((double) LOOPREPEAT *
516 			    (double) CLOCKS_PER_SEC));
517 		}
518 
519 	      extra = pcre_study (re, study_options, &error);
520 	      if (error != NULL)
521 		fprintf (outfile, "Failed to study: %s\n", error);
522 	      else if (extra == NULL)
523 		fprintf (outfile, "Study returned NULL\n");
524 
525 	      else if (do_showinfo)
526 		{
527 		  uschar *start_bits = NULL;
528 		  new_info (re, extra, PCRE_INFO_FIRSTTABLE, &start_bits);
529 		  if (start_bits == NULL)
530 		    fprintf (outfile, "No starting character set\n");
531 		  else
532 		    {
533 		      int i;
534 		      int c = 24;
535 		      fprintf (outfile, "Starting character set: ");
536 		      for (i = 0; i < 256; i++)
537 			{
538 			  if ((start_bits[i / 8] & (1 << (i % 8))) != 0)
539 			    {
540 			      if (c > 75)
541 				{
542 				  fprintf (outfile, "\n  ");
543 				  c = 2;
544 				}
545 			      if (isprint (i) && i != ' ')
546 				{
547 				  fprintf (outfile, "%c ", i);
548 				  c += 2;
549 				}
550 			      else
551 				{
552 				  fprintf (outfile, "\\x%02x ", i);
553 				  c += 5;
554 				}
555 			    }
556 			}
557 		      fprintf (outfile, "\n");
558 		    }
559 		}
560 	    }
561 
562 	  /* Compilation succeeded; print data if required. There are now two
563 	     info-returning functions. The old one has a limited interface and
564 	     returns only limited data. Check that it agrees with the newer one. */
565 
566 	  if (do_showinfo)
567 	    {
568 	      unsigned long int get_options;
569 	      int old_first_char, old_options, old_count;
570 	      int count, backrefmax, first_char, need_char;
571 	      size_t size;
572 
573 	      if (do_debug)
574 		pcre_debug (re);
575 
576 	      new_info (re, NULL, PCRE_INFO_OPTIONS, &get_options);
577 	      new_info (re, NULL, PCRE_INFO_SIZE, &size);
578 	      new_info (re, NULL, PCRE_INFO_CAPTURECOUNT, &count);
579 	      new_info (re, NULL, PCRE_INFO_BACKREFMAX, &backrefmax);
580 	      new_info (re, NULL, PCRE_INFO_FIRSTCHAR, &first_char);
581 	      new_info (re, NULL, PCRE_INFO_LASTLITERAL, &need_char);
582 
583 	      if (count < 0)
584 		fprintf (outfile, "Error %d from pcre_info()\n", count);
585 
586 	      if (size != gotten_store)
587 		fprintf (outfile, "Size disagreement: pcre_fullinfo=%d call to malloc for %d\n",
588 			 size, gotten_store);
589 
590 	      fprintf (outfile, "Capturing subpattern count = %d\n", count);
591 	      if (backrefmax > 0)
592 		fprintf (outfile, "Max back reference = %d\n", backrefmax);
593 	      if (get_options == 0)
594 		fprintf (outfile, "No options\n");
595 	      else
596 		fprintf (outfile, "Options:%s%s%s%s%s%s%s%s\n",
597 			 ((get_options & PCRE_ANCHORED) !=
598 			  0) ? " anchored" : "",
599 			 ((get_options & PCRE_CASELESS) !=
600 			  0) ? " caseless" : "",
601 			 ((get_options & PCRE_EXTENDED) !=
602 			  0) ? " extended" : "",
603 			 ((get_options & PCRE_MULTILINE) !=
604 			  0) ? " multiline" : "",
605 			 ((get_options & PCRE_DOTALL) != 0) ? " dotall" : "",
606 			 ((get_options & PCRE_DOLLAR_ENDONLY) !=
607 			  0) ? " dollar_endonly" : "",
608 			 ((get_options & PCRE_EXTRA) != 0) ? " extra" : "",
609 			 ((get_options & PCRE_UNGREEDY) !=
610 			  0) ? " ungreedy" : "");
611 
612 	      if (((re->options) & PCRE_ICHANGED) != 0)
613 		fprintf (outfile, "Case state changes\n");
614 	    }
615 	}
616 
617       /* Read data lines and test them */
618 
619       for (;;)
620 	{
621 	  unsigned char *q;
622 	  unsigned char *bptr = dbuffer;
623 	  int *use_offsets = offsets;
624 	  int use_size_offsets = size_offsets;
625 	  int count, c;
626 	  int copystrings = 0;
627 	  int getstrings = 0;
628 	  int getlist = 0;
629 	  int gmatched = 0;
630 	  int start_offset = 0;
631 	  int g_notempty = 0;
632 
633 	  options = 0;
634 
635 #ifdef HAVE_ISATTY
636 	  if (isatty (fileno (infile)))
637 	    fprintf (outfile, "data> ");
638 #endif
639 	  if (fgets ((char *) buffer, sizeof (buffer), infile) == NULL)
640 	    {
641 	      done = 1;
642 	      goto CONTINUE;
643 	    }
644 #ifdef HAVE_ISATTY
645 	  if (!isatty (fileno (infile)) || !isatty (fileno (outfile)))
646 #endif
647 	    fprintf (outfile, "%s", (char *) buffer);
648 
649 	  len = (int) strlen ((char *) buffer);
650 	  while (len > 0 && isspace (buffer[len - 1]))
651 	    len--;
652 	  buffer[len] = 0;
653 	  if (len == 0)
654 	    break;
655 
656 	  p = buffer;
657 	  while (isspace (*p))
658 	    p++;
659 
660 	  q = dbuffer;
661 	  while ((c = *p++) != 0)
662 	    {
663 	      int i = 0;
664 	      int n = 0;
665 	      if (c == '\\')
666 		switch ((c = *p++))
667 		  {
668 		  case 'a':
669 		    c = 7;
670 		    break;
671 		  case 'b':
672 		    c = '\b';
673 		    break;
674 		  case 'e':
675 		    c = 27;
676 		    break;
677 		  case 'f':
678 		    c = '\f';
679 		    break;
680 		  case 'n':
681 		    c = '\n';
682 		    break;
683 		  case 'r':
684 		    c = '\r';
685 		    break;
686 		  case 't':
687 		    c = '\t';
688 		    break;
689 		  case 'v':
690 		    c = '\v';
691 		    break;
692 
693 		  case '0':
694 		  case '1':
695 		  case '2':
696 		  case '3':
697 		  case '4':
698 		  case '5':
699 		  case '6':
700 		  case '7':
701 		    c -= '0';
702 		    while (i++ < 2 && isdigit (*p) && *p != '8'
703 			   && *p != '9')
704 		      c = c * 8 + *p++ - '0';
705 		    break;
706 
707 		  case 'x':
708 		    c = 0;
709 		    while (i++ < 2 && isxdigit (*p))
710 		      {
711 			c =
712 			  c * 16 + tolower (*p) -
713 			  ((isdigit (*p)) ? '0' : 'W');
714 			p++;
715 		      }
716 		    break;
717 
718 		  case 0:	/* Allows for an empty line */
719 		    p--;
720 		    continue;
721 
722 		  case 'A':	/* Option setting */
723 		    options |= PCRE_ANCHORED;
724 		    continue;
725 
726 		  case 'B':
727 		    options |= PCRE_NOTBOL;
728 		    continue;
729 
730 		  case 'C':
731 		    while (isdigit (*p))
732 		      n = n * 10 + *p++ - '0';
733 		    copystrings |= 1 << n;
734 		    continue;
735 
736 		  case 'G':
737 		    while (isdigit (*p))
738 		      n = n * 10 + *p++ - '0';
739 		    getstrings |= 1 << n;
740 		    continue;
741 
742 		  case 'L':
743 		    getlist = 1;
744 		    continue;
745 
746 		  case 'N':
747 		    options |= PCRE_NOTEMPTY;
748 		    continue;
749 
750 		  case 'O':
751 		    while (isdigit (*p))
752 		      n = n * 10 + *p++ - '0';
753 		    if (n > size_offsets_max)
754 		      {
755 			size_offsets_max = n;
756 			free (offsets);
757 			use_offsets = offsets =
758 			  malloc (size_offsets_max * sizeof (int));
759 			if (offsets == NULL)
760 			  {
761 			    printf
762 			      ("** Failed to get %d bytes of memory for offsets vector\n",
763 			       size_offsets_max * sizeof (int));
764 			    return 1;
765 			  }
766 		      }
767 		    use_size_offsets = n;
768 		    if (n == 0)
769 		      use_offsets = NULL;
770 		    continue;
771 
772 		  case 'Z':
773 		    options |= PCRE_NOTEOL;
774 		    continue;
775 		  }
776 	      *q++ = c;
777 	    }
778 	  *q = 0;
779 	  len = q - dbuffer;
780 
781 	  /* Handle matching via the POSIX interface, which does not
782 	     support timing. */
783 
784 	  if (do_posix)
785 	    {
786 	      int rc;
787 	      int eflags = 0;
788 	      regmatch_t *pmatch =
789 		malloc (sizeof (regmatch_t) * use_size_offsets);
790 	      if ((options & PCRE_NOTBOL) != 0)
791 		eflags |= REG_NOTBOL;
792 	      if ((options & PCRE_NOTEOL) != 0)
793 		eflags |= REG_NOTEOL;
794 
795 	      rc =
796 		regnexec (&preg, (const char *) bptr, len,
797 			  use_size_offsets, pmatch, eflags);
798 
799 	      if (rc != 0)
800 		{
801 		  (void) regerror (rc, &preg, (char *) buffer,
802 				   sizeof (buffer));
803 		  fprintf (outfile, "No match: POSIX code %d: %s\n", rc,
804 			   buffer);
805 		}
806 	      else
807 		{
808 		  size_t i;
809 		  for (i = 0; i < use_size_offsets; i++)
810 		    {
811 		      if (pmatch[i].rm_so == -1)
812 			continue;
813 		      fprintf (outfile, "%2d: ", (int) i);
814 		      pchars (dbuffer + pmatch[i].rm_so,
815 			      pmatch[i].rm_eo - pmatch[i].rm_so);
816 		      fprintf (outfile, "\n");
817 		      if (i == 0 && do_showrest)
818 			{
819 			  fprintf (outfile, " 0+ ");
820 			  pchars (dbuffer + pmatch[i].rm_eo,
821 				  len - pmatch[i].rm_eo);
822 			  fprintf (outfile, "\n");
823 			}
824 		    }
825 		}
826 	      free (pmatch);
827 	    }
828 
829 	  /* Handle matching via the native interface - repeats for /g and /G */
830 
831 	  else
832 	    for (;; gmatched++)	/* Loop for /g or /G */
833 	      {
834 		fflush(outfile);
835 		if (timeit)
836 		  {
837 		    register int i;
838 		    clock_t time_taken;
839 		    clock_t start_time = clock ();
840 		    for (i = 0; i < LOOPREPEAT; i++)
841 		      count = pcre_exec (re, extra, (char *) bptr, len,
842 					 start_offset,
843 					 options | g_notempty,
844 					 use_offsets, use_size_offsets);
845 		    time_taken = clock () - start_time;
846 		    fprintf (outfile, "Execute time %.3f milliseconds\n",
847 			     ((double) time_taken * 1000.0) /
848 			     ((double) LOOPREPEAT *
849 			      (double) CLOCKS_PER_SEC));
850 		  }
851 
852 		count = pcre_exec (re, extra, (char *) bptr, len,
853 				   start_offset, options | g_notempty,
854 				   use_offsets, use_size_offsets);
855 
856 		if (count == 0)
857 		  {
858 		    fprintf (outfile, "Matched, but too many substrings\n");
859 		    count = use_size_offsets / 3;
860 		  }
861 
862 		/* Matched */
863 
864 		if (count >= 0)
865 		  {
866 		    int i;
867 		    for (i = 0; i < count * 2; i += 2)
868 		      {
869 			if (use_offsets[i] < 0)
870 			  fprintf (outfile, "%2d: <unset>\n", i / 2);
871 			else
872 			  {
873 			    fprintf (outfile, "%2d: ", i / 2);
874 			    pchars (bptr + use_offsets[i],
875 				    use_offsets[i + 1] - use_offsets[i]);
876 			    fprintf (outfile, "\n");
877 			    if (i == 0)
878 			      {
879 				if (do_showrest)
880 				  {
881 				    fprintf (outfile, " 0+ ");
882 				    pchars (bptr + use_offsets[i + 1],
883 					    len - use_offsets[i + 1]);
884 				    fprintf (outfile, "\n");
885 				  }
886 			      }
887 			  }
888 		      }
889 
890 		    for (i = 0; i < 32; i++)
891 		      {
892 			if ((copystrings & (1 << i)) != 0)
893 			  {
894 			    char copybuffer[16];
895 			    int rc =
896 			      pcre_copy_substring ((char *) bptr,
897 						   use_offsets,
898 						   count,
899 						   i, copybuffer,
900 						   sizeof (copybuffer));
901 			    if (rc < 0)
902 			      fprintf (outfile, "copy substring %d failed %d\n", i,
903 				      rc);
904 			    else
905 			      fprintf (outfile, "%2dC %s (%d)\n", i,
906 				       copybuffer, rc);
907 			  }
908 		      }
909 
910 		    for (i = 0; i < 32; i++)
911 		      {
912 			if ((getstrings & (1 << i)) != 0)
913 			  {
914 			    const char *substring;
915 			    int rc =
916 			      pcre_get_substring ((char *) bptr,
917 						  use_offsets,
918 						  count,
919 						  i, &substring);
920 			    if (rc < 0)
921 			      fprintf (outfile, "get substring %d failed %d\n", i,
922 				      rc);
923 			    else
924 			      {
925 				fprintf (outfile, "%2dG %s (%d)\n", i,
926 					 substring, rc);
927 				/* free((void *)substring); */
928 				pcre_free_substring (substring);
929 			      }
930 			  }
931 		      }
932 
933 		    if (getlist)
934 		      {
935 			const char **stringlist;
936 			int rc =
937 			  pcre_get_substring_list ((char *) bptr,
938 						   use_offsets,
939 						   count,
940 						   &stringlist);
941 			if (rc < 0)
942 			  fprintf (outfile, "get substring list failed %d\n", rc);
943 			else
944 			  {
945 			    for (i = 0; i < count; i++)
946 			      fprintf (outfile, "%2dL %s\n", i,
947 				       stringlist[i]);
948 			    if (stringlist[i] != NULL)
949 			      fprintf (outfile, "string list not terminated by NULL\n");
950 				/* free((void *)stringlist); */
951 			    pcre_free_substring_list (stringlist);
952 			  }
953 		      }
954 		  }
955 
956 		/* Failed to match. If this is a /g or /G loop and we previously set
957 		   g_notempty after a null match, this is not necessarily the end.
958 		   We want to advance the start offset, and continue. Fudge the offset
959 		   values to achieve this. We won't be at the end of the string - that
960 		   was checked before setting g_notempty. */
961 
962 		else
963 		  {
964 		    if (g_notempty != 0)
965 		      {
966 			use_offsets[0] = start_offset;
967 			use_offsets[1] = start_offset + 1;
968 		      }
969 		    else
970 		      {
971 			if (gmatched == 0)	/* Error if no previous matches */
972 			  {
973 			    if (count == -1)
974 			      fprintf (outfile, "No match\n");
975 			    else
976 			      fprintf (outfile, "Error %d\n", count);
977 			  }
978 			break;	/* Out of the /g loop */
979 		      }
980 		  }
981 
982 		/* If not /g or /G we are done */
983 
984 		if (!do_g && !do_G)
985 		  break;
986 
987 		/* If we have matched an empty string, first check to see if we are at
988 		   the end of the subject. If so, the /g loop is over. Otherwise, mimic
989 		   what Perl's /g options does. This turns out to be rather cunning. First
990 		   we set PCRE_NOTEMPTY and PCRE_ANCHORED and try the match again at the
991 		   same point. If this fails (picked up above) we advance to the next
992 		   character. */
993 
994 		g_notempty = 0;
995 		if (use_offsets[0] == use_offsets[1])
996 		  {
997 		    if (use_offsets[0] == len)
998 		      break;
999 		    g_notempty = PCRE_NOTEMPTY | PCRE_ANCHORED;
1000 		  }
1001 
1002 		/* For /g, update the start offset, leaving the rest alone */
1003 
1004 		if (do_g)
1005 		  start_offset = use_offsets[1];
1006 
1007 		/* For /G, update the pointer and length */
1008 
1009 		else
1010 		  {
1011 		    bptr += use_offsets[1];
1012 		    len -= use_offsets[1];
1013 		  }
1014 	      }		/* End of loop for /g and /G */
1015 	}			/* End of loop for data lines */
1016 
1017     CONTINUE:
1018 
1019       if (do_posix)
1020 	regfree (&preg);
1021 
1022       if (re != NULL)
1023 	free (re);
1024       if (extra != NULL)
1025 	free (extra);
1026       if (tables != NULL)
1027 	{
1028 	  free ((void *) tables);
1029 	  setlocale (LC_CTYPE, "C");
1030 	}
1031     }
1032 
1033   fprintf (outfile, "\n");
1034   return 0;
1035 }
1036 
1037 /* End */
1038