pcretest.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:33k
源码类别:

生物技术

开发平台:

C/C++

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