xref: /freebsd/contrib/netbsd-tests/lib/libc/regex/debug.c (revision 257e70f1d5ee61037c8c59b116538d3b6b1427a2)
1  /*	$NetBSD: debug.c,v 1.3 2017/01/14 00:50:56 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 <sys/types.h>
30  #include <ctype.h>
31  #include <limits.h>
32  #include <regex.h>
33  #include <stdio.h>
34  #include <stdlib.h>
35  #include <string.h>
36  #include <wchar.h>
37  #include <wctype.h>
38  
39  /* Don't sort these! */
40  #include "utils.h"
41  #include "regex2.h"
42  
43  #include "test_regex.h"
44  
45  #ifdef __NetBSD__
46  static void s_print(struct re_guts *, FILE *);
47  static char *regchar(int);
48  
49  /*
50   * regprint - print a regexp for debugging
51   */
52  void
53  regprint(regex_t *r, FILE *d)
54  {
55  	struct re_guts *g = r->re_g;
56  	int c;
57  	int last;
58  	int nincat[NC];
59  
60  	fprintf(d, "%ld states, %zu categories", (long)g->nstates,
61  							g->ncategories);
62  	fprintf(d, ", first %ld last %ld", (long)g->firststate,
63  						(long)g->laststate);
64  	if (g->iflags&USEBOL)
65  		fprintf(d, ", USEBOL");
66  	if (g->iflags&USEEOL)
67  		fprintf(d, ", USEEOL");
68  	if (g->iflags&BAD)
69  		fprintf(d, ", BAD");
70  	if (g->nsub > 0)
71  		fprintf(d, ", nsub=%ld", (long)g->nsub);
72  	if (g->must != NULL)
73  		fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen,
74  								g->must);
75  	if (g->backrefs)
76  		fprintf(d, ", backrefs");
77  	if (g->nplus > 0)
78  		fprintf(d, ", nplus %ld", (long)g->nplus);
79  	fprintf(d, "\n");
80  	s_print(g, d);
81  	for (size_t i = 0; i < g->ncategories; i++) {
82  		nincat[i] = 0;
83  		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
84  			if (g->categories[c] == i)
85  				nincat[i]++;
86  	}
87  	fprintf(d, "cc0#%d", nincat[0]);
88  	for (size_t i = 1; i < g->ncategories; i++)
89  		if (nincat[i] == 1) {
90  			for (c = CHAR_MIN; c <= CHAR_MAX; c++)
91  				if (g->categories[c] == i)
92  					break;
93  			fprintf(d, ", %zu=%s", i, regchar(c));
94  		}
95  	fprintf(d, "\n");
96  	for (size_t i = 1; i < g->ncategories; i++)
97  		if (nincat[i] != 1) {
98  			fprintf(d, "cc%zu\t", i);
99  			last = -1;
100  			for (c = CHAR_MIN; c <= CHAR_MAX+1; c++)	/* +1 does flush */
101  				if (c <= CHAR_MAX && g->categories[c] == i) {
102  					if (last < 0) {
103  						fprintf(d, "%s", regchar(c));
104  						last = c;
105  					}
106  				} else {
107  					if (last >= 0) {
108  						if (last != c-1)
109  							fprintf(d, "-%s",
110  								regchar(c-1));
111  						last = -1;
112  					}
113  				}
114  			fprintf(d, "\n");
115  		}
116  }
117  
118  /*
119   * s_print - print the strip for debugging
120   */
121  static void
122  s_print(struct re_guts *g, FILE *d)
123  {
124  	sop *s;
125  	cset *cs;
126  	int done = 0;
127  	sop opnd;
128  	int col = 0;
129  	ssize_t last;
130  	sopno offset = 2;
131  #	define	GAP()	{	if (offset % 5 == 0) { \
132  					if (col > 40) { \
133  						fprintf(d, "\n\t"); \
134  						col = 0; \
135  					} else { \
136  						fprintf(d, " "); \
137  						col++; \
138  					} \
139  				} else \
140  					col++; \
141  				offset++; \
142  			}
143  
144  	if (OP(g->strip[0]) != OEND)
145  		fprintf(d, "missing initial OEND!\n");
146  	for (s = &g->strip[1]; !done; s++) {
147  		opnd = OPND(*s);
148  		switch (OP(*s)) {
149  		case OEND:
150  			fprintf(d, "\n");
151  			done = 1;
152  			break;
153  		case OCHAR:
154  			if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL)
155  				fprintf(d, "\\%c", (char)opnd);
156  			else
157  				fprintf(d, "%s", regchar((char)opnd));
158  			break;
159  		case OBOL:
160  			fprintf(d, "^");
161  			break;
162  		case OEOL:
163  			fprintf(d, "$");
164  			break;
165  		case OBOW:
166  			fprintf(d, "\\{");
167  			break;
168  		case OEOW:
169  			fprintf(d, "\\}");
170  			break;
171  		case OANY:
172  			fprintf(d, ".");
173  			break;
174  		case OANYOF:
175  			fprintf(d, "[(%ld)", (long)opnd);
176  			cs = &g->sets[opnd];
177  			last = -1;
178  			for (size_t i = 0; i < g->csetsize+1; i++)	/* +1 flushes */
179  				if (CHIN(cs, i) && i < g->csetsize) {
180  					if (last < 0) {
181  						fprintf(d, "%s", regchar(i));
182  						last = i;
183  					}
184  				} else {
185  					if (last >= 0) {
186  						if (last != (ssize_t)i - 1)
187  							fprintf(d, "-%s",
188  							    regchar(i - 1));
189  						last = -1;
190  					}
191  				}
192  			fprintf(d, "]");
193  			break;
194  		case OBACK_:
195  			fprintf(d, "(\\<%ld>", (long)opnd);
196  			break;
197  		case O_BACK:
198  			fprintf(d, "<%ld>\\)", (long)opnd);
199  			break;
200  		case OPLUS_:
201  			fprintf(d, "(+");
202  			if (OP(*(s+opnd)) != O_PLUS)
203  				fprintf(d, "<%ld>", (long)opnd);
204  			break;
205  		case O_PLUS:
206  			if (OP(*(s-opnd)) != OPLUS_)
207  				fprintf(d, "<%ld>", (long)opnd);
208  			fprintf(d, "+)");
209  			break;
210  		case OQUEST_:
211  			fprintf(d, "(?");
212  			if (OP(*(s+opnd)) != O_QUEST)
213  				fprintf(d, "<%ld>", (long)opnd);
214  			break;
215  		case O_QUEST:
216  			if (OP(*(s-opnd)) != OQUEST_)
217  				fprintf(d, "<%ld>", (long)opnd);
218  			fprintf(d, "?)");
219  			break;
220  		case OLPAREN:
221  			fprintf(d, "((<%ld>", (long)opnd);
222  			break;
223  		case ORPAREN:
224  			fprintf(d, "<%ld>))", (long)opnd);
225  			break;
226  		case OCH_:
227  			fprintf(d, "<");
228  			if (OP(*(s+opnd)) != OOR2)
229  				fprintf(d, "<%ld>", (long)opnd);
230  			break;
231  		case OOR1:
232  			if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_)
233  				fprintf(d, "<%ld>", (long)opnd);
234  			fprintf(d, "|");
235  			break;
236  		case OOR2:
237  			fprintf(d, "|");
238  			if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH)
239  				fprintf(d, "<%ld>", (long)opnd);
240  			break;
241  		case O_CH:
242  			if (OP(*(s-opnd)) != OOR1)
243  				fprintf(d, "<%ld>", (long)opnd);
244  			fprintf(d, ">");
245  			break;
246  		default:
247  			fprintf(d, "!%d(%d)!", OP(*s), opnd);
248  			break;
249  		}
250  		if (!done)
251  			GAP();
252  	}
253  }
254  
255  /*
256   * regchar - make a character printable
257   */
258  static char *			/* -> representation */
259  regchar(int ch)
260  {
261  	static char buf[10];
262  
263  	if (isprint(ch) || ch == ' ')
264  		sprintf(buf, "%c", ch);
265  	else
266  		sprintf(buf, "\\%o", ch);
267  	return(buf);
268  }
269  #else
270  void
271  regprint(regex_t *r, FILE *d)
272  {
273  
274  }
275  #endif
276