xref: /netbsd-src/usr.bin/error/subr.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: subr.c,v 1.14 2003/08/07 11:13:38 agc Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1993
5  *	The Regents of the University of California.  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  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)subr.c	8.1 (Berkeley) 6/6/93";
36 #endif
37 __RCSID("$NetBSD: subr.c,v 1.14 2003/08/07 11:13:38 agc Exp $");
38 #endif /* not lint */
39 
40 #include <ctype.h>
41 #include <err.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include "error.h"
46 /*
47  *	Arrayify a list of rules
48  */
49 void
50 arrayify(int *e_length, Eptr **e_array, Eptr header)
51 {
52 	Eptr	errorp;
53 	Eptr	*array;
54 	int	listlength;
55 	int	listindex;
56 
57 	for (errorp = header, listlength = 0;
58 	     errorp; errorp = errorp->error_next, listlength++)
59 		continue;
60 	array = (Eptr*)Calloc(listlength+1, sizeof (Eptr));
61 	for(listindex = 0, errorp = header;
62 	    listindex < listlength;
63 	    listindex++, errorp = errorp->error_next){
64 		array[listindex] = errorp;
65 		errorp->error_position = listindex;
66 	}
67 	array[listindex] = NULL;
68 	*e_length = listlength;
69 	*e_array = array;
70 }
71 
72 char *
73 Calloc(int nelements, int size)
74 {
75 	char	*back;
76 	if ( (back = (char *)calloc(nelements, size)) == NULL)
77 		errx(1, "Ran out of memory.");
78 	return(back);
79 }
80 
81 /*
82  *	find the position of a given character in a string
83  *		(one based)
84  */
85 int
86 position(char *string, char ch)
87 {
88 	int	i;
89 	if (string)
90 	for (i=1; *string; string++, i++){
91 		if (*string == ch)
92 			return(i);
93 	}
94 	return(-1);
95 }
96 
97 /*
98  *	clobber the first occurance of ch in string by the new character
99  */
100 char *
101 substitute(char *string, char chold, char chnew)
102 {
103 	char	*cp = string;
104 
105 	if (cp)
106 	while (*cp){
107 		if (*cp == chold){
108 			*cp = chnew;
109 			break;
110 		}
111 		cp++;
112 	}
113 	return(string);
114 }
115 
116 char
117 lastchar(char *string)
118 {
119 	int	length;
120 	if (string == NULL) return('\0');
121 	length = strlen(string);
122 	if (length >= 1)
123 		return(string[length-1]);
124 	else
125 		return('\0');
126 }
127 
128 char
129 firstchar(char *string)
130 {
131 	if (string)
132 		return(string[0]);
133 	else
134 		return('\0');
135 }
136 
137 char
138 next_lastchar(char *string)
139 {
140 	int	length;
141 	if (string == NULL) return('\0');
142 	length = strlen(string);
143 	if (length >= 2)
144 		return(string[length - 2]);
145 	else
146 		return('\0');
147 }
148 
149 void
150 clob_last(char *string, char newstuff)
151 {
152 	int	length = 0;
153 	if (string)
154 		length = strlen(string);
155 	if (length >= 1)
156 		string[length - 1] = newstuff;
157 }
158 
159 /*
160  *	parse a string that is the result of a format %s(%d)
161  *	return TRUE if this is of the proper format
162  */
163 boolean
164 persperdexplode(char *string, char **r_perd, char **r_pers)
165 {
166 	char	*cp;
167 	int	length = 0;
168 
169 	if (string)
170 		length = strlen(string);
171 	if (   (length >= 4)
172 	    && (string[length - 1] == ')' ) ){
173 		for (cp = &string[length - 2];
174 		     (isdigit((unsigned char)*cp)) && (*cp != '(');
175 		     --cp)
176 			continue;
177 		if (*cp == '('){
178 			string[length - 1] = '\0';	/* clobber the ) */
179 			*r_perd = strdup(cp+1);
180 			string[length - 1] = ')';
181 			*cp = '\0';			/* clobber the ( */
182 			*r_pers = strdup(string);
183 			*cp = '(';
184 			return(TRUE);
185 		}
186 	}
187 	return(FALSE);
188 }
189 
190 /*
191  *	parse a quoted string that is the result of a format \"%s\"(%d)
192  *	return TRUE if this is of the proper format
193  */
194 boolean
195 qpersperdexplode(char *string, char **r_perd, char **r_pers)
196 {
197 	char	*cp;
198 	int	length = 0;
199 
200 	if (string)
201 		length = strlen(string);
202 	if (   (length >= 4)
203 	    && (string[length - 1] == ')' ) ){
204 		for (cp = &string[length - 2];
205 		     (isdigit((unsigned char)*cp)) && (*cp != '(');
206 		     --cp)
207 			continue;
208 		if (*cp == '(' && *(cp - 1) == '"'){
209 			string[length - 1] = '\0';
210 			*r_perd = strdup(cp+1);
211 			string[length - 1] = ')';
212 			*(cp - 1) = '\0';		/* clobber the " */
213 			*r_pers = strdup(string + 1);
214 			*(cp - 1) = '"';
215 			return(TRUE);
216 		}
217 	}
218 	return(FALSE);
219 }
220 
221 static	char	cincomment[] = CINCOMMENT;
222 static	char	coutcomment[] = COUTCOMMENT;
223 static	char	fincomment[] = FINCOMMENT;
224 static	char	foutcomment[] = FOUTCOMMENT;
225 static	char	newline[] = NEWLINE;
226 static	char	piincomment[] = PIINCOMMENT;
227 static	char	pioutcomment[] = PIOUTCOMMENT;
228 static	char	lispincomment[] = LISPINCOMMENT;
229 static	char	riincomment[] = RIINCOMMENT;
230 static	char	rioutcomment[] = RIOUTCOMMENT;
231 static	char	troffincomment[] = TROFFINCOMMENT;
232 static	char	troffoutcomment[] = TROFFOUTCOMMENT;
233 static	char	mod2incomment[] = MOD2INCOMMENT;
234 static	char	mod2outcomment[] = MOD2OUTCOMMENT;
235 
236 struct	lang_desc lang_table[] = {
237 	{ /*INUNKNOWN	0*/	"unknown", cincomment,	coutcomment },
238 	{ /*INCPP	1*/	"cpp",	cincomment,    coutcomment },
239 	{ /*INCC	2*/	"cc",	cincomment,    coutcomment },
240 	{ /*INAS	3*/	"as",	ASINCOMMENT,   newline },
241 	{ /*INLD	4*/	"ld",	cincomment,    coutcomment },
242 	{ /*INLINT	5*/	"lint",	cincomment,    coutcomment },
243 	{ /*INF77	6*/	"f77",	fincomment,    foutcomment },
244 	{ /*INPI	7*/	"pi",	piincomment,   pioutcomment },
245 	{ /*INPC	8*/	"pc",	piincomment,   pioutcomment },
246 	{ /*INFRANZ	9*/	"franz",lispincomment, newline },
247 	{ /*INLISP	10*/	"lisp",	lispincomment, newline },
248 	{ /*INVAXIMA	11*/	"vaxima",lispincomment,newline },
249 	{ /*INRATFOR	12*/	"ratfor",fincomment,   foutcomment },
250 	{ /*INLEX	13*/	"lex",	cincomment,    coutcomment },
251 	{ /*INYACC	14*/	"yacc",	cincomment,    coutcomment },
252 	{ /*INAPL	15*/	"apl",	".lm",	       newline },
253 	{ /*INMAKE	16*/	"make",	ASINCOMMENT,   newline },
254 	{ /*INRI	17*/	"ri",	riincomment,   rioutcomment },
255 	{ /*INTROFF	18*/	"troff",troffincomment,troffoutcomment },
256 	{ /*INMOD2	19*/	"mod2",	mod2incomment, mod2outcomment },
257 	{			0,	0,	     0 }
258 };
259 
260 void
261 printerrors(boolean look_at_subclass, int errorc, Eptr errorv[])
262 {
263 	int	i;
264 	Eptr	errorp;
265 
266 	for (errorp = errorv[i = 0]; i < errorc; errorp = errorv[++i]){
267 		if (errorp->error_e_class == C_IGNORE)
268 			continue;
269 		if (look_at_subclass && errorp->error_s_class == C_DUPL)
270 			continue;
271 		printf("Error %d, (%s error) [%s], text = \"",
272 			i,
273 			class_table[errorp->error_e_class],
274 			lang_table[errorp->error_language].lang_name);
275 		wordvprint(stdout,errorp->error_lgtext,errorp->error_text);
276 		printf("\"\n");
277 	}
278 }
279 
280 void
281 wordvprint(FILE *fyle, int wordc, char **wordv)
282 {
283 	int	i;
284 	char *sep = "";
285 
286 	for(i = 0; i < wordc; i++)
287 		if (wordv[i]) {
288 			fprintf(fyle, "%s%s",sep,wordv[i]);
289 			sep = " ";
290 		}
291 }
292 
293 /*
294  *	Given a string, parse it into a number of words, and build
295  *	a wordc wordv combination pointing into it.
296  */
297 void
298 wordvbuild(char *string, int *r_wordc, char ***r_wordv)
299 {
300 	char 	*cp;
301 	char	**wordv;
302 	int	wordcount;
303 	int	wordindex;
304 
305 	for (wordcount = 0, cp = string; *cp; wordcount++){
306 		while (*cp  && isspace((unsigned char)*cp))
307 			cp++;
308 		if (*cp == '\0')
309 			break;
310 		while (*cp && !isspace((unsigned char)*cp))
311 			cp++;
312 	}
313 	wordv = (char **)Calloc(wordcount + 1, sizeof (char *));
314 	for (cp=string,wordindex=0; wordcount; wordindex++,--wordcount){
315 		while (*cp && isspace((unsigned char)*cp))
316 			cp++;
317 		if (*cp == '\0')
318 			break;
319 		wordv[wordindex] = cp;
320 		while(*cp && !isspace((unsigned char)*cp))
321 			cp++;
322 		*cp++ = '\0';
323 	}
324 	if (wordcount != 0)
325 		errx(6, "Initial miscount of the number of words in a line");
326 	wordv[wordindex] = NULL;
327 #ifdef FULLDEBUG
328 	for (wordcount = 0; wordcount < wordindex; wordcount++)
329 		printf("Word %d = \"%s\"\n", wordcount, wordv[wordcount]);
330 	printf("\n");
331 #endif
332 	*r_wordc = wordindex;
333 	*r_wordv = wordv;
334 }
335 
336 /*
337  *	Compare two 0 based wordvectors
338  */
339 int
340 wordvcmp(char **wordv1, int wordc, char **wordv2)
341 {
342 	int i;
343 	int	back;
344 
345 	for (i = 0; i < wordc; i++){
346 		if (wordv1[i] == NULL || wordv2[i] == NULL)
347 			return(-1);
348 		if ((back = strcmp(wordv1[i], wordv2[i])) != 0)
349 			return(back);
350 	}
351 	return(0);	/* they are equal */
352 }
353 
354 /*
355  *	splice a 0 basedword vector onto the tail of a
356  *	new wordv, allowing the first emptyhead slots to be empty
357  */
358 char	**
359 wordvsplice(int emptyhead, int wordc, char **wordv)
360 {
361 	char	**nwordv;
362 	int	nwordc = emptyhead + wordc;
363 	int	i;
364 
365 	nwordv = (char **)Calloc(nwordc, sizeof (char *));
366 	for (i = 0; i < emptyhead; i++)
367 		nwordv[i] = NULL;
368 	for(i = emptyhead; i < nwordc; i++){
369 		nwordv[i] = wordv[i-emptyhead];
370 	}
371 	return(nwordv);
372 }
373 
374 /*
375  *	plural'ize and verb forms
376  */
377 static	char	*S = "s";
378 static	char	*N = "";
379 
380 char *
381 plural(int n)
382 {
383 	return( n > 1 ? S : N);
384 }
385 
386 char *
387 verbform(int n)
388 {
389 	return( n > 1 ? N : S);
390 }
391