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