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