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 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 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 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 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 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 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 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 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 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 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 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 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 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 524 catchall(void) 525 { 526 /* 527 * Catches random things. 528 */ 529 language = INUNKNOWN; 530 return (C_NONSPEC); 531 } 532 533 Errorclass 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 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 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