1 /* $NetBSD: input.c,v 1.16 2009/08/13 06:59:37 dholland Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/6/93"; 36 #endif 37 __RCSID("$NetBSD: input.c,v 1.16 2009/08/13 06:59:37 dholland Exp $"); 38 #endif /* not lint */ 39 40 #include <stdio.h> 41 #include <ctype.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include "error.h" 45 46 int cur_wordc; /* how long the current error message is */ 47 char **cur_wordv; /* the actual error message */ 48 49 static Errorclass catchall(void); 50 static Errorclass cpp(void); 51 static Errorclass f77(void); 52 static Errorclass lint0(void); 53 static Errorclass lint1(void); 54 static Errorclass lint2(void); 55 static Errorclass lint3(void); 56 static Errorclass make(void); 57 static Errorclass mod2(void); 58 static Errorclass onelong(void); 59 static Errorclass pccccom(void); /* Portable C Compiler C Compiler */ 60 static Errorclass ri(void); 61 static Errorclass richieccom(void); /* Richie Compiler for 11 */ 62 static Errorclass troff(void); 63 64 /* 65 * Eat all of the lines in the input file, attempting to categorize 66 * them by their various flavors 67 */ 68 void 69 eaterrors(int *r_errorc, Eptr **r_errorv) 70 { 71 Errorclass errorclass = C_SYNC; 72 char *line; 73 const char *inbuffer; 74 size_t inbuflen; 75 76 for (;;) { 77 if ((inbuffer = fgetln(errorfile, &inbuflen)) == NULL) 78 break; 79 line = Calloc(inbuflen + 1, sizeof(char)); 80 memcpy(line, inbuffer, inbuflen); 81 line[inbuflen] = '\0'; 82 wordvbuild(line, &cur_wordc, &cur_wordv); 83 84 /* 85 * for convenience, convert cur_wordv to be 1 based, instead 86 * of 0 based. 87 */ 88 cur_wordv -= 1; 89 if (cur_wordc > 0 && 90 ((( errorclass = onelong() ) != C_UNKNOWN) 91 || (( errorclass = cpp() ) != C_UNKNOWN) 92 || (( errorclass = pccccom() ) != C_UNKNOWN) 93 || (( errorclass = richieccom() ) != C_UNKNOWN) 94 || (( errorclass = lint0() ) != C_UNKNOWN) 95 || (( errorclass = lint1() ) != C_UNKNOWN) 96 || (( errorclass = lint2() ) != C_UNKNOWN) 97 || (( errorclass = lint3() ) != C_UNKNOWN) 98 || (( errorclass = make() ) != C_UNKNOWN) 99 || (( errorclass = f77() ) != C_UNKNOWN) 100 || ((errorclass = pi() ) != C_UNKNOWN) 101 || (( errorclass = ri() )!= C_UNKNOWN) 102 || (( errorclass = mod2() )!= C_UNKNOWN) 103 || (( errorclass = troff() )!= C_UNKNOWN)) 104 ) ; 105 else 106 errorclass = catchall(); 107 if (cur_wordc) 108 erroradd(cur_wordc, cur_wordv+1, errorclass, C_UNKNOWN); 109 } 110 #ifdef FULLDEBUG 111 printf("%d errorentrys\n", nerrors); 112 #endif 113 arrayify(r_errorc, r_errorv, er_head); 114 } 115 116 /* 117 * create a new error entry, given a zero based array and count 118 */ 119 void 120 erroradd(int errorlength, char **errorv, Errorclass errorclass, 121 Errorclass errorsubclass) 122 { 123 Eptr newerror; 124 const char *cp; 125 126 if (errorclass == C_TRUE) { 127 /* check canonicalization of the second argument*/ 128 for (cp = errorv[1]; *cp && isdigit((unsigned char)*cp); cp++) 129 continue; 130 errorclass = (*cp == '\0') ? C_TRUE : C_NONSPEC; 131 #ifdef FULLDEBUG 132 if (errorclass != C_TRUE) 133 printf("The 2nd word, \"%s\" is not a number.\n", 134 errorv[1]); 135 #endif 136 } 137 if (errorlength > 0) { 138 newerror = Calloc(1, sizeof(Edesc)); 139 newerror->error_language = language; /* language is global */ 140 newerror->error_text = errorv; 141 newerror->error_lgtext = errorlength; 142 if (errorclass == C_TRUE) 143 newerror->error_line = atoi(errorv[1]); 144 newerror->error_e_class = errorclass; 145 newerror->error_s_class = errorsubclass; 146 switch (newerror->error_e_class = discardit(newerror)) { 147 case C_SYNC: nsyncerrors++; break; 148 case C_DISCARD: ndiscard++; break; 149 case C_NULLED: nnulled++; break; 150 case C_NONSPEC: nnonspec++; break; 151 case C_THISFILE: nthisfile++; break; 152 case C_TRUE: ntrue++; break; 153 case C_UNKNOWN: nunknown++; break; 154 case C_IGNORE: nignore++; break; 155 } 156 newerror->error_next = er_head; 157 er_head = newerror; 158 newerror->error_no = nerrors++; 159 } /* length > 0 */ 160 } 161 162 static Errorclass 163 onelong(void) 164 { 165 char **nwordv; 166 167 if (cur_wordc == 1 && language != INLD) { 168 /* 169 * We have either: 170 * a) file name from cc 171 * b) Assembler telling world that it is complaining 172 * c) Noise from make ("Stop.") 173 * c) Random noise 174 */ 175 cur_wordc = 0; 176 if (strcmp(cur_wordv[1], "Stop.") == 0) { 177 language = INMAKE; 178 return (C_SYNC); 179 } 180 if (strcmp(cur_wordv[1], "Assembler:") == 0) { 181 /* assembler always alerts us to what happened*/ 182 language = INAS; 183 return (C_SYNC); 184 } else 185 if (strcmp(cur_wordv[1], "Undefined:") == 0) { 186 /* loader complains about unknown symbols*/ 187 language = INLD; 188 return (C_SYNC); 189 } 190 if (lastchar(cur_wordv[1]) == ':') { 191 /* cc tells us what file we are in */ 192 currentfilename = cur_wordv[1]; 193 (void)substitute(currentfilename, ':', '\0'); 194 language = INCC; 195 return (C_SYNC); 196 } 197 } else 198 if (cur_wordc == 1 && language == INLD) { 199 nwordv = Calloc(4, sizeof(char *)); 200 nwordv[0] = Strdup("ld:"); /* XXX leaked */ 201 nwordv[1] = cur_wordv[1]; 202 nwordv[2] = Strdup("is"); /* XXX leaked */ 203 nwordv[3] = Strdup("undefined.");/* XXX leaked */ 204 cur_wordc = 4; 205 cur_wordv = nwordv - 1; 206 return (C_NONSPEC); 207 } else 208 if (cur_wordc == 1) { 209 return (C_SYNC); 210 } 211 return (C_UNKNOWN); 212 } /* end of one long */ 213 214 static Errorclass 215 cpp(void) 216 { 217 /* 218 * Now attempt a cpp error message match 219 * Examples: 220 * ./morse.h: 23: undefined control 221 * morsesend.c: 229: MAGNIBBL: argument mismatch 222 * morsesend.c: 237: MAGNIBBL: argument mismatch 223 * test1.c: 6: undefined control 224 */ 225 if (cur_wordc < 3) 226 return (C_UNKNOWN); 227 if (language != INLD /* loader errors have almost same fmt */ 228 && lastchar(cur_wordv[1]) == ':' 229 && isdigit((unsigned char)firstchar(cur_wordv[2])) 230 && lastchar(cur_wordv[2]) == ':') { 231 language = INCPP; 232 clob_last(cur_wordv[1], '\0'); 233 clob_last(cur_wordv[2], '\0'); 234 return (C_TRUE); 235 } 236 return (C_UNKNOWN); 237 } /*end of cpp*/ 238 239 static Errorclass 240 pccccom(void) 241 { 242 /* 243 * Now attempt a ccom error message match: 244 * Examples: 245 * "morsesend.c", line 237: operands of & have incompatible types 246 * "test.c", line 7: warning: old-fashioned initialization: use = 247 * "subdir.d/foo2.h", line 1: illegal initialization 248 */ 249 if (cur_wordc < 4) 250 return (C_UNKNOWN); 251 if (firstchar(cur_wordv[1]) == '"' 252 && lastchar(cur_wordv[1]) == ',' 253 && next_lastchar(cur_wordv[1]) == '"' 254 && strcmp(cur_wordv[2], "line") == 0 255 && isdigit((unsigned char)firstchar(cur_wordv[3])) 256 && lastchar(cur_wordv[3]) == ':') { 257 clob_last(cur_wordv[1], '\0'); /* drop last , */ 258 clob_last(cur_wordv[1], '\0'); /* drop last " */ 259 cur_wordv[1]++; /* drop first " */ 260 clob_last(cur_wordv[3], '\0'); /* drop : on line number */ 261 cur_wordv[2] = cur_wordv[1]; /* overwrite "line" */ 262 cur_wordv++; /*compensate*/ 263 cur_wordc--; 264 currentfilename = cur_wordv[1]; 265 language = INCC; 266 return (C_TRUE); 267 } 268 return (C_UNKNOWN); 269 } /* end of ccom */ 270 271 /* 272 * Do the error message from the Richie C Compiler for the PDP11, 273 * which has this source: 274 * 275 * if (filename[0]) 276 * fprintf(stderr, "%s:", filename); 277 * fprintf(stderr, "%d: ", line); 278 * 279 */ 280 281 static Errorclass 282 richieccom(void) 283 { 284 char *cp; 285 char **nwordv; 286 char *file; 287 288 if (cur_wordc < 2) 289 return (C_UNKNOWN); 290 291 if (lastchar(cur_wordv[1]) == ':') { 292 cp = cur_wordv[1] + strlen(cur_wordv[1]) - 1; 293 while (isdigit((unsigned char)*--cp)) 294 continue; 295 if (*cp == ':') { 296 clob_last(cur_wordv[1], '\0'); /* last : */ 297 *cp = '\0'; /* first : */ 298 file = cur_wordv[1]; 299 nwordv = wordvsplice(1, cur_wordc, cur_wordv+1); 300 nwordv[0] = file; 301 nwordv[1] = cp + 1; 302 cur_wordc += 1; 303 cur_wordv = nwordv - 1; 304 language = INCC; 305 currentfilename = cur_wordv[1]; 306 return (C_TRUE); 307 } 308 } 309 return (C_UNKNOWN); 310 } 311 312 static Errorclass 313 lint0(void) 314 { 315 char **nwordv; 316 char *line, *file; 317 318 /* 319 * Attempt a match for the new lint style normal compiler 320 * error messages, of the form 321 * 322 * printf("%s(%d): %s\n", filename, linenumber, message); 323 */ 324 if (cur_wordc < 2) 325 return (C_UNKNOWN); 326 327 if (lastchar(cur_wordv[1]) == ':' 328 && next_lastchar(cur_wordv[1]) == ')') { 329 clob_last(cur_wordv[1], '\0'); /* colon */ 330 if (persperdexplode(cur_wordv[1], &line, &file)) { 331 nwordv = wordvsplice(1, cur_wordc, cur_wordv+1); 332 nwordv[0] = file; /* file name */ 333 nwordv[1] = line; /* line number */ 334 cur_wordc += 1; 335 cur_wordv = nwordv - 1; 336 language = INLINT; 337 return (C_TRUE); 338 } 339 cur_wordv[1][strlen(cur_wordv[1])] = ':'; 340 } 341 return (C_UNKNOWN); 342 } 343 344 static Errorclass 345 lint1(void) 346 { 347 char *line1 = NULL, *line2 = NULL; 348 char *file1 = NULL, *file2 = NULL; 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 (cur_wordc > 1 && strcmp(cur_wordv[cur_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 (cur_wordc > 2 367 && persperdexplode(cur_wordv[cur_wordc], &line2, &file2) 368 && persperdexplode(cur_wordv[cur_wordc-2], &line1, &file1)) { 369 nwordv1 = wordvsplice(2, cur_wordc, cur_wordv+1); 370 nwordv2 = wordvsplice(2, cur_wordc, cur_wordv+1); 371 nwordv1[0] = file1; 372 nwordv1[1] = line1; 373 erroradd(cur_wordc+2, nwordv1, C_TRUE, C_DUPL); /* takes 0 based*/ 374 nwordv2[0] = file2; 375 nwordv2[1] = line2; 376 cur_wordc = cur_wordc + 2; 377 cur_wordv = nwordv2 - 1; /* 1 based */ 378 return (C_TRUE); 379 } 380 } 381 if (file2) 382 free(file2); 383 if (file1) 384 free(file1); 385 if (line2) 386 free(line2); 387 if (line1) 388 free(line1); 389 return (C_UNKNOWN); 390 } /* end of lint 1*/ 391 392 static Errorclass 393 lint2(void) 394 { 395 char *file; 396 char *line; 397 char **nwordv; 398 399 /* 400 * Look for type 2 lint errors 401 * 402 * %.7s used( %s(%d) ), but not defined 403 * %.7s defined( %s(%d) ), but never used 404 * %.7s declared( %s(%d) ), but never used or defined 405 * 406 * bufp defined( "./metric.h"(10) ), but never used 407 */ 408 if (cur_wordc < 5) 409 return (C_UNKNOWN); 410 411 if (lastchar(cur_wordv[2]) == '(' /* ')' */ 412 && strcmp(cur_wordv[4], "),") == 0) { 413 language = INLINT; 414 if (persperdexplode(cur_wordv[3], &line, &file)) { 415 nwordv = wordvsplice(2, cur_wordc, cur_wordv+1); 416 nwordv[0] = file; 417 nwordv[1] = line; 418 cur_wordc = cur_wordc + 2; 419 cur_wordv = nwordv - 1; /* 1 based */ 420 return (C_TRUE); 421 } 422 } 423 return (C_UNKNOWN); 424 } /* end of lint 2*/ 425 426 #if 0 /* not const-correct */ 427 static char *Lint31[4] = {"returns", "value", "which", "is"}; 428 static char *Lint32[6] = {"value", "is", "used,", "but", "none", "returned"}; 429 #else 430 DECL_STRINGS_4(static, Lint31, 431 "returns", "value", "which", "is"); 432 DECL_STRINGS_6(static, Lint32, 433 "value", "is", "used,", "but", "none", "returned"); 434 #endif 435 436 static Errorclass 437 lint3(void) 438 { 439 if (cur_wordc < 3) 440 return (C_UNKNOWN); 441 if (wordvcmp(cur_wordv+2, 4, Lint31) == 0 442 || wordvcmp(cur_wordv+2, 6, Lint32) == 0) { 443 language = INLINT; 444 return (C_NONSPEC); 445 } 446 return (C_UNKNOWN); 447 } 448 449 /* 450 * Special word vectors for use by F77 recognition 451 */ 452 #if 0 /* not const-correct */ 453 static char *F77_fatal[3] = {"Compiler", "error", "line"}; 454 static char *F77_error[3] = {"Error", "on", "line"}; 455 static char *F77_warning[3] = {"Warning", "on", "line"}; 456 static char *F77_no_ass[3] = {"Error.","No","assembly."}; 457 #else 458 DECL_STRINGS_3(static, F77_fatal, "Compiler", "error", "line"); 459 DECL_STRINGS_3(static, F77_error, "Error", "on", "line"); 460 DECL_STRINGS_3(static, F77_warning, "Warning", "on", "line"); 461 DECL_STRINGS_3(static, F77_no_ass, "Error.", "No", "assembly."); 462 #endif 463 464 static Errorclass 465 f77(void) 466 { 467 char **nwordv; 468 469 /* 470 * look for f77 errors: 471 * Error messages from /usr/src/cmd/f77/error.c, with 472 * these printf formats: 473 * 474 * Compiler error line %d of %s: %s 475 * Error on line %d of %s: %s 476 * Warning on line %d of %s: %s 477 * Error. No assembly. 478 */ 479 if (cur_wordc == 3 && wordvcmp(cur_wordv+1, 3, F77_no_ass) == 0) { 480 cur_wordc = 0; 481 return (C_SYNC); 482 } 483 if (cur_wordc < 6) 484 return (C_UNKNOWN); 485 if (lastchar(cur_wordv[6]) == ':' 486 && ( 487 wordvcmp(cur_wordv+1, 3, F77_fatal) == 0 488 || wordvcmp(cur_wordv+1, 3, F77_error) == 0 489 || wordvcmp(cur_wordv+1, 3, F77_warning) == 0 490 ) 491 ) { 492 language = INF77; 493 nwordv = wordvsplice(2, cur_wordc, cur_wordv+1); 494 nwordv[0] = cur_wordv[6]; 495 clob_last(nwordv[0],'\0'); 496 nwordv[1] = cur_wordv[4]; 497 cur_wordc += 2; 498 cur_wordv = nwordv - 1; /* 1 based */ 499 return (C_TRUE); 500 } 501 return (C_UNKNOWN); 502 } /* end of f77 */ 503 504 #if 0 /* not const-correct */ 505 static char *Make_Croak[3] = {"***", "Error", "code"}; 506 static char *Make_NotRemade[5] = {"not", "remade", "because", "of", "errors"}; 507 #else 508 DECL_STRINGS_3(static, Make_Croak, "***", "Error", "code"); 509 DECL_STRINGS_5(static, Make_NotRemade, 510 "not", "remade", "because", "of", "errors"); 511 #endif 512 513 static Errorclass 514 make(void) 515 { 516 if (wordvcmp(cur_wordv+1, 3, Make_Croak) == 0) { 517 language = INMAKE; 518 return (C_SYNC); 519 } 520 if (wordvcmp(cur_wordv+2, 5, Make_NotRemade) == 0) { 521 language = INMAKE; 522 return (C_SYNC); 523 } 524 return (C_UNKNOWN); 525 } 526 527 static Errorclass 528 ri(void) 529 { 530 /* 531 * Match an error message produced by ri; here is the 532 * procedure yanked from the distributed version of ri 533 * April 24, 1980. 534 * 535 * serror(str, x1, x2, x3) 536 * char str[]; 537 * char *x1, *x2, *x3; 538 * { 539 * extern int yylineno; 540 * 541 * putc('"', stdout); 542 * fputs(srcfile, stdout); 543 * putc('"', stdout); 544 * fprintf(stdout, " %d: ", yylineno); 545 * fprintf(stdout, str, x1, x2, x3); 546 * fprintf(stdout, "\n"); 547 * synerrs++; 548 * } 549 */ 550 if (cur_wordc < 3) 551 return (C_UNKNOWN); 552 if (firstchar(cur_wordv[1]) == '"' 553 && lastchar(cur_wordv[1]) == '"' 554 && lastchar(cur_wordv[2]) == ':' 555 && isdigit((unsigned char)firstchar(cur_wordv[2]))) { 556 clob_last(cur_wordv[1], '\0'); /* drop the last " */ 557 cur_wordv[1]++; /* skip over the first " */ 558 clob_last(cur_wordv[2], '\0'); 559 language = INRI; 560 return (C_TRUE); 561 } 562 return (C_UNKNOWN); 563 } 564 565 static Errorclass 566 catchall(void) 567 { 568 /* 569 * Catches random things. 570 */ 571 language = INUNKNOWN; 572 return (C_NONSPEC); 573 } /* end of catch all*/ 574 575 static Errorclass 576 troff(void) 577 { 578 /* 579 * troff source error message, from eqn, bib, tbl... 580 * Just like pcc ccom, except uses `' 581 */ 582 if (cur_wordc < 4) 583 return (C_UNKNOWN); 584 585 if (firstchar(cur_wordv[1]) == '`' 586 && lastchar(cur_wordv[1]) == ',' 587 && next_lastchar(cur_wordv[1]) == '\'' 588 && strcmp(cur_wordv[2], "line") == 0 589 && isdigit((unsigned char)firstchar(cur_wordv[3])) 590 && lastchar(cur_wordv[3]) == ':') { 591 clob_last(cur_wordv[1], '\0'); /* drop last , */ 592 clob_last(cur_wordv[1], '\0'); /* drop last " */ 593 cur_wordv[1]++; /* drop first " */ 594 clob_last(cur_wordv[3], '\0'); /* drop : on line number */ 595 cur_wordv[2] = cur_wordv[1]; /* overwrite "line" */ 596 cur_wordv++; /*compensate*/ 597 currentfilename = cur_wordv[1]; 598 language = INTROFF; 599 return (C_TRUE); 600 } 601 return (C_UNKNOWN); 602 } 603 604 static Errorclass 605 mod2(void) 606 { 607 /* 608 * for decwrl modula2 compiler (powell) 609 */ 610 if (cur_wordc < 5) 611 return (C_UNKNOWN); 612 if ((strcmp(cur_wordv[1], "!!!") == 0 /* early version */ 613 || strcmp(cur_wordv[1], "File") == 0) /* later version */ 614 && lastchar(cur_wordv[2]) == ',' /* file name */ 615 && strcmp(cur_wordv[3], "line") == 0 616 && isdigit((unsigned char)firstchar(cur_wordv[4])) /* line number */ 617 && lastchar(cur_wordv[4]) == ':' /* line number */ 618 ) { 619 clob_last(cur_wordv[2], '\0'); /* drop last , on file name */ 620 clob_last(cur_wordv[4], '\0'); /* drop last : on line number */ 621 cur_wordv[3] = cur_wordv[2]; /* file name on top of "line" */ 622 cur_wordv += 2; 623 cur_wordc -= 2; 624 currentfilename = cur_wordv[1]; 625 language = INMOD2; 626 return (C_TRUE); 627 } 628 return (C_UNKNOWN); 629 } 630