xref: /original-bsd/usr.bin/error/input.c (revision 9a96b58b)
1 static	char *sccsid = "@(#)input.c	1.6 (Berkeley) 82/05/04";
2 #include <stdio.h>
3 #include <ctype.h>
4 #include "error.h"
5 
6 int	wordc;		/* how long the current error message is */
7 char	**wordv;	/* the actual error message */
8 
9 int	nerrors;
10 int	language;
11 
12 Errorclass	onelong();
13 Errorclass	cpp();
14 Errorclass	pccccom();	/* Portable C Compiler C Compiler */
15 Errorclass	richieccom();	/* Richie Compiler for 11 */
16 Errorclass	lint0();
17 Errorclass	lint1();
18 Errorclass	lint2();
19 Errorclass	lint3();
20 Errorclass	make();
21 Errorclass	f77();
22 Errorclass	pi();
23 Errorclass	ri();
24 /*
25  *	Eat all of the lines in the input file, attempting to categorize
26  *	them by their various flavors
27  */
28 static	char	inbuffer[BUFSIZ];
29 
30 eaterrors(r_errorc, r_errorv)
31 	int	*r_errorc;
32 	Eptr	**r_errorv;
33 {
34 	extern	boolean	piflag;
35 	Errorclass	errorclass = C_SYNC;
36 
37     for (;;){
38 	if (fgets(inbuffer, BUFSIZ, errorfile) == NULL)
39 		break;
40 	wordvbuild(inbuffer, &wordc, &wordv);
41 	/*
42 	 *	for convience, convert wordv to be 1 based, instead
43 	 *	of 0 based.
44 	 */
45 	wordv -= 1;
46 	if ( 0
47 	   || (( errorclass = onelong() ) != C_UNKNOWN)
48 	   || (( errorclass = cpp() ) != C_UNKNOWN)
49 	   || (( errorclass = pccccom() ) != C_UNKNOWN)
50 	   || (( errorclass = richieccom() ) != C_UNKNOWN)
51 	   || (( errorclass = lint0() ) != C_UNKNOWN)
52 	   || (( errorclass = lint1() ) != C_UNKNOWN)
53 	   || (( errorclass = lint2() ) != C_UNKNOWN)
54 	   || (( errorclass = lint3() ) != C_UNKNOWN)
55 	   || (( errorclass = make() ) != C_UNKNOWN)
56 	   || (( errorclass = f77() ) != C_UNKNOWN)
57 	   || ((errorclass = pi() ) != C_UNKNOWN)
58 	   || (( errorclass = ri() )!= C_UNKNOWN)
59 	) ;
60 	else
61 		errorclass = catchall();
62 	if (wordc)
63 		erroradd(wordc, wordv+1, errorclass, C_UNKNOWN);
64     }
65 #ifdef FULLDEBUG
66     printf("%d errorentrys\n", nerrors);
67 #endif
68     arrayify(r_errorc, r_errorv, er_head);
69 }
70 
71 /*
72  *	create a new error entry, given a zero based array and count
73  */
74 erroradd(errorlength, errorv, errorclass, errorsubclass)
75 	int		errorlength;
76 	char		**errorv;
77 	Errorclass	errorclass;
78 	Errorclass	errorsubclass;
79 {
80 	reg	Eptr	newerror;
81 	reg	char	*cp;
82 
83 	if (errorclass == C_TRUE){
84 		/* check canonicalization of the second argument*/
85 		for(cp = errorv[1]; *cp && isdigit(*cp); cp++)
86 			continue;
87 		errorclass = (*cp == '\0') ? C_TRUE : C_NONSPEC;
88 #ifdef FULLDEBUG
89 		if (errorclass != C_TRUE)
90 			printf("The 2nd word, \"%s\" is not a number.\n",
91 				errorv[1]);
92 #endif
93 	}
94 	if (errorlength > 0){
95 		newerror = (Eptr)Calloc(1, sizeof(Edesc));
96 		newerror->error_language = language; /* language is global */
97 		newerror->error_text = errorv;
98 		newerror->error_lgtext = errorlength;
99 		if (errorclass == C_TRUE)
100 			newerror->error_line = atoi(errorv[1]);
101 		newerror->error_e_class = errorclass;
102 		newerror->error_s_class = errorsubclass;
103 		switch(newerror->error_e_class = discardit(newerror)){
104 			case C_SYNC:		nsyncerrors++; break;
105 			case C_DISCARD: 	ndiscard++; break;
106 			case C_NULLED:		nnulled++; break;
107 			case C_NONSPEC:		nnonspec++; break;
108 			case C_THISFILE: 	nthisfile++; break;
109 			case C_TRUE:		ntrue++; break;
110 			case C_UNKNOWN:		nunknown++; break;
111 			case C_IGNORE:		nignore++; break;
112 		}
113 		newerror->error_next = er_head;
114 		er_head = newerror;
115 		newerror->error_no = nerrors++;
116 	}	/* length > 0 */
117 }
118 
119 Errorclass onelong()
120 {
121 	char	**nwordv;
122 	if ( (wordc == 1) && (language != INLD) ){
123 		/*
124 		 *	We have either:
125 		 *	a)	file name from cc
126 		 *	b)	Assembler telling world that it is complaining
127 		 *	c)	Noise from make ("Stop.")
128 		 *	c)	Random noise
129 		 */
130 		wordc = 0;
131 		if (strcmp(wordv[2], "Stop.") == 0){
132 			language = INMAKE; return(C_SYNC);
133 		}
134 		if (strcmp(wordv[1], "Assembler:") == 0){
135 			/* assembler always alerts us to what happened*/
136 			language = INAS; return(C_SYNC);
137 		} else
138 		if (strcmp(wordv[1], "Undefined:") == 0){
139 			/* loader complains about unknown symbols*/
140 			language = INLD; return(C_SYNC);
141 		}
142 		if (lastchar(wordv[1]) == ':'){
143 			/* cc tells us what file we are in */
144 			currentfilename = wordv[1];
145 			(void)substitute(currentfilename, ':', '\0');
146 			language = INCC; return(C_SYNC);
147 		}
148 	} else
149 	if ( (wordc == 1) && (language == INLD) ){
150 		nwordv = (char **)Calloc(4, sizeof(char *));
151 		nwordv[0] = "ld:";
152 		nwordv[1] = wordv[1];
153 		nwordv[2] = "is";
154 		nwordv[3] = "undefined.";
155 		wordc = 4;
156 		wordv = nwordv - 1;
157 		return(C_NONSPEC);
158 	} else
159 	if (wordc == 1){
160 		return(C_SYNC);
161 	}
162 	return(C_UNKNOWN);
163 }	/* end of one long */
164 
165 Errorclass	cpp()
166 {
167 	/*
168 	 *	Now attempt a cpp error message match
169 	 *	Examples:
170 	 *		./morse.h: 23: undefined control
171 	 *		morsesend.c: 229: MAGNIBBL: argument mismatch
172 	 *		morsesend.c: 237: MAGNIBBL: argument mismatch
173 	 *		test1.c: 6: undefined control
174 	 */
175 	if (   (language != INLD)		/* loader errors have almost same fmt*/
176 	    && (lastchar(wordv[1]) == ':')
177 	    && (isdigit(firstchar(wordv[2])))
178 	    && (lastchar(wordv[2]) == ':') ){
179 		language = INCPP;
180 		clob_last(wordv[1], '\0');
181 		clob_last(wordv[2], '\0');
182 		return(C_TRUE);
183 	}
184 	return(C_UNKNOWN);
185 }	/*end of cpp*/
186 
187 Errorclass pccccom()
188 {
189 	/*
190 	 *	Now attempt a ccom error message match:
191 	 *	Examples:
192 	 *	  "morsesend.c", line 237: operands of & have incompatible types
193 	 *	  "test.c", line 7: warning: old-fashioned initialization: use =
194 	 *	  "subdir.d/foo2.h", line 1: illegal initialization
195 	 */
196 	if (   (firstchar(wordv[1]) == '"')
197 	    && (lastchar(wordv[1]) == ',')
198 	    && (next_lastchar(wordv[1]) == '"')
199 	    && (strcmp(wordv[2],"line") == 0)
200 	    && (isdigit(firstchar(wordv[3])))
201 	    && (lastchar(wordv[3]) == ':') ){
202 		clob_last(wordv[1], '\0');	/* drop last , */
203 		clob_last(wordv[1], '\0');	/* drop last " */
204 		wordv[1]++;			/* drop first " */
205 		clob_last(wordv[3], '\0');	/* drop : on line number */
206 		wordv[2] = wordv[1];	/* overwrite "line" */
207 		wordv++;		/*compensate*/
208 		currentfilename = wordv[1];
209 		language = INCC;
210 		return(C_TRUE);
211 	}
212 	return(C_UNKNOWN);
213 }	/* end of ccom */
214 /*
215  *	Do the error message from the Richie C Compiler for the PDP11,
216  *	which has this source:
217  *
218  *	if (filename[0])
219  *		fprintf(stderr, "%s:", filename);
220  *	fprintf(stderr, "%d: ", line);
221  *
222  */
223 Errorclass richieccom()
224 {
225 	reg	char	*cp;
226 	reg	char	**nwordv;
227 		char	*file;
228 
229 	if (lastchar(wordv[1]) == ':'){
230 		cp = wordv[1] + strlen(wordv[1]) - 1;
231 		while (isdigit(*--cp))
232 			continue;
233 		if (*cp == ':'){
234 			clob_last(wordv[1], '\0');	/* last : */
235 			*cp = '\0';			/* first : */
236 			file = wordv[1];
237 			nwordv = wordvsplice(1, wordc, wordv+1);
238 			nwordv[0] = file;
239 			nwordv[1] = cp + 1;
240 			wordc += 1;
241 			wordv = nwordv - 1;
242 			language = INCC;
243 			currentfilename = wordv[1];
244 			return(C_TRUE);
245 		}
246 	}
247 	return(C_UNKNOWN);
248 }
249 
250 Errorclass lint0()
251 {
252 	reg	char	**nwordv;
253 		char	*line, *file;
254 	/*
255 	 *	Attempt a match for the new lint style normal compiler
256 	 *	error messages, of the form
257 	 *
258 	 *	printf("%s(%d): %s\n", filename, linenumber, message);
259 	 */
260 	if (wordc >= 2){
261 		if (   (lastchar(wordv[1]) == ':')
262 		    && (next_lastchar(wordv[1]) == ')')
263 		) {
264 			clob_last(wordv[1], '\0'); /* colon */
265 			if (persperdexplode(wordv[1], &line, &file)){
266 				nwordv = wordvsplice(1, wordc, wordv+1);
267 				nwordv[0] = file;	/* file name */
268 				nwordv[1] = line;	/* line number */
269 				wordc += 1;
270 				wordv = nwordv - 1;
271 				language = INLINT;
272 				return(C_TRUE);
273 			}
274 			wordv[1][strlen(wordv[1])] = ':';
275 		}
276 	}
277 	return (C_UNKNOWN);
278 }
279 
280 Errorclass lint1()
281 {
282 	char	*line1, *line2;
283 	char	*file1, *file2;
284 	char	**nwordv1, **nwordv2;
285 
286 	/*
287 	 *	Now, attempt a match for the various errors that lint
288 	 *	can complain about.
289 	 *
290 	 *	Look first for type 1 lint errors
291 	 */
292 	if (strcmp(wordv[wordc-1], "::") == 0){
293 	 /*
294   	  * %.7s, arg. %d used inconsistently %s(%d) :: %s(%d)
295   	  * %.7s value used inconsistently %s(%d) :: %s(%d)
296   	  * %.7s multiply declared %s(%d) :: %s(%d)
297   	  * %.7s value declared inconsistently %s(%d) :: %s(%d)
298   	  * %.7s function value type must be declared before use %s(%d) :: %s(%d)
299 	  */
300 		language = INLINT;
301 		if (    (persperdexplode(wordv[wordc], &line2, &file2))
302 		     && (persperdexplode(wordv[wordc-2], &line1, &file1)) ){
303 			nwordv1 = wordvsplice(2, wordc, wordv+1);
304 			nwordv2 = wordvsplice(2, wordc, wordv+1);
305 			nwordv1[0] = file1; nwordv1[1] = line1;
306 			erroradd(wordc+2, nwordv1, C_TRUE, C_DUPL); /* takes 0 based*/
307 			nwordv2[0] = file2; nwordv2[1] = line2;
308 			wordc = wordc + 2;
309 			wordv = nwordv2 - 1;	/* 1 based */
310 			return(C_TRUE);
311 		}
312 	}
313 	return(C_UNKNOWN);
314 } /* end of lint 1*/
315 
316 Errorclass lint2()
317 {
318 	char	*file;
319 	char	*line;
320 	char	**nwordv;
321 	/*
322 	 *	Look for type 2 lint errors
323 	 *
324 	 *	%.7s used( %s(%d) ), but not defined
325 	 *	%.7s defined( %s(%d) ), but never used
326 	 *	%.7s declared( %s(%d) ), but never used or defined
327 	 *
328 	 *	bufp defined( "./metric.h"(10) ), but never used
329 	 */
330 	if (   (lastchar(wordv[2]) == '(' /* ')' */ )
331 	    && (strcmp(wordv[4], "),") == 0) ){
332 		language = INLINT;
333 		if (persperdexplode(wordv[3], &line, &file)){
334 			nwordv = wordvsplice(2, wordc, wordv+1);
335 			nwordv[0] = file; nwordv[1] = line;
336 			wordc = wordc + 2;
337 			wordv = nwordv - 1;	/* 1 based */
338 			return(C_TRUE);
339 		}
340 	}
341 	return(C_UNKNOWN);
342 } /* end of lint 2*/
343 
344 char	*Lint31[4] = {"returns", "value", "which", "is"};
345 char	*Lint32[6] = {"value", "is", "used,", "but", "none", "returned"};
346 Errorclass lint3()
347 {
348 	if (   (wordvcmp(wordv+2, 4, Lint31) == 0)
349 	    || (wordvcmp(wordv+2, 6, Lint32) == 0) ){
350 		language = INLINT;
351 		return(C_NONSPEC);
352 	}
353 	return(C_UNKNOWN);
354 }
355 
356 /*
357  *	Special word vectors for use by F77 recognition
358  */
359 char	*F77_fatal[3] = {"Compiler", "error", "line"};
360 char	*F77_error[3] = {"Error", "on", "line"};
361 char	*F77_warning[3] = {"Warning", "on", "line"};
362 f77()
363 {
364 	char	**nwordv;
365 	/*
366 	 *	look for f77 errors:
367 	 *	Error messages from /usr/src/cmd/f77/error.c, with
368 	 *	these printf formats:
369 	 *
370 	 *		Compiler error line %d of %s: %s
371 	 *		Error on line %d of %s: %s
372 	 *		Warning on line %d of %s: %s
373 	 */
374 	if (wordc < 6)
375 		return(C_UNKNOWN);
376 	if (	(lastchar(wordv[6]) == ':')
377 	    &&(
378 	       (wordvcmp(wordv+1, 3, F77_fatal) == 0)
379 	    || (wordvcmp(wordv+1, 3, F77_error) == 0)
380 	    || (wordvcmp(wordv+1, 3, F77_warning) == 0) )
381 	){
382 		language = INF77;
383 		nwordv = wordvsplice(2, wordc, wordv+1);
384 		nwordv[0] = wordv[6];
385 		clob_last(nwordv[0],'\0');
386 		nwordv[1] = wordv[4];
387 		wordc += 2;
388 		wordv = nwordv - 1;	/* 1 based */
389 		return(C_TRUE);
390 	}
391 	return(C_UNKNOWN);
392 } /* end of f77 */
393 
394 char	*Make_Croak[3] = {"***", "Error", "code"};
395 char	*Make_NotRemade[5] = {"not", "remade", "because", "of", "errors"};
396 Errorclass make()
397 {
398 	if (wordvcmp(wordv+1, 3, Make_Croak) == 0){
399 		language = INMAKE;
400 		return(C_SYNC);
401 	}
402 	if  (wordvcmp(wordv+2, 5, Make_NotRemade) == 0){
403 		language = INMAKE;
404 		return(C_SYNC);
405 	}
406 	return(C_UNKNOWN);
407 }
408 Errorclass ri()
409 {
410 /*
411  *	Match an error message produced by ri; here is the
412  *	procedure yanked from the distributed version of ri
413  *	April 24, 1980.
414  *
415  *	serror(str, x1, x2, x3)
416  *		char str[];
417  *		char *x1, *x2, *x3;
418  *	{
419  *		extern int yylineno;
420  *
421  *		putc('"', stdout);
422  *		fputs(srcfile, stdout);
423  *		putc('"', stdout);
424  *		fprintf(stdout, " %d: ", yylineno);
425  *		fprintf(stdout, str, x1, x2, x3);
426  *		fprintf(stdout, "\n");
427  *		synerrs++;
428  *	}
429  */
430 	if (  (firstchar(wordv[1]) == '"')
431 	    &&(lastchar(wordv[1]) == '"')
432 	    &&(lastchar(wordv[2]) == ':')
433 	    &&(isdigit(firstchar(wordv[2]))) ){
434 		clob_last(wordv[1], '\0');	/* drop the last " */
435 		wordv[1]++;	/* skip over the first " */
436 		clob_last(wordv[2], '\0');
437 		language = INRI;
438 		return(C_TRUE);
439 	}
440 	return(C_UNKNOWN);
441 }
442 
443 Errorclass catchall()
444 {
445 	/*
446 	 *	Catches random things.
447 	 */
448 	language = INUNKNOWN;
449 	return(C_NONSPEC);
450 } /* end of catch all*/
451