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