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 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 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 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 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 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 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 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 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 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 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 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 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 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 519 catchall(void) 520 { 521 /* 522 * Catches random things. 523 */ 524 language = INUNKNOWN; 525 return (C_NONSPEC); 526 } 527 528 Errorclass 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 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 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