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