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