1 /* Id: f77.c,v 1.22 2011/08/04 08:32:32 mickey Exp */ 2 /* $NetBSD: f77.c,v 1.1.1.4 2011/09/01 12:47:05 plunky Exp $ */ 3 /* 4 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * Redistributions of source code and documentation must retain the above 11 * copyright notice, this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditionsand the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed or owned by Caldera 18 * International, Inc. 19 * Neither the name of Caldera International, Inc. nor the names of other 20 * contributors may be used to endorse or promote products derived from 21 * this software without specific prior written permission. 22 * 23 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE 28 * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, 32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 char xxxvers[] = "FORTRAN 77 DRIVER, VERSION 1.11, 28 JULY 1978\n"; 38 39 #include <sys/wait.h> 40 41 #include <stdio.h> 42 #include <ctype.h> 43 #include <signal.h> 44 #include <unistd.h> 45 #include <string.h> 46 #include <stdlib.h> 47 #include <stdarg.h> 48 #include <errno.h> 49 50 #include "ccconfig.h" 51 52 typedef FILE *FILEP; 53 typedef int flag; 54 #define YES 1 55 #define NO 0 56 57 FILEP diagfile; 58 59 static int pid; 60 static int sigivalue = 0; 61 static int sigqvalue = 0; 62 63 #ifndef FCOM 64 #define FCOM "fcom" 65 #endif 66 67 #ifndef ASSEMBLER 68 #define ASSEMBLER "as" 69 #endif 70 71 #ifndef LINKER 72 #define LINKER "ld" 73 #endif 74 75 static char *fcom = LIBEXECDIR "/" FCOM ; 76 static char *asmname = ASSEMBLER ; 77 static char *ldname = LINKER ; 78 static char *startfiles[] = STARTFILES; 79 static char *endfiles[] = ENDFILES; 80 static char *dynlinker[] = DYNLINKER; 81 static char *crt0file = CRT0FILE; 82 static char *macroname = "m4"; 83 static char *shellname = "/bin/sh"; 84 static char *aoutname = "a.out" ; 85 static char *libdir = LIBDIR ; 86 static char *liblist[] = F77LIBLIST; 87 88 static char *infname; 89 static char asmfname[15]; 90 static char prepfname[15]; 91 92 #define MAXARGS 100 93 int ffmax; 94 static char *ffary[MAXARGS]; 95 static char eflags[30] = ""; 96 static char rflags[30] = ""; 97 static char lflag[3] = "-x"; 98 static char *eflagp = eflags; 99 static char *rflagp = rflags; 100 static char **loadargs; 101 static char **loadp; 102 static int oflag; 103 104 static flag loadflag = YES; 105 static flag saveasmflag = NO; 106 static flag profileflag = NO; 107 static flag optimflag = NO; 108 static flag debugflag = NO; 109 static flag verbose = NO; 110 static flag fortonly = NO; 111 static flag macroflag = NO; 112 113 static char *setdoto(char *), *lastchar(char *), *lastfield(char *); 114 static void intrupt(int); 115 static void enbint(void (*)(int)); 116 static void crfnames(void); 117 static void fatal1(char *, ...); 118 static void done(int), texec(char *, char **); 119 static char *copyn(int, char *); 120 static int dotchar(char *), unreadable(char *), sys(char *), dofort(char *); 121 static int nodup(char *); 122 static int await(int); 123 static void rmf(char *), doload(char *[], char *[]), doasm(char *); 124 static int callsys(char *, char **); 125 static void errorx(char *, ...); 126 127 static void 128 addarg(char **ary, int *num, char *arg) 129 { 130 ary[(*num)++] = arg; 131 if ((*num) == MAXARGS) { 132 fprintf(stderr, "argument array too small\n"); 133 exit(1); 134 } 135 } 136 137 int 138 main(int argc, char **argv) 139 { 140 int i, c, status; 141 char *s; 142 char fortfile[20], *t; 143 char buff[100]; 144 145 diagfile = stderr; 146 147 sigivalue = (int) signal(SIGINT, SIG_IGN) & 01; 148 sigqvalue = (int) signal(SIGQUIT, SIG_IGN) & 01; 149 enbint(intrupt); 150 151 pid = getpid(); 152 crfnames(); 153 154 loadargs = (char **)calloc(1, (argc + 20) * sizeof(*loadargs)); 155 if (!loadargs) 156 fatal1("out of memory"); 157 loadp = loadargs; 158 159 --argc; 160 ++argv; 161 162 while(argc>0 && argv[0][0]=='-' && argv[0][1]!='\0') { 163 for(s = argv[0]+1 ; *s ; ++s) 164 switch(*s) { 165 case 'T': /* use special passes */ 166 switch(*++s) { 167 case '1': 168 fcom = s+1; goto endfor; 169 case 'a': 170 asmname = s+1; goto endfor; 171 case 'l': 172 ldname = s+1; goto endfor; 173 case 'm': 174 macroname = s+1; goto endfor; 175 default: 176 fatal1("bad option -T%c", *s); 177 } 178 break; 179 180 case 'w': /* F66 warn or no warn */ 181 addarg(ffary, &ffmax, s-1); 182 break; 183 184 case 'q': 185 /* 186 * Suppress printing of procedure names during 187 * compilation. 188 */ 189 addarg(ffary, &ffmax, s-1); 190 break; 191 192 copyfflag: 193 case 'u': 194 case 'U': 195 case 'M': 196 case '1': 197 case 'C': 198 addarg(ffary, &ffmax, s-1); 199 break; 200 201 case 'O': 202 optimflag = YES; 203 addarg(ffary, &ffmax, s-1); 204 break; 205 206 case 'm': 207 if(s[1] == '4') 208 ++s; 209 macroflag = YES; 210 break; 211 212 case 'S': 213 saveasmflag = YES; 214 215 case 'c': 216 loadflag = NO; 217 break; 218 219 case 'v': 220 verbose = YES; 221 break; 222 223 case 'd': 224 debugflag = YES; 225 goto copyfflag; 226 227 case 'p': 228 profileflag = YES; 229 goto copyfflag; 230 231 case 'o': 232 if(!strcmp(s, "onetrip")) { 233 addarg(ffary, &ffmax, s-1); 234 goto endfor; 235 } 236 oflag = 1; 237 aoutname = *++argv; 238 --argc; 239 break; 240 241 case 'F': 242 fortonly = YES; 243 loadflag = NO; 244 break; 245 246 case 'I': 247 if(s[1]=='2' || s[1]=='4' || s[1]=='s') 248 goto copyfflag; 249 fprintf(diagfile, "invalid flag -I%c\n", s[1]); 250 done(1); 251 252 case 'l': /* letter ell--library */ 253 s[-1] = '-'; 254 *loadp++ = s-1; 255 goto endfor; 256 257 case 'E': /* EFL flag argument */ 258 while(( *eflagp++ = *++s)) 259 ; 260 *eflagp++ = ' '; 261 goto endfor; 262 case 'R': 263 while(( *rflagp++ = *++s )) 264 ; 265 *rflagp++ = ' '; 266 goto endfor; 267 default: 268 lflag[1] = *s; 269 *loadp++ = copyn(strlen(lflag), lflag); 270 break; 271 } 272 endfor: 273 --argc; 274 ++argv; 275 } 276 277 if (verbose) 278 fprintf(stderr, xxxvers); 279 280 if (argc == 0) 281 errorx("No input files"); 282 283 #ifdef mach_pdp11 284 if(nofloating) 285 *loadp++ = (profileflag ? NOFLPROF : NOFLFOOT); 286 else 287 #endif 288 289 for(i = 0 ; i<argc ; ++i) 290 switch(c = dotchar(infname = argv[i]) ) { 291 case 'r': /* Ratfor file */ 292 case 'e': /* EFL file */ 293 if( unreadable(argv[i]) ) 294 break; 295 s = fortfile; 296 t = lastfield(argv[i]); 297 while(( *s++ = *t++)) 298 ; 299 s[-2] = 'f'; 300 301 if(macroflag) { 302 snprintf(buff, sizeof(buff), "%s %s >%s", 303 macroname, infname, prepfname); 304 if(sys(buff)) { 305 rmf(prepfname); 306 break; 307 } 308 infname = prepfname; 309 } 310 311 if(c == 'e') 312 snprintf(buff, sizeof(buff), "efl %s %s >%s", 313 eflags, infname, fortfile); 314 else 315 snprintf(buff, sizeof(buff), "ratfor %s %s >%s", 316 rflags, infname, fortfile); 317 status = sys(buff); 318 if(macroflag) 319 rmf(infname); 320 if(status) { 321 loadflag = NO; 322 rmf(fortfile); 323 break; 324 } 325 326 if( ! fortonly ) { 327 infname = argv[i] = lastfield(argv[i]); 328 *lastchar(infname) = 'f'; 329 330 if( dofort(argv[i]) ) 331 loadflag = NO; 332 else { 333 if( nodup(t = setdoto(argv[i])) ) 334 *loadp++ = t; 335 rmf(fortfile); 336 } 337 } 338 break; 339 340 case 'f': /* Fortran file */ 341 case 'F': 342 if( unreadable(argv[i]) ) 343 break; 344 if( dofort(argv[i]) ) 345 loadflag = NO; 346 else if( nodup(t=setdoto(argv[i])) ) 347 *loadp++ = t; 348 break; 349 350 case 'c': /* C file */ 351 case 's': /* Assembler file */ 352 if( unreadable(argv[i]) ) 353 break; 354 fprintf(diagfile, "%s:\n", argv[i]); 355 snprintf(buff, sizeof(buff), "cc -c %s", argv[i]); 356 if( sys(buff) ) 357 loadflag = NO; 358 else 359 if( nodup(t = setdoto(argv[i])) ) 360 *loadp++ = t; 361 break; 362 363 case 'o': 364 if( nodup(argv[i]) ) 365 *loadp++ = argv[i]; 366 break; 367 368 default: 369 if( ! strcmp(argv[i], "-o") ) 370 aoutname = argv[++i]; 371 else 372 *loadp++ = argv[i]; 373 break; 374 } 375 376 if(loadflag) 377 doload(loadargs, loadp); 378 done(0); 379 return 0; 380 } 381 382 #define ADD(x) addarg(params, &nparms, (x)) 383 384 static int 385 dofort(char *s) 386 { 387 int nparms, i; 388 char *params[MAXARGS]; 389 390 nparms = 0; 391 ADD(FCOM); 392 for (i = 0; i < ffmax; i++) 393 ADD(ffary[i]); 394 ADD(s); 395 ADD(asmfname); 396 ADD(NULL); 397 398 infname = s; 399 if (callsys(fcom, params)) 400 errorx("Error. No assembly."); 401 doasm(s); 402 403 if (saveasmflag == NO) 404 rmf(asmfname); 405 return(0); 406 } 407 408 409 static void 410 doasm(char *s) 411 { 412 char *obj; 413 char *params[MAXARGS]; 414 int nparms; 415 416 if (oflag && loadflag == NO) 417 obj = aoutname; 418 else 419 obj = setdoto(s); 420 421 nparms = 0; 422 ADD(asmname); 423 ADD("-o"); 424 ADD(obj); 425 ADD(asmfname); 426 ADD(NULL); 427 428 if (callsys(asmname, params)) 429 fatal1("assembler error"); 430 if(verbose) 431 fprintf(diagfile, "\n"); 432 } 433 434 435 static void 436 doload(char *v0[], char *v[]) 437 { 438 int nparms, i; 439 char *params[MAXARGS]; 440 char **p; 441 442 nparms = 0; 443 ADD(ldname); 444 ADD("-X"); 445 ADD("-d"); 446 for (i = 0; dynlinker[i]; i++) 447 ADD(dynlinker[i]); 448 ADD("-o"); 449 ADD(aoutname); 450 ADD(crt0file); 451 for (i = 0; startfiles[i]; i++) 452 ADD(startfiles[i]); 453 *v = NULL; 454 for(p = v0; *p ; p++) 455 ADD(*p); 456 if (libdir) 457 ADD(libdir); 458 for(p = liblist ; *p ; p++) 459 ADD(*p); 460 for (i = 0; endfiles[i]; i++) 461 ADD(endfiles[i]); 462 ADD(NULL); 463 464 if (callsys(ldname, params)) 465 fatal1("couldn't load %s", ldname); 466 467 if(verbose) 468 fprintf(diagfile, "\n"); 469 } 470 471 /* Process control and Shell-simulating routines */ 472 473 /* 474 * Execute f[] with parameter array v[]. 475 * Copied from cc. 476 */ 477 static int 478 callsys(char f[], char *v[]) 479 { 480 int t, status = 0; 481 pid_t p; 482 char *s; 483 484 if (debugflag || verbose) { 485 fprintf(stderr, "%s ", f); 486 for (t = 1; v[t]; t++) 487 fprintf(stderr, "%s ", v[t]); 488 fprintf(stderr, "\n"); 489 } 490 491 if ((p = fork()) == 0) { 492 #ifdef notyet 493 if (Bflag) { 494 size_t len = strlen(Bflag) + 8; 495 char *a = malloc(len); 496 if (a == NULL) { 497 error("callsys: malloc failed"); 498 exit(1); 499 } 500 if ((s = strrchr(f, '/'))) { 501 strlcpy(a, Bflag, len); 502 strlcat(a, s, len); 503 execv(a, v); 504 } 505 } 506 #endif 507 execvp(f, v); 508 if ((s = strrchr(f, '/'))) 509 execvp(s+1, v); 510 fprintf(stderr, "Can't find %s\n", f); 511 _exit(100); 512 } else { 513 if (p == -1) { 514 printf("Try again\n"); 515 return(100); 516 } 517 } 518 while (waitpid(p, &status, 0) == -1 && errno == EINTR) 519 ; 520 if (WIFEXITED(status)) 521 return (WEXITSTATUS(status)); 522 if (WIFSIGNALED(status)) 523 done(1); 524 fatal1("Fatal error in %s", f); 525 return 0; /* XXX */ 526 } 527 528 529 static int 530 sys(char *str) 531 { 532 char *s, *t; 533 char *argv[100], path[100]; 534 char *inname, *outname; 535 int append = 0; 536 int wait_pid; 537 int argc; 538 539 540 if(debugflag) 541 fprintf(diagfile, "%s\n", str); 542 inname = NULL; 543 outname = NULL; 544 argv[0] = shellname; 545 argc = 1; 546 547 t = str; 548 while( isspace((int)*t) ) 549 ++t; 550 while(*t) { 551 if(*t == '<') 552 inname = t+1; 553 else if(*t == '>') { 554 if(t[1] == '>') { 555 append = YES; 556 outname = t+2; 557 } else { 558 append = NO; 559 outname = t+1; 560 } 561 } else 562 argv[argc++] = t; 563 while( !isspace((int)*t) && *t!='\0' ) 564 ++t; 565 if(*t) { 566 *t++ = '\0'; 567 while( isspace((int)*t) ) 568 ++t; 569 } 570 } 571 572 if(argc == 1) /* no command */ 573 return(-1); 574 argv[argc] = 0; 575 576 s = path; 577 t = "/usr/bin/"; 578 while(*t) 579 *s++ = *t++; 580 for(t = argv[1] ; (*s++ = *t++) ; ) 581 ; 582 if((wait_pid = fork()) == 0) { 583 if(inname) 584 freopen(inname, "r", stdin); 585 if(outname) 586 freopen(outname, (append ? "a" : "w"), stdout); 587 enbint(SIG_DFL); 588 589 texec(path+9, argv); /* command */ 590 texec(path+4, argv); /* /bin/command */ 591 texec(path , argv); /* /usr/bin/command */ 592 593 fatal1("Cannot load %s",path+9); 594 } 595 596 return( await(wait_pid) ); 597 } 598 599 /* modified version from the Shell */ 600 static void 601 texec(char *f, char **av) 602 { 603 604 execv(f, av+1); 605 606 if (errno==ENOEXEC) { 607 av[1] = f; 608 execv(shellname, av); 609 fatal1("No shell!"); 610 } 611 if (errno==ENOMEM) 612 fatal1("%s: too large", f); 613 } 614 615 /* 616 * Cleanup and exit with value k. 617 */ 618 static void 619 done(int k) 620 { 621 static int recurs = NO; 622 623 if(recurs == NO) { 624 recurs = YES; 625 if (saveasmflag == NO) 626 rmf(asmfname); 627 } 628 exit(k); 629 } 630 631 632 static void 633 enbint(void (*k)(int)) 634 { 635 if(sigivalue == 0) 636 signal(SIGINT,k); 637 if(sigqvalue == 0) 638 signal(SIGQUIT,k); 639 } 640 641 642 643 static void 644 intrupt(int a) 645 { 646 done(2); 647 } 648 649 650 static int 651 await(int wait_pid) 652 { 653 int w, status; 654 655 enbint(SIG_IGN); 656 while ( (w = wait(&status)) != wait_pid) 657 if(w == -1) 658 fatal1("bad wait code"); 659 enbint(intrupt); 660 if(status & 0377) 661 { 662 if(status != SIGINT) 663 fprintf(diagfile, "Termination code %d", status); 664 done(3); 665 } 666 return(status>>8); 667 } 668 669 /* File Name and File Manipulation Routines */ 671 672 static int 673 unreadable(char *s) 674 { 675 FILE *fp; 676 677 if((fp = fopen(s, "r"))) { 678 fclose(fp); 679 return(NO); 680 } else { 681 fprintf(diagfile, "Error: Cannot read file %s\n", s); 682 loadflag = NO; 683 return(YES); 684 } 685 } 686 687 688 static void 689 crfnames(void) 690 { 691 snprintf(asmfname, sizeof(asmfname), "fort%d.%s", pid, "s"); 692 snprintf(prepfname, sizeof(prepfname), "fort%d.%s", pid, "p"); 693 } 694 695 696 697 static void 698 rmf(char *fn) 699 { 700 if(!debugflag && fn!=NULL && *fn!='\0') 701 unlink(fn); 702 } 703 704 705 static int 706 dotchar(char *s) 707 { 708 for( ; *s ; ++s) 709 if(s[0]=='.' && s[1]!='\0' && s[2]=='\0') 710 return( s[1] ); 711 return(NO); 712 } 713 714 715 static char * 716 lastfield(char *s) 717 { 718 char *t; 719 for(t = s; *s ; ++s) 720 if(*s == '/') 721 t = s+1; 722 return(t); 723 } 724 725 726 static char * 727 lastchar(char *s) 728 { 729 while(*s) 730 ++s; 731 return(s-1); 732 } 733 734 735 static char * 736 setdoto(char *s) 737 { 738 *lastchar(s) = 'o'; 739 return( lastfield(s) ); 740 } 741 742 743 static char * 744 copyn(int n, char *s) 745 { 746 char *p, *q; 747 748 p = q = (char *)calloc(1, (unsigned) n + 1); 749 if (!p) 750 fatal1("out of memory"); 751 752 while(n-- > 0) 753 *q++ = *s++; 754 return (p); 755 } 756 757 758 static int 759 nodup(char *s) 760 { 761 char **p; 762 763 for(p = loadargs ; p < loadp ; ++p) 764 if( !strcmp(*p, s) ) 765 return(NO); 766 767 return(YES); 768 } 769 770 771 static void 772 errorx(char *fmt, ...) 773 { 774 va_list ap; 775 776 va_start(ap, fmt); 777 vfprintf(diagfile, fmt, ap); 778 fprintf(diagfile, "\n"); 779 va_end(ap); 780 781 if (debugflag) 782 abort(); 783 done(1); 784 } 785 786 787 static void 788 fatal1(char *fmt, ...) 789 { 790 va_list ap; 791 792 va_start(ap, fmt); 793 fprintf(diagfile, "Compiler error in file %s: ", infname); 794 vfprintf(diagfile, fmt, ap); 795 fprintf(diagfile, "\n"); 796 va_end(ap); 797 798 if (debugflag) 799 abort(); 800 done(1); 801 } 802