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