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