~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/pcre/pcretest.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*************************************************
 
2
*             PCRE testing program               *
 
3
*************************************************/
 
4
 
 
5
/* This program was hacked up as a tester for PCRE. I really should have
 
6
written it more tidily in the first place. Will I ever learn? It has grown and
 
7
been extended and consequently is now rather untidy in places.
 
8
 
 
9
-----------------------------------------------------------------------------
 
10
Redistribution and use in source and binary forms, with or without
 
11
modification, are permitted provided that the following conditions are met:
 
12
 
 
13
    * Redistributions of source code must retain the above copyright notice,
 
14
      this list of conditions and the following disclaimer.
 
15
 
 
16
    * Redistributions in binary form must reproduce the above copyright
 
17
      notice, this list of conditions and the following disclaimer in the
 
18
      documentation and/or other materials provided with the distribution.
 
19
 
 
20
    * Neither the name of the University of Cambridge nor the names of its
 
21
      contributors may be used to endorse or promote products derived from
 
22
      this software without specific prior written permission.
 
23
 
 
24
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
25
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
26
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
27
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 
28
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
29
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
30
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
31
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
32
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
33
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
34
POSSIBILITY OF SUCH DAMAGE.
 
35
-----------------------------------------------------------------------------
 
36
*/
 
37
 
 
38
 
 
39
#include <ctype.h>
 
40
#include <stdio.h>
 
41
#include <string.h>
 
42
#include <stdlib.h>
 
43
#include <time.h>
 
44
#include <locale.h>
 
45
#include <errno.h>
 
46
 
 
47
/* We need the internal info for displaying the results of pcre_study(). Also
 
48
for getting the opcodes for showing compiled code. */
 
49
 
 
50
#define PCRE_SPY        /* For Win32 build, import data, not export */
 
51
#include "internal.h"
 
52
 
 
53
/* It is possible to compile this test program without including support for
 
54
testing the POSIX interface, though this is not available via the standard
 
55
Makefile. */
 
56
 
 
57
#if !defined NOPOSIX
 
58
#include "pcreposix.h"
 
59
#endif
 
60
 
 
61
#ifndef CLOCKS_PER_SEC
 
62
#ifdef CLK_TCK
 
63
#define CLOCKS_PER_SEC CLK_TCK
 
64
#else
 
65
#define CLOCKS_PER_SEC 100
 
66
#endif
 
67
#endif
 
68
 
 
69
#define LOOPREPEAT 500000
 
70
 
 
71
#define BUFFER_SIZE 30000
 
72
#define PBUFFER_SIZE BUFFER_SIZE
 
73
#define DBUFFER_SIZE BUFFER_SIZE
 
74
 
 
75
 
 
76
static FILE *outfile;
 
77
static int log_store = 0;
 
78
static int callout_count;
 
79
static int callout_extra;
 
80
static int callout_fail_count;
 
81
static int callout_fail_id;
 
82
static int first_callout;
 
83
static int show_malloc;
 
84
static int use_utf8;
 
85
static size_t gotten_store;
 
86
 
 
87
static uschar *pbuffer = NULL;
 
88
 
 
89
 
 
90
static const int utf8_table1[] = {
 
91
  0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff};
 
92
 
 
93
static const int utf8_table2[] = {
 
94
  0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
 
95
 
 
96
static const int utf8_table3[] = {
 
97
  0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
 
98
 
 
99
 
 
100
 
 
101
/*************************************************
 
102
*         Print compiled regex                   *
 
103
*************************************************/
 
104
 
 
105
/* The code for doing this is held in a separate file that is also included in
 
106
pcre.c when it is compiled with the debug switch. It defines a function called
 
107
print_internals(), which uses a table of opcode lengths defined by the macro
 
108
OP_LENGTHS, whose name must be OP_lengths. It also uses a table that translates
 
109
Unicode property names to numbers; this is kept in a separate file. */
 
110
 
 
111
static uschar OP_lengths[] = { OP_LENGTHS };
 
112
 
 
113
#include "ucp.h"
 
114
#include "ucptypetable.c"
 
115
#include "printint.c"
 
116
 
 
117
 
 
118
 
 
119
/*************************************************
 
120
*          Read number from string               *
 
121
*************************************************/
 
122
 
 
123
/* We don't use strtoul() because SunOS4 doesn't have it. Rather than mess
 
124
around with conditional compilation, just do the job by hand. It is only used
 
125
for unpicking the -o argument, so just keep it simple.
 
126
 
 
127
Arguments:
 
128
  str           string to be converted
 
129
  endptr        where to put the end pointer
 
130
 
 
131
Returns:        the unsigned long
 
132
*/
 
133
 
 
134
static int
 
135
get_value(unsigned char *str, unsigned char **endptr)
 
136
{
 
137
int result = 0;
 
138
while(*str != 0 && isspace(*str)) str++;
 
139
while (isdigit(*str)) result = result * 10 + (int)(*str++ - '0');
 
140
*endptr = str;
 
141
return(result);
 
142
}
 
143
 
 
144
 
 
145
 
 
146
/*************************************************
 
147
*       Convert character value to UTF-8         *
 
148
*************************************************/
 
149
 
 
150
/* This function takes an integer value in the range 0 - 0x7fffffff
 
151
and encodes it as a UTF-8 character in 0 to 6 bytes.
 
152
 
 
153
Arguments:
 
154
  cvalue     the character value
 
155
  buffer     pointer to buffer for result - at least 6 bytes long
 
156
 
 
157
Returns:     number of characters placed in the buffer
 
158
             -1 if input character is negative
 
159
             0 if input character is positive but too big (only when
 
160
             int is longer than 32 bits)
 
161
*/
 
162
 
 
163
static int
 
164
ord2utf8(int cvalue, unsigned char *buffer)
 
165
{
 
166
register int i, j;
 
167
for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
 
168
  if (cvalue <= utf8_table1[i]) break;
 
169
if (i >= sizeof(utf8_table1)/sizeof(int)) return 0;
 
170
if (cvalue < 0) return -1;
 
171
 
 
172
buffer += i;
 
173
for (j = i; j > 0; j--)
 
174
 {
 
175
 *buffer-- = 0x80 | (cvalue & 0x3f);
 
176
 cvalue >>= 6;
 
177
 }
 
178
*buffer = utf8_table2[i] | cvalue;
 
179
return i + 1;
 
180
}
 
181
 
 
182
 
 
183
/*************************************************
 
184
*            Convert UTF-8 string to value       *
 
185
*************************************************/
 
186
 
 
187
/* This function takes one or more bytes that represents a UTF-8 character,
 
188
and returns the value of the character.
 
189
 
 
190
Argument:
 
191
  buffer   a pointer to the byte vector
 
192
  vptr     a pointer to an int to receive the value
 
193
 
 
194
Returns:   >  0 => the number of bytes consumed
 
195
           -6 to 0 => malformed UTF-8 character at offset = (-return)
 
196
*/
 
197
 
 
198
static int
 
199
utf82ord(unsigned char *buffer, int *vptr)
 
200
{
 
201
int c = *buffer++;
 
202
int d = c;
 
203
int i, j, s;
 
204
 
 
205
for (i = -1; i < 6; i++)               /* i is number of additional bytes */
 
206
  {
 
207
  if ((d & 0x80) == 0) break;
 
208
  d <<= 1;
 
209
  }
 
210
 
 
211
if (i == -1) { *vptr = c; return 1; }  /* ascii character */
 
212
if (i == 0 || i == 6) return 0;        /* invalid UTF-8 */
 
213
 
 
214
/* i now has a value in the range 1-5 */
 
215
 
 
216
s = 6*i;
 
217
d = (c & utf8_table3[i]) << s;
 
218
 
 
219
for (j = 0; j < i; j++)
 
220
  {
 
221
  c = *buffer++;
 
222
  if ((c & 0xc0) != 0x80) return -(j+1);
 
223
  s -= 6;
 
224
  d |= (c & 0x3f) << s;
 
225
  }
 
226
 
 
227
/* Check that encoding was the correct unique one */
 
228
 
 
229
for (j = 0; j < sizeof(utf8_table1)/sizeof(int); j++)
 
230
  if (d <= utf8_table1[j]) break;
 
231
if (j != i) return -(i+1);
 
232
 
 
233
/* Valid value */
 
234
 
 
235
*vptr = d;
 
236
return i+1;
 
237
}
 
238
 
 
239
 
 
240
 
 
241
/*************************************************
 
242
*             Print character string             *
 
243
*************************************************/
 
244
 
 
245
/* Character string printing function. Must handle UTF-8 strings in utf8
 
246
mode. Yields number of characters printed. If handed a NULL file, just counts
 
247
chars without printing. */
 
248
 
 
249
static int pchars(unsigned char *p, int length, FILE *f)
 
250
{
 
251
int c;
 
252
int yield = 0;
 
253
 
 
254
while (length-- > 0)
 
255
  {
 
256
  if (use_utf8)
 
257
    {
 
258
    int rc = utf82ord(p, &c);
 
259
 
 
260
    if (rc > 0 && rc <= length + 1)   /* Mustn't run over the end */
 
261
      {
 
262
      length -= rc - 1;
 
263
      p += rc;
 
264
      if (c < 256 && isprint(c))
 
265
        {
 
266
        if (f != NULL) fprintf(f, "%c", c);
 
267
        yield++;
 
268
        }
 
269
      else
 
270
        {
 
271
        int n;
 
272
        if (f != NULL) fprintf(f, "\\x{%02x}%n", c, &n);
 
273
        yield += n;
 
274
        }
 
275
      continue;
 
276
      }
 
277
    }
 
278
 
 
279
   /* Not UTF-8, or malformed UTF-8  */
 
280
 
 
281
  if (isprint(c = *(p++)))
 
282
    {
 
283
    if (f != NULL) fprintf(f, "%c", c);
 
284
    yield++;
 
285
    }
 
286
  else
 
287
    {
 
288
    if (f != NULL) fprintf(f, "\\x%02x", c);
 
289
    yield += 4;
 
290
    }
 
291
  }
 
292
 
 
293
return yield;
 
294
}
 
295
 
 
296
 
 
297
 
 
298
/*************************************************
 
299
*              Callout function                  *
 
300
*************************************************/
 
301
 
 
302
/* Called from PCRE as a result of the (?C) item. We print out where we are in
 
303
the match. Yield zero unless more callouts than the fail count, or the callout
 
304
data is not zero. */
 
305
 
 
306
static int callout(pcre_callout_block *cb)
 
307
{
 
308
FILE *f = (first_callout | callout_extra)? outfile : NULL;
 
309
int i, pre_start, post_start, subject_length;
 
310
 
 
311
if (callout_extra)
 
312
  {
 
313
  fprintf(f, "Callout %d: last capture = %d\n",
 
314
    cb->callout_number, cb->capture_last);
 
315
 
 
316
  for (i = 0; i < cb->capture_top * 2; i += 2)
 
317
    {
 
318
    if (cb->offset_vector[i] < 0)
 
319
      fprintf(f, "%2d: <unset>\n", i/2);
 
320
    else
 
321
      {
 
322
      fprintf(f, "%2d: ", i/2);
 
323
      (void)pchars((unsigned char *)cb->subject + cb->offset_vector[i],
 
324
        cb->offset_vector[i+1] - cb->offset_vector[i], f);
 
325
      fprintf(f, "\n");
 
326
      }
 
327
    }
 
328
  }
 
329
 
 
330
/* Re-print the subject in canonical form, the first time or if giving full
 
331
datails. On subsequent calls in the same match, we use pchars just to find the
 
332
printed lengths of the substrings. */
 
333
 
 
334
if (f != NULL) fprintf(f, "--->");
 
335
 
 
336
pre_start = pchars((unsigned char *)cb->subject, cb->start_match, f);
 
337
post_start = pchars((unsigned char *)(cb->subject + cb->start_match),
 
338
  cb->current_position - cb->start_match, f);
 
339
 
 
340
subject_length = pchars((unsigned char *)cb->subject, cb->subject_length, NULL);
 
341
 
 
342
(void)pchars((unsigned char *)(cb->subject + cb->current_position),
 
343
  cb->subject_length - cb->current_position, f);
 
344
 
 
345
if (f != NULL) fprintf(f, "\n");
 
346
 
 
347
/* Always print appropriate indicators, with callout number if not already
 
348
shown. For automatic callouts, show the pattern offset. */
 
349
 
 
350
if (cb->callout_number == 255)
 
351
  {
 
352
  fprintf(outfile, "%+3d ", cb->pattern_position);
 
353
  if (cb->pattern_position > 99) fprintf(outfile, "\n    ");
 
354
  }
 
355
else
 
356
  {
 
357
  if (callout_extra) fprintf(outfile, "    ");
 
358
    else fprintf(outfile, "%3d ", cb->callout_number);
 
359
  }
 
360
 
 
361
for (i = 0; i < pre_start; i++) fprintf(outfile, " ");
 
362
fprintf(outfile, "^");
 
363
 
 
364
if (post_start > 0)
 
365
  {
 
366
  for (i = 0; i < post_start - 1; i++) fprintf(outfile, " ");
 
367
  fprintf(outfile, "^");
 
368
  }
 
369
 
 
370
for (i = 0; i < subject_length - pre_start - post_start + 4; i++)
 
371
  fprintf(outfile, " ");
 
372
 
 
373
fprintf(outfile, "%.*s", (cb->next_item_length == 0)? 1 : cb->next_item_length,
 
374
  pbuffer + cb->pattern_position);
 
375
 
 
376
fprintf(outfile, "\n");
 
377
first_callout = 0;
 
378
 
 
379
if (cb->callout_data != NULL)
 
380
  {
 
381
  int callout_data = *((int *)(cb->callout_data));
 
382
  if (callout_data != 0)
 
383
    {
 
384
    fprintf(outfile, "Callout data = %d\n", callout_data);
 
385
    return callout_data;
 
386
    }
 
387
  }
 
388
 
 
389
return (cb->callout_number != callout_fail_id)? 0 :
 
390
       (++callout_count >= callout_fail_count)? 1 : 0;
 
391
}
 
392
 
 
393
 
 
394
/*************************************************
 
395
*            Local malloc functions              *
 
396
*************************************************/
 
397
 
 
398
/* Alternative malloc function, to test functionality and show the size of the
 
399
compiled re. */
 
400
 
 
401
static void *new_malloc(size_t size)
 
402
{
 
403
void *block = malloc(size);
 
404
gotten_store = size;
 
405
if (show_malloc)
 
406
  fprintf(outfile, "malloc       %3d %p\n", size, block);
 
407
return block;
 
408
}
 
409
 
 
410
static void new_free(void *block)
 
411
{
 
412
if (show_malloc)
 
413
  fprintf(outfile, "free             %p\n", block);
 
414
free(block);
 
415
}
 
416
 
 
417
 
 
418
/* For recursion malloc/free, to test stacking calls */
 
419
 
 
420
static void *stack_malloc(size_t size)
 
421
{
 
422
void *block = malloc(size);
 
423
if (show_malloc)
 
424
  fprintf(outfile, "stack_malloc %3d %p\n", size, block);
 
425
return block;
 
426
}
 
427
 
 
428
static void stack_free(void *block)
 
429
{
 
430
if (show_malloc)
 
431
  fprintf(outfile, "stack_free       %p\n", block);
 
432
free(block);
 
433
}
 
434
 
 
435
 
 
436
/*************************************************
 
437
*          Call pcre_fullinfo()                  *
 
438
*************************************************/
 
439
 
 
440
/* Get one piece of information from the pcre_fullinfo() function */
 
441
 
 
442
static void new_info(pcre *re, pcre_extra *study, int option, void *ptr)
 
443
{
 
444
int rc;
 
445
if ((rc = pcre_fullinfo(re, study, option, ptr)) < 0)
 
446
  fprintf(outfile, "Error %d from pcre_fullinfo(%d)\n", rc, option);
 
447
}
 
448
 
 
449
 
 
450
 
 
451
/*************************************************
 
452
*         Byte flipping function                 *
 
453
*************************************************/
 
454
 
 
455
static long int
 
456
byteflip(long int value, int n)
 
457
{
 
458
if (n == 2) return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8);
 
459
return ((value & 0x000000ff) << 24) |
 
460
       ((value & 0x0000ff00) <<  8) |
 
461
       ((value & 0x00ff0000) >>  8) |
 
462
       ((value & 0xff000000) >> 24);
 
463
}
 
464
 
 
465
 
 
466
 
 
467
 
 
468
/*************************************************
 
469
*                Main Program                    *
 
470
*************************************************/
 
471
 
 
472
/* Read lines from named file or stdin and write to named file or stdout; lines
 
473
consist of a regular expression, in delimiters and optionally followed by
 
474
options, followed by a set of test data, terminated by an empty line. */
 
475
 
 
476
int main(int argc, char **argv)
 
477
{
 
478
FILE *infile = stdin;
 
479
int options = 0;
 
480
int study_options = 0;
 
481
int op = 1;
 
482
int timeit = 0;
 
483
int showinfo = 0;
 
484
int showstore = 0;
 
485
int size_offsets = 45;
 
486
int size_offsets_max;
 
487
int *offsets;
 
488
#if !defined NOPOSIX
 
489
int posix = 0;
 
490
#endif
 
491
int debug = 0;
 
492
int done = 0;
 
493
 
 
494
unsigned char *buffer;
 
495
unsigned char *dbuffer;
 
496
 
 
497
/* Get buffers from malloc() so that Electric Fence will check their misuse
 
498
when I am debugging. */
 
499
 
 
500
buffer = (unsigned char *)malloc(BUFFER_SIZE);
 
501
dbuffer = (unsigned char *)malloc(DBUFFER_SIZE);
 
502
pbuffer = (unsigned char *)malloc(PBUFFER_SIZE);
 
503
 
 
504
/* The outfile variable is static so that new_malloc can use it. The _setmode()
 
505
stuff is some magic that I don't understand, but which apparently does good
 
506
things in Windows. It's related to line terminations.  */
 
507
 
 
508
#if defined(_WIN32) || defined(WIN32)
 
509
_setmode( _fileno( stdout ), 0x8000 );
 
510
#endif  /* defined(_WIN32) || defined(WIN32) */
 
511
 
 
512
outfile = stdout;
 
513
 
 
514
/* Scan options */
 
515
 
 
516
while (argc > 1 && argv[op][0] == '-')
 
517
  {
 
518
  unsigned char *endptr;
 
519
 
 
520
  if (strcmp(argv[op], "-s") == 0 || strcmp(argv[op], "-m") == 0)
 
521
    showstore = 1;
 
522
  else if (strcmp(argv[op], "-t") == 0) timeit = 1;
 
523
  else if (strcmp(argv[op], "-i") == 0) showinfo = 1;
 
524
  else if (strcmp(argv[op], "-d") == 0) showinfo = debug = 1;
 
525
  else if (strcmp(argv[op], "-o") == 0 && argc > 2 &&
 
526
      ((size_offsets = get_value((unsigned char *)argv[op+1], &endptr)),
 
527
        *endptr == 0))
 
528
    {
 
529
    op++;
 
530
    argc--;
 
531
    }
 
532
#if !defined NOPOSIX
 
533
  else if (strcmp(argv[op], "-p") == 0) posix = 1;
 
534
#endif
 
535
  else if (strcmp(argv[op], "-C") == 0)
 
536
    {
 
537
    int rc;
 
538
    printf("PCRE version %s\n", pcre_version());
 
539
    printf("Compiled with\n");
 
540
    (void)pcre_config(PCRE_CONFIG_UTF8, &rc);
 
541
    printf("  %sUTF-8 support\n", rc? "" : "No ");
 
542
    (void)pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &rc);
 
543
    printf("  %sUnicode properties support\n", rc? "" : "No ");
 
544
    (void)pcre_config(PCRE_CONFIG_NEWLINE, &rc);
 
545
    printf("  Newline character is %s\n", (rc == '\r')? "CR" : "LF");
 
546
    (void)pcre_config(PCRE_CONFIG_LINK_SIZE, &rc);
 
547
    printf("  Internal link size = %d\n", rc);
 
548
    (void)pcre_config(PCRE_CONFIG_POSIX_MALLOC_THRESHOLD, &rc);
 
549
    printf("  POSIX malloc threshold = %d\n", rc);
 
550
    (void)pcre_config(PCRE_CONFIG_MATCH_LIMIT, &rc);
 
551
    printf("  Default match limit = %d\n", rc);
 
552
    (void)pcre_config(PCRE_CONFIG_STACKRECURSE, &rc);
 
553
    printf("  Match recursion uses %s\n", rc? "stack" : "heap");
 
554
    exit(0);
 
555
    }
 
556
  else
 
557
    {
 
558
    printf("** Unknown or malformed option %s\n", argv[op]);
 
559
    printf("Usage:   pcretest [-d] [-i] [-o <n>] [-p] [-s] [-t] [<input> [<output>]]\n");
 
560
    printf("  -C     show PCRE compile-time options and exit\n");
 
561
    printf("  -d     debug: show compiled code; implies -i\n"
 
562
           "  -i     show information about compiled pattern\n"
 
563
           "  -m     output memory used information\n"
 
564
           "  -o <n> set size of offsets vector to <n>\n");
 
565
#if !defined NOPOSIX
 
566
    printf("  -p     use POSIX interface\n");
 
567
#endif
 
568
    printf("  -s     output store (memory) used information\n"
 
569
           "  -t     time compilation and execution\n");
 
570
    return 1;
 
571
    }
 
572
  op++;
 
573
  argc--;
 
574
  }
 
575
 
 
576
/* Get the store for the offsets vector, and remember what it was */
 
577
 
 
578
size_offsets_max = size_offsets;
 
579
offsets = (int *)malloc(size_offsets_max * sizeof(int));
 
580
if (offsets == NULL)
 
581
  {
 
582
  printf("** Failed to get %d bytes of memory for offsets vector\n",
 
583
    size_offsets_max * sizeof(int));
 
584
  return 1;
 
585
  }
 
586
 
 
587
/* Sort out the input and output files */
 
588
 
 
589
if (argc > 1)
 
590
  {
 
591
  infile = fopen(argv[op], "rb");
 
592
  if (infile == NULL)
 
593
    {
 
594
    printf("** Failed to open %s\n", argv[op]);
 
595
    return 1;
 
596
    }
 
597
  }
 
598
 
 
599
if (argc > 2)
 
600
  {
 
601
  outfile = fopen(argv[op+1], "wb");
 
602
  if (outfile == NULL)
 
603
    {
 
604
    printf("** Failed to open %s\n", argv[op+1]);
 
605
    return 1;
 
606
    }
 
607
  }
 
608
 
 
609
/* Set alternative malloc function */
 
610
 
 
611
pcre_malloc = new_malloc;
 
612
pcre_free = new_free;
 
613
pcre_stack_malloc = stack_malloc;
 
614
pcre_stack_free = stack_free;
 
615
 
 
616
/* Heading line, then prompt for first regex if stdin */
 
617
 
 
618
fprintf(outfile, "PCRE version %s\n\n", pcre_version());
 
619
 
 
620
/* Main loop */
 
621
 
 
622
while (!done)
 
623
  {
 
624
  pcre *re = NULL;
 
625
  pcre_extra *extra = NULL;
 
626
 
 
627
#if !defined NOPOSIX  /* There are still compilers that require no indent */
 
628
  regex_t preg;
 
629
  int do_posix = 0;
 
630
#endif
 
631
 
 
632
  const char *error;
 
633
  unsigned char *p, *pp, *ppp;
 
634
  unsigned char *to_file = NULL;
 
635
  const unsigned char *tables = NULL;
 
636
  unsigned long int true_size, true_study_size = 0;
 
637
  size_t size, regex_gotten_store;
 
638
  int do_study = 0;
 
639
  int do_debug = debug;
 
640
  int do_G = 0;
 
641
  int do_g = 0;
 
642
  int do_showinfo = showinfo;
 
643
  int do_showrest = 0;
 
644
  int do_flip = 0;
 
645
  int erroroffset, len, delimiter;
 
646
 
 
647
  use_utf8 = 0;
 
648
 
 
649
  if (infile == stdin) printf("  re> ");
 
650
  if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL) break;
 
651
  if (infile != stdin) fprintf(outfile, "%s", (char *)buffer);
 
652
  fflush(outfile);
 
653
 
 
654
  p = buffer;
 
655
  while (isspace(*p)) p++;
 
656
  if (*p == 0) continue;
 
657
 
 
658
  /* See if the pattern is to be loaded pre-compiled from a file. */
 
659
 
 
660
  if (*p == '<' && strchr((char *)(p+1), '<') == NULL)
 
661
    {
 
662
    unsigned long int magic;
 
663
    uschar sbuf[8];
 
664
    FILE *f;
 
665
 
 
666
    p++;
 
667
    pp = p + (int)strlen((char *)p);
 
668
    while (isspace(pp[-1])) pp--;
 
669
    *pp = 0;
 
670
 
 
671
    f = fopen((char *)p, "rb");
 
672
    if (f == NULL)
 
673
      {
 
674
      fprintf(outfile, "Failed to open %s: %s\n", p, strerror(errno));
 
675
      continue;
 
676
      }
 
677
 
 
678
    if (fread(sbuf, 1, 8, f) != 8) goto FAIL_READ;
 
679
 
 
680
    true_size =
 
681
      (sbuf[0] << 24) | (sbuf[1] << 16) | (sbuf[2] << 8) | sbuf[3];
 
682
    true_study_size =
 
683
      (sbuf[4] << 24) | (sbuf[5] << 16) | (sbuf[6] << 8) | sbuf[7];
 
684
 
 
685
    re = (real_pcre *)new_malloc(true_size);
 
686
    regex_gotten_store = gotten_store;
 
687
 
 
688
    if (fread(re, 1, true_size, f) != true_size) goto FAIL_READ;
 
689
 
 
690
    magic = ((real_pcre *)re)->magic_number;
 
691
    if (magic != MAGIC_NUMBER)
 
692
      {
 
693
      if (byteflip(magic, sizeof(magic)) == MAGIC_NUMBER)
 
694
        {
 
695
        do_flip = 1;
 
696
        }
 
697
      else
 
698
        {
 
699
        fprintf(outfile, "Data in %s is not a compiled PCRE regex\n", p);
 
700
        fclose(f);
 
701
        continue;
 
702
        }
 
703
      }
 
704
 
 
705
    fprintf(outfile, "Compiled regex%s loaded from %s\n",
 
706
      do_flip? " (byte-inverted)" : "", p);
 
707
 
 
708
    /* Need to know if UTF-8 for printing data strings */
 
709
 
 
710
    new_info(re, NULL, PCRE_INFO_OPTIONS, &options);
 
711
    use_utf8 = (options & PCRE_UTF8) != 0;
 
712
 
 
713
    /* Now see if there is any following study data */
 
714
 
 
715
    if (true_study_size != 0)
 
716
      {
 
717
      pcre_study_data *psd;
 
718
 
 
719
      extra = (pcre_extra *)new_malloc(sizeof(pcre_extra) + true_study_size);
 
720
      extra->flags = PCRE_EXTRA_STUDY_DATA;
 
721
 
 
722
      psd = (pcre_study_data *)(((char *)extra) + sizeof(pcre_extra));
 
723
      extra->study_data = psd;
 
724
 
 
725
      if (fread(psd, 1, true_study_size, f) != true_study_size)
 
726
        {
 
727
        FAIL_READ:
 
728
        fprintf(outfile, "Failed to read data from %s\n", p);
 
729
        if (extra != NULL) new_free(extra);
 
730
        if (re != NULL) new_free(re);
 
731
        fclose(f);
 
732
        continue;
 
733
        }
 
734
      fprintf(outfile, "Study data loaded from %s\n", p);
 
735
      do_study = 1;     /* To get the data output if requested */
 
736
      }
 
737
    else fprintf(outfile, "No study data\n");
 
738
 
 
739
    fclose(f);
 
740
    goto SHOW_INFO;
 
741
    }
 
742
 
 
743
  /* In-line pattern (the usual case). Get the delimiter and seek the end of
 
744
  the pattern; if is isn't complete, read more. */
 
745
 
 
746
  delimiter = *p++;
 
747
 
 
748
  if (isalnum(delimiter) || delimiter == '\\')
 
749
    {
 
750
    fprintf(outfile, "** Delimiter must not be alphameric or \\\n");
 
751
    goto SKIP_DATA;
 
752
    }
 
753
 
 
754
  pp = p;
 
755
 
 
756
  for(;;)
 
757
    {
 
758
    while (*pp != 0)
 
759
      {
 
760
      if (*pp == '\\' && pp[1] != 0) pp++;
 
761
        else if (*pp == delimiter) break;
 
762
      pp++;
 
763
      }
 
764
    if (*pp != 0) break;
 
765
 
 
766
    len = BUFFER_SIZE - (pp - buffer);
 
767
    if (len < 256)
 
768
      {
 
769
      fprintf(outfile, "** Expression too long - missing delimiter?\n");
 
770
      goto SKIP_DATA;
 
771
      }
 
772
 
 
773
    if (infile == stdin) printf("    > ");
 
774
    if (fgets((char *)pp, len, infile) == NULL)
 
775
      {
 
776
      fprintf(outfile, "** Unexpected EOF\n");
 
777
      done = 1;
 
778
      goto CONTINUE;
 
779
      }
 
780
    if (infile != stdin) fprintf(outfile, "%s", (char *)pp);
 
781
    }
 
782
 
 
783
  /* If the first character after the delimiter is backslash, make
 
784
  the pattern end with backslash. This is purely to provide a way
 
785
  of testing for the error message when a pattern ends with backslash. */
 
786
 
 
787
  if (pp[1] == '\\') *pp++ = '\\';
 
788
 
 
789
  /* Terminate the pattern at the delimiter, and save a copy of the pattern
 
790
  for callouts. */
 
791
 
 
792
  *pp++ = 0;
 
793
  strcpy((char *)pbuffer, (char *)p);
 
794
 
 
795
  /* Look for options after final delimiter */
 
796
 
 
797
  options = 0;
 
798
  study_options = 0;
 
799
  log_store = showstore;  /* default from command line */
 
800
 
 
801
  while (*pp != 0)
 
802
    {
 
803
    switch (*pp++)
 
804
      {
 
805
      case 'g': do_g = 1; break;
 
806
      case 'i': options |= PCRE_CASELESS; break;
 
807
      case 'm': options |= PCRE_MULTILINE; break;
 
808
      case 's': options |= PCRE_DOTALL; break;
 
809
      case 'x': options |= PCRE_EXTENDED; break;
 
810
 
 
811
      case '+': do_showrest = 1; break;
 
812
      case 'A': options |= PCRE_ANCHORED; break;
 
813
      case 'C': options |= PCRE_AUTO_CALLOUT; break;
 
814
      case 'D': do_debug = do_showinfo = 1; break;
 
815
      case 'E': options |= PCRE_DOLLAR_ENDONLY; break;
 
816
      case 'F': do_flip = 1; break;
 
817
      case 'G': do_G = 1; break;
 
818
      case 'I': do_showinfo = 1; break;
 
819
      case 'M': log_store = 1; break;
 
820
      case 'N': options |= PCRE_NO_AUTO_CAPTURE; break;
 
821
 
 
822
#if !defined NOPOSIX
 
823
      case 'P': do_posix = 1; break;
 
824
#endif
 
825
 
 
826
      case 'S': do_study = 1; break;
 
827
      case 'U': options |= PCRE_UNGREEDY; break;
 
828
      case 'X': options |= PCRE_EXTRA; break;
 
829
      case '8': options |= PCRE_UTF8; use_utf8 = 1; break;
 
830
      case '?': options |= PCRE_NO_UTF8_CHECK; break;
 
831
 
 
832
      case 'L':
 
833
      ppp = pp;
 
834
      while (*ppp != '\n' && *ppp != ' ') ppp++;
 
835
      *ppp = 0;
 
836
      if (setlocale(LC_CTYPE, (const char *)pp) == NULL)
 
837
        {
 
838
        fprintf(outfile, "** Failed to set locale \"%s\"\n", pp);
 
839
        goto SKIP_DATA;
 
840
        }
 
841
      tables = pcre_maketables();
 
842
      pp = ppp;
 
843
      break;
 
844
 
 
845
      case '>':
 
846
      to_file = pp;
 
847
      while (*pp != 0) pp++;
 
848
      while (isspace(pp[-1])) pp--;
 
849
      *pp = 0;
 
850
      break;
 
851
 
 
852
      case '\n': case ' ': break;
 
853
 
 
854
      default:
 
855
      fprintf(outfile, "** Unknown option '%c'\n", pp[-1]);
 
856
      goto SKIP_DATA;
 
857
      }
 
858
    }
 
859
 
 
860
  /* Handle compiling via the POSIX interface, which doesn't support the
 
861
  timing, showing, or debugging options, nor the ability to pass over
 
862
  local character tables. */
 
863
 
 
864
#if !defined NOPOSIX
 
865
  if (posix || do_posix)
 
866
    {
 
867
    int rc;
 
868
    int cflags = 0;
 
869
 
 
870
    if ((options & PCRE_CASELESS) != 0) cflags |= REG_ICASE;
 
871
    if ((options & PCRE_MULTILINE) != 0) cflags |= REG_NEWLINE;
 
872
    rc = regcomp(&preg, (char *)p, cflags);
 
873
 
 
874
    /* Compilation failed; go back for another re, skipping to blank line
 
875
    if non-interactive. */
 
876
 
 
877
    if (rc != 0)
 
878
      {
 
879
      (void)regerror(rc, &preg, (char *)buffer, BUFFER_SIZE);
 
880
      fprintf(outfile, "Failed: POSIX code %d: %s\n", rc, buffer);
 
881
      goto SKIP_DATA;
 
882
      }
 
883
    }
 
884
 
 
885
  /* Handle compiling via the native interface */
 
886
 
 
887
  else
 
888
#endif  /* !defined NOPOSIX */
 
889
 
 
890
    {
 
891
    if (timeit)
 
892
      {
 
893
      register int i;
 
894
      clock_t time_taken;
 
895
      clock_t start_time = clock();
 
896
      for (i = 0; i < LOOPREPEAT; i++)
 
897
        {
 
898
        re = pcre_compile((char *)p, options, &error, &erroroffset, tables);
 
899
        if (re != NULL) free(re);
 
900
        }
 
901
      time_taken = clock() - start_time;
 
902
      fprintf(outfile, "Compile time %.3f milliseconds\n",
 
903
        (((double)time_taken * 1000.0) / (double)LOOPREPEAT) /
 
904
          (double)CLOCKS_PER_SEC);
 
905
      }
 
906
 
 
907
    re = pcre_compile((char *)p, options, &error, &erroroffset, tables);
 
908
 
 
909
    /* Compilation failed; go back for another re, skipping to blank line
 
910
    if non-interactive. */
 
911
 
 
912
    if (re == NULL)
 
913
      {
 
914
      fprintf(outfile, "Failed: %s at offset %d\n", error, erroroffset);
 
915
      SKIP_DATA:
 
916
      if (infile != stdin)
 
917
        {
 
918
        for (;;)
 
919
          {
 
920
          if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL)
 
921
            {
 
922
            done = 1;
 
923
            goto CONTINUE;
 
924
            }
 
925
          len = (int)strlen((char *)buffer);
 
926
          while (len > 0 && isspace(buffer[len-1])) len--;
 
927
          if (len == 0) break;
 
928
          }
 
929
        fprintf(outfile, "\n");
 
930
        }
 
931
      goto CONTINUE;
 
932
      }
 
933
 
 
934
    /* Compilation succeeded; print data if required. There are now two
 
935
    info-returning functions. The old one has a limited interface and
 
936
    returns only limited data. Check that it agrees with the newer one. */
 
937
 
 
938
    if (log_store)
 
939
      fprintf(outfile, "Memory allocation (code space): %d\n",
 
940
        (int)(gotten_store -
 
941
              sizeof(real_pcre) -
 
942
              ((real_pcre *)re)->name_count * ((real_pcre *)re)->name_entry_size));
 
943
 
 
944
    /* Extract the size for possible writing before possibly flipping it,
 
945
    and remember the store that was got. */
 
946
 
 
947
    true_size = ((real_pcre *)re)->size;
 
948
    regex_gotten_store = gotten_store;
 
949
 
 
950
    /* If /S was present, study the regexp to generate additional info to
 
951
    help with the matching. */
 
952
 
 
953
    if (do_study)
 
954
      {
 
955
      if (timeit)
 
956
        {
 
957
        register int i;
 
958
        clock_t time_taken;
 
959
        clock_t start_time = clock();
 
960
        for (i = 0; i < LOOPREPEAT; i++)
 
961
          extra = pcre_study(re, study_options, &error);
 
962
        time_taken = clock() - start_time;
 
963
        if (extra != NULL) free(extra);
 
964
        fprintf(outfile, "  Study time %.3f milliseconds\n",
 
965
          (((double)time_taken * 1000.0) / (double)LOOPREPEAT) /
 
966
            (double)CLOCKS_PER_SEC);
 
967
        }
 
968
      extra = pcre_study(re, study_options, &error);
 
969
      if (error != NULL)
 
970
        fprintf(outfile, "Failed to study: %s\n", error);
 
971
      else if (extra != NULL)
 
972
        true_study_size = ((pcre_study_data *)(extra->study_data))->size;
 
973
      }
 
974
 
 
975
    /* If the 'F' option was present, we flip the bytes of all the integer
 
976
    fields in the regex data block and the study block. This is to make it
 
977
    possible to test PCRE's handling of byte-flipped patterns, e.g. those
 
978
    compiled on a different architecture. */
 
979
 
 
980
    if (do_flip)
 
981
      {
 
982
      real_pcre *rre = (real_pcre *)re;
 
983
      rre->magic_number = byteflip(rre->magic_number, sizeof(rre->magic_number));
 
984
      rre->size = byteflip(rre->size, sizeof(rre->size));
 
985
      rre->options = byteflip(rre->options, sizeof(rre->options));
 
986
      rre->top_bracket = byteflip(rre->top_bracket, sizeof(rre->top_bracket));
 
987
      rre->top_backref = byteflip(rre->top_backref, sizeof(rre->top_backref));
 
988
      rre->first_byte = byteflip(rre->first_byte, sizeof(rre->first_byte));
 
989
      rre->req_byte = byteflip(rre->req_byte, sizeof(rre->req_byte));
 
990
      rre->name_table_offset = byteflip(rre->name_table_offset,
 
991
        sizeof(rre->name_table_offset));
 
992
      rre->name_entry_size = byteflip(rre->name_entry_size,
 
993
        sizeof(rre->name_entry_size));
 
994
      rre->name_count = byteflip(rre->name_count, sizeof(rre->name_count));
 
995
 
 
996
      if (extra != NULL)
 
997
        {
 
998
        pcre_study_data *rsd = (pcre_study_data *)(extra->study_data);
 
999
        rsd->size = byteflip(rsd->size, sizeof(rsd->size));
 
1000
        rsd->options = byteflip(rsd->options, sizeof(rsd->options));
 
1001
        }
 
1002
      }
 
1003
 
 
1004
    /* Extract information from the compiled data if required */
 
1005
 
 
1006
    SHOW_INFO:
 
1007
 
 
1008
    if (do_showinfo)
 
1009
      {
 
1010
      unsigned long int get_options, all_options;
 
1011
      int old_first_char, old_options, old_count;
 
1012
      int count, backrefmax, first_char, need_char;
 
1013
      int nameentrysize, namecount;
 
1014
      const uschar *nametable;
 
1015
 
 
1016
      if (do_debug)
 
1017
        {
 
1018
        fprintf(outfile, "------------------------------------------------------------------\n");
 
1019
        print_internals(re, outfile);
 
1020
        }
 
1021
 
 
1022
      new_info(re, NULL, PCRE_INFO_OPTIONS, &get_options);
 
1023
      new_info(re, NULL, PCRE_INFO_SIZE, &size);
 
1024
      new_info(re, NULL, PCRE_INFO_CAPTURECOUNT, &count);
 
1025
      new_info(re, NULL, PCRE_INFO_BACKREFMAX, &backrefmax);
 
1026
      new_info(re, NULL, PCRE_INFO_FIRSTBYTE, &first_char);
 
1027
      new_info(re, NULL, PCRE_INFO_LASTLITERAL, &need_char);
 
1028
      new_info(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &nameentrysize);
 
1029
      new_info(re, NULL, PCRE_INFO_NAMECOUNT, &namecount);
 
1030
      new_info(re, NULL, PCRE_INFO_NAMETABLE, (void *)&nametable);
 
1031
 
 
1032
      old_count = pcre_info(re, &old_options, &old_first_char);
 
1033
      if (count < 0) fprintf(outfile,
 
1034
        "Error %d from pcre_info()\n", count);
 
1035
      else
 
1036
        {
 
1037
        if (old_count != count) fprintf(outfile,
 
1038
          "Count disagreement: pcre_fullinfo=%d pcre_info=%d\n", count,
 
1039
            old_count);
 
1040
 
 
1041
        if (old_first_char != first_char) fprintf(outfile,
 
1042
          "First char disagreement: pcre_fullinfo=%d pcre_info=%d\n",
 
1043
            first_char, old_first_char);
 
1044
 
 
1045
        if (old_options != (int)get_options) fprintf(outfile,
 
1046
          "Options disagreement: pcre_fullinfo=%ld pcre_info=%d\n",
 
1047
            get_options, old_options);
 
1048
        }
 
1049
 
 
1050
      if (size != regex_gotten_store) fprintf(outfile,
 
1051
        "Size disagreement: pcre_fullinfo=%d call to malloc for %d\n",
 
1052
        size, regex_gotten_store);
 
1053
 
 
1054
      fprintf(outfile, "Capturing subpattern count = %d\n", count);
 
1055
      if (backrefmax > 0)
 
1056
        fprintf(outfile, "Max back reference = %d\n", backrefmax);
 
1057
 
 
1058
      if (namecount > 0)
 
1059
        {
 
1060
        fprintf(outfile, "Named capturing subpatterns:\n");
 
1061
        while (namecount-- > 0)
 
1062
          {
 
1063
          fprintf(outfile, "  %s %*s%3d\n", nametable + 2,
 
1064
            nameentrysize - 3 - (int)strlen((char *)nametable + 2), "",
 
1065
            GET2(nametable, 0));
 
1066
          nametable += nameentrysize;
 
1067
          }
 
1068
        }
 
1069
 
 
1070
      /* The NOPARTIAL bit is a private bit in the options, so we have
 
1071
      to fish it out via out back door */
 
1072
 
 
1073
      all_options = ((real_pcre *)re)->options;
 
1074
      if (do_flip)
 
1075
        {
 
1076
        all_options = byteflip(all_options, sizeof(all_options));
 
1077
        }
 
1078
 
 
1079
      if ((all_options & PCRE_NOPARTIAL) != 0)
 
1080
        fprintf(outfile, "Partial matching not supported\n");
 
1081
 
 
1082
      if (get_options == 0) fprintf(outfile, "No options\n");
 
1083
        else fprintf(outfile, "Options:%s%s%s%s%s%s%s%s%s%s\n",
 
1084
          ((get_options & PCRE_ANCHORED) != 0)? " anchored" : "",
 
1085
          ((get_options & PCRE_CASELESS) != 0)? " caseless" : "",
 
1086
          ((get_options & PCRE_EXTENDED) != 0)? " extended" : "",
 
1087
          ((get_options & PCRE_MULTILINE) != 0)? " multiline" : "",
 
1088
          ((get_options & PCRE_DOTALL) != 0)? " dotall" : "",
 
1089
          ((get_options & PCRE_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "",
 
1090
          ((get_options & PCRE_EXTRA) != 0)? " extra" : "",
 
1091
          ((get_options & PCRE_UNGREEDY) != 0)? " ungreedy" : "",
 
1092
          ((get_options & PCRE_UTF8) != 0)? " utf8" : "",
 
1093
          ((get_options & PCRE_NO_UTF8_CHECK) != 0)? " no_utf8_check" : "");
 
1094
 
 
1095
      if (((((real_pcre *)re)->options) & PCRE_ICHANGED) != 0)
 
1096
        fprintf(outfile, "Case state changes\n");
 
1097
 
 
1098
      if (first_char == -1)
 
1099
        {
 
1100
        fprintf(outfile, "First char at start or follows \\n\n");
 
1101
        }
 
1102
      else if (first_char < 0)
 
1103
        {
 
1104
        fprintf(outfile, "No first char\n");
 
1105
        }
 
1106
      else
 
1107
        {
 
1108
        int ch = first_char & 255;
 
1109
        const char *caseless = ((first_char & REQ_CASELESS) == 0)?
 
1110
          "" : " (caseless)";
 
1111
        if (isprint(ch))
 
1112
          fprintf(outfile, "First char = \'%c\'%s\n", ch, caseless);
 
1113
        else
 
1114
          fprintf(outfile, "First char = %d%s\n", ch, caseless);
 
1115
        }
 
1116
 
 
1117
      if (need_char < 0)
 
1118
        {
 
1119
        fprintf(outfile, "No need char\n");
 
1120
        }
 
1121
      else
 
1122
        {
 
1123
        int ch = need_char & 255;
 
1124
        const char *caseless = ((need_char & REQ_CASELESS) == 0)?
 
1125
          "" : " (caseless)";
 
1126
        if (isprint(ch))
 
1127
          fprintf(outfile, "Need char = \'%c\'%s\n", ch, caseless);
 
1128
        else
 
1129
          fprintf(outfile, "Need char = %d%s\n", ch, caseless);
 
1130
        }
 
1131
 
 
1132
      /* Don't output study size; at present it is in any case a fixed
 
1133
      value, but it varies, depending on the computer architecture, and
 
1134
      so messes up the test suite. (And with the /F option, it might be
 
1135
      flipped.) */
 
1136
 
 
1137
      if (do_study)
 
1138
        {
 
1139
        if (extra == NULL)
 
1140
          fprintf(outfile, "Study returned NULL\n");
 
1141
        else
 
1142
          {
 
1143
          uschar *start_bits = NULL;
 
1144
          new_info(re, extra, PCRE_INFO_FIRSTTABLE, &start_bits);
 
1145
 
 
1146
          if (start_bits == NULL)
 
1147
            fprintf(outfile, "No starting byte set\n");
 
1148
          else
 
1149
            {
 
1150
            int i;
 
1151
            int c = 24;
 
1152
            fprintf(outfile, "Starting byte set: ");
 
1153
            for (i = 0; i < 256; i++)
 
1154
              {
 
1155
              if ((start_bits[i/8] & (1<<(i&7))) != 0)
 
1156
                {
 
1157
                if (c > 75)
 
1158
                  {
 
1159
                  fprintf(outfile, "\n  ");
 
1160
                  c = 2;
 
1161
                  }
 
1162
                if (isprint(i) && i != ' ')
 
1163
                  {
 
1164
                  fprintf(outfile, "%c ", i);
 
1165
                  c += 2;
 
1166
                  }
 
1167
                else
 
1168
                  {
 
1169
                  fprintf(outfile, "\\x%02x ", i);
 
1170
                  c += 5;
 
1171
                  }
 
1172
                }
 
1173
              }
 
1174
            fprintf(outfile, "\n");
 
1175
            }
 
1176
          }
 
1177
        }
 
1178
      }
 
1179
 
 
1180
    /* If the '>' option was present, we write out the regex to a file, and
 
1181
    that is all. The first 8 bytes of the file are the regex length and then
 
1182
    the study length, in big-endian order. */
 
1183
 
 
1184
    if (to_file != NULL)
 
1185
      {
 
1186
      FILE *f = fopen((char *)to_file, "wb");
 
1187
      if (f == NULL)
 
1188
        {
 
1189
        fprintf(outfile, "Unable to open %s: %s\n", to_file, strerror(errno));
 
1190
        }
 
1191
      else
 
1192
        {
 
1193
        uschar sbuf[8];
 
1194
        sbuf[0] = (true_size >> 24)  & 255;
 
1195
        sbuf[1] = (true_size >> 16)  & 255;
 
1196
        sbuf[2] = (true_size >>  8)  & 255;
 
1197
        sbuf[3] = (true_size)  & 255;
 
1198
 
 
1199
        sbuf[4] = (true_study_size >> 24)  & 255;
 
1200
        sbuf[5] = (true_study_size >> 16)  & 255;
 
1201
        sbuf[6] = (true_study_size >>  8)  & 255;
 
1202
        sbuf[7] = (true_study_size)  & 255;
 
1203
 
 
1204
        if (fwrite(sbuf, 1, 8, f) < 8 ||
 
1205
            fwrite(re, 1, true_size, f) < true_size)
 
1206
          {
 
1207
          fprintf(outfile, "Write error on %s: %s\n", to_file, strerror(errno));
 
1208
          }
 
1209
        else
 
1210
          {
 
1211
          fprintf(outfile, "Compiled regex written to %s\n", to_file);
 
1212
          if (extra != NULL)
 
1213
            {
 
1214
            if (fwrite(extra->study_data, 1, true_study_size, f) <
 
1215
                true_study_size)
 
1216
              {
 
1217
              fprintf(outfile, "Write error on %s: %s\n", to_file,
 
1218
                strerror(errno));
 
1219
              }
 
1220
            else fprintf(outfile, "Study data written to %s\n", to_file);
 
1221
            }
 
1222
          }
 
1223
        fclose(f);
 
1224
        }
 
1225
      continue;  /* With next regex */
 
1226
      }
 
1227
    }        /* End of non-POSIX compile */
 
1228
 
 
1229
  /* Read data lines and test them */
 
1230
 
 
1231
  for (;;)
 
1232
    {
 
1233
    unsigned char *q;
 
1234
    unsigned char *bptr = dbuffer;
 
1235
    int *use_offsets = offsets;
 
1236
    int use_size_offsets = size_offsets;
 
1237
    int callout_data = 0;
 
1238
    int callout_data_set = 0;
 
1239
    int count, c;
 
1240
    int copystrings = 0;
 
1241
    int find_match_limit = 0;
 
1242
    int getstrings = 0;
 
1243
    int getlist = 0;
 
1244
    int gmatched = 0;
 
1245
    int start_offset = 0;
 
1246
    int g_notempty = 0;
 
1247
 
 
1248
    options = 0;
 
1249
 
 
1250
    pcre_callout = callout;
 
1251
    first_callout = 1;
 
1252
    callout_extra = 0;
 
1253
    callout_count = 0;
 
1254
    callout_fail_count = 999999;
 
1255
    callout_fail_id = -1;
 
1256
    show_malloc = 0;
 
1257
 
 
1258
    if (infile == stdin) printf("data> ");
 
1259
    if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL)
 
1260
      {
 
1261
      done = 1;
 
1262
      goto CONTINUE;
 
1263
      }
 
1264
    if (infile != stdin) fprintf(outfile, "%s", (char *)buffer);
 
1265
 
 
1266
    len = (int)strlen((char *)buffer);
 
1267
    while (len > 0 && isspace(buffer[len-1])) len--;
 
1268
    buffer[len] = 0;
 
1269
    if (len == 0) break;
 
1270
 
 
1271
    p = buffer;
 
1272
    while (isspace(*p)) p++;
 
1273
 
 
1274
    q = dbuffer;
 
1275
    while ((c = *p++) != 0)
 
1276
      {
 
1277
      int i = 0;
 
1278
      int n = 0;
 
1279
 
 
1280
      if (c == '\\') switch ((c = *p++))
 
1281
        {
 
1282
        case 'a': c =    7; break;
 
1283
        case 'b': c = '\b'; break;
 
1284
        case 'e': c =   27; break;
 
1285
        case 'f': c = '\f'; break;
 
1286
        case 'n': c = '\n'; break;
 
1287
        case 'r': c = '\r'; break;
 
1288
        case 't': c = '\t'; break;
 
1289
        case 'v': c = '\v'; break;
 
1290
 
 
1291
        case '0': case '1': case '2': case '3':
 
1292
        case '4': case '5': case '6': case '7':
 
1293
        c -= '0';
 
1294
        while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9')
 
1295
          c = c * 8 + *p++ - '0';
 
1296
        break;
 
1297
 
 
1298
        case 'x':
 
1299
 
 
1300
        /* Handle \x{..} specially - new Perl thing for utf8 */
 
1301
 
 
1302
        if (*p == '{')
 
1303
          {
 
1304
          unsigned char *pt = p;
 
1305
          c = 0;
 
1306
          while (isxdigit(*(++pt)))
 
1307
            c = c * 16 + tolower(*pt) - ((isdigit(*pt))? '0' : 'W');
 
1308
          if (*pt == '}')
 
1309
            {
 
1310
            unsigned char buff8[8];
 
1311
            int ii, utn;
 
1312
            utn = ord2utf8(c, buff8);
 
1313
            for (ii = 0; ii < utn - 1; ii++) *q++ = buff8[ii];
 
1314
            c = buff8[ii];   /* Last byte */
 
1315
            p = pt + 1;
 
1316
            break;
 
1317
            }
 
1318
          /* Not correct form; fall through */
 
1319
          }
 
1320
 
 
1321
        /* Ordinary \x */
 
1322
 
 
1323
        c = 0;
 
1324
        while (i++ < 2 && isxdigit(*p))
 
1325
          {
 
1326
          c = c * 16 + tolower(*p) - ((isdigit(*p))? '0' : 'W');
 
1327
          p++;
 
1328
          }
 
1329
        break;
 
1330
 
 
1331
        case 0:   /* \ followed by EOF allows for an empty line */
 
1332
        p--;
 
1333
        continue;
 
1334
 
 
1335
        case '>':
 
1336
        while(isdigit(*p)) start_offset = start_offset * 10 + *p++ - '0';
 
1337
        continue;
 
1338
 
 
1339
        case 'A':  /* Option setting */
 
1340
        options |= PCRE_ANCHORED;
 
1341
        continue;
 
1342
 
 
1343
        case 'B':
 
1344
        options |= PCRE_NOTBOL;
 
1345
        continue;
 
1346
 
 
1347
        case 'C':
 
1348
        if (isdigit(*p))    /* Set copy string */
 
1349
          {
 
1350
          while(isdigit(*p)) n = n * 10 + *p++ - '0';
 
1351
          copystrings |= 1 << n;
 
1352
          }
 
1353
        else if (isalnum(*p))
 
1354
          {
 
1355
          uschar name[256];
 
1356
          uschar *npp = name;
 
1357
          while (isalnum(*p)) *npp++ = *p++;
 
1358
          *npp = 0;
 
1359
          n = pcre_get_stringnumber(re, (char *)name);
 
1360
          if (n < 0)
 
1361
            fprintf(outfile, "no parentheses with name \"%s\"\n", name);
 
1362
          else copystrings |= 1 << n;
 
1363
          }
 
1364
        else if (*p == '+')
 
1365
          {
 
1366
          callout_extra = 1;
 
1367
          p++;
 
1368
          }
 
1369
        else if (*p == '-')
 
1370
          {
 
1371
          pcre_callout = NULL;
 
1372
          p++;
 
1373
          }
 
1374
        else if (*p == '!')
 
1375
          {
 
1376
          callout_fail_id = 0;
 
1377
          p++;
 
1378
          while(isdigit(*p))
 
1379
            callout_fail_id = callout_fail_id * 10 + *p++ - '0';
 
1380
          callout_fail_count = 0;
 
1381
          if (*p == '!')
 
1382
            {
 
1383
            p++;
 
1384
            while(isdigit(*p))
 
1385
              callout_fail_count = callout_fail_count * 10 + *p++ - '0';
 
1386
            }
 
1387
          }
 
1388
        else if (*p == '*')
 
1389
          {
 
1390
          int sign = 1;
 
1391
          callout_data = 0;
 
1392
          if (*(++p) == '-') { sign = -1; p++; }
 
1393
          while(isdigit(*p))
 
1394
            callout_data = callout_data * 10 + *p++ - '0';
 
1395
          callout_data *= sign;
 
1396
          callout_data_set = 1;
 
1397
          }
 
1398
        continue;
 
1399
 
 
1400
        case 'G':
 
1401
        if (isdigit(*p))
 
1402
          {
 
1403
          while(isdigit(*p)) n = n * 10 + *p++ - '0';
 
1404
          getstrings |= 1 << n;
 
1405
          }
 
1406
        else if (isalnum(*p))
 
1407
          {
 
1408
          uschar name[256];
 
1409
          uschar *npp = name;
 
1410
          while (isalnum(*p)) *npp++ = *p++;
 
1411
          *npp = 0;
 
1412
          n = pcre_get_stringnumber(re, (char *)name);
 
1413
          if (n < 0)
 
1414
            fprintf(outfile, "no parentheses with name \"%s\"\n", name);
 
1415
          else getstrings |= 1 << n;
 
1416
          }
 
1417
        continue;
 
1418
 
 
1419
        case 'L':
 
1420
        getlist = 1;
 
1421
        continue;
 
1422
 
 
1423
        case 'M':
 
1424
        find_match_limit = 1;
 
1425
        continue;
 
1426
 
 
1427
        case 'N':
 
1428
        options |= PCRE_NOTEMPTY;
 
1429
        continue;
 
1430
 
 
1431
        case 'O':
 
1432
        while(isdigit(*p)) n = n * 10 + *p++ - '0';
 
1433
        if (n > size_offsets_max)
 
1434
          {
 
1435
          size_offsets_max = n;
 
1436
          free(offsets);
 
1437
          use_offsets = offsets = (int *)malloc(size_offsets_max * sizeof(int));
 
1438
          if (offsets == NULL)
 
1439
            {
 
1440
            printf("** Failed to get %d bytes of memory for offsets vector\n",
 
1441
              size_offsets_max * sizeof(int));
 
1442
            return 1;
 
1443
            }
 
1444
          }
 
1445
        use_size_offsets = n;
 
1446
        if (n == 0) use_offsets = NULL;   /* Ensures it can't write to it */
 
1447
        continue;
 
1448
 
 
1449
        case 'P':
 
1450
        options |= PCRE_PARTIAL;
 
1451
        continue;
 
1452
 
 
1453
        case 'S':
 
1454
        show_malloc = 1;
 
1455
        continue;
 
1456
 
 
1457
        case 'Z':
 
1458
        options |= PCRE_NOTEOL;
 
1459
        continue;
 
1460
 
 
1461
        case '?':
 
1462
        options |= PCRE_NO_UTF8_CHECK;
 
1463
        continue;
 
1464
        }
 
1465
      *q++ = c;
 
1466
      }
 
1467
    *q = 0;
 
1468
    len = q - dbuffer;
 
1469
 
 
1470
    /* Handle matching via the POSIX interface, which does not
 
1471
    support timing or playing with the match limit or callout data. */
 
1472
 
 
1473
#if !defined NOPOSIX
 
1474
    if (posix || do_posix)
 
1475
      {
 
1476
      int rc;
 
1477
      int eflags = 0;
 
1478
      regmatch_t *pmatch = NULL;
 
1479
      if (use_size_offsets > 0)
 
1480
        pmatch = (regmatch_t *)malloc(sizeof(regmatch_t) * use_size_offsets);
 
1481
      if ((options & PCRE_NOTBOL) != 0) eflags |= REG_NOTBOL;
 
1482
      if ((options & PCRE_NOTEOL) != 0) eflags |= REG_NOTEOL;
 
1483
 
 
1484
      rc = regexec(&preg, (const char *)bptr, use_size_offsets, pmatch, eflags);
 
1485
 
 
1486
      if (rc != 0)
 
1487
        {
 
1488
        (void)regerror(rc, &preg, (char *)buffer, BUFFER_SIZE);
 
1489
        fprintf(outfile, "No match: POSIX code %d: %s\n", rc, buffer);
 
1490
        }
 
1491
      else
 
1492
        {
 
1493
        size_t i;
 
1494
        for (i = 0; i < (size_t)use_size_offsets; i++)
 
1495
          {
 
1496
          if (pmatch[i].rm_so >= 0)
 
1497
            {
 
1498
            fprintf(outfile, "%2d: ", (int)i);
 
1499
            (void)pchars(dbuffer + pmatch[i].rm_so,
 
1500
              pmatch[i].rm_eo - pmatch[i].rm_so, outfile);
 
1501
            fprintf(outfile, "\n");
 
1502
            if (i == 0 && do_showrest)
 
1503
              {
 
1504
              fprintf(outfile, " 0+ ");
 
1505
              (void)pchars(dbuffer + pmatch[i].rm_eo, len - pmatch[i].rm_eo,
 
1506
                outfile);
 
1507
              fprintf(outfile, "\n");
 
1508
              }
 
1509
            }
 
1510
          }
 
1511
        }
 
1512
      free(pmatch);
 
1513
      }
 
1514
 
 
1515
    /* Handle matching via the native interface - repeats for /g and /G */
 
1516
 
 
1517
    else
 
1518
#endif  /* !defined NOPOSIX */
 
1519
 
 
1520
    for (;; gmatched++)    /* Loop for /g or /G */
 
1521
      {
 
1522
      if (timeit)
 
1523
        {
 
1524
        register int i;
 
1525
        clock_t time_taken;
 
1526
        clock_t start_time = clock();
 
1527
        for (i = 0; i < LOOPREPEAT; i++)
 
1528
          count = pcre_exec(re, extra, (char *)bptr, len,
 
1529
            start_offset, options | g_notempty, use_offsets, use_size_offsets);
 
1530
        time_taken = clock() - start_time;
 
1531
        fprintf(outfile, "Execute time %.3f milliseconds\n",
 
1532
          (((double)time_taken * 1000.0) / (double)LOOPREPEAT) /
 
1533
            (double)CLOCKS_PER_SEC);
 
1534
        }
 
1535
 
 
1536
      /* If find_match_limit is set, we want to do repeated matches with
 
1537
      varying limits in order to find the minimum value. */
 
1538
 
 
1539
      if (find_match_limit)
 
1540
        {
 
1541
        int min = 0;
 
1542
        int mid = 64;
 
1543
        int max = -1;
 
1544
 
 
1545
        if (extra == NULL)
 
1546
          {
 
1547
          extra = (pcre_extra *)malloc(sizeof(pcre_extra));
 
1548
          extra->flags = 0;
 
1549
          }
 
1550
        extra->flags |= PCRE_EXTRA_MATCH_LIMIT;
 
1551
 
 
1552
        for (;;)
 
1553
          {
 
1554
          extra->match_limit = mid;
 
1555
          count = pcre_exec(re, extra, (char *)bptr, len, start_offset,
 
1556
            options | g_notempty, use_offsets, use_size_offsets);
 
1557
          if (count == PCRE_ERROR_MATCHLIMIT)
 
1558
            {
 
1559
            /* fprintf(outfile, "Testing match limit = %d\n", mid); */
 
1560
            min = mid;
 
1561
            mid = (mid == max - 1)? max : (max > 0)? (min + max)/2 : mid*2;
 
1562
            }
 
1563
          else if (count >= 0 || count == PCRE_ERROR_NOMATCH ||
 
1564
                                 count == PCRE_ERROR_PARTIAL)
 
1565
            {
 
1566
            if (mid == min + 1)
 
1567
              {
 
1568
              fprintf(outfile, "Minimum match limit = %d\n", mid);
 
1569
              break;
 
1570
              }
 
1571
            /* fprintf(outfile, "Testing match limit = %d\n", mid); */
 
1572
            max = mid;
 
1573
            mid = (min + mid)/2;
 
1574
            }
 
1575
          else break;    /* Some other error */
 
1576
          }
 
1577
 
 
1578
        extra->flags &= ~PCRE_EXTRA_MATCH_LIMIT;
 
1579
        }
 
1580
 
 
1581
      /* If callout_data is set, use the interface with additional data */
 
1582
 
 
1583
      else if (callout_data_set)
 
1584
        {
 
1585
        if (extra == NULL)
 
1586
          {
 
1587
          extra = (pcre_extra *)malloc(sizeof(pcre_extra));
 
1588
          extra->flags = 0;
 
1589
          }
 
1590
        extra->flags |= PCRE_EXTRA_CALLOUT_DATA;
 
1591
        extra->callout_data = &callout_data;
 
1592
        count = pcre_exec(re, extra, (char *)bptr, len, start_offset,
 
1593
          options | g_notempty, use_offsets, use_size_offsets);
 
1594
        extra->flags &= ~PCRE_EXTRA_CALLOUT_DATA;
 
1595
        }
 
1596
 
 
1597
      /* The normal case is just to do the match once, with the default
 
1598
      value of match_limit. */
 
1599
 
 
1600
      else
 
1601
        {
 
1602
        count = pcre_exec(re, extra, (char *)bptr, len,
 
1603
          start_offset, options | g_notempty, use_offsets, use_size_offsets);
 
1604
        }
 
1605
 
 
1606
      if (count == 0)
 
1607
        {
 
1608
        fprintf(outfile, "Matched, but too many substrings\n");
 
1609
        count = use_size_offsets/3;
 
1610
        }
 
1611
 
 
1612
      /* Matched */
 
1613
 
 
1614
      if (count >= 0)
 
1615
        {
 
1616
        int i;
 
1617
        for (i = 0; i < count * 2; i += 2)
 
1618
          {
 
1619
          if (use_offsets[i] < 0)
 
1620
            fprintf(outfile, "%2d: <unset>\n", i/2);
 
1621
          else
 
1622
            {
 
1623
            fprintf(outfile, "%2d: ", i/2);
 
1624
            (void)pchars(bptr + use_offsets[i],
 
1625
              use_offsets[i+1] - use_offsets[i], outfile);
 
1626
            fprintf(outfile, "\n");
 
1627
            if (i == 0)
 
1628
              {
 
1629
              if (do_showrest)
 
1630
                {
 
1631
                fprintf(outfile, " 0+ ");
 
1632
                (void)pchars(bptr + use_offsets[i+1], len - use_offsets[i+1],
 
1633
                  outfile);
 
1634
                fprintf(outfile, "\n");
 
1635
                }
 
1636
              }
 
1637
            }
 
1638
          }
 
1639
 
 
1640
        for (i = 0; i < 32; i++)
 
1641
          {
 
1642
          if ((copystrings & (1 << i)) != 0)
 
1643
            {
 
1644
            char copybuffer[16];
 
1645
            int rc = pcre_copy_substring((char *)bptr, use_offsets, count,
 
1646
              i, copybuffer, sizeof(copybuffer));
 
1647
            if (rc < 0)
 
1648
              fprintf(outfile, "copy substring %d failed %d\n", i, rc);
 
1649
            else
 
1650
              fprintf(outfile, "%2dC %s (%d)\n", i, copybuffer, rc);
 
1651
            }
 
1652
          }
 
1653
 
 
1654
        for (i = 0; i < 32; i++)
 
1655
          {
 
1656
          if ((getstrings & (1 << i)) != 0)
 
1657
            {
 
1658
            const char *substring;
 
1659
            int rc = pcre_get_substring((char *)bptr, use_offsets, count,
 
1660
              i, &substring);
 
1661
            if (rc < 0)
 
1662
              fprintf(outfile, "get substring %d failed %d\n", i, rc);
 
1663
            else
 
1664
              {
 
1665
              fprintf(outfile, "%2dG %s (%d)\n", i, substring, rc);
 
1666
              /* free((void *)substring); */
 
1667
              pcre_free_substring(substring);
 
1668
              }
 
1669
            }
 
1670
          }
 
1671
 
 
1672
        if (getlist)
 
1673
          {
 
1674
          const char **stringlist;
 
1675
          int rc = pcre_get_substring_list((char *)bptr, use_offsets, count,
 
1676
            &stringlist);
 
1677
          if (rc < 0)
 
1678
            fprintf(outfile, "get substring list failed %d\n", rc);
 
1679
          else
 
1680
            {
 
1681
            for (i = 0; i < count; i++)
 
1682
              fprintf(outfile, "%2dL %s\n", i, stringlist[i]);
 
1683
            if (stringlist[i] != NULL)
 
1684
              fprintf(outfile, "string list not terminated by NULL\n");
 
1685
            /* free((void *)stringlist); */
 
1686
            pcre_free_substring_list(stringlist);
 
1687
            }
 
1688
          }
 
1689
        }
 
1690
 
 
1691
      /* There was a partial match */
 
1692
 
 
1693
      else if (count == PCRE_ERROR_PARTIAL)
 
1694
        {
 
1695
        fprintf(outfile, "Partial match\n");
 
1696
        break;  /* Out of the /g loop */
 
1697
        }
 
1698
 
 
1699
      /* Failed to match. If this is a /g or /G loop and we previously set
 
1700
      g_notempty after a null match, this is not necessarily the end.
 
1701
      We want to advance the start offset, and continue. In the case of UTF-8
 
1702
      matching, the advance must be one character, not one byte. Fudge the
 
1703
      offset values to achieve this. We won't be at the end of the string -
 
1704
      that was checked before setting g_notempty. */
 
1705
 
 
1706
      else
 
1707
        {
 
1708
        if (g_notempty != 0)
 
1709
          {
 
1710
          int onechar = 1;
 
1711
          use_offsets[0] = start_offset;
 
1712
          if (use_utf8)
 
1713
            {
 
1714
            while (start_offset + onechar < len)
 
1715
              {
 
1716
              int tb = bptr[start_offset+onechar];
 
1717
              if (tb <= 127) break;
 
1718
              tb &= 0xc0;
 
1719
              if (tb != 0 && tb != 0xc0) onechar++;
 
1720
              }
 
1721
            }
 
1722
          use_offsets[1] = start_offset + onechar;
 
1723
          }
 
1724
        else
 
1725
          {
 
1726
          if (count == PCRE_ERROR_NOMATCH)
 
1727
            {
 
1728
            if (gmatched == 0) fprintf(outfile, "No match\n");
 
1729
            }
 
1730
          else fprintf(outfile, "Error %d\n", count);
 
1731
          break;  /* Out of the /g loop */
 
1732
          }
 
1733
        }
 
1734
 
 
1735
      /* If not /g or /G we are done */
 
1736
 
 
1737
      if (!do_g && !do_G) break;
 
1738
 
 
1739
      /* If we have matched an empty string, first check to see if we are at
 
1740
      the end of the subject. If so, the /g loop is over. Otherwise, mimic
 
1741
      what Perl's /g options does. This turns out to be rather cunning. First
 
1742
      we set PCRE_NOTEMPTY and PCRE_ANCHORED and try the match again at the
 
1743
      same point. If this fails (picked up above) we advance to the next
 
1744
      character. */
 
1745
 
 
1746
      g_notempty = 0;
 
1747
      if (use_offsets[0] == use_offsets[1])
 
1748
        {
 
1749
        if (use_offsets[0] == len) break;
 
1750
        g_notempty = PCRE_NOTEMPTY | PCRE_ANCHORED;
 
1751
        }
 
1752
 
 
1753
      /* For /g, update the start offset, leaving the rest alone */
 
1754
 
 
1755
      if (do_g) start_offset = use_offsets[1];
 
1756
 
 
1757
      /* For /G, update the pointer and length */
 
1758
 
 
1759
      else
 
1760
        {
 
1761
        bptr += use_offsets[1];
 
1762
        len -= use_offsets[1];
 
1763
        }
 
1764
      }  /* End of loop for /g and /G */
 
1765
    }    /* End of loop for data lines */
 
1766
 
 
1767
  CONTINUE:
 
1768
 
 
1769
#if !defined NOPOSIX
 
1770
  if (posix || do_posix) regfree(&preg);
 
1771
#endif
 
1772
 
 
1773
  if (re != NULL) free(re);
 
1774
  if (extra != NULL) free(extra);
 
1775
  if (tables != NULL)
 
1776
    {
 
1777
    free((void *)tables);
 
1778
    setlocale(LC_CTYPE, "C");
 
1779
    }
 
1780
  }
 
1781
 
 
1782
if (infile == stdin) fprintf(outfile, "\n");
 
1783
return 0;
 
1784
}
 
1785
 
 
1786
/* End */