1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include "error.h"
36 
37 /*
38  *	Arrayify a list of rules
39  */
40 void
41 arrayify(int *e_length, Eptr **e_array, Eptr header)
42 {
43 	Eptr	errorp;
44 	Eptr	*array;
45 	int	listlength;
46 	int	listindex;
47 
48 	for (errorp = header, listlength = 0;
49 	    errorp; errorp = errorp->error_next, listlength++)
50 		continue;
51 	array = Calloc(listlength+1, sizeof (Eptr));
52 	for (listindex = 0, errorp = header;
53 	    listindex < listlength;
54 	    listindex++, errorp = errorp->error_next) {
55 		array[listindex] = errorp;
56 		errorp->error_position = listindex;
57 	}
58 	array[listindex] = (Eptr)0;
59 	*e_length = listlength;
60 	*e_array = array;
61 }
62 
63 /*PRINTFLIKE1*/
64 static void
65 error(char *format, ...)
66 {
67 	va_list	args;
68 
69 	va_start(args, format);
70 	(void) fprintf(stderr, "Error: ");
71 	(void) vfprintf(stderr, format, args);
72 	(void) fprintf(stderr, "\n");
73 	(void) fflush(stdout);
74 	(void) fflush(stderr);
75 	va_end(args);
76 	exit(6);
77 }
78 
79 void *
80 Calloc(int nelements, int size)
81 {
82 	void	*back;
83 	if ((back = calloc(nelements, size)) == NULL) {
84 		error("Ran out of memory.\n");
85 		exit(1);
86 	}
87 	return (back);
88 }
89 
90 char *
91 strsave(char *instring)
92 {
93 	char	*outstring;
94 	(void) strcpy(outstring = Calloc(1, strlen(instring) + 1),
95 	    instring);
96 	return (outstring);
97 }
98 /*
99  *	find the position of a given character in a string
100  *		(one based)
101  */
102 int
103 position(char *string, char ch)
104 {
105 	int	i;
106 	if (string)
107 	for (i = 1; *string; string++, i++) {
108 		if (*string == ch)
109 			return (i);
110 	}
111 	return (-1);
112 }
113 /*
114  *	clobber the first occurance of ch in string by the new character
115  */
116 char *
117 substitute(char *string, char chold, char chnew)
118 {
119 	char	*cp = string;
120 
121 	if (cp)
122 	while (*cp) {
123 		if (*cp == chold) {
124 			*cp = chnew;
125 			break;
126 		}
127 		cp++;
128 	}
129 	return (string);
130 }
131 
132 char
133 lastchar(char *string)
134 {
135 	int	length;
136 
137 	if (string == NULL)
138 		return ('\0');
139 	length = strlen(string);
140 	if (length >= 1)
141 		return (string[length-1]);
142 	else
143 		return ('\0');
144 }
145 
146 char
147 firstchar(char *string)
148 {
149 	if (string)
150 		return (string[0]);
151 	else
152 		return ('\0');
153 }
154 
155 char
156 next_lastchar(char *string)
157 {
158 	int	length;
159 
160 	if (string == NULL)
161 		return ('\0');
162 	length = strlen(string);
163 	if (length >= 2)
164 		return (string[length - 2]);
165 	else
166 		return ('\0');
167 }
168 
169 void
170 clob_last(char *string, char newstuff)
171 {
172 	int	length = 0;
173 	if (string)
174 		length = strlen(string);
175 	if (length >= 1)
176 		string[length - 1] = newstuff;
177 }
178 
179 /*
180  *	parse a string that is the result of a format %s(%d)
181  *	return TRUE if this is of the proper format
182  */
183 boolean
184 persperdexplode(char *string, char **r_perd, char **r_pers)
185 {
186 	char	*cp;
187 	int	length = 0;
188 
189 	if (string)
190 		length = strlen(string);
191 	if ((length >= 4) && (string[length - 1] == ')')) {
192 		for (cp = &string[length - 2];
193 		    (isdigit(*cp)) && (*cp != '('); --cp)
194 			continue;
195 		if (*cp == '(') {
196 			string[length - 1] = '\0';	/* clobber the ) */
197 			*r_perd = strsave(cp+1);
198 			string[length - 1] = ')';
199 			*cp = '\0';			/* clobber the ( */
200 			*r_pers = strsave(string);
201 			*cp = '(';
202 			return (TRUE);
203 		}
204 	}
205 	return (FALSE);
206 }
207 
208 static	char	cincomment[] = CINCOMMENT;
209 static	char	coutcomment[] = COUTCOMMENT;
210 static	char	fincomment[] = FINCOMMENT;
211 static	char	foutcomment[] = FOUTCOMMENT;
212 static	char	newline[] = NEWLINE;
213 static	char	piincomment[] = PIINCOMMENT;
214 static	char	pioutcomment[] = PIOUTCOMMENT;
215 static	char	lispincomment[] = LISPINCOMMENT;
216 static	char	riincomment[] = RIINCOMMENT;
217 static	char	rioutcomment[] = RIOUTCOMMENT;
218 static	char	troffincomment[] = TROFFINCOMMENT;
219 static	char	troffoutcomment[] = TROFFOUTCOMMENT;
220 static	char	mod2incomment[] = MOD2INCOMMENT;
221 static	char	mod2outcomment[] = MOD2OUTCOMMENT;
222 
223 struct lang_desc lang_table[] = {
224 	/* INUNKNOWN	0 */	"unknown", cincomment,	coutcomment,
225 	/* INCPP	1 */	"cpp",	cincomment,    coutcomment,
226 	/* INCC		2 */	"cc",	cincomment,    coutcomment,
227 	/* INAS		3 */	"as",	ASINCOMMENT,   newline,
228 	/* INLD		4 */	"ld",	cincomment,    coutcomment,
229 	/* INLINT	5 */	"lint",	cincomment,    coutcomment,
230 	/* INF77	6 */	"f77",	fincomment,    foutcomment,
231 	/* INPI		7 */	"pi",	piincomment,   pioutcomment,
232 	/* INPC		8 */	"pc",	piincomment,   pioutcomment,
233 	/* INFRANZ	9 */	"franz", lispincomment, newline,
234 	/* INLISP	10 */	"lisp",	lispincomment, newline,
235 	/* INVAXIMA	11 */	"vaxima", lispincomment, newline,
236 	/* INRATFOR	12 */	"ratfor", fincomment,   foutcomment,
237 	/* INLEX	13 */	"lex",	cincomment,    coutcomment,
238 	/* INYACC	14 */	"yacc",	cincomment,    coutcomment,
239 	/* INAPL	15 */	"apl",	".lm", newline,
240 	/* INMAKE	16 */	"make",	ASINCOMMENT,   newline,
241 	/* INRI		17 */	"ri",	riincomment,   rioutcomment,
242 	/* INTROFF	18 */	"troff", troffincomment, troffoutcomment,
243 	/* INMOD2	19 */	"mod2",	mod2incomment, mod2outcomment,
244 	/* INSUNF77	20 */	"Sunf77", fincomment,   foutcomment,
245 	0,	0,	0
246 };
247 
248 void
249 printerrors(boolean look_at_subclass, int errorc, Eptr errorv[])
250 {
251 	int	i;
252 	Eptr	errorp;
253 
254 	for (errorp = errorv[i = 0]; i < errorc; errorp = errorv[++i]) {
255 		if (errorp->error_e_class == C_IGNORE)
256 			continue;
257 		if (look_at_subclass && errorp->error_s_class == C_DUPL)
258 			continue;
259 		(void) printf("Error %d, (%s error) [%s], text = \"",
260 		    i,
261 		    class_table[errorp->error_e_class],
262 		    lang_table[errorp->error_language].lang_name);
263 		wordvprint(stdout, errorp->error_lgtext, errorp->error_text);
264 		(void) printf("\"\n");
265 	}
266 }
267 
268 void
269 wordvprint(FILE *fyle, int wordc, char *wordv[])
270 {
271 	int	i;
272 	char *sep = "";
273 
274 	for (i = 0; i < wordc; i++)
275 		if (wordv[i]) {
276 			(void) fprintf(fyle, "%s%s", sep, wordv[i]);
277 			sep = " ";
278 		}
279 }
280 
281 /*
282  *	Given a string, parse it into a number of words, and build
283  *	a wordc wordv combination pointing into it.
284  */
285 void
286 wordvbuild(char *string, int *r_wordc, char ***r_wordv)
287 {
288 	char 	*cp;
289 	char	*saltedbuffer;
290 	char	**wordv;
291 	int	wordcount;
292 	int	wordindex;
293 
294 	saltedbuffer = strsave(string);
295 	for (wordcount = 0, cp = saltedbuffer; *cp; wordcount++) {
296 		while (*cp && isspace(*cp))
297 			cp++;
298 		while (*cp && !isspace(*cp))
299 			cp++;
300 	}
301 	wordv = Calloc(wordcount + 1, sizeof (char *));
302 	for (cp = saltedbuffer, wordindex = 0; wordcount;
303 	    wordindex++, --wordcount) {
304 		while (*cp && isspace(*cp))
305 			cp++;
306 		if (*cp == 0)
307 			break;
308 		wordv[wordindex] = cp;
309 		while (*cp && !isspace(*cp))
310 			cp++;
311 		*cp++ = '\0';
312 	}
313 	if (wordcount != 0)
314 		error("Initial miscount of the number of words in a line\n");
315 	wordv[wordindex] = NULL;
316 #ifdef FULLDEBUG
317 	for (wordcount = 0; wordcount < wordindex; wordcount++)
318 		(void) printf("Word %d = \"%s\"\n", wordcount,
319 		    wordv[wordcount]);
320 	(void) printf("\n");
321 #endif
322 	*r_wordc = wordindex;
323 	*r_wordv = wordv;
324 }
325 /*
326  *	Compare two 0 based wordvectors
327  */
328 int
329 wordvcmp(char **wordv1, int wordc, char **wordv2)
330 {
331 	int i;
332 	int	back;
333 
334 	for (i = 0; i < wordc; i++) {
335 		if (wordv1[i] == 0 || wordv2[i] == 0)
336 				return (-1);
337 		if (back = strcmp(wordv1[i], wordv2[i])) {
338 			return (back);
339 		}
340 	}
341 	return (0);	/* they are equal */
342 }
343 
344 /*
345  *	splice a 0 basedword vector onto the tail of a
346  *	new wordv, allowing the first emptyhead slots to be empty
347  */
348 char **
349 wordvsplice(int emptyhead, int wordc, char **wordv)
350 {
351 	char	**nwordv;
352 	int	nwordc = emptyhead + wordc;
353 	int	i;
354 
355 	nwordv = Calloc(nwordc, sizeof (char *));
356 	for (i = 0; i < emptyhead; i++)
357 		nwordv[i] = 0;
358 	for (i = emptyhead; i < nwordc; i++) {
359 		nwordv[i] = wordv[i-emptyhead];
360 	}
361 	return (nwordv);
362 }
363 
364 /*
365  *	plural'ize and verb forms
366  */
367 static	char	*S = "s";
368 static	char	*N = "";
369 
370 char *
371 plural(int n)
372 {
373 	return (n > 1 ? S : N);
374 }
375 
376 char *
377 verbform(int n)
378 {
379 	return (n > 1 ? N : S);
380 }
381