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