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