xref: /netbsd-src/usr.bin/error/input.c (revision f4748aaa01faf324805f9747191535eb6600f82c)
1 /*	$NetBSD: input.c,v 1.18 2020/01/10 18:35:29 christos 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[] = "@(#)input.c	8.1 (Berkeley) 6/6/93";
36 #endif
37 __RCSID("$NetBSD: input.c,v 1.18 2020/01/10 18:35:29 christos Exp $");
38 #endif /* not lint */
39 
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include "error.h"
45 
46 int cur_wordc;		/* how long the current error message is */
47 char **cur_wordv;	/* the actual error message */
48 
49 static Errorclass catchall(void);
50 static Errorclass cpp(void);
51 static Errorclass f77(void);
52 static Errorclass lint0(void);
53 static Errorclass lint1(void);
54 static Errorclass lint2(void);
55 static Errorclass lint3(void);
56 static Errorclass make(void);
57 static Errorclass mod2(void);
58 static Errorclass onelong(void);
59 static Errorclass pccccom(void);	/* Portable C Compiler C Compiler */
60 static Errorclass ri(void);
61 static Errorclass richieccom(void);	/* Richie Compiler for 11 */
62 static Errorclass gcc45ccom(void);	/* gcc45+ */
63 static Errorclass troff(void);
64 
65 /*
66  * Eat all of the lines in the input file, attempting to categorize
67  * them by their various flavors
68  */
69 void
70 eaterrors(int *r_errorc, Eptr **r_errorv)
71 {
72 	Errorclass errorclass = C_SYNC;
73 	char *line;
74 	size_t inbuflen;
75 
76     for (;;) {
77 	line = NULL;
78 	inbuflen = 0;
79 	if (getline(&line, &inbuflen, errorfile) == -1)
80 		break;
81 	wordvbuild(line, &cur_wordc, &cur_wordv);
82 
83 	/*
84 	 * for convenience, convert cur_wordv to be 1 based, instead
85 	 * of 0 based.
86 	 */
87 	cur_wordv -= 1;
88 	if (cur_wordc > 0 &&
89 	   ((( errorclass = onelong() ) != C_UNKNOWN)
90 	   || (( errorclass = cpp() ) != C_UNKNOWN)
91 	   || (( errorclass = gcc45ccom() ) != C_UNKNOWN)
92 	   || (( errorclass = pccccom() ) != C_UNKNOWN)
93 	   || (( errorclass = richieccom() ) != C_UNKNOWN)
94 	   || (( errorclass = lint0() ) != C_UNKNOWN)
95 	   || (( errorclass = lint1() ) != C_UNKNOWN)
96 	   || (( errorclass = lint2() ) != C_UNKNOWN)
97 	   || (( errorclass = lint3() ) != C_UNKNOWN)
98 	   || (( errorclass = make() ) != C_UNKNOWN)
99 	   || (( errorclass = f77() ) != C_UNKNOWN)
100 	   || ((errorclass = pi() ) != C_UNKNOWN)
101 	   || (( errorclass = ri() )!= C_UNKNOWN)
102 	   || (( errorclass = mod2() )!= C_UNKNOWN)
103 	   || (( errorclass = troff() )!= C_UNKNOWN))
104 	) ;
105 	else
106 		errorclass = catchall();
107 	if (cur_wordc)
108 		erroradd(cur_wordc, cur_wordv+1, errorclass, C_UNKNOWN);
109     }
110 #ifdef FULLDEBUG
111     printf("%d errorentrys\n", nerrors);
112 #endif
113     arrayify(r_errorc, r_errorv, er_head);
114 }
115 
116 /*
117  * create a new error entry, given a zero based array and count
118  */
119 void
120 erroradd(int errorlength, char **errorv, Errorclass errorclass,
121 	 Errorclass errorsubclass)
122 {
123 	Eptr newerror;
124 	const char *cp;
125 
126 	if (errorclass == C_TRUE) {
127 		/* check canonicalization of the second argument*/
128 		for (cp = errorv[1]; *cp && isdigit((unsigned char)*cp); cp++)
129 			continue;
130 		errorclass = (*cp == '\0') ? C_TRUE : C_NONSPEC;
131 #ifdef FULLDEBUG
132 		if (errorclass != C_TRUE)
133 			printf("The 2nd word, \"%s\" is not a number.\n",
134 				errorv[1]);
135 #endif
136 	}
137 	if (errorlength > 0) {
138 		newerror = Calloc(1, sizeof(Edesc));
139 		newerror->error_language = language; /* language is global */
140 		newerror->error_text = errorv;
141 		newerror->error_lgtext = errorlength;
142 		if (errorclass == C_TRUE)
143 			newerror->error_line = atoi(errorv[1]);
144 		newerror->error_e_class = errorclass;
145 		newerror->error_s_class = errorsubclass;
146 		switch (newerror->error_e_class = discardit(newerror)) {
147 			case C_SYNC:		nsyncerrors++; break;
148 			case C_DISCARD: 	ndiscard++; break;
149 			case C_NULLED:		nnulled++; break;
150 			case C_NONSPEC:		nnonspec++; break;
151 			case C_THISFILE: 	nthisfile++; break;
152 			case C_TRUE:		ntrue++; break;
153 			case C_UNKNOWN:		nunknown++; break;
154 			case C_IGNORE:		nignore++; break;
155 		}
156 		newerror->error_next = er_head;
157 		er_head = newerror;
158 		newerror->error_no = nerrors++;
159 	}	/* length > 0 */
160 }
161 
162 static Errorclass
163 onelong(void)
164 {
165 	char **nwordv;
166 
167 	if (cur_wordc == 1 && language != INLD) {
168 		/*
169 		 * We have either:
170 		 *	a) file name from cc
171 		 *	b) Assembler telling world that it is complaining
172 		 *	c) Noise from make ("Stop.")
173 		 *	c) Random noise
174 		 */
175 		cur_wordc = 0;
176 		if (strcmp(cur_wordv[1], "Stop.") == 0) {
177 			language = INMAKE;
178 			return (C_SYNC);
179 		}
180 		if (strcmp(cur_wordv[1], "Assembler:") == 0) {
181 			/* assembler always alerts us to what happened*/
182 			language = INAS;
183 			return (C_SYNC);
184 		} else
185 		if (strcmp(cur_wordv[1], "Undefined:") == 0) {
186 			/* loader complains about unknown symbols*/
187 			language = INLD;
188 			return (C_SYNC);
189 		}
190 		if (lastchar(cur_wordv[1]) == ':') {
191 			/* cc tells us what file we are in */
192 			currentfilename = cur_wordv[1];
193 			(void)substitute(currentfilename, ':', '\0');
194 			language = INCC;
195 			return (C_SYNC);
196 		}
197 	} else
198 	if (cur_wordc == 1 && language == INLD) {
199 		nwordv = Calloc(4, sizeof(char *));
200 		nwordv[0] = Strdup("ld:");	/* XXX leaked */
201 		nwordv[1] = cur_wordv[1];
202 		nwordv[2] = Strdup("is");	/* XXX leaked */
203 		nwordv[3] = Strdup("undefined.");/* XXX leaked */
204 		cur_wordc = 4;
205 		cur_wordv = nwordv - 1;
206 		return (C_NONSPEC);
207 	} else
208 	if (cur_wordc == 1) {
209 		return (C_SYNC);
210 	}
211 	return (C_UNKNOWN);
212 }	/* end of one long */
213 
214 static Errorclass
215 cpp(void)
216 {
217 	/*
218 	 * Now attempt a cpp error message match
219 	 * Examples:
220 	 *	./morse.h: 23: undefined control
221 	 *	morsesend.c: 229: MAGNIBBL: argument mismatch
222 	 *	morsesend.c: 237: MAGNIBBL: argument mismatch
223 	 *	test1.c: 6: undefined control
224 	 */
225 	if (cur_wordc < 3)
226 		return (C_UNKNOWN);
227 	if (language != INLD		/* loader errors have almost same fmt */
228 	    && lastchar(cur_wordv[1]) == ':'
229 	    && isdigit((unsigned char)firstchar(cur_wordv[2]))
230 	    && lastchar(cur_wordv[2]) == ':') {
231 		language = INCPP;
232 		clob_last(cur_wordv[1], '\0');
233 		clob_last(cur_wordv[2], '\0');
234 		return (C_TRUE);
235 	}
236 	return (C_UNKNOWN);
237 }	/*end of cpp*/
238 
239 static Errorclass
240 pccccom(void)
241 {
242 	/*
243 	 * Now attempt a ccom error message match:
244 	 * Examples:
245 	 *	"morsesend.c", line 237: operands of & have incompatible types
246 	 *	"test.c", line 7: warning: old-fashioned initialization: use =
247 	 *	"subdir.d/foo2.h", line 1: illegal initialization
248 	 */
249 	if (cur_wordc < 4)
250 		return (C_UNKNOWN);
251 	if (firstchar(cur_wordv[1]) == '"'
252 	    && lastchar(cur_wordv[1]) == ','
253 	    && next_lastchar(cur_wordv[1]) == '"'
254 	    && strcmp(cur_wordv[2], "line") == 0
255 	    && isdigit((unsigned char)firstchar(cur_wordv[3]))
256 	    && lastchar(cur_wordv[3]) == ':') {
257 		clob_last(cur_wordv[1], '\0');	/* drop last , */
258 		clob_last(cur_wordv[1], '\0');	/* drop last " */
259 		cur_wordv[1]++;			/* drop first " */
260 		clob_last(cur_wordv[3], '\0');	/* drop : on line number */
261 		cur_wordv[2] = cur_wordv[1];	/* overwrite "line" */
262 		cur_wordv++;		/*compensate*/
263 		cur_wordc--;
264 		currentfilename = cur_wordv[1];
265 		language = INCC;
266 		return (C_TRUE);
267 	}
268 	return (C_UNKNOWN);
269 }	/* end of ccom */
270 
271 /*
272  * Do the error message from gcc 4.5+ which prints:
273  *
274  *	fprintf(stderr, "%s:%d:%d: ", filename, line, column);
275  */
276 
277 static Errorclass
278 gcc45ccom(void)
279 {
280 	char *cp, *ccp;
281 	char **nwordv;
282 	char *file;
283 
284 	if (cur_wordc < 2)
285 		return C_UNKNOWN;
286 
287 	if (lastchar(cur_wordv[1]) != ':')
288 		return C_UNKNOWN;
289 
290 	cp = cur_wordv[1] + strlen(cur_wordv[1]) - 1;
291 	while (isdigit((unsigned char)*--cp))
292 		continue;
293 	if (*cp != ':')
294 		return C_UNKNOWN;
295 
296 	ccp = cp;
297 	while (isdigit((unsigned char)*--cp))
298 		continue;
299 	if (*cp != ':')
300 		return C_UNKNOWN;
301 
302 	clob_last(cur_wordv[1], '\0');	/* last : */
303 	*ccp = '\0';			/* middle : */
304 	*cp = '\0';			/* first : */
305 	file = cur_wordv[1];
306 #ifdef notyet
307 #define EHEAD 2
308 #else
309 #define EHEAD 1	/* Nothing to do with column info yet */
310 #endif
311 	nwordv = wordvsplice(EHEAD, cur_wordc, cur_wordv + 1);
312 	nwordv[0] = file;
313 	nwordv[1] = cp + 1;
314 #ifdef notyet
315 	nwordv[2] = ccp + 1;
316 #endif
317 	cur_wordc += 1;
318 	cur_wordv = nwordv - 1;
319 	language = INCC;
320 	currentfilename = cur_wordv[1];
321 	return C_TRUE;
322 }
323 
324 /*
325  * Do the error message from the Richie C Compiler for the PDP11,
326  * which has this source:
327  *
328  *	if (filename[0])
329  *		fprintf(stderr, "%s:", filename);
330  *	fprintf(stderr, "%d: ", line);
331  *
332  */
333 
334 static Errorclass
335 richieccom(void)
336 {
337 	char *cp;
338 	char **nwordv;
339 	char *file;
340 
341 	if (cur_wordc < 2)
342 		return (C_UNKNOWN);
343 
344 	if (lastchar(cur_wordv[1]) == ':') {
345 		cp = cur_wordv[1] + strlen(cur_wordv[1]) - 1;
346 		while (isdigit((unsigned char)*--cp))
347 			continue;
348 		if (*cp == ':') {
349 			clob_last(cur_wordv[1], '\0');	/* last : */
350 			*cp = '\0';			/* first : */
351 			file = cur_wordv[1];
352 			nwordv = wordvsplice(1, cur_wordc, cur_wordv+1);
353 			nwordv[0] = file;
354 			nwordv[1] = cp + 1;
355 			cur_wordc += 1;
356 			cur_wordv = nwordv - 1;
357 			language = INCC;
358 			currentfilename = cur_wordv[1];
359 			return (C_TRUE);
360 		}
361 	}
362 	return (C_UNKNOWN);
363 }
364 
365 static Errorclass
366 lint0(void)
367 {
368 	char **nwordv;
369 	char *line, *file;
370 
371 	/*
372 	 * Attempt a match for the new lint style normal compiler
373 	 * error messages, of the form
374 	 *
375 	 *	printf("%s(%d): %s\n", filename, linenumber, message);
376 	 */
377 	if (cur_wordc < 2)
378 		return (C_UNKNOWN);
379 
380 	if (lastchar(cur_wordv[1]) == ':'
381 	    && next_lastchar(cur_wordv[1]) == ')') {
382 		clob_last(cur_wordv[1], '\0'); /* colon */
383 		if (persperdexplode(cur_wordv[1], &line, &file)) {
384 			nwordv = wordvsplice(1, cur_wordc, cur_wordv+1);
385 			nwordv[0] = file;	/* file name */
386 			nwordv[1] = line;	/* line number */
387 			cur_wordc += 1;
388 			cur_wordv = nwordv - 1;
389 			language = INLINT;
390 			return (C_TRUE);
391 		}
392 		cur_wordv[1][strlen(cur_wordv[1])] = ':';
393 	}
394 	return (C_UNKNOWN);
395 }
396 
397 static Errorclass
398 lint1(void)
399 {
400 	char *line1 = NULL, *line2 = NULL;
401 	char *file1 = NULL, *file2 = NULL;
402 	char **nwordv1, **nwordv2;
403 
404 	/*
405 	 * Now, attempt a match for the various errors that lint
406 	 * can complain about.
407 	 *
408 	 * Look first for type 1 lint errors
409 	 */
410 	if (cur_wordc > 1 && strcmp(cur_wordv[cur_wordc-1], "::") == 0) {
411 	 /*
412   	  * %.7s, arg. %d used inconsistently %s(%d) :: %s(%d)
413   	  * %.7s value used inconsistently %s(%d) :: %s(%d)
414   	  * %.7s multiply declared %s(%d) :: %s(%d)
415   	  * %.7s value declared inconsistently %s(%d) :: %s(%d)
416   	  * %.7s function value type must be declared before use %s(%d) :: %s(%d)
417 	  */
418 		language = INLINT;
419 		if (cur_wordc > 2
420 		    && persperdexplode(cur_wordv[cur_wordc], &line2, &file2)
421 		    && persperdexplode(cur_wordv[cur_wordc-2], &line1, &file1)) {
422 			nwordv1 = wordvsplice(2, cur_wordc, cur_wordv+1);
423 			nwordv2 = wordvsplice(2, cur_wordc, cur_wordv+1);
424 			nwordv1[0] = file1;
425 			nwordv1[1] = line1;
426 			erroradd(cur_wordc+2, nwordv1, C_TRUE, C_DUPL); /* takes 0 based*/
427 			nwordv2[0] = file2;
428 			nwordv2[1] = line2;
429 			cur_wordc = cur_wordc + 2;
430 			cur_wordv = nwordv2 - 1;	/* 1 based */
431 			return (C_TRUE);
432 		}
433 	}
434 	if (file2)
435 		free(file2);
436 	if (file1)
437 		free(file1);
438 	if (line2)
439 		free(line2);
440 	if (line1)
441 		free(line1);
442 	return (C_UNKNOWN);
443 } /* end of lint 1*/
444 
445 static Errorclass
446 lint2(void)
447 {
448 	char *file;
449 	char *line;
450 	char **nwordv;
451 
452 	/*
453 	 * Look for type 2 lint errors
454 	 *
455 	 *	%.7s used( %s(%d) ), but not defined
456 	 *	%.7s defined( %s(%d) ), but never used
457 	 *	%.7s declared( %s(%d) ), but never used or defined
458 	 *
459 	 *	bufp defined( "./metric.h"(10) ), but never used
460 	 */
461 	if (cur_wordc < 5)
462 		return (C_UNKNOWN);
463 
464 	if (lastchar(cur_wordv[2]) == '(' /* ')' */
465 	    && strcmp(cur_wordv[4], "),") == 0) {
466 		language = INLINT;
467 		if (persperdexplode(cur_wordv[3], &line, &file)) {
468 			nwordv = wordvsplice(2, cur_wordc, cur_wordv+1);
469 			nwordv[0] = file;
470 			nwordv[1] = line;
471 			cur_wordc = cur_wordc + 2;
472 			cur_wordv = nwordv - 1;	/* 1 based */
473 			return (C_TRUE);
474 		}
475 	}
476 	return (C_UNKNOWN);
477 } /* end of lint 2*/
478 
479 #if 0 /* not const-correct */
480 static char *Lint31[4] = {"returns", "value", "which", "is"};
481 static char *Lint32[6] = {"value", "is", "used,", "but", "none", "returned"};
482 #else
483 DECL_STRINGS_4(static, Lint31,
484 	       "returns", "value", "which", "is");
485 DECL_STRINGS_6(static, Lint32,
486 	       "value", "is", "used,", "but", "none", "returned");
487 #endif
488 
489 static Errorclass
490 lint3(void)
491 {
492 	if (cur_wordc < 3)
493 		return (C_UNKNOWN);
494 	if (wordvcmp(cur_wordv+2, 4, Lint31) == 0
495 	    || wordvcmp(cur_wordv+2, 6, Lint32) == 0) {
496 		language = INLINT;
497 		return (C_NONSPEC);
498 	}
499 	return (C_UNKNOWN);
500 }
501 
502 /*
503  * Special word vectors for use by F77 recognition
504  */
505 #if 0 /* not const-correct */
506 static char *F77_fatal[3] = {"Compiler", "error", "line"};
507 static char *F77_error[3] = {"Error", "on", "line"};
508 static char *F77_warning[3] = {"Warning", "on", "line"};
509 static char *F77_no_ass[3] = {"Error.","No","assembly."};
510 #else
511 DECL_STRINGS_3(static, F77_fatal, "Compiler", "error", "line");
512 DECL_STRINGS_3(static, F77_error, "Error", "on", "line");
513 DECL_STRINGS_3(static, F77_warning, "Warning", "on", "line");
514 DECL_STRINGS_3(static, F77_no_ass, "Error.", "No", "assembly.");
515 #endif
516 
517 static Errorclass
518 f77(void)
519 {
520 	char **nwordv;
521 
522 	/*
523 	 * look for f77 errors:
524 	 * Error messages from /usr/src/cmd/f77/error.c, with
525 	 * these printf formats:
526 	 *
527 	 *	Compiler error line %d of %s: %s
528 	 *	Error on line %d of %s: %s
529 	 *	Warning on line %d of %s: %s
530 	 *	Error.  No assembly.
531 	 */
532 	if (cur_wordc == 3 && wordvcmp(cur_wordv+1, 3, F77_no_ass) == 0) {
533 		cur_wordc = 0;
534 		return (C_SYNC);
535 	}
536 	if (cur_wordc < 6)
537 		return (C_UNKNOWN);
538 	if (lastchar(cur_wordv[6]) == ':'
539 	    && (
540 		wordvcmp(cur_wordv+1, 3, F77_fatal) == 0
541 		|| wordvcmp(cur_wordv+1, 3, F77_error) == 0
542 		|| wordvcmp(cur_wordv+1, 3, F77_warning) == 0
543 	       )
544 	) {
545 		language = INF77;
546 		nwordv = wordvsplice(2, cur_wordc, cur_wordv+1);
547 		nwordv[0] = cur_wordv[6];
548 		clob_last(nwordv[0],'\0');
549 		nwordv[1] = cur_wordv[4];
550 		cur_wordc += 2;
551 		cur_wordv = nwordv - 1;	/* 1 based */
552 		return (C_TRUE);
553 	}
554 	return (C_UNKNOWN);
555 } /* end of f77 */
556 
557 #if 0 /* not const-correct */
558 static char *Make_Croak[3] = {"***", "Error", "code"};
559 static char *Make_NotRemade[5] = {"not", "remade", "because", "of", "errors"};
560 #else
561 DECL_STRINGS_3(static, Make_Croak, "***", "Error", "code");
562 DECL_STRINGS_5(static, Make_NotRemade,
563 	       "not", "remade", "because", "of", "errors");
564 #endif
565 
566 static Errorclass
567 make(void)
568 {
569 	if (wordvcmp(cur_wordv+1, 3, Make_Croak) == 0) {
570 		language = INMAKE;
571 		return (C_SYNC);
572 	}
573 	if (wordvcmp(cur_wordv+2, 5, Make_NotRemade) == 0) {
574 		language = INMAKE;
575 		return (C_SYNC);
576 	}
577 	return (C_UNKNOWN);
578 }
579 
580 static Errorclass
581 ri(void)
582 {
583 /*
584  * Match an error message produced by ri; here is the
585  * procedure yanked from the distributed version of ri
586  * April 24, 1980.
587  *
588  *	serror(str, x1, x2, x3)
589  *		char str[];
590  *		char *x1, *x2, *x3;
591  *	{
592  *		extern int yylineno;
593  *
594  *		putc('"', stdout);
595  *		fputs(srcfile, stdout);
596  *		putc('"', stdout);
597  *		fprintf(stdout, " %d: ", yylineno);
598  *		fprintf(stdout, str, x1, x2, x3);
599  *		fprintf(stdout, "\n");
600  *		synerrs++;
601  *	}
602  */
603 	if (cur_wordc < 3)
604 		return (C_UNKNOWN);
605 	if (firstchar(cur_wordv[1]) == '"'
606 	    && lastchar(cur_wordv[1]) == '"'
607 	    && lastchar(cur_wordv[2]) == ':'
608 	    && isdigit((unsigned char)firstchar(cur_wordv[2]))) {
609 		clob_last(cur_wordv[1], '\0');	/* drop the last " */
610 		cur_wordv[1]++;			/* skip over the first " */
611 		clob_last(cur_wordv[2], '\0');
612 		language = INRI;
613 		return (C_TRUE);
614 	}
615 	return (C_UNKNOWN);
616 }
617 
618 static Errorclass
619 catchall(void)
620 {
621 	/*
622 	 * Catches random things.
623 	 */
624 	language = INUNKNOWN;
625 	return (C_NONSPEC);
626 } /* end of catch all*/
627 
628 static Errorclass
629 troff(void)
630 {
631 	/*
632 	 * troff source error message, from eqn, bib, tbl...
633 	 * Just like pcc ccom, except uses `'
634 	 */
635 	if (cur_wordc < 4)
636 		return (C_UNKNOWN);
637 
638 	if (firstchar(cur_wordv[1]) == '`'
639 	    && lastchar(cur_wordv[1]) == ','
640 	    && next_lastchar(cur_wordv[1]) == '\''
641 	    && strcmp(cur_wordv[2], "line") == 0
642 	    && isdigit((unsigned char)firstchar(cur_wordv[3]))
643 	    && lastchar(cur_wordv[3]) == ':') {
644 		clob_last(cur_wordv[1], '\0');	/* drop last , */
645 		clob_last(cur_wordv[1], '\0');	/* drop last " */
646 		cur_wordv[1]++;			/* drop first " */
647 		clob_last(cur_wordv[3], '\0');	/* drop : on line number */
648 		cur_wordv[2] = cur_wordv[1];	/* overwrite "line" */
649 		cur_wordv++;			/*compensate*/
650 		currentfilename = cur_wordv[1];
651 		language = INTROFF;
652 		return (C_TRUE);
653 	}
654 	return (C_UNKNOWN);
655 }
656 
657 static Errorclass
658 mod2(void)
659 {
660 	/*
661 	 * for decwrl modula2 compiler (powell)
662 	 */
663 	if (cur_wordc < 5)
664 		return (C_UNKNOWN);
665 	if ((strcmp(cur_wordv[1], "!!!") == 0		/* early version */
666 	     || strcmp(cur_wordv[1], "File") == 0)	/* later version */
667 	    && lastchar(cur_wordv[2]) == ','		/* file name */
668 	    && strcmp(cur_wordv[3], "line") == 0
669 	    && isdigit((unsigned char)firstchar(cur_wordv[4]))	/* line number */
670 	    && lastchar(cur_wordv[4]) == ':'	/* line number */
671 	) {
672 		clob_last(cur_wordv[2], '\0');	/* drop last , on file name */
673 		clob_last(cur_wordv[4], '\0');	/* drop last : on line number */
674 		cur_wordv[3] = cur_wordv[2];	/* file name on top of "line" */
675 		cur_wordv += 2;
676 		cur_wordc -= 2;
677 		currentfilename = cur_wordv[1];
678 		language = INMOD2;
679 		return (C_TRUE);
680 	}
681 	return (C_UNKNOWN);
682 }
683