home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / icont / link.c < prev    next >
C/C++ Source or Header  |  1996-03-22  |  14KB  |  539 lines

  1. /*
  2.  * link.c -- linker main program that controls the linking process.
  3.  */
  4.  
  5. #include "link.h"
  6. #include "tproto.h"
  7. #include "tglobals.h"
  8. #include "::h:header.h"
  9.  
  10. #if SCCX_MX
  11. #undef ISICONT
  12. #define ISICONT
  13. #include "ixhdr.h"
  14. #endif                    /* SCCX_MX */
  15.  
  16. #ifdef Header
  17. #ifndef ShellHeader
  18. #include "hdr.h"
  19. #endif                    /* ShellHeader */
  20.  
  21.  
  22. #ifndef MaxHeader
  23. #define MaxHeader MaxHdr
  24. #endif                    /* MaxHeader */
  25.  
  26. #endif                    /* Header */
  27.  
  28. /*
  29.  * Prototype.
  30.  */
  31.  
  32. hidden    novalue    setexe    Params((char *fname));
  33.  
  34.  
  35. /*
  36.  * The following code is operating-system dependent [@link.01].  Include
  37.  *  system-dependent files and declarations.
  38.  */
  39.  
  40. #if PORT
  41.    /* nothing to do */
  42. Deliberate Syntax Error
  43. #endif                    /* PORT */
  44.  
  45. #if AMIGA || ATARI_ST || MACINTOSH || VM || VMS
  46.    /* nothing to do */
  47. #endif                    /* AMIGA || ATARI_ST || ... */
  48.  
  49. #if ARM
  50. #include "kernel.h"
  51. #include "swis.h"
  52. #endif                    /* ARM */
  53.  
  54. #if MSDOS
  55.    extern char pathToIconDOS[];
  56. #if MICROSOFT || TURBO || BORLAND_286 || BORLAND_386
  57. #include <fcntl.h>
  58. #endif                    /* MICROSOFT || TURBO ... */
  59. #endif                    /* MSDOS */
  60.  
  61. #if MVS
  62. char *routname;                /* real output file name */
  63. #endif                    /* MVS */
  64.  
  65. #if OS2
  66. #if MICROSOFT || CSET2
  67. #include <fcntl.h>
  68. #endif                    /* MICROSOFT || CSET2 */
  69. #endif                    /* OS2 */
  70.  
  71. #if UNIX
  72. #ifdef CRAY
  73. #define word word_fubar
  74. #include <sys/types.h>
  75. #include <sys/stat.h>
  76. #undef word
  77. #else                    /* CRAY */
  78. #ifndef XWindows
  79. #include <sys/types.h>
  80. #endif                    /* XWindows */
  81. #include <sys/stat.h>
  82. #endif                    /* CRAY */
  83. #endif                    /* UNIX */
  84.  
  85. /*
  86.  * End of operating-system specific code.
  87.  */
  88.  
  89. FILE *infile;                /* input file (.u1 or .u2) */
  90. FILE *outfile;                /* interpreter code output file */
  91.  
  92. extern char *ofile;            /* output file name */
  93.  
  94. #ifdef DeBugLinker
  95. FILE *dbgfile;                /* debug file */
  96. static char dbgname[MaxFileName];    /* debug file name */
  97. #endif                    /* DeBugLinker */
  98.  
  99. char inname[MaxFileName];        /* input file name */
  100. static char icnname[MaxFileName];    /* icon source file name */
  101.  
  102. struct lfile *llfiles = NULL;        /* List of files to link */
  103.  
  104. int colmno = 0;                /* current source column number */
  105. int lineno = 0;                /* current source line number */
  106. int fatals = 0;                /* number of errors encountered */
  107.  
  108. /*
  109.  *  ilink - link a number of files, returning error count
  110.  */
  111. int ilink(ifiles,outname)
  112. char **ifiles;
  113. char *outname;
  114.    {
  115.  
  116.  
  117.    int i;
  118.    struct lfile *lf,*lfls;
  119.    char *filename;            /* name of current input file */
  120.  
  121.    linit();                /* initialize memory structures */
  122.    while (*ifiles)
  123.       alsolink(*ifiles++);        /* make initial list of files */
  124.  
  125.    /*
  126.     * Phase I: load global information contained in .u2 files into
  127.     *  data structures.
  128.     *
  129.     * The list of files to link is maintained as a queue with llfiles
  130.     *  as the base.  lf moves along the list.  Each file is processed
  131.     *  in turn by forming .u2 and .icn names from each file name, each
  132.     *  of which ends in .u1.  The .u2 file is opened and globals is called
  133.     *  to process it.  When the end of the list is reached, lf becomes
  134.     *  NULL and the loop is terminated, completing phase I.  Note that
  135.     *  link instructions in the .u2 file cause files to be added to list
  136.     *  of files to link.
  137.     */
  138.    for (lf = llfiles; lf != NULL; lf = lf->lf_link) {
  139.       filename = lf->lf_name;
  140.       makename(inname, SourceDir, filename, U2Suffix);
  141.       makename(icnname, TargetDir, filename, SourceSuffix);
  142.  
  143. #if MVS || VM
  144. /*
  145.  * Even though the ucode data is all reasonable text characters, use
  146.  *  of text I/O may cause problems if a line is larger than LRECL.
  147.  *  This is likely to be true with any compiler, though the precise
  148.  *  disaster which results may vary.
  149.  */
  150.       infile = fopen(inname, ReadBinary);
  151. #else
  152.       infile = fopen(inname, ReadText);
  153. #endif                    /* MVS || VM */
  154.  
  155.       if (infile == NULL)
  156.          quitf("cannot open %s",inname);
  157.       readglob();
  158.       fclose(infile);
  159.       }
  160.  
  161.    /* Phase II (optional): scan code and suppress unreferenced procs. */
  162.    if (!strinv)
  163.       scanrefs();
  164.  
  165.    /* Phase III: resolve undeclared variables and generate code. */
  166.  
  167.    /*
  168.     * Open the output file.
  169.     */
  170.  
  171. #if MVS
  172.    routname = outname;
  173.    outfile = tmpfile();         /* write icode to temporary file to
  174.                                    avoid fseek-PDS limitations */
  175. #else                    /* MVS */
  176.    outfile = fopen(outname, WriteBinary);
  177. #endif                    /* MVS */
  178.  
  179. /*
  180.  * The following code is operating-system dependent [@link.02].  Set
  181.  *  untranslated mode if necessary.
  182.  */
  183.  
  184. #if PORT
  185.    /* probably nothing */
  186. Deliberate Syntax Error
  187. #endif                    /* PORT */
  188.  
  189. #if AMIGA || ARM || ATARI_ST || MACINTOSH || MVS || UNIX || VM || VMS
  190.    /* nothing to do */
  191. #endif                    /* AMIGA || ARM || ATARI_ST || ... */
  192.  
  193. #if MSDOS
  194.  
  195. #if MICROSOFT || TURBO || BORLAND_286 || BORLAND_386
  196.    setmode(fileno(outfile),O_BINARY);    /* set for untranslated mode */
  197. #endif                    /* MICROSOFT || TURBO ... */
  198. #endif                    /* MSDOS */
  199.  
  200. #if OS2
  201. #if MICROSOFT || CSET2
  202.    setmode(fileno(outfile),O_BINARY);
  203. #endif                    /* MICROSOFT || CSET2 */
  204. #endif                    /* OS2 */
  205.  
  206. /*
  207.  * End of operating-system specific code.
  208.  */
  209.  
  210.    if (outfile == NULL) {        /* may exist, but can't open for "w" */
  211.       ofile = NULL;            /* so don't delete if it's there */
  212.       quitf("cannot create %s",outname);
  213.       }
  214.  
  215. #if MSDOS && (!NT)
  216.    /*
  217.     * This prepends ixhdr.exe to outfile, so it'll be executable.
  218.     *
  219.     * I don't know what that #if Header stuff was about since my MSDOS
  220.     * distribution didn't include "hdr.h", but it looks very similar to
  221.     * what I'm doing, so I'll put my stuff here, & if somebody who
  222.     * understands all the multi-operating-system porting thinks my code could
  223.     * be folded into it, having it here should make it easy. -- Will Mengarini.
  224.     */
  225.  
  226.    if (makeExe) {
  227.  
  228. #if SCCX_MX
  229.     unsigned long i;
  230.     for( i=0; i<IXHDRSIZE; ++i)
  231.         fputc( ixhdrarray[i], outfile);
  232.     fileOffsetOfStuffThatGoesInICX = IXHDRSIZE;
  233. #else
  234.       FILE *fIconDOS = fopen(pathToIconDOS, "rb");
  235.       char bytesThatBeginEveryExe[2] = {0,0}, oneChar;
  236.       unsigned short originalExeBytesMod512, originalExePages;
  237.       unsigned long originalExeBytes, byteCounter;
  238.  
  239.       if (!fIconDOS)
  240.          quit("unable to find ixhdr.exe in same dir as icont");
  241.       if (setvbuf(fIconDOS, 0, _IOFBF, 4096))
  242.          if (setvbuf(fIconDOS, 0, _IOFBF, 128))
  243.             quit("setvbuf() failure");
  244.       fread (&bytesThatBeginEveryExe, 2, 1, fIconDOS);
  245.       if (bytesThatBeginEveryExe[0] != 'M' ||
  246.           bytesThatBeginEveryExe[1] != 'Z')
  247.          quit("ixhdr header is corrupt");
  248.       fread (&originalExeBytesMod512, sizeof originalExeBytesMod512,
  249.             1, fIconDOS);
  250.       fread (&originalExePages,       sizeof originalExePages,
  251.             1, fIconDOS);
  252.       originalExeBytes = (originalExePages - 1)*512 + originalExeBytesMod512;
  253.  
  254.       if (ferror(fIconDOS) || feof(fIconDOS) || !originalExeBytes)
  255.          quit("ixhdr header is corrupt");
  256.       fseek (fIconDOS, 0, 0);
  257.  
  258. #ifdef MSWindows
  259.       for (oneChar=fgetc(fIconDOS); !feof(fIconDOS); oneChar=fgetc(fIconDOS)) {
  260.          if (ferror(fIconDOS) || ferror(outfile)) {
  261.             quit("Error copying ixhdr.exe");
  262.         }
  263.          fputc (oneChar, outfile);
  264.          }
  265. #else                    /* MSWindows */
  266.  
  267.       for (byteCounter = 0; byteCounter < originalExeBytes; byteCounter++) {
  268.          oneChar = fgetc (fIconDOS);
  269.          if (ferror(fIconDOS) || feof(fIconDOS) || ferror(outfile)) {
  270.             quit("Error copying ixhdr.exe");
  271.         }
  272.          fputc (oneChar, outfile);
  273.          }
  274. #endif                    /* MSWindows */
  275.  
  276.       fclose (fIconDOS);
  277.       fileOffsetOfStuffThatGoesInICX = ftell (outfile);
  278. #endif                    /* SCCX_MX */
  279.    }
  280. #endif                                  /* MSDOS && (!NT) */
  281.  
  282. #ifdef Header
  283.    /*
  284.     * Write the bootstrap header to the output file.
  285.     */
  286.  
  287. #ifdef ShellHeader
  288.    /*
  289.     * Write a short shell header terminated by \n\f\n\0.
  290.     * Use magic "#!/bin/sh" to ensure that $0 is set when run via $PATH.
  291.     * Pad header to a multiple of 8 characters.
  292.     */
  293.    {
  294.    char cmd[MaxPath + 100], script[2 * MaxPath + 200];
  295.  
  296. #if NT
  297.    sprintf(script,
  298.            "@echo off\n%s %%0.cmd %%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9\n",
  299.            ((iconxloc!=NULL)?iconxloc:"wiconx"), outname);
  300.    strcat(script,"rem [executable Icon binary follows]\n");
  301.    strcat(script, "        \n\f\n" + ((int)(strlen(script) + 4) % 8));
  302.    hdrsize = strlen(script) + 1;    /* length includes \0 at end */
  303.    fwrite(script, hdrsize, 1, outfile);    /* write header */
  304. #else                    /* NT */
  305.    sprintf(cmd, "exec \"${ICONX-%s}\" \"$0\"", iconxloc);
  306.    sprintf(script, "%s   0) %s;;\n   *) %s \"$@\";;%s\n",
  307.       "#!/bin/sh\n\ncase $# in\n", cmd, cmd,
  308.       "\nesac\n\n[executable Icon binary follows]");
  309.    strcat(script, "        \n\f\n" + ((int)(strlen(script) + 4) % 8));
  310.    hdrsize = strlen(script) + 1;    /* length includes \0 at end */
  311.    fwrite(script, hdrsize, 1, outfile);    /* write header */
  312. #endif                    /* NT */
  313.    }
  314. #else                    /* ShellHeader */
  315.    /*
  316.     *  Always write MaxHeader bytes.
  317.     */
  318.    fwrite(iconxhdr, sizeof(char), MaxHeader, outfile);
  319.    hdrsize = MaxHeader;
  320. #endif                    /* ShellHeader */
  321. #endif                    /* Header */
  322.  
  323.    for (i = sizeof(struct header); i--;)
  324.       putc(0, outfile);
  325.    fflush(outfile);
  326.    if (ferror(outfile) != 0)
  327.       quit("unable to write to icode file");
  328.  
  329. #ifdef DeBugLinker
  330.    /*
  331.     * Open the .ux file if debugging is on.
  332.     */
  333.    if (Dflag) {
  334.       makename(dbgname, TargetDir, llfiles->lf_name, ".ux");
  335.       dbgfile = fopen(dbgname, WriteText);
  336.       if (dbgfile == NULL)
  337.          quitf("cannot create %s", dbgname);
  338.       }
  339. #endif                    /* DeBugLinker */
  340.  
  341.    /*
  342.     * Loop through input files and generate code for each.
  343.     */
  344.    lfls = llfiles;
  345.  
  346. #if SCCX_MX
  347.    /* Avoid compiler warning */
  348.    while( (lf = getlfile(&lfls)) != 0) {
  349. #else
  350.    while (lf = getlfile(&lfls)) {
  351. #endif                /* SCCX_MX */
  352.  
  353.       filename = lf->lf_name;
  354.       makename(inname, SourceDir, filename, U1Suffix);
  355.       makename(icnname, TargetDir, filename, SourceSuffix);
  356.  
  357. #if MVS || VM
  358.       infile = fopen(inname, ReadBinary);
  359.       if (infile != NULL)         /* discard the extra blank we had */
  360.          (void) getc(infile);     /* to write to make it non-empty  */
  361. #else                                   /* MVS || VM */
  362.       infile = fopen(inname, ReadText);
  363. #endif                                  /* MVS || VM */
  364.  
  365.       if (infile == NULL)
  366.          quitf("cannot open %s", inname);
  367.       gencode();
  368.  
  369.  
  370.       fclose(infile);
  371.       }
  372.  
  373.  
  374.    gentables();        /* Generate record, field, global, global names,
  375.                static, and identifier tables. */
  376.    fclose(outfile);
  377.    lmfree();
  378.    if (fatals > 0)
  379.       return fatals;
  380.    setexe(outname);
  381.    return 0;
  382.    }
  383.  
  384. /*
  385.  * lwarn - issue a linker warning message.
  386.  */
  387. novalue lwarn(s1, s2, s3)
  388. char *s1, *s2, *s3;
  389.    {
  390.    fprintf(stderr, "%s: ", icnname);
  391.    if (lineno)
  392.       fprintf(stderr, "Line %d # :", lineno);
  393.    fprintf(stderr, "\"%s\": %s%s\n", s1, s2, s3);
  394.    fflush(stderr);
  395.    }
  396.  
  397. /*
  398.  * lfatal - issue a fatal linker error message.
  399.  */
  400.  
  401. novalue lfatal(s1, s2)
  402. char *s1, *s2;
  403.    {
  404.  
  405.    fprintf(stderr, "%s: ", icnname);
  406.    if (lineno)
  407.       fprintf(stderr, "Line %d # : ", lineno);
  408.    fprintf(stderr, "\"%s\": %s\n", s1, s2);
  409.    fatals++;
  410.    }
  411.  
  412. /*
  413.  * setexe - mark the output file as executable
  414.  */
  415.  
  416. static novalue setexe(fname)
  417. char *fname;
  418.    {
  419.  
  420. /*
  421.  * The following code is operating-system dependent [@link.03].  It changes the
  422.  *  mode of executable file so that it can be executed directly.
  423.  */
  424.  
  425. #if PORT
  426.    /* something is needed */
  427. Deliberate Syntax Error
  428. #endif                    /* PORT */
  429.  
  430. #if AMIGA
  431.    /* not necessary */
  432. #endif                    /* AMIGA */
  433.  
  434. #if ARM
  435.    {
  436.       _kernel_swi_regs regs;
  437.  
  438.       regs.r[0] = 31;
  439.       regs.r[1] = (int)"Icon";
  440.       if (_kernel_swi(OS_FSControl,®s,®s) == NULL)
  441.       {
  442.          regs.r[0] = 18;
  443.          regs.r[1] = (int)fname;
  444.          _kernel_swi(OS_File,®s,®s);
  445.       }
  446.    }
  447. #endif                    /* ARM */
  448.  
  449. #if ATARI_ST || MSDOS || MVS || VM || VMS
  450.    /*
  451.     * can't be made executable
  452.     * note: VMS files can't be made executable, but see "iexe.com" under VMS.
  453.     */
  454. #endif                    /* ATARI_ST || MSDOS || ... */
  455.  
  456. #if MACINTOSH
  457. #if MPW
  458.    /* Nothing to do here -- file is set to type TEXT
  459.       (so it can be executed as a script) in tmain.c.
  460.    */
  461. /* #pragma unused(fname) */
  462. #endif                    /* MPW */
  463. #endif                    /* MACINTOSH */
  464.  
  465. #if MSDOS
  466. #if MICROSOFT || TURBO || BORLAND_286 || BORLAND_386
  467.    chmod(fname,0755);    /* probably could be smarter... */
  468. #endif                    /* MICROSOFT || TURBO ... */
  469. #endif                    /* MSDOS */
  470.  
  471. #if OS2
  472.     /*
  473.      *    Obtain the EXE stub resource from icont (or xicont)
  474.      *    and write it out as the executable name.  Invoke the resource
  475.      *    compiler to add the icode file as a resource to the executable
  476.      *    This should be portable to Windows NT I believe.  Cheyenne.
  477.      */
  478.     {
  479.     char    *exeres;        /* EXE stub resource pointer */
  480.     unsigned long exereslen;    /* Length of resource */
  481.     char loadmoderr[256];
  482.  
  483.     char exename[256];
  484.     char rcname[256];
  485.     char cmdbuffer[256];
  486.     FILE *exefile;
  487.     FILE *rcfile;
  488.  
  489.     if( noexe ) return;        /* Nothing to do.. */
  490.  
  491.     DosGetResource(0,0x4844,1,&exeres);
  492.     DosQueryResourceSize(0,0x4844,1,&exereslen);
  493.  
  494.     makename(exename,NULL,fname,".exe");
  495.     exefile = fopen(exename,WriteBinary);
  496.     fwrite( exeres, sizeof(char), exereslen, exefile);
  497.     fclose(exefile);
  498.     DosFreeResource(exeres);
  499.  
  500.     makename(rcname,NULL,fname,".rc");
  501.     rcfile = fopen(rcname,WriteText);
  502.  
  503.     fprintf(rcfile,"RESOURCE 0x4843 1 %s\n",fname);
  504.     fclose(rcfile);
  505.  
  506.     sprintf(cmdbuffer,"rc %s %s",rcname,exename);
  507.  
  508.     system(cmdbuffer);
  509.  
  510.     unlink(rcname);
  511.     makename(rcname,NULL,fname,".res");
  512.     unlink(rcname);
  513.     unlink(fname);
  514.     }
  515. #endif                    /* OS2 */
  516.  
  517. #if UNIX
  518.       {
  519.       struct stat stbuf;
  520.       int u, r, m;
  521.       /*
  522.        * Set each of the three execute bits (owner,group,other) if allowed by
  523.        *  the current umask and if the corresponding read bit is set; do not
  524.        *  clear any bits already set.
  525.        */
  526.       umask(u = umask(0));        /* get and restore umask */
  527.       if (stat(fname,&stbuf) == 0)  {    /* must first read existing mode */
  528.          r = (stbuf.st_mode & 0444) >> 2;    /* get & position read bits */
  529.          m = stbuf.st_mode | (r & ~u);        /* set execute bits */
  530.          chmod(fname,m);         /* change file mode */
  531.          }
  532.       }
  533. #endif                    /* UNIX */
  534.  
  535. /*
  536.  * End of operating-system specific code.
  537.  */
  538.    }
  539.