1 /* $NetBSD: debug.c,v 1.2 2011/10/10 04:32:41 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1993 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <ctype.h> 30 #include <limits.h> 31 #include <regex.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include <sys/types.h> 37 #ifdef __FreeBSD__ 38 #include <wchar.h> 39 #include <wctype.h> 40 #endif 41 42 /* Don't sort these! */ 43 #include "utils.h" 44 #include "regex2.h" 45 46 #include "test_regex.h" 47 48 static void s_print(struct re_guts *, FILE *); 49 static char *regchar(int); 50 51 /* 52 * regprint - print a regexp for debugging 53 */ 54 void 55 regprint(regex_t *r, FILE *d) 56 { 57 #ifdef __NetBSD__ 58 struct re_guts *g = r->re_g; 59 int c; 60 int last; 61 int nincat[NC]; 62 63 fprintf(d, "%ld states, %zu categories", (long)g->nstates, 64 g->ncategories); 65 fprintf(d, ", first %ld last %ld", (long)g->firststate, 66 (long)g->laststate); 67 if (g->iflags&USEBOL) 68 fprintf(d, ", USEBOL"); 69 if (g->iflags&USEEOL) 70 fprintf(d, ", USEEOL"); 71 if (g->iflags&BAD) 72 fprintf(d, ", BAD"); 73 if (g->nsub > 0) 74 fprintf(d, ", nsub=%ld", (long)g->nsub); 75 if (g->must != NULL) 76 fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen, 77 g->must); 78 if (g->backrefs) 79 fprintf(d, ", backrefs"); 80 if (g->nplus > 0) 81 fprintf(d, ", nplus %ld", (long)g->nplus); 82 fprintf(d, "\n"); 83 s_print(g, d); 84 for (size_t i = 0; i < g->ncategories; i++) { 85 nincat[i] = 0; 86 for (c = CHAR_MIN; c <= CHAR_MAX; c++) 87 if (g->categories[c] == i) 88 nincat[i]++; 89 } 90 fprintf(d, "cc0#%d", nincat[0]); 91 for (size_t i = 1; i < g->ncategories; i++) 92 if (nincat[i] == 1) { 93 for (c = CHAR_MIN; c <= CHAR_MAX; c++) 94 if (g->categories[c] == i) 95 break; 96 fprintf(d, ", %zu=%s", i, regchar(c)); 97 } 98 fprintf(d, "\n"); 99 for (size_t i = 1; i < g->ncategories; i++) 100 if (nincat[i] != 1) { 101 fprintf(d, "cc%zu\t", i); 102 last = -1; 103 for (c = CHAR_MIN; c <= CHAR_MAX+1; c++) /* +1 does flush */ 104 if (c <= CHAR_MAX && g->categories[c] == i) { 105 if (last < 0) { 106 fprintf(d, "%s", regchar(c)); 107 last = c; 108 } 109 } else { 110 if (last >= 0) { 111 if (last != c-1) 112 fprintf(d, "-%s", 113 regchar(c-1)); 114 last = -1; 115 } 116 } 117 fprintf(d, "\n"); 118 } 119 #endif 120 } 121 122 /* 123 * s_print - print the strip for debugging 124 */ 125 static void 126 s_print(struct re_guts *g, FILE *d) 127 { 128 sop *s; 129 cset *cs; 130 int done = 0; 131 sop opnd; 132 int col = 0; 133 ssize_t last; 134 sopno offset = 2; 135 # define GAP() { if (offset % 5 == 0) { \ 136 if (col > 40) { \ 137 fprintf(d, "\n\t"); \ 138 col = 0; \ 139 } else { \ 140 fprintf(d, " "); \ 141 col++; \ 142 } \ 143 } else \ 144 col++; \ 145 offset++; \ 146 } 147 148 if (OP(g->strip[0]) != OEND) 149 fprintf(d, "missing initial OEND!\n"); 150 for (s = &g->strip[1]; !done; s++) { 151 opnd = OPND(*s); 152 switch (OP(*s)) { 153 case OEND: 154 fprintf(d, "\n"); 155 done = 1; 156 break; 157 case OCHAR: 158 if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL) 159 fprintf(d, "\\%c", (char)opnd); 160 else 161 fprintf(d, "%s", regchar((char)opnd)); 162 break; 163 case OBOL: 164 fprintf(d, "^"); 165 break; 166 case OEOL: 167 fprintf(d, "$"); 168 break; 169 case OBOW: 170 fprintf(d, "\\{"); 171 break; 172 case OEOW: 173 fprintf(d, "\\}"); 174 break; 175 case OANY: 176 fprintf(d, "."); 177 break; 178 case OANYOF: 179 fprintf(d, "[(%ld)", (long)opnd); 180 #ifdef __NetBSD__ 181 cs = &g->sets[opnd]; 182 last = -1; 183 for (size_t i = 0; i < g->csetsize+1; i++) /* +1 flushes */ 184 if (CHIN(cs, i) && i < g->csetsize) { 185 if (last < 0) { 186 fprintf(d, "%s", regchar(i)); 187 last = i; 188 } 189 } else { 190 if (last >= 0) { 191 if (last != (ssize_t)i - 1) 192 fprintf(d, "-%s", 193 regchar(i - 1)); 194 last = -1; 195 } 196 } 197 #endif 198 fprintf(d, "]"); 199 break; 200 case OBACK_: 201 fprintf(d, "(\\<%ld>", (long)opnd); 202 break; 203 case O_BACK: 204 fprintf(d, "<%ld>\\)", (long)opnd); 205 break; 206 case OPLUS_: 207 fprintf(d, "(+"); 208 if (OP(*(s+opnd)) != O_PLUS) 209 fprintf(d, "<%ld>", (long)opnd); 210 break; 211 case O_PLUS: 212 if (OP(*(s-opnd)) != OPLUS_) 213 fprintf(d, "<%ld>", (long)opnd); 214 fprintf(d, "+)"); 215 break; 216 case OQUEST_: 217 fprintf(d, "(?"); 218 if (OP(*(s+opnd)) != O_QUEST) 219 fprintf(d, "<%ld>", (long)opnd); 220 break; 221 case O_QUEST: 222 if (OP(*(s-opnd)) != OQUEST_) 223 fprintf(d, "<%ld>", (long)opnd); 224 fprintf(d, "?)"); 225 break; 226 case OLPAREN: 227 fprintf(d, "((<%ld>", (long)opnd); 228 break; 229 case ORPAREN: 230 fprintf(d, "<%ld>))", (long)opnd); 231 break; 232 case OCH_: 233 fprintf(d, "<"); 234 if (OP(*(s+opnd)) != OOR2) 235 fprintf(d, "<%ld>", (long)opnd); 236 break; 237 case OOR1: 238 if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_) 239 fprintf(d, "<%ld>", (long)opnd); 240 fprintf(d, "|"); 241 break; 242 case OOR2: 243 fprintf(d, "|"); 244 if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH) 245 fprintf(d, "<%ld>", (long)opnd); 246 break; 247 case O_CH: 248 if (OP(*(s-opnd)) != OOR1) 249 fprintf(d, "<%ld>", (long)opnd); 250 fprintf(d, ">"); 251 break; 252 default: 253 #ifdef __FreeBSD__ 254 fprintf(d, "!%ld(%ld)!", OP(*s), opnd); 255 #else 256 fprintf(d, "!%d(%d)!", OP(*s), opnd); 257 #endif 258 break; 259 } 260 if (!done) 261 GAP(); 262 } 263 } 264 265 /* 266 * regchar - make a character printable 267 */ 268 static char * /* -> representation */ 269 regchar(int ch) 270 { 271 static char buf[10]; 272 273 if (isprint(ch) || ch == ' ') 274 sprintf(buf, "%c", ch); 275 else 276 sprintf(buf, "\\%o", ch); 277 return(buf); 278 } 279