1 /* $NetBSD: input.c,v 1.11 2006/04/09 19:27:22 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. 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.11 2006/04/09 19:27:22 christos 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 wordc; /* how long the current error message is */ 47 char **wordv; /* the actual error message */ 48 49 Errorclass catchall(void); 50 Errorclass cpp(void); 51 Errorclass f77(void); 52 Errorclass lint0(void); 53 Errorclass lint1(void); 54 Errorclass lint2(void); 55 Errorclass lint3(void); 56 Errorclass make(void); 57 Errorclass mod2(void); 58 Errorclass onelong(void); 59 Errorclass pccccom(void); /* Portable C Compiler C Compiler */ 60 Errorclass pi(void); 61 Errorclass ri(void); 62 Errorclass richieccom(void); /* Richie Compiler for 11 */ 63 Errorclass troff(void); 64 65 /* 66 * Eat all of the lines in the input file, attempting to categorize 67 * them by their various flavors 68 */ 69 void 70 eaterrors(int *r_errorc, Eptr **r_errorv) 71 { 72 Errorclass errorclass = C_SYNC; 73 char *line; 74 char *inbuffer; 75 size_t inbuflen; 76 77 for (;;){ 78 if ((inbuffer = fgetln(errorfile, &inbuflen)) == NULL) 79 break; 80 line = Calloc(inbuflen + 1, sizeof(char)); 81 memcpy(line, inbuffer, inbuflen); 82 line[inbuflen] = '\0'; 83 wordvbuild(line, &wordc, &wordv); 84 /* 85 * for convience, convert wordv to be 1 based, instead 86 * of 0 based. 87 */ 88 wordv -= 1; 89 if ( 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 (wordc) 108 erroradd(wordc, 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 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 = (Eptr)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 Errorclass 163 onelong(void) 164 { 165 char **nwordv; 166 if ( (wordc == 1) && (language != INLD) ){ 167 /* 168 * We have either: 169 * a) file name from cc 170 * b) Assembler telling world that it is complaining 171 * c) Noise from make ("Stop.") 172 * c) Random noise 173 */ 174 wordc = 0; 175 if (strcmp(wordv[1], "Stop.") == 0){ 176 language = INMAKE; return(C_SYNC); 177 } 178 if (strcmp(wordv[1], "Assembler:") == 0){ 179 /* assembler always alerts us to what happened*/ 180 language = INAS; return(C_SYNC); 181 } else 182 if (strcmp(wordv[1], "Undefined:") == 0){ 183 /* loader complains about unknown symbols*/ 184 language = INLD; return(C_SYNC); 185 } 186 if (lastchar(wordv[1]) == ':'){ 187 /* cc tells us what file we are in */ 188 currentfilename = wordv[1]; 189 (void)substitute(currentfilename, ':', '\0'); 190 language = INCC; return(C_SYNC); 191 } 192 } else 193 if ( (wordc == 1) && (language == INLD) ){ 194 nwordv = (char **)Calloc(4, sizeof(char *)); 195 nwordv[0] = "ld:"; 196 nwordv[1] = wordv[1]; 197 nwordv[2] = "is"; 198 nwordv[3] = "undefined."; 199 wordc = 4; 200 wordv = nwordv - 1; 201 return(C_NONSPEC); 202 } else 203 if (wordc == 1){ 204 return(C_SYNC); 205 } 206 return(C_UNKNOWN); 207 } /* end of one long */ 208 209 Errorclass 210 cpp(void) 211 { 212 /* 213 * Now attempt a cpp error message match 214 * Examples: 215 * ./morse.h: 23: undefined control 216 * morsesend.c: 229: MAGNIBBL: argument mismatch 217 * morsesend.c: 237: MAGNIBBL: argument mismatch 218 * test1.c: 6: undefined control 219 */ 220 if (wordc < 3) 221 return (C_UNKNOWN); 222 if ( (language != INLD) /* loader errors have almost same fmt*/ 223 && (lastchar(wordv[1]) == ':') 224 && (isdigit((unsigned char)firstchar(wordv[2]))) 225 && (lastchar(wordv[2]) == ':') ){ 226 language = INCPP; 227 clob_last(wordv[1], '\0'); 228 clob_last(wordv[2], '\0'); 229 return(C_TRUE); 230 } 231 return(C_UNKNOWN); 232 } /*end of cpp*/ 233 234 Errorclass 235 pccccom(void) 236 { 237 /* 238 * Now attempt a ccom error message match: 239 * Examples: 240 * "morsesend.c", line 237: operands of & have incompatible types 241 * "test.c", line 7: warning: old-fashioned initialization: use = 242 * "subdir.d/foo2.h", line 1: illegal initialization 243 */ 244 if (wordc < 4) 245 return (C_UNKNOWN); 246 if ( (firstchar(wordv[1]) == '"') 247 && (lastchar(wordv[1]) == ',') 248 && (next_lastchar(wordv[1]) == '"') 249 && (strcmp(wordv[2],"line") == 0) 250 && (isdigit((unsigned char)firstchar(wordv[3]))) 251 && (lastchar(wordv[3]) == ':') ){ 252 clob_last(wordv[1], '\0'); /* drop last , */ 253 clob_last(wordv[1], '\0'); /* drop last " */ 254 wordv[1]++; /* drop first " */ 255 clob_last(wordv[3], '\0'); /* drop : on line number */ 256 wordv[2] = wordv[1]; /* overwrite "line" */ 257 wordv++; /*compensate*/ 258 wordc--; 259 currentfilename = wordv[1]; 260 language = INCC; 261 return(C_TRUE); 262 } 263 return(C_UNKNOWN); 264 } /* end of ccom */ 265 /* 266 * Do the error message from the Richie C Compiler for the PDP11, 267 * which has this source: 268 * 269 * if (filename[0]) 270 * fprintf(stderr, "%s:", filename); 271 * fprintf(stderr, "%d: ", line); 272 * 273 */ 274 275 Errorclass 276 richieccom(void) 277 { 278 char *cp; 279 char **nwordv; 280 char *file; 281 282 if (wordc < 2) 283 return (C_UNKNOWN); 284 285 if (lastchar(wordv[1]) == ':'){ 286 cp = wordv[1] + strlen(wordv[1]) - 1; 287 while (isdigit((unsigned char)*--cp)) 288 continue; 289 if (*cp == ':'){ 290 clob_last(wordv[1], '\0'); /* last : */ 291 *cp = '\0'; /* first : */ 292 file = wordv[1]; 293 nwordv = wordvsplice(1, wordc, wordv+1); 294 nwordv[0] = file; 295 nwordv[1] = cp + 1; 296 wordc += 1; 297 wordv = nwordv - 1; 298 language = INCC; 299 currentfilename = wordv[1]; 300 return(C_TRUE); 301 } 302 } 303 return(C_UNKNOWN); 304 } 305 306 Errorclass 307 lint0(void) 308 { 309 char **nwordv; 310 char *line, *file; 311 /* 312 * Attempt a match for the new lint style normal compiler 313 * error messages, of the form 314 * 315 * printf("%s(%d): %s\n", filename, linenumber, message); 316 */ 317 if (wordc < 2) 318 return (C_UNKNOWN); 319 320 if ( (lastchar(wordv[1]) == ':') 321 && (next_lastchar(wordv[1]) == ')') ) { 322 clob_last(wordv[1], '\0'); /* colon */ 323 if (persperdexplode(wordv[1], &line, &file)){ 324 nwordv = wordvsplice(1, wordc, wordv+1); 325 nwordv[0] = file; /* file name */ 326 nwordv[1] = line; /* line number */ 327 wordc += 1; 328 wordv = nwordv - 1; 329 language = INLINT; 330 return(C_TRUE); 331 } 332 wordv[1][strlen(wordv[1])] = ':'; 333 } 334 return (C_UNKNOWN); 335 } 336 337 Errorclass 338 lint1(void) 339 { 340 char *line1 = NULL, *line2 = NULL; 341 char *file1 = NULL, *file2 = NULL; 342 char **nwordv1, **nwordv2; 343 344 /* 345 * Now, attempt a match for the various errors that lint 346 * can complain about. 347 * 348 * Look first for type 1 lint errors 349 */ 350 if (wordc > 1 && strcmp(wordv[wordc-1], "::") == 0){ 351 /* 352 * %.7s, arg. %d used inconsistently %s(%d) :: %s(%d) 353 * %.7s value used inconsistently %s(%d) :: %s(%d) 354 * %.7s multiply declared %s(%d) :: %s(%d) 355 * %.7s value declared inconsistently %s(%d) :: %s(%d) 356 * %.7s function value type must be declared before use %s(%d) :: %s(%d) 357 */ 358 language = INLINT; 359 if (wordc > 2 360 && (persperdexplode(wordv[wordc], &line2, &file2)) 361 && (persperdexplode(wordv[wordc-2], &line1, &file1)) ){ 362 nwordv1 = wordvsplice(2, wordc, wordv+1); 363 nwordv2 = wordvsplice(2, wordc, wordv+1); 364 nwordv1[0] = file1; nwordv1[1] = line1; 365 erroradd(wordc+2, nwordv1, C_TRUE, C_DUPL); /* takes 0 based*/ 366 nwordv2[0] = file2; nwordv2[1] = line2; 367 wordc = wordc + 2; 368 wordv = nwordv2 - 1; /* 1 based */ 369 return(C_TRUE); 370 } 371 } 372 if (file2) 373 free(file2); 374 if (file1) 375 free(file1); 376 if (line2) 377 free(line2); 378 if (line1) 379 free(line1); 380 return(C_UNKNOWN); 381 } /* end of lint 1*/ 382 383 Errorclass 384 lint2(void) 385 { 386 char *file; 387 char *line; 388 char **nwordv; 389 /* 390 * Look for type 2 lint errors 391 * 392 * %.7s used( %s(%d) ), but not defined 393 * %.7s defined( %s(%d) ), but never used 394 * %.7s declared( %s(%d) ), but never used or defined 395 * 396 * bufp defined( "./metric.h"(10) ), but never used 397 */ 398 if (wordc < 5) 399 return (C_UNKNOWN); 400 401 if ( (lastchar(wordv[2]) == '(' /* ')' */ ) 402 && (strcmp(wordv[4], "),") == 0) ){ 403 language = INLINT; 404 if (persperdexplode(wordv[3], &line, &file)){ 405 nwordv = wordvsplice(2, wordc, wordv+1); 406 nwordv[0] = file; nwordv[1] = line; 407 wordc = wordc + 2; 408 wordv = nwordv - 1; /* 1 based */ 409 return(C_TRUE); 410 } 411 } 412 return(C_UNKNOWN); 413 } /* end of lint 2*/ 414 415 char *Lint31[4] = {"returns", "value", "which", "is"}; 416 char *Lint32[6] = {"value", "is", "used,", "but", "none", "returned"}; 417 418 Errorclass 419 lint3(void) 420 { 421 if (wordc < 3) 422 return(C_UNKNOWN); 423 if ( (wordvcmp(wordv+2, 4, Lint31) == 0) 424 || (wordvcmp(wordv+2, 6, Lint32) == 0) ){ 425 language = INLINT; 426 return(C_NONSPEC); 427 } 428 return(C_UNKNOWN); 429 } 430 431 /* 432 * Special word vectors for use by F77 recognition 433 */ 434 char *F77_fatal[3] = {"Compiler", "error", "line"}; 435 char *F77_error[3] = {"Error", "on", "line"}; 436 char *F77_warning[3] = {"Warning", "on", "line"}; 437 char *F77_no_ass[3] = {"Error.","No","assembly."}; 438 439 Errorclass 440 f77(void) 441 { 442 char **nwordv; 443 /* 444 * look for f77 errors: 445 * Error messages from /usr/src/cmd/f77/error.c, with 446 * these printf formats: 447 * 448 * Compiler error line %d of %s: %s 449 * Error on line %d of %s: %s 450 * Warning on line %d of %s: %s 451 * Error. No assembly. 452 */ 453 if (wordc == 3 && wordvcmp(wordv+1, 3, F77_no_ass) == 0) { 454 wordc = 0; 455 return(C_SYNC); 456 } 457 if (wordc < 6) 458 return(C_UNKNOWN); 459 if ( (lastchar(wordv[6]) == ':') 460 &&( 461 (wordvcmp(wordv+1, 3, F77_fatal) == 0) 462 || (wordvcmp(wordv+1, 3, F77_error) == 0) 463 || (wordvcmp(wordv+1, 3, F77_warning) == 0) ) 464 ){ 465 language = INF77; 466 nwordv = wordvsplice(2, wordc, wordv+1); 467 nwordv[0] = wordv[6]; 468 clob_last(nwordv[0],'\0'); 469 nwordv[1] = wordv[4]; 470 wordc += 2; 471 wordv = nwordv - 1; /* 1 based */ 472 return(C_TRUE); 473 } 474 return(C_UNKNOWN); 475 } /* end of f77 */ 476 477 char *Make_Croak[3] = {"***", "Error", "code"}; 478 char *Make_NotRemade[5] = {"not", "remade", "because", "of", "errors"}; 479 480 Errorclass 481 make(void) 482 { 483 if (wordvcmp(wordv+1, 3, Make_Croak) == 0){ 484 language = INMAKE; 485 return(C_SYNC); 486 } 487 if (wordvcmp(wordv+2, 5, Make_NotRemade) == 0){ 488 language = INMAKE; 489 return(C_SYNC); 490 } 491 return(C_UNKNOWN); 492 } 493 494 Errorclass 495 ri(void) 496 { 497 /* 498 * Match an error message produced by ri; here is the 499 * procedure yanked from the distributed version of ri 500 * April 24, 1980. 501 * 502 * serror(str, x1, x2, x3) 503 * char str[]; 504 * char *x1, *x2, *x3; 505 * { 506 * extern int yylineno; 507 * 508 * putc('"', stdout); 509 * fputs(srcfile, stdout); 510 * putc('"', stdout); 511 * fprintf(stdout, " %d: ", yylineno); 512 * fprintf(stdout, str, x1, x2, x3); 513 * fprintf(stdout, "\n"); 514 * synerrs++; 515 * } 516 */ 517 if (wordc < 3) 518 return(C_UNKNOWN); 519 if ( (firstchar(wordv[1]) == '"') 520 &&(lastchar(wordv[1]) == '"') 521 &&(lastchar(wordv[2]) == ':') 522 &&(isdigit((unsigned char)firstchar(wordv[2]))) ){ 523 clob_last(wordv[1], '\0'); /* drop the last " */ 524 wordv[1]++; /* skip over the first " */ 525 clob_last(wordv[2], '\0'); 526 language = INRI; 527 return(C_TRUE); 528 } 529 return(C_UNKNOWN); 530 } 531 532 Errorclass 533 catchall(void) 534 { 535 /* 536 * Catches random things. 537 */ 538 language = INUNKNOWN; 539 return(C_NONSPEC); 540 } /* end of catch all*/ 541 542 Errorclass 543 troff(void) 544 { 545 /* 546 * troff source error message, from eqn, bib, tbl... 547 * Just like pcc ccom, except uses `' 548 */ 549 if (wordc < 4) 550 return(C_UNKNOWN); 551 552 if ( (firstchar(wordv[1]) == '`') 553 && (lastchar(wordv[1]) == ',') 554 && (next_lastchar(wordv[1]) == '\'') 555 && (strcmp(wordv[2],"line") == 0) 556 && (isdigit((unsigned char)firstchar(wordv[3]))) 557 && (lastchar(wordv[3]) == ':') ){ 558 clob_last(wordv[1], '\0'); /* drop last , */ 559 clob_last(wordv[1], '\0'); /* drop last " */ 560 wordv[1]++; /* drop first " */ 561 clob_last(wordv[3], '\0'); /* drop : on line number */ 562 wordv[2] = wordv[1]; /* overwrite "line" */ 563 wordv++; /*compensate*/ 564 currentfilename = wordv[1]; 565 language = INTROFF; 566 return(C_TRUE); 567 } 568 return(C_UNKNOWN); 569 } 570 571 Errorclass 572 mod2(void) 573 { 574 /* 575 * for decwrl modula2 compiler (powell) 576 */ 577 if (wordc < 5) 578 return(C_UNKNOWN); 579 if ( ( (strcmp(wordv[1], "!!!") == 0) /* early version */ 580 ||(strcmp(wordv[1], "File") == 0)) /* later version */ 581 && (lastchar(wordv[2]) == ',') /* file name */ 582 && (strcmp(wordv[3], "line") == 0) 583 && (isdigit((unsigned char)firstchar(wordv[4]))) /* line number */ 584 && (lastchar(wordv[4]) == ':') /* line number */ 585 ){ 586 clob_last(wordv[2], '\0'); /* drop last , on file name */ 587 clob_last(wordv[4], '\0'); /* drop last : on line number */ 588 wordv[3] = wordv[2]; /* file name on top of "line" */ 589 wordv += 2; 590 wordc -= 2; 591 currentfilename = wordv[1]; 592 language = INMOD2; 593 return(C_TRUE); 594 } 595 return(C_UNKNOWN); 596 } 597