tools/pcre/pcredemo.c
author David Anderson <dvander@alliedmods.net>
Thu Oct 29 00:06:12 2009 -0700 (2009-10-29)
changeset 2844 87f951bece2d
parent 2762 d2d467bf1b5a
child 3831 babd0eee3c5e
permissions -rw-r--r--
Fix iloop race when using AddCommandListener and SourceMod unloads (bug 4077, r=pred).
dvander@2762
     1
/*************************************************
dvander@2762
     2
*           PCRE DEMONSTRATION PROGRAM           *
dvander@2762
     3
*************************************************/
dvander@2762
     4
dvander@2762
     5
/* This is a demonstration program to illustrate the most straightforward ways
dvander@2762
     6
of calling the PCRE regular expression library from a C program. See the
dvander@2762
     7
pcresample documentation for a short discussion ("man pcresample" if you have
dvander@2762
     8
the PCRE man pages installed).
dvander@2762
     9
dvander@2762
    10
In Unix-like environments, compile this program thuswise:
dvander@2762
    11
dvander@2762
    12
  gcc -Wall pcredemo.c -I/usr/local/include -L/usr/local/lib \
dvander@2762
    13
    -R/usr/local/lib -lpcre
dvander@2762
    14
dvander@2762
    15
Replace "/usr/local/include" and "/usr/local/lib" with wherever the include and
dvander@2762
    16
library files for PCRE are installed on your system. You don't need -I and -L
dvander@2762
    17
if PCRE is installed in the standard system libraries. Only some operating
dvander@2762
    18
systems (e.g. Solaris) use the -R option.
dvander@2762
    19
dvander@2762
    20
Building under Windows:
dvander@2762
    21
dvander@2762
    22
If you want to statically link this program against a non-dll .a file, you must
dvander@2762
    23
define PCRE_STATIC before including pcre.h, otherwise the pcre_malloc() and
dvander@2762
    24
pcre_free() exported functions will be declared __declspec(dllimport), with
dvander@2762
    25
unwanted results. So in this environment, uncomment the following line. */
dvander@2762
    26
dvander@2762
    27
/* #define PCRE_STATIC */
dvander@2762
    28
dvander@2762
    29
#include <stdio.h>
dvander@2762
    30
#include <string.h>
dvander@2762
    31
#include <pcre.h>
dvander@2762
    32
dvander@2762
    33
#define OVECCOUNT 30    /* should be a multiple of 3 */
dvander@2762
    34
dvander@2762
    35
dvander@2762
    36
int main(int argc, char **argv)
dvander@2762
    37
{
dvander@2762
    38
pcre *re;
dvander@2762
    39
const char *error;
dvander@2762
    40
char *pattern;
dvander@2762
    41
char *subject;
dvander@2762
    42
unsigned char *name_table;
dvander@2762
    43
int erroffset;
dvander@2762
    44
int find_all;
dvander@2762
    45
int namecount;
dvander@2762
    46
int name_entry_size;
dvander@2762
    47
int ovector[OVECCOUNT];
dvander@2762
    48
int subject_length;
dvander@2762
    49
int rc, i;
dvander@2762
    50
dvander@2762
    51
dvander@2762
    52
/**************************************************************************
dvander@2762
    53
* First, sort out the command line. There is only one possible option at  *
dvander@2762
    54
* the moment, "-g" to request repeated matching to find all occurrences,  *
dvander@2762
    55
* like Perl's /g option. We set the variable find_all to a non-zero value *
dvander@2762
    56
* if the -g option is present. Apart from that, there must be exactly two *
dvander@2762
    57
* arguments.                                                              *
dvander@2762
    58
**************************************************************************/
dvander@2762
    59
dvander@2762
    60
find_all = 0;
dvander@2762
    61
for (i = 1; i < argc; i++)
dvander@2762
    62
  {
dvander@2762
    63
  if (strcmp(argv[i], "-g") == 0) find_all = 1;
dvander@2762
    64
    else break;
dvander@2762
    65
  }
dvander@2762
    66
dvander@2762
    67
/* After the options, we require exactly two arguments, which are the pattern,
dvander@2762
    68
and the subject string. */
dvander@2762
    69
dvander@2762
    70
if (argc - i != 2)
dvander@2762
    71
  {
dvander@2762
    72
  printf("Two arguments required: a regex and a subject string\n");
dvander@2762
    73
  return 1;
dvander@2762
    74
  }
dvander@2762
    75
dvander@2762
    76
pattern = argv[i];
dvander@2762
    77
subject = argv[i+1];
dvander@2762
    78
subject_length = (int)strlen(subject);
dvander@2762
    79
dvander@2762
    80
dvander@2762
    81
/*************************************************************************
dvander@2762
    82
* Now we are going to compile the regular expression pattern, and handle *
dvander@2762
    83
* and errors that are detected.                                          *
dvander@2762
    84
*************************************************************************/
dvander@2762
    85
dvander@2762
    86
re = pcre_compile(
dvander@2762
    87
  pattern,              /* the pattern */
dvander@2762
    88
  0,                    /* default options */
dvander@2762
    89
  &error,               /* for error message */
dvander@2762
    90
  &erroffset,           /* for error offset */
dvander@2762
    91
  NULL);                /* use default character tables */
dvander@2762
    92
dvander@2762
    93
/* Compilation failed: print the error message and exit */
dvander@2762
    94
dvander@2762
    95
if (re == NULL)
dvander@2762
    96
  {
dvander@2762
    97
  printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
dvander@2762
    98
  return 1;
dvander@2762
    99
  }
dvander@2762
   100
dvander@2762
   101
dvander@2762
   102
/*************************************************************************
dvander@2762
   103
* If the compilation succeeded, we call PCRE again, in order to do a     *
dvander@2762
   104
* pattern match against the subject string. This does just ONE match. If *
dvander@2762
   105
* further matching is needed, it will be done below.                     *
dvander@2762
   106
*************************************************************************/
dvander@2762
   107
dvander@2762
   108
rc = pcre_exec(
dvander@2762
   109
  re,                   /* the compiled pattern */
dvander@2762
   110
  NULL,                 /* no extra data - we didn't study the pattern */
dvander@2762
   111
  subject,              /* the subject string */
dvander@2762
   112
  subject_length,       /* the length of the subject */
dvander@2762
   113
  0,                    /* start at offset 0 in the subject */
dvander@2762
   114
  0,                    /* default options */
dvander@2762
   115
  ovector,              /* output vector for substring information */
dvander@2762
   116
  OVECCOUNT);           /* number of elements in the output vector */
dvander@2762
   117
dvander@2762
   118
/* Matching failed: handle error cases */
dvander@2762
   119
dvander@2762
   120
if (rc < 0)
dvander@2762
   121
  {
dvander@2762
   122
  switch(rc)
dvander@2762
   123
    {
dvander@2762
   124
    case PCRE_ERROR_NOMATCH: printf("No match\n"); break;
dvander@2762
   125
    /*
dvander@2762
   126
    Handle other special cases if you like
dvander@2762
   127
    */
dvander@2762
   128
    default: printf("Matching error %d\n", rc); break;
dvander@2762
   129
    }
dvander@2762
   130
  pcre_free(re);     /* Release memory used for the compiled pattern */
dvander@2762
   131
  return 1;
dvander@2762
   132
  }
dvander@2762
   133
dvander@2762
   134
/* Match succeded */
dvander@2762
   135
dvander@2762
   136
printf("\nMatch succeeded at offset %d\n", ovector[0]);
dvander@2762
   137
dvander@2762
   138
dvander@2762
   139
/*************************************************************************
dvander@2762
   140
* We have found the first match within the subject string. If the output *
dvander@2762
   141
* vector wasn't big enough, say so. Then output any substrings that were *
dvander@2762
   142
* captured.                                                              *
dvander@2762
   143
*************************************************************************/
dvander@2762
   144
dvander@2762
   145
/* The output vector wasn't big enough */
dvander@2762
   146
dvander@2762
   147
if (rc == 0)
dvander@2762
   148
  {
dvander@2762
   149
  rc = OVECCOUNT/3;
dvander@2762
   150
  printf("ovector only has room for %d captured substrings\n", rc - 1);
dvander@2762
   151
  }
dvander@2762
   152
dvander@2762
   153
/* Show substrings stored in the output vector by number. Obviously, in a real
dvander@2762
   154
application you might want to do things other than print them. */
dvander@2762
   155
dvander@2762
   156
for (i = 0; i < rc; i++)
dvander@2762
   157
  {
dvander@2762
   158
  char *substring_start = subject + ovector[2*i];
dvander@2762
   159
  int substring_length = ovector[2*i+1] - ovector[2*i];
dvander@2762
   160
  printf("%2d: %.*s\n", i, substring_length, substring_start);
dvander@2762
   161
  }
dvander@2762
   162
dvander@2762
   163
dvander@2762
   164
/**************************************************************************
dvander@2762
   165
* That concludes the basic part of this demonstration program. We have    *
dvander@2762
   166
* compiled a pattern, and performed a single match. The code that follows *
dvander@2762
   167
* shows first how to access named substrings, and then how to code for    *
dvander@2762
   168
* repeated matches on the same subject.                                   *
dvander@2762
   169
**************************************************************************/
dvander@2762
   170
dvander@2762
   171
/* See if there are any named substrings, and if so, show them by name. First
dvander@2762
   172
we have to extract the count of named parentheses from the pattern. */
dvander@2762
   173
dvander@2762
   174
(void)pcre_fullinfo(
dvander@2762
   175
  re,                   /* the compiled pattern */
dvander@2762
   176
  NULL,                 /* no extra data - we didn't study the pattern */
dvander@2762
   177
  PCRE_INFO_NAMECOUNT,  /* number of named substrings */
dvander@2762
   178
  &namecount);          /* where to put the answer */
dvander@2762
   179
dvander@2762
   180
if (namecount <= 0) printf("No named substrings\n"); else
dvander@2762
   181
  {
dvander@2762
   182
  unsigned char *tabptr;
dvander@2762
   183
  printf("Named substrings\n");
dvander@2762
   184
dvander@2762
   185
  /* Before we can access the substrings, we must extract the table for
dvander@2762
   186
  translating names to numbers, and the size of each entry in the table. */
dvander@2762
   187
dvander@2762
   188
  (void)pcre_fullinfo(
dvander@2762
   189
    re,                       /* the compiled pattern */
dvander@2762
   190
    NULL,                     /* no extra data - we didn't study the pattern */
dvander@2762
   191
    PCRE_INFO_NAMETABLE,      /* address of the table */
dvander@2762
   192
    &name_table);             /* where to put the answer */
dvander@2762
   193
dvander@2762
   194
  (void)pcre_fullinfo(
dvander@2762
   195
    re,                       /* the compiled pattern */
dvander@2762
   196
    NULL,                     /* no extra data - we didn't study the pattern */
dvander@2762
   197
    PCRE_INFO_NAMEENTRYSIZE,  /* size of each entry in the table */
dvander@2762
   198
    &name_entry_size);        /* where to put the answer */
dvander@2762
   199
dvander@2762
   200
  /* Now we can scan the table and, for each entry, print the number, the name,
dvander@2762
   201
  and the substring itself. */
dvander@2762
   202
dvander@2762
   203
  tabptr = name_table;
dvander@2762
   204
  for (i = 0; i < namecount; i++)
dvander@2762
   205
    {
dvander@2762
   206
    int n = (tabptr[0] << 8) | tabptr[1];
dvander@2762
   207
    printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2,
dvander@2762
   208
      ovector[2*n+1] - ovector[2*n], subject + ovector[2*n]);
dvander@2762
   209
    tabptr += name_entry_size;
dvander@2762
   210
    }
dvander@2762
   211
  }
dvander@2762
   212
dvander@2762
   213
dvander@2762
   214
/*************************************************************************
dvander@2762
   215
* If the "-g" option was given on the command line, we want to continue  *
dvander@2762
   216
* to search for additional matches in the subject string, in a similar   *
dvander@2762
   217
* way to the /g option in Perl. This turns out to be trickier than you   *
dvander@2762
   218
* might think because of the possibility of matching an empty string.    *
dvander@2762
   219
* What happens is as follows:                                            *
dvander@2762
   220
*                                                                        *
dvander@2762
   221
* If the previous match was NOT for an empty string, we can just start   *
dvander@2762
   222
* the next match at the end of the previous one.                         *
dvander@2762
   223
*                                                                        *
dvander@2762
   224
* If the previous match WAS for an empty string, we can't do that, as it *
dvander@2762
   225
* would lead to an infinite loop. Instead, a special call of pcre_exec() *
dvander@2762
   226
* is made with the PCRE_NOTEMPTY and PCRE_ANCHORED flags set. The first  *
dvander@2762
   227
* of these tells PCRE that an empty string is not a valid match; other   *
dvander@2762
   228
* possibilities must be tried. The second flag restricts PCRE to one     *
dvander@2762
   229
* match attempt at the initial string position. If this match succeeds,  *
dvander@2762
   230
* an alternative to the empty string match has been found, and we can    *
dvander@2762
   231
* proceed round the loop.                                                *
dvander@2762
   232
*************************************************************************/
dvander@2762
   233
dvander@2762
   234
if (!find_all)
dvander@2762
   235
  {
dvander@2762
   236
  pcre_free(re);   /* Release the memory used for the compiled pattern */
dvander@2762
   237
  return 0;        /* Finish unless -g was given */
dvander@2762
   238
  }
dvander@2762
   239
dvander@2762
   240
/* Loop for second and subsequent matches */
dvander@2762
   241
dvander@2762
   242
for (;;)
dvander@2762
   243
  {
dvander@2762
   244
  int options = 0;                 /* Normally no options */
dvander@2762
   245
  int start_offset = ovector[1];   /* Start at end of previous match */
dvander@2762
   246
dvander@2762
   247
  /* If the previous match was for an empty string, we are finished if we are
dvander@2762
   248
  at the end of the subject. Otherwise, arrange to run another match at the
dvander@2762
   249
  same point to see if a non-empty match can be found. */
dvander@2762
   250
dvander@2762
   251
  if (ovector[0] == ovector[1])
dvander@2762
   252
    {
dvander@2762
   253
    if (ovector[0] == subject_length) break;
dvander@2762
   254
    options = PCRE_NOTEMPTY | PCRE_ANCHORED;
dvander@2762
   255
    }
dvander@2762
   256
dvander@2762
   257
  /* Run the next matching operation */
dvander@2762
   258
dvander@2762
   259
  rc = pcre_exec(
dvander@2762
   260
    re,                   /* the compiled pattern */
dvander@2762
   261
    NULL,                 /* no extra data - we didn't study the pattern */
dvander@2762
   262
    subject,              /* the subject string */
dvander@2762
   263
    subject_length,       /* the length of the subject */
dvander@2762
   264
    start_offset,         /* starting offset in the subject */
dvander@2762
   265
    options,              /* options */
dvander@2762
   266
    ovector,              /* output vector for substring information */
dvander@2762
   267
    OVECCOUNT);           /* number of elements in the output vector */
dvander@2762
   268
dvander@2762
   269
  /* This time, a result of NOMATCH isn't an error. If the value in "options"
dvander@2762
   270
  is zero, it just means we have found all possible matches, so the loop ends.
dvander@2762
   271
  Otherwise, it means we have failed to find a non-empty-string match at a
dvander@2762
   272
  point where there was a previous empty-string match. In this case, we do what
dvander@2762
   273
  Perl does: advance the matching position by one, and continue. We do this by
dvander@2762
   274
  setting the "end of previous match" offset, because that is picked up at the
dvander@2762
   275
  top of the loop as the point at which to start again. */
dvander@2762
   276
dvander@2762
   277
  if (rc == PCRE_ERROR_NOMATCH)
dvander@2762
   278
    {
dvander@2762
   279
    if (options == 0) break;
dvander@2762
   280
    ovector[1] = start_offset + 1;
dvander@2762
   281
    continue;    /* Go round the loop again */
dvander@2762
   282
    }
dvander@2762
   283
dvander@2762
   284
  /* Other matching errors are not recoverable. */
dvander@2762
   285
dvander@2762
   286
  if (rc < 0)
dvander@2762
   287
    {
dvander@2762
   288
    printf("Matching error %d\n", rc);
dvander@2762
   289
    pcre_free(re);    /* Release memory used for the compiled pattern */
dvander@2762
   290
    return 1;
dvander@2762
   291
    }
dvander@2762
   292
dvander@2762
   293
  /* Match succeded */
dvander@2762
   294
dvander@2762
   295
  printf("\nMatch succeeded again at offset %d\n", ovector[0]);
dvander@2762
   296
dvander@2762
   297
  /* The match succeeded, but the output vector wasn't big enough. */
dvander@2762
   298
dvander@2762
   299
  if (rc == 0)
dvander@2762
   300
    {
dvander@2762
   301
    rc = OVECCOUNT/3;
dvander@2762
   302
    printf("ovector only has room for %d captured substrings\n", rc - 1);
dvander@2762
   303
    }
dvander@2762
   304
dvander@2762
   305
  /* As before, show substrings stored in the output vector by number, and then
dvander@2762
   306
  also any named substrings. */
dvander@2762
   307
dvander@2762
   308
  for (i = 0; i < rc; i++)
dvander@2762
   309
    {
dvander@2762
   310
    char *substring_start = subject + ovector[2*i];
dvander@2762
   311
    int substring_length = ovector[2*i+1] - ovector[2*i];
dvander@2762
   312
    printf("%2d: %.*s\n", i, substring_length, substring_start);
dvander@2762
   313
    }
dvander@2762
   314
dvander@2762
   315
  if (namecount <= 0) printf("No named substrings\n"); else
dvander@2762
   316
    {
dvander@2762
   317
    unsigned char *tabptr = name_table;
dvander@2762
   318
    printf("Named substrings\n");
dvander@2762
   319
    for (i = 0; i < namecount; i++)
dvander@2762
   320
      {
dvander@2762
   321
      int n = (tabptr[0] << 8) | tabptr[1];
dvander@2762
   322
      printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2,
dvander@2762
   323
        ovector[2*n+1] - ovector[2*n], subject + ovector[2*n]);
dvander@2762
   324
      tabptr += name_entry_size;
dvander@2762
   325
      }
dvander@2762
   326
    }
dvander@2762
   327
  }      /* End of loop to find second and subsequent matches */
dvander@2762
   328
dvander@2762
   329
printf("\n");
dvander@2762
   330
pcre_free(re);       /* Release memory used for the compiled pattern */
dvander@2762
   331
return 0;
dvander@2762
   332
}
dvander@2762
   333
dvander@2762
   334
/* End of pcredemo.c */