chiark / gitweb /
Patch from Graham Inggs to add symbols support (Closes: #767374)
[pcre3.git] / pcre_printint.c
1 /*************************************************
2 *      Perl-Compatible Regular Expressions       *
3 *************************************************/
4
5 /* PCRE is a library of functions to support regular expressions whose syntax
6 and semantics are as close as possible to those of the Perl 5 language.
7
8                        Written by Philip Hazel
9            Copyright (c) 1997-2012 University of Cambridge
10
11 -----------------------------------------------------------------------------
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14
15     * Redistributions of source code must retain the above copyright notice,
16       this list of conditions and the following disclaimer.
17
18     * Redistributions in binary form must reproduce the above copyright
19       notice, this list of conditions and the following disclaimer in the
20       documentation and/or other materials provided with the distribution.
21
22     * Neither the name of the University of Cambridge nor the names of its
23       contributors may be used to endorse or promote products derived from
24       this software without specific prior written permission.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 POSSIBILITY OF SUCH DAMAGE.
37 -----------------------------------------------------------------------------
38 */
39
40
41 /* This module contains a PCRE private debugging function for printing out the
42 internal form of a compiled regular expression, along with some supporting
43 local functions. This source file is used in two places:
44
45 (1) It is #included by pcre_compile.c when it is compiled in debugging mode
46 (PCRE_DEBUG defined in pcre_internal.h). It is not included in production
47 compiles. In this case PCRE_INCLUDED is defined.
48
49 (2) It is also compiled separately and linked with pcretest.c, which can be
50 asked to print out a compiled regex for debugging purposes. */
51
52 #ifndef PCRE_INCLUDED
53
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
57
58 /* For pcretest program. */
59 #define PRIV(name) name
60
61 /* We have to include pcre_internal.h because we need the internal info for
62 displaying the results of pcre_study() and we also need to know about the
63 internal macros, structures, and other internal data values; pcretest has
64 "inside information" compared to a program that strictly follows the PCRE API.
65
66 Although pcre_internal.h does itself include pcre.h, we explicitly include it
67 here before pcre_internal.h so that the PCRE_EXP_xxx macros get set
68 appropriately for an application, not for building PCRE. */
69
70 #include "pcre.h"
71 #include "pcre_internal.h"
72
73 /* These are the funtions that are contained within. It doesn't seem worth
74 having a separate .h file just for this. */
75
76 #endif /* PCRE_INCLUDED */
77
78 #ifdef PCRE_INCLUDED
79 static /* Keep the following function as private. */
80 #endif
81
82 #if defined COMPILE_PCRE8
83 void pcre_printint(pcre *external_re, FILE *f, BOOL print_lengths);
84 #elif defined COMPILE_PCRE16
85 void pcre16_printint(pcre *external_re, FILE *f, BOOL print_lengths);
86 #elif defined COMPILE_PCRE32
87 void pcre32_printint(pcre *external_re, FILE *f, BOOL print_lengths);
88 #endif
89
90 /* Macro that decides whether a character should be output as a literal or in
91 hexadecimal. We don't use isprint() because that can vary from system to system
92 (even without the use of locales) and we want the output always to be the same,
93 for testing purposes. */
94
95 #ifdef EBCDIC
96 #define PRINTABLE(c) ((c) >= 64 && (c) < 255)
97 #else
98 #define PRINTABLE(c) ((c) >= 32 && (c) < 127)
99 #endif
100
101 /* The table of operator names. */
102
103 static const char *priv_OP_names[] = { OP_NAME_LIST };
104
105 /* This table of operator lengths is not actually used by the working code,
106 but its size is needed for a check that ensures it is the correct size for the
107 number of opcodes (thus catching update omissions). */
108
109 static const pcre_uint8 priv_OP_lengths[] = { OP_LENGTHS };
110
111
112
113 /*************************************************
114 *       Print single- or multi-byte character    *
115 *************************************************/
116
117 static unsigned int
118 print_char(FILE *f, pcre_uchar *ptr, BOOL utf)
119 {
120 pcre_uint32 c = *ptr;
121
122 #ifndef SUPPORT_UTF
123
124 (void)utf;  /* Avoid compiler warning */
125 if (PRINTABLE(c)) fprintf(f, "%c", (char)c);
126 else if (c <= 0x80) fprintf(f, "\\x%02x", c);
127 else fprintf(f, "\\x{%x}", c);
128 return 0;
129
130 #else
131
132 #if defined COMPILE_PCRE8
133
134 if (!utf || (c & 0xc0) != 0xc0)
135   {
136   if (PRINTABLE(c)) fprintf(f, "%c", (char)c);
137   else if (c < 0x80) fprintf(f, "\\x%02x", c);
138   else fprintf(f, "\\x{%02x}", c);
139   return 0;
140   }
141 else
142   {
143   int i;
144   int a = PRIV(utf8_table4)[c & 0x3f];  /* Number of additional bytes */
145   int s = 6*a;
146   c = (c & PRIV(utf8_table3)[a]) << s;
147   for (i = 1; i <= a; i++)
148     {
149     /* This is a check for malformed UTF-8; it should only occur if the sanity
150     check has been turned off. Rather than swallow random bytes, just stop if
151     we hit a bad one. Print it with \X instead of \x as an indication. */
152
153     if ((ptr[i] & 0xc0) != 0x80)
154       {
155       fprintf(f, "\\X{%x}", c);
156       return i - 1;
157       }
158
159     /* The byte is OK */
160
161     s -= 6;
162     c |= (ptr[i] & 0x3f) << s;
163     }
164   fprintf(f, "\\x{%x}", c);
165   return a;
166   }
167
168 #elif defined COMPILE_PCRE16
169
170 if (!utf || (c & 0xfc00) != 0xd800)
171   {
172   if (PRINTABLE(c)) fprintf(f, "%c", (char)c);
173   else if (c <= 0x80) fprintf(f, "\\x%02x", c);
174   else fprintf(f, "\\x{%02x}", c);
175   return 0;
176   }
177 else
178   {
179   /* This is a check for malformed UTF-16; it should only occur if the sanity
180   check has been turned off. Rather than swallow a low surrogate, just stop if
181   we hit a bad one. Print it with \X instead of \x as an indication. */
182
183   if ((ptr[1] & 0xfc00) != 0xdc00)
184     {
185     fprintf(f, "\\X{%x}", c);
186     return 0;
187     }
188
189   c = (((c & 0x3ff) << 10) | (ptr[1] & 0x3ff)) + 0x10000;
190   fprintf(f, "\\x{%x}", c);
191   return 1;
192   }
193
194 #elif defined COMPILE_PCRE32
195
196 if (!utf || (c & 0xfffff800u) != 0xd800u)
197   {
198   if (PRINTABLE(c)) fprintf(f, "%c", (char)c);
199   else if (c <= 0x80) fprintf(f, "\\x%02x", c);
200   else fprintf(f, "\\x{%x}", c);
201   return 0;
202   }
203 else
204   {
205   /* This is a check for malformed UTF-32; it should only occur if the sanity
206   check has been turned off. Rather than swallow a surrogate, just stop if
207   we hit one. Print it with \X instead of \x as an indication. */
208   fprintf(f, "\\X{%x}", c);
209   return 0;
210   }
211
212 #endif /* COMPILE_PCRE[8|16|32] */
213
214 #endif /* SUPPORT_UTF */
215 }
216
217 /*************************************************
218 *  Print uchar string (regardless of utf)        *
219 *************************************************/
220
221 static void
222 print_puchar(FILE *f, PCRE_PUCHAR ptr)
223 {
224 while (*ptr != '\0')
225   {
226   register pcre_uint32 c = *ptr++;
227   if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c);
228   }
229 }
230
231 /*************************************************
232 *          Find Unicode property name            *
233 *************************************************/
234
235 static const char *
236 get_ucpname(unsigned int ptype, unsigned int pvalue)
237 {
238 #ifdef SUPPORT_UCP
239 int i;
240 for (i = PRIV(utt_size) - 1; i >= 0; i--)
241   {
242   if (ptype == PRIV(utt)[i].type && pvalue == PRIV(utt)[i].value) break;
243   }
244 return (i >= 0)? PRIV(utt_names) + PRIV(utt)[i].name_offset : "??";
245 #else
246 /* It gets harder and harder to shut off unwanted compiler warnings. */
247 ptype = ptype * pvalue;
248 return (ptype == pvalue)? "??" : "??";
249 #endif
250 }
251
252
253 /*************************************************
254 *       Print Unicode property value             *
255 *************************************************/
256
257 /* "Normal" properties can be printed from tables. The PT_CLIST property is a
258 pseudo-property that contains a pointer to a list of case-equivalent
259 characters. This is used only when UCP support is available and UTF mode is
260 selected. It should never occur otherwise, but just in case it does, have
261 something ready to print. */
262
263 static void
264 print_prop(FILE *f, pcre_uchar *code, const char *before, const char *after)
265 {
266 if (code[1] != PT_CLIST)
267   {
268   fprintf(f, "%s%s %s%s", before, priv_OP_names[*code], get_ucpname(code[1],
269     code[2]), after);
270   }
271 else
272   {
273   const char *not = (*code == OP_PROP)? "" : "not ";
274 #ifndef SUPPORT_UCP
275   fprintf(f, "%s%sclist %d%s", before, not, code[2], after);
276 #else
277   const pcre_uint32 *p = PRIV(ucd_caseless_sets) + code[2];
278   fprintf (f, "%s%sclist", before, not);
279   while (*p < NOTACHAR) fprintf(f, " %04x", *p++);
280   fprintf(f, "%s", after);
281 #endif
282   }
283 }
284
285
286
287
288 /*************************************************
289 *         Print compiled regex                   *
290 *************************************************/
291
292 /* Make this function work for a regex with integers either byte order.
293 However, we assume that what we are passed is a compiled regex. The
294 print_lengths flag controls whether offsets and lengths of items are printed.
295 They can be turned off from pcretest so that automatic tests on bytecode can be
296 written that do not depend on the value of LINK_SIZE. */
297
298 #ifdef PCRE_INCLUDED
299 static /* Keep the following function as private. */
300 #endif
301 #if defined COMPILE_PCRE8
302 void
303 pcre_printint(pcre *external_re, FILE *f, BOOL print_lengths)
304 #elif defined COMPILE_PCRE16
305 void
306 pcre16_printint(pcre *external_re, FILE *f, BOOL print_lengths)
307 #elif defined COMPILE_PCRE32
308 void
309 pcre32_printint(pcre *external_re, FILE *f, BOOL print_lengths)
310 #endif
311 {
312 REAL_PCRE *re = (REAL_PCRE *)external_re;
313 pcre_uchar *codestart, *code;
314 BOOL utf;
315
316 unsigned int options = re->options;
317 int offset = re->name_table_offset;
318 int count = re->name_count;
319 int size = re->name_entry_size;
320
321 if (re->magic_number != MAGIC_NUMBER)
322   {
323   offset = ((offset << 8) & 0xff00) | ((offset >> 8) & 0xff);
324   count = ((count << 8) & 0xff00) | ((count >> 8) & 0xff);
325   size = ((size << 8) & 0xff00) | ((size >> 8) & 0xff);
326   options = ((options << 24) & 0xff000000) |
327             ((options <<  8) & 0x00ff0000) |
328             ((options >>  8) & 0x0000ff00) |
329             ((options >> 24) & 0x000000ff);
330   }
331
332 code = codestart = (pcre_uchar *)re + offset + count * size;
333 /* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */
334 utf = (options & PCRE_UTF8) != 0;
335
336 for(;;)
337   {
338   pcre_uchar *ccode;
339   const char *flag = "  ";
340   pcre_uint32 c;
341   unsigned int extra = 0;
342
343   if (print_lengths)
344     fprintf(f, "%3d ", (int)(code - codestart));
345   else
346     fprintf(f, "    ");
347
348   switch(*code)
349     {
350 /* ========================================================================== */
351       /* These cases are never obeyed. This is a fudge that causes a compile-
352       time error if the vectors OP_names or OP_lengths, which are indexed
353       by opcode, are not the correct length. It seems to be the only way to do
354       such a check at compile time, as the sizeof() operator does not work in
355       the C preprocessor. */
356
357       case OP_TABLE_LENGTH:
358       case OP_TABLE_LENGTH +
359         ((sizeof(priv_OP_names)/sizeof(const char *) == OP_TABLE_LENGTH) &&
360         (sizeof(priv_OP_lengths) == OP_TABLE_LENGTH)):
361       break;
362 /* ========================================================================== */
363
364     case OP_END:
365     fprintf(f, "    %s\n", priv_OP_names[*code]);
366     fprintf(f, "------------------------------------------------------------------\n");
367     return;
368
369     case OP_CHAR:
370     fprintf(f, "    ");
371     do
372       {
373       code++;
374       code += 1 + print_char(f, code, utf);
375       }
376     while (*code == OP_CHAR);
377     fprintf(f, "\n");
378     continue;
379
380     case OP_CHARI:
381     fprintf(f, " /i ");
382     do
383       {
384       code++;
385       code += 1 + print_char(f, code, utf);
386       }
387     while (*code == OP_CHARI);
388     fprintf(f, "\n");
389     continue;
390
391     case OP_CBRA:
392     case OP_CBRAPOS:
393     case OP_SCBRA:
394     case OP_SCBRAPOS:
395     if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
396       else fprintf(f, "    ");
397     fprintf(f, "%s %d", priv_OP_names[*code], GET2(code, 1+LINK_SIZE));
398     break;
399
400     case OP_BRA:
401     case OP_BRAPOS:
402     case OP_SBRA:
403     case OP_SBRAPOS:
404     case OP_KETRMAX:
405     case OP_KETRMIN:
406     case OP_KETRPOS:
407     case OP_ALT:
408     case OP_KET:
409     case OP_ASSERT:
410     case OP_ASSERT_NOT:
411     case OP_ASSERTBACK:
412     case OP_ASSERTBACK_NOT:
413     case OP_ONCE:
414     case OP_ONCE_NC:
415     case OP_COND:
416     case OP_SCOND:
417     case OP_REVERSE:
418     if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
419       else fprintf(f, "    ");
420     fprintf(f, "%s", priv_OP_names[*code]);
421     break;
422
423     case OP_CLOSE:
424     fprintf(f, "    %s %d", priv_OP_names[*code], GET2(code, 1));
425     break;
426
427     case OP_CREF:
428     fprintf(f, "%3d %s", GET2(code,1), priv_OP_names[*code]);
429     break;
430
431     case OP_DNCREF:
432       {
433       pcre_uchar *entry = (pcre_uchar *)re + offset + (GET2(code, 1) * size) +
434         IMM2_SIZE;
435       fprintf(f, " %s Cond ref <", flag);
436       print_puchar(f, entry);
437       fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
438       }
439     break;
440
441     case OP_RREF:
442     c = GET2(code, 1);
443     if (c == RREF_ANY)
444       fprintf(f, "    Cond recurse any");
445     else
446       fprintf(f, "    Cond recurse %d", c);
447     break;
448
449     case OP_DNRREF:
450       {
451       pcre_uchar *entry = (pcre_uchar *)re + offset + (GET2(code, 1) * size) +
452         IMM2_SIZE;
453       fprintf(f, " %s Cond recurse <", flag);
454       print_puchar(f, entry);
455       fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
456       }
457     break;
458
459     case OP_DEF:
460     fprintf(f, "    Cond def");
461     break;
462
463     case OP_STARI:
464     case OP_MINSTARI:
465     case OP_POSSTARI:
466     case OP_PLUSI:
467     case OP_MINPLUSI:
468     case OP_POSPLUSI:
469     case OP_QUERYI:
470     case OP_MINQUERYI:
471     case OP_POSQUERYI:
472     flag = "/i";
473     /* Fall through */
474     case OP_STAR:
475     case OP_MINSTAR:
476     case OP_POSSTAR:
477     case OP_PLUS:
478     case OP_MINPLUS:
479     case OP_POSPLUS:
480     case OP_QUERY:
481     case OP_MINQUERY:
482     case OP_POSQUERY:
483     case OP_TYPESTAR:
484     case OP_TYPEMINSTAR:
485     case OP_TYPEPOSSTAR:
486     case OP_TYPEPLUS:
487     case OP_TYPEMINPLUS:
488     case OP_TYPEPOSPLUS:
489     case OP_TYPEQUERY:
490     case OP_TYPEMINQUERY:
491     case OP_TYPEPOSQUERY:
492     fprintf(f, " %s ", flag);
493     if (*code >= OP_TYPESTAR)
494       {
495       if (code[1] == OP_PROP || code[1] == OP_NOTPROP)
496         {
497         print_prop(f, code + 1, "", " ");
498         extra = 2;
499         }
500       else fprintf(f, "%s", priv_OP_names[code[1]]);
501       }
502     else extra = print_char(f, code+1, utf);
503     fprintf(f, "%s", priv_OP_names[*code]);
504     break;
505
506     case OP_EXACTI:
507     case OP_UPTOI:
508     case OP_MINUPTOI:
509     case OP_POSUPTOI:
510     flag = "/i";
511     /* Fall through */
512     case OP_EXACT:
513     case OP_UPTO:
514     case OP_MINUPTO:
515     case OP_POSUPTO:
516     fprintf(f, " %s ", flag);
517     extra = print_char(f, code + 1 + IMM2_SIZE, utf);
518     fprintf(f, "{");
519     if (*code != OP_EXACT && *code != OP_EXACTI) fprintf(f, "0,");
520     fprintf(f, "%d}", GET2(code,1));
521     if (*code == OP_MINUPTO || *code == OP_MINUPTOI) fprintf(f, "?");
522       else if (*code == OP_POSUPTO || *code == OP_POSUPTOI) fprintf(f, "+");
523     break;
524
525     case OP_TYPEEXACT:
526     case OP_TYPEUPTO:
527     case OP_TYPEMINUPTO:
528     case OP_TYPEPOSUPTO:
529     if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
530       {
531       print_prop(f, code + IMM2_SIZE + 1, "    ", " ");
532       extra = 2;
533       }
534     else fprintf(f, "    %s", priv_OP_names[code[1 + IMM2_SIZE]]);
535     fprintf(f, "{");
536     if (*code != OP_TYPEEXACT) fprintf(f, "0,");
537     fprintf(f, "%d}", GET2(code,1));
538     if (*code == OP_TYPEMINUPTO) fprintf(f, "?");
539       else if (*code == OP_TYPEPOSUPTO) fprintf(f, "+");
540     break;
541
542     case OP_NOTI:
543     flag = "/i";
544     /* Fall through */
545     case OP_NOT:
546     fprintf(f, " %s [^", flag);
547     extra = print_char(f, code + 1, utf);
548     fprintf(f, "]");
549     break;
550
551     case OP_NOTSTARI:
552     case OP_NOTMINSTARI:
553     case OP_NOTPOSSTARI:
554     case OP_NOTPLUSI:
555     case OP_NOTMINPLUSI:
556     case OP_NOTPOSPLUSI:
557     case OP_NOTQUERYI:
558     case OP_NOTMINQUERYI:
559     case OP_NOTPOSQUERYI:
560     flag = "/i";
561     /* Fall through */
562
563     case OP_NOTSTAR:
564     case OP_NOTMINSTAR:
565     case OP_NOTPOSSTAR:
566     case OP_NOTPLUS:
567     case OP_NOTMINPLUS:
568     case OP_NOTPOSPLUS:
569     case OP_NOTQUERY:
570     case OP_NOTMINQUERY:
571     case OP_NOTPOSQUERY:
572     fprintf(f, " %s [^", flag);
573     extra = print_char(f, code + 1, utf);
574     fprintf(f, "]%s", priv_OP_names[*code]);
575     break;
576
577     case OP_NOTEXACTI:
578     case OP_NOTUPTOI:
579     case OP_NOTMINUPTOI:
580     case OP_NOTPOSUPTOI:
581     flag = "/i";
582     /* Fall through */
583
584     case OP_NOTEXACT:
585     case OP_NOTUPTO:
586     case OP_NOTMINUPTO:
587     case OP_NOTPOSUPTO:
588     fprintf(f, " %s [^", flag);
589     extra = print_char(f, code + 1 + IMM2_SIZE, utf);
590     fprintf(f, "]{");
591     if (*code != OP_NOTEXACT && *code != OP_NOTEXACTI) fprintf(f, "0,");
592     fprintf(f, "%d}", GET2(code,1));
593     if (*code == OP_NOTMINUPTO || *code == OP_NOTMINUPTOI) fprintf(f, "?");
594       else
595     if (*code == OP_NOTPOSUPTO || *code == OP_NOTPOSUPTOI) fprintf(f, "+");
596     break;
597
598     case OP_RECURSE:
599     if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
600       else fprintf(f, "    ");
601     fprintf(f, "%s", priv_OP_names[*code]);
602     break;
603
604     case OP_REFI:
605     flag = "/i";
606     /* Fall through */
607     case OP_REF:
608     fprintf(f, " %s \\%d", flag, GET2(code,1));
609     ccode = code + priv_OP_lengths[*code];
610     goto CLASS_REF_REPEAT;
611
612     case OP_DNREFI:
613     flag = "/i";
614     /* Fall through */
615     case OP_DNREF:
616       {
617       pcre_uchar *entry = (pcre_uchar *)re + offset + (GET2(code, 1) * size) +
618         IMM2_SIZE;
619       fprintf(f, " %s \\k<", flag);
620       print_puchar(f, entry);
621       fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
622       }
623     ccode = code + priv_OP_lengths[*code];
624     goto CLASS_REF_REPEAT;
625
626     case OP_CALLOUT:
627     fprintf(f, "    %s %d %d %d", priv_OP_names[*code], code[1], GET(code,2),
628       GET(code, 2 + LINK_SIZE));
629     break;
630
631     case OP_PROP:
632     case OP_NOTPROP:
633     print_prop(f, code, "    ", "");
634     break;
635
636     /* OP_XCLASS cannot occur in 8-bit, non-UTF mode. However, there's no harm
637     in having this code always here, and it makes it less messy without all
638     those #ifdefs. */
639
640     case OP_CLASS:
641     case OP_NCLASS:
642     case OP_XCLASS:
643       {
644       int i;
645       unsigned int min, max;
646       BOOL printmap;
647       BOOL invertmap = FALSE;
648       pcre_uint8 *map;
649       pcre_uint8 inverted_map[32];
650
651       fprintf(f, "    [");
652
653       if (*code == OP_XCLASS)
654         {
655         extra = GET(code, 1);
656         ccode = code + LINK_SIZE + 1;
657         printmap = (*ccode & XCL_MAP) != 0;
658         if ((*ccode & XCL_NOT) != 0)
659           {
660           invertmap = (*ccode & XCL_HASPROP) == 0;
661           fprintf(f, "^");
662           }
663         ccode++;
664         }
665       else
666         {
667         printmap = TRUE;
668         ccode = code + 1;
669         }
670
671       /* Print a bit map */
672
673       if (printmap)
674         {
675         map = (pcre_uint8 *)ccode;
676         if (invertmap)
677           {
678           for (i = 0; i < 32; i++) inverted_map[i] = ~map[i];
679           map = inverted_map;
680           }
681
682         for (i = 0; i < 256; i++)
683           {
684           if ((map[i/8] & (1 << (i&7))) != 0)
685             {
686             int j;
687             for (j = i+1; j < 256; j++)
688               if ((map[j/8] & (1 << (j&7))) == 0) break;
689             if (i == '-' || i == ']') fprintf(f, "\\");
690             if (PRINTABLE(i)) fprintf(f, "%c", i);
691               else fprintf(f, "\\x%02x", i);
692             if (--j > i)
693               {
694               if (j != i + 1) fprintf(f, "-");
695               if (j == '-' || j == ']') fprintf(f, "\\");
696               if (PRINTABLE(j)) fprintf(f, "%c", j);
697                 else fprintf(f, "\\x%02x", j);
698               }
699             i = j;
700             }
701           }
702         ccode += 32 / sizeof(pcre_uchar);
703         }
704
705       /* For an XCLASS there is always some additional data */
706
707       if (*code == OP_XCLASS)
708         {
709         pcre_uchar ch;
710         while ((ch = *ccode++) != XCL_END)
711           {
712           BOOL not = FALSE;
713           const char *notch = "";
714
715           switch(ch)
716             {
717             case XCL_NOTPROP:
718             not = TRUE;
719             notch = "^";
720             /* Fall through */
721
722             case XCL_PROP:
723               {
724               unsigned int ptype = *ccode++;
725               unsigned int pvalue = *ccode++;
726
727               switch(ptype)
728                 {
729                 case PT_PXGRAPH:
730                 fprintf(f, "[:%sgraph:]", notch);
731                 break;
732
733                 case PT_PXPRINT:
734                 fprintf(f, "[:%sprint:]", notch);
735                 break;
736
737                 case PT_PXPUNCT:
738                 fprintf(f, "[:%spunct:]", notch);
739                 break;
740
741                 default:
742                 fprintf(f, "\\%c{%s}", (not? 'P':'p'),
743                   get_ucpname(ptype, pvalue));
744                 break;
745                 }
746               }
747             break;
748
749             default:
750             ccode += 1 + print_char(f, ccode, utf);
751             if (ch == XCL_RANGE)
752               {
753               fprintf(f, "-");
754               ccode += 1 + print_char(f, ccode, utf);
755               }
756             break;
757             }
758           }
759         }
760
761       /* Indicate a non-UTF class which was created by negation */
762
763       fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : "");
764
765       /* Handle repeats after a class or a back reference */
766
767       CLASS_REF_REPEAT:
768       switch(*ccode)
769         {
770         case OP_CRSTAR:
771         case OP_CRMINSTAR:
772         case OP_CRPLUS:
773         case OP_CRMINPLUS:
774         case OP_CRQUERY:
775         case OP_CRMINQUERY:
776         case OP_CRPOSSTAR:
777         case OP_CRPOSPLUS:
778         case OP_CRPOSQUERY:
779         fprintf(f, "%s", priv_OP_names[*ccode]);
780         extra += priv_OP_lengths[*ccode];
781         break;
782
783         case OP_CRRANGE:
784         case OP_CRMINRANGE:
785         case OP_CRPOSRANGE:
786         min = GET2(ccode,1);
787         max = GET2(ccode,1 + IMM2_SIZE);
788         if (max == 0) fprintf(f, "{%u,}", min);
789         else fprintf(f, "{%u,%u}", min, max);
790         if (*ccode == OP_CRMINRANGE) fprintf(f, "?");
791         else if (*ccode == OP_CRPOSRANGE) fprintf(f, "+");
792         extra += priv_OP_lengths[*ccode];
793         break;
794
795         /* Do nothing if it's not a repeat; this code stops picky compilers
796         warning about the lack of a default code path. */
797
798         default:
799         break;
800         }
801       }
802     break;
803
804     case OP_MARK:
805     case OP_PRUNE_ARG:
806     case OP_SKIP_ARG:
807     case OP_THEN_ARG:
808     fprintf(f, "    %s ", priv_OP_names[*code]);
809     print_puchar(f, code + 2);
810     extra += code[1];
811     break;
812
813     case OP_THEN:
814     fprintf(f, "    %s", priv_OP_names[*code]);
815     break;
816
817     case OP_CIRCM:
818     case OP_DOLLM:
819     flag = "/m";
820     /* Fall through */
821
822     /* Anything else is just an item with no data, but possibly a flag. */
823
824     default:
825     fprintf(f, " %s %s", flag, priv_OP_names[*code]);
826     break;
827     }
828
829   code += priv_OP_lengths[*code] + extra;
830   fprintf(f, "\n");
831   }
832 }
833
834 /* End of pcre_printint.src */