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