home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol078 / l2new.c < prev    next >
C/C++ Source or Header  |  1984-04-29  |  26KB  |  1,013 lines

  1.  
  2. /*    ********
  3.     * L2.C *    New linker for BDS C
  4.     ********
  5.             Written 1980 by Scott W. Layson
  6.             This code is in the public domain.
  7.  
  8.     This is an improved linker for BDS C CRL format.  It eliminates the
  9.     jump table at the beginning of each function in the object code,
  10.     thus saving up to 10% or so in code space with a slight improvement
  11.     in speed.  
  12.  
  13.             Modified further 30th July, 1982 by
  14.             Steve de Plater
  15.     v2.23
  16.  
  17.     Now allows the "-s" parameter to send the Link
  18.     Map to the screen, as in CLINK. Functions are sorted
  19.     in address order.Use the "-sa" parameter to select
  20.     alphabetical order.
  21.  
  22.             Modified 1982 by John Woolner
  23.     v.2.22
  24.  
  25.     Automatic searching of all DEFF files in the following order, existing
  26.     on the default drive.
  27.     DEFF9 DEFF8 DEFF7 DEFF6 DEFF5 DEFF4 DEFF3 DEFF1 DEFF0 DEFF DEFF2
  28.     Note that DEFF2 is scanned last, and later libraries should NOT require
  29.     functions from libraries earlier in the list (they won't be found).
  30.     (if they don't exist on the default disk they will be skipped, no error
  31.      message will be generated).
  32.  
  33.     A carriage return to the '... file to be searched' question initiates
  34.     a scan of all DEFF as described above.
  35.  
  36.     '-o filename' allows setting output filename. If not specified output
  37.     will be first progfile loaded.
  38.  
  39.     Auto repeating disk designators now exist. If a disk is specified in
  40.     the command line it will be used for all subsequent loads/searches
  41.     unless a new designator is specified. (then that new one will repeat
  42.     for remainder of line etc.).
  43.     e.g.
  44.     l2 b:l2 -l chario scott
  45.         will load l2.crl from disk B
  46.              scan chario.crl & scott.crl on disk B
  47.              scan CP/M default disk for 'DEFF's
  48.         and write output l2.com to disk B.
  49.  
  50.     l2 b:l2 -l chario a:scott
  51.         will do as above but will search scott.crl on disk A
  52.  
  53.     CAUTION
  54.  
  55.     l2 l2 -l b:chario scott
  56.         will load l2.crl from disk A
  57.              scan chario.crl & scott.crl from disk B
  58.              scan CP/M default drive for DEFF's
  59.         and WRITE L2.COM to disk B    (last designator before write)!!!
  60.  
  61.    use instead
  62.     l2 a:l2 -l b:chario scott    (first progfile has designator
  63.                      therefore output file has designator)
  64.    or
  65.     l2 l2 -l b:chario scott -o a:l2 (output file set with designator).
  66.  
  67.  
  68.  
  69.  
  70.  
  71. */
  72.  
  73.  
  74. /**************** Globals ****************/
  75.  
  76. /*    #define SDOS                /* comment this out for CP/M */*/
  77.  
  78. /*    commented out --------------------------
  79. #define OVERLAYS            /* comment this out for shorter version */
  80. -------- end comment out */
  81.  
  82. /*    comment out -----------------------------
  83. #define MARC                /* for MARC cross-linker version 
  84.                                 (enables the "-marc" option) */
  85. -------- end comment out */
  86.  
  87.  
  88.  
  89. #include "bdscio.h"            /* for i/o buffer defs */
  90.  
  91. #define NUL        0
  92. #define FLAG        char
  93. #define repeat    while (1)
  94.  
  95. #define STDOUT        1
  96.  
  97. /* Phase control */
  98. #define INMEM        1        /* while everything still fits */
  99. #define DISK1        2        /* overflow; finish building table */
  100. #define DISK2        3        /* use table to do window link */
  101. int phase;
  102.  
  103.  
  104. /* function table */
  105. struct funct {
  106.     char fname[9];
  107.     FLAG flinkedp;            /* in memory already? */
  108.     char *faddr;            /* address of first ref link if not linked */
  109.     } *ftab;
  110. int nfuncts;                /* no. of functions in    table */
  111. int maxfuncts;                /* table size */
  112.  
  113. #define LINKED        1        /* (flinkedp) function really here */
  114. #define EXTERNAL    2        /* function defined in separate symbol table */
  115.  
  116. char fdir [512];            /* CRL file function directory */
  117.  
  118. /* command line parameters etc. */
  119. int nprogs, nlibs;
  120.  
  121. char defdisk;                /* optional default drive */
  122. FLAG indeff;                /* set when scanning DEFF files */
  123.  
  124. FLAG outflag;                /* flag for if output set on command */
  125. char outfile [15];            /* output file name   */
  126. char progfiles [30] [15];        /* program file names */
  127. char libfiles [20] [15];        /* library file names */
  128. FLAG symsp,                /* write symbols to .sym file? */
  129.     appstatsp,            /* append stats to .sym file? */
  130.     sepstatsp;            /* write stats to .lnk file? */
  131.  
  132. #ifdef MARC
  133. FLAG maxmemp,                /* punt MARC shell? */
  134.     marcp;                /* uses CM.CCC */
  135. #endif
  136.  
  137. char mainfunct[10];
  138. FLAG ovlp;                /* make overlay? */
  139. char symsfile [15];            /* file to load symbols from (for overlays) */
  140.  
  141. FLAG Tflag;                /* TRUE if "-t" option given    */
  142. unsigned Tval;                /* arg to "-t", if present    */
  143.  
  144. FLAG Sflag;                /* TRUE if "-s" option given    */
  145. FLAG SAflag;                /* TRUE if "-sa" option given    */
  146.  
  147. /* useful things to have defined */
  148. struct inst {
  149.     char opcode;
  150.     char *address;
  151.     };
  152.  
  153. union ptr {
  154.     unsigned u;            /* an int */
  155.     unsigned *w;            /* a word ptr */
  156.     char *b;                /* a byte ptr */
  157.     struct inst *i;        /* an instruction ptr */
  158.     };
  159.  
  160.  
  161. /* Link control variables */
  162.  
  163. union ptr codend;            /* last used byte of code buffer + 1 */
  164. union ptr exts;            /* start of externals */
  165. union ptr acodend;            /* actual code-end address */
  166. unsigned extspc;            /* size of externals */
  167. unsigned origin;            /* origin of code */
  168. unsigned buforg;            /* origin of code buffer */
  169. unsigned jtsaved;            /* bytes of jump table saved */
  170.  
  171. char *lspace;                /* space to link in */
  172. char *lspcend;                /* end of link area */
  173. char *lodstart;            /* beginning of current file */
  174.  
  175.  
  176. /* i/o buffer */
  177. struct iobuf {
  178.     int fd;
  179.     int isect;            /* currently buffered sector */
  180.     int nextc;            /* index of next char in buffer */
  181.     char buff [128];
  182.     } ibuf, obuf;
  183.  
  184. /* BDS C i/o buffer */
  185. char symbuf[BUFSIZ];
  186.  
  187. /* seek opcodes */
  188. #define ABSOLUTE 0
  189. #define RELATIVE 1
  190.  
  191. #define INPUT 0
  192.  
  193. #define TRUE (-1)
  194. #define FALSE 0
  195. #define NULL 0
  196.  
  197. /* 8080 instructions */
  198. #define LHLD 0x2A
  199. #define LXISP 0x31
  200. #define LXIH 0x21
  201. #define SPHL 0xF9
  202. #define JMP  0xC3
  203. #define CALL 0xCD
  204.  
  205. /* strcmp7 locals, made global for speed */
  206. char _c1, _c2, _end1, _end2;
  207.  
  208. /**************** End of Globals ****************/
  209.  
  210.  
  211. main (argc, argv)
  212.     int argc;
  213.     char **argv;
  214. {
  215.     puts ("Mark of the Unicorn Linker for BDS C, vsn. 2.23  (jdw & sdep)\n\n");
  216.     setup (argc, argv);
  217.     linkprog();
  218.     linklibs();
  219.     if (phase == DISK1) rescan();
  220.     else wrtcom();
  221.     if (symsp) wrtsyms();
  222.     }
  223.  
  224.  
  225. setup (argc, argv)            /* initialize function table, etc. */
  226.     int argc;
  227.     char **argv;
  228. {
  229.     symsp = appstatsp = sepstatsp = FALSE;    /* default options */
  230. #ifdef MARC
  231.     marcp = maxmemp = FALSE;
  232. #endif
  233.     outflag = ovlp = Tflag = Sflag = SAflag = indeff = FALSE;
  234.     defdisk = nprogs = nlibs = 0;
  235.     strcpy7(&mainfunct, "MAIN");    /* default top-level function */
  236.     origin = 0x100;            /* default origin */
  237.     maxfuncts = 200;            /* default function table size */
  238.     cmdline (argc, argv);
  239.     ftab = endext();
  240.     lspace = ftab + maxfuncts;
  241.     lspcend = topofmem() - (1024 + 2100);
  242.     if (lspace > lspcend)
  243.         Fatal ("Insufficient memory to do anything at all!\n");
  244.     loadccc();
  245.     nfuncts = 0;
  246. #ifdef OVERLAYS
  247.     if (ovlp) loadsyms();
  248. #endif
  249.     intern (&mainfunct);
  250.     phase = INMEM;
  251.     buforg = origin;
  252.     jtsaved = 0;
  253.     }
  254.  
  255.  
  256. cmdline (argc, argv)        /* process command line */
  257.     int argc;
  258.     char **argv;
  259. {
  260.     int i, progp;
  261.  
  262.     if (argc == 1) {
  263.         puts ("Usage is:\n");
  264.         puts ("  l2 {program files} -l {library files}\n");
  265.         puts ("\t[-w | -wa | -ws] [-m <main_name>]\n");
  266.         puts ("\t[-f <maxfuncts>] [-org <addr>] [-s | -sa]\n");
  267.         puts ("\t[-t <addr>] [-o <outfile>]\n");
  268. #ifdef OVERLAYS
  269.         puts ("\t[-ovl <rootname> <addr>]");
  270. #endif
  271. #ifdef MARC
  272.         puts ("\t[-marc]");
  273. #endif
  274.         exit (1);
  275.         }
  276.     progp = TRUE;
  277.     for (i=1; i < argc; ++i) {
  278.         if (argv[i][0] == '-') {
  279.             if (!strcmp7 (argv[i], "-F")) {
  280.                 if (++i >= argc) Fatal ("-f argument missing.\n");
  281.                 sscanf (argv[i], "%d", &maxfuncts);
  282.                 }
  283.             else if (!strcmp7 (argv[i], "-L")) progp = FALSE;
  284.             else if (!strcmp7 (argv[i], "-M")) {
  285.                 if (++i >= argc) Fatal ("-m argument missing.\n");
  286.                 strcpy7(&mainfunct, argv[i]);
  287.                 }
  288.             else if (!strcmp7 (argv[i], "-O")) {
  289.                 if (++i >= argc) Fatal ("-o argument missing.\n");
  290.                 strcpy7(&outfile, argv[i]);
  291.                 outflag = TRUE;
  292.                 }
  293. #ifdef MARC
  294.             else if (!strcmp7 (argv[i], "-MARC")) {
  295.                 maxmemp = TRUE;
  296.                 marcp = TRUE;
  297.                 }
  298. #endif
  299.             else if (!strcmp7 (argv[i], "-ORG")) {
  300.                 if (++i >= argc) Fatal ("-org argument missing.\n");
  301.                 sscanf (argv[i], "%x", &origin);
  302.                 }
  303.             else if (!strcmp7 (argv[i], "-T")) {
  304.                 if (++i >= argc) Fatal ("-t argument missing.\n");
  305.                 Tflag = TRUE;
  306.                 sscanf (argv[i], "%x", &Tval);
  307.                 }
  308.             else if (!strcmp7 (argv[i], "-S")) {
  309.                 Sflag = TRUE;
  310.                 ++i;
  311.                 }
  312.             else if (!strcmp7 (argv[i], "-SA")) {
  313.                 Sflag = SAflag = TRUE;
  314.                 ++i;
  315.                 }
  316. #ifdef OVERLAYS
  317.             else if (!strcmp7 (argv[i], "-OVL")) {
  318.                 ovlp = TRUE;
  319.                 if (i + 2 >= argc) Fatal ("-ovl argument missing.\n");
  320.                 strcpy7(&symsfile, argv[++i]);
  321.                 sscanf (argv[++i], "%x", &origin);
  322.                 }
  323. #endif
  324.             else if (!strcmp7 (argv[i], "-W")) symsp = TRUE;
  325.             else if (!strcmp7 (argv[i], "-WA")) symsp = appstatsp = TRUE;
  326.             else if (!strcmp7 (argv[i], "-WS")) symsp = sepstatsp = TRUE;
  327.             else printf ("Unknown option: '%s'\n", argv[i]);
  328.             }
  329.         else {
  330.             if (progp) strcpy7(&progfiles[nprogs++], argv[i]);
  331.             else strcpy7 (&libfiles[nlibs++], argv[i]);
  332.             }
  333.         }
  334.     if (ovlp) strcpy7 (&mainfunct, &progfiles[0]);
  335.     if (!outflag) strcpy7(&outfile, &progfiles[0]);
  336. #ifdef MARC
  337.     strcpy7 (&libfiles[nlibs++], marcp ? "DEFFM" : "DEFF");
  338.     strcpy7 (&libfiles[nlibs++], marcp ? "DEFF2M" : "DEFF2");
  339. #else
  340.     strcpy7 (&libfiles[nlibs++], "DEFF");
  341. /*    strcpy7 (&libfiles[nlibs++], "DEFF2");     */
  342. #endif
  343.     }
  344.  
  345.  
  346. loadccc()                    /* load C.CCC (runtime library) */
  347. {
  348.     union ptr temp;
  349.     unsigned len;
  350.  
  351.     codend.b = lspace;
  352.     if (!ovlp) {
  353. #ifdef MARC
  354.         if (copen (&ibuf, marcp ? "CM.CCC" : "C.CCC") < 0)
  355. #else
  356.         if (copen (&ibuf, "C.CCC") < 0)
  357. #endif
  358.             Fatal ("Can't open C.CCC\n");
  359.         else
  360.           printf ("<< Loading  %14s >>\n", "C.CCC");
  361.         if (cread (&ibuf, lspace, 128) < 128)    /* read a sector */
  362.             Fatal ("C.CCC: read error!\n");
  363.         temp.b = lspace + 0x17;
  364.         len = *temp.w;                        /* how long is it? */
  365.         cread (&ibuf, lspace + 128, len - 128); /* read rest */
  366.         codend.b += len;
  367.         cclose (&ibuf);
  368.         }
  369.     else codend.i++->opcode = JMP;
  370.     }
  371.  
  372.  
  373. linkprog()                /* link in all program files */
  374. {
  375.     int i;
  376.     union ptr dirtmp;
  377.     struct funct *fnct;
  378.  
  379.     for (i=0; i<nprogs; ++i) {
  380.         makeext (&progfiles[i], "CRL");
  381.         if (copen (&ibuf, progfiles[i]) < 0) {
  382.             printf ("Can't open %s\n", progfiles[i]);
  383.             continue;
  384.             }
  385.         printf ("<< Loading  %14s >>\n", &progfiles[i]);
  386.         readprog (i==0);
  387.         for (dirtmp.b=&fdir; *dirtmp.b != 0x80;) {
  388.             fnct = intern (dirtmp.b);            /* for each module */
  389.             skip7 (&dirtmp);                    /* in directory */
  390.             if (!fnct->flinkedp)
  391.                 linkmod (fnct, lodstart + *dirtmp.w - 0x205);
  392.             else if (phase != DISK2) {
  393.                 puts ("Duplicate program function '");
  394.                 puts (&fnct->fname);
  395.                 puts ("', not linked.\n");
  396.                 }
  397.             dirtmp.w++;
  398.             }                                /* intern & link it */
  399.         cclose (&ibuf);
  400.         }
  401.     }
  402.  
  403.  
  404. linklibs()                /* link in library files */
  405. {
  406.     int ifile;
  407.  
  408.     for (ifile=0; ifile<nlibs; ++ifile) scanlib (ifile);
  409.     while (missingp()) {
  410.         puts ("Enter the name of a file to be searched: ");
  411.         gets (&libfiles[nlibs]);
  412.         if(strlen(&libfiles[nlibs])==0) strcpy7(&libfiles[nlibs],"DEFF");
  413.         scanlib (nlibs++);
  414.         }
  415.     acodend.b = codend.b - lspace + buforg;        /* save that number! */
  416.     if (!exts.b) exts.b = acodend.b;
  417.     }
  418.  
  419.  
  420. missingp()                /* are any functions missing?  print them out */
  421. {
  422.     int i, foundp;
  423.  
  424.     foundp = FALSE;
  425.     for (i=0; i<nfuncts; ++i)
  426.         if (!ftab[i].flinkedp) {
  427.             if (!foundp) puts ("*** Missing functions:\n");
  428.             puts (&ftab[i].fname);
  429.             puts ("\n");
  430.             foundp = TRUE;
  431.             }
  432.     return (foundp);
  433.     }
  434.  
  435.  
  436. rescan()                    /* perform second disk phase */
  437. {
  438.     int i;
  439.     
  440.     for (i=0; i < nfuncts; ++i)
  441.         if (ftab[i].flinkedp == LINKED) ftab[i].flinkedp = FALSE;
  442.     phase = DISK2;
  443.     buforg = origin;
  444.     puts ("\n\n**** Beginning second disk pass ****\n");
  445.     if (!ovlp) makeext (&outfile, "COM");
  446.     else makeext (&outfile, "OVL");
  447.     printf ("<< Opening  %14s >>\n", &outfile);
  448.     ccreat (&obuf, &outfile);
  449.     loadccc();
  450.     hackccc();
  451.     linkprog();
  452.     linklibs();
  453.     if (cwrite (&obuf, lspace, codend.b - lspace) == -1
  454.         ||    cflush (&obuf) < 0) Fatal ("Disk write error!\n");
  455.     cclose (&obuf);
  456.     printf ("<< Closed   %14s >>\n", &outfile);
  457.     stats (STDOUT);
  458.     }
  459.  
  460.  
  461.  
  462. readprog (mainp)            /* read in a program file */
  463.     FLAG mainp;
  464. {
  465.     char extp;                            /* was -e used? */
  466.     char *extstmp;
  467.     union ptr dir;
  468.     unsigned len;
  469.  
  470.     if (cread (&ibuf, &fdir, 512) < 512)            /* read directory */
  471.         Fatal ("-- read error!\n");
  472.     if (phase == INMEM  &&    mainp) {
  473.         cread (&ibuf, &extp, 1);
  474.         cread (&ibuf, &extstmp, 2);
  475.         cread (&ibuf, &extspc, 2);
  476.         if (extp) exts.b = extstmp;
  477.         else exts.b = 0;                        /* will be set later */
  478.         }
  479.     else cseek (&ibuf, 5, RELATIVE);
  480.     for (dir.b=&fdir; *dir.b != 0x80; nextd (&dir));    /* find end of dir */
  481.     ++dir.b;
  482.     len = *dir.w - 0x205;
  483.     readobj (len);
  484.     }
  485.  
  486.  
  487. readobj (len)                /* read in an object (program or lib funct) */
  488.     unsigned len;
  489. {
  490.     if (phase == DISK1  ||    codend.b + len >= lspcend) {
  491.         if (phase == INMEM) {
  492.             puts ("\n** Out of memory -- switching to disk mode **\n");
  493.             phase = DISK1;
  494.             }
  495.         if (phase == DISK2) {
  496.             if (cwrite (&obuf, lspace, codend.b - lspace) == -1)
  497.                 Fatal ("Disk write error!\n");
  498.             }
  499.         buforg += codend.b - lspace;
  500.         codend.b = lspace;
  501.         if (codend.b + len >= lspcend)
  502.             Fatal ("Module won't fit in memory at all!\n");
  503.         }
  504.     lodstart = codend.b;
  505.     if (cread (&ibuf, lodstart, len) < len) Fatal ("-- read error!\n");
  506.     }
  507.  
  508. /**********************************************************************/
  509.  
  510. scanlib (ifile)
  511. int ifile;
  512. {
  513.  
  514. int i,opn;
  515. union ptr dirtmp;
  516. char deffcount,deffchar;
  517.  
  518.     if(indeff = (strcmp7("DEFF",&libfiles[ifile])==0)) deffcount = '9';
  519.     else deffcount = 0;
  520.  
  521.     while(TRUE)
  522.     {
  523.     if(deffcount)    /* for searching all 'DEFF's in the following order */
  524.     {        /* 9 8 7 6 5 4 3 1 0 . 2  where . = DEFF.CRL        */
  525.  
  526.         deffchar = deffcount;
  527.         if(deffcount<='2') deffchar--;    /* translate so get correct */
  528.         if(deffchar == '/') deffchar = 0;    /* order of scanning        */
  529.         if(deffchar == '.') deffchar = '2';
  530.  
  531.         sprintf(&libfiles[ifile],"DEFF%c",deffchar);
  532.         if(deffcount-- == '/') deffcount = 0;
  533.  
  534.     }
  535.  
  536.     makeext (&libfiles[ifile], "CRL");
  537. /*    printf("processing file %s\n",&libfiles[ifile]);   for DEBUG */
  538.     if (copen(&ibuf, libfiles[ifile]) != -1)
  539.     {
  540.  
  541.         printf ("<< Scanning %14s >>\n", &libfiles[ifile]);
  542.         if (cread (&ibuf, &fdir, 512) < 512)    /* read directory */
  543.         Fatal("-- Read error!\n");
  544.         for (i=0; i<nfuncts; ++i)
  545.         {              /* scan needed functions */
  546.         if (!ftab[i].flinkedp
  547.             && (dirtmp.b = dirsearch (&ftab[i].fname)))
  548.         {
  549.             readfunct (dirtmp.b);
  550.             linkmod (&ftab[i], lodstart);
  551.         }
  552.         }
  553.         cclose (&ibuf);
  554.     }
  555.     else if(!deffcount)
  556.          {
  557.           printf ("Can't open %s\n", libfiles[ifile]);
  558.  
  559.          }
  560.     if (indeff)            /* incase second pass */
  561.     {
  562.        sprintf(&libfiles[ifile],"DEFF%c",0);     
  563. /*       printf("Whacking  %s\n", &libfiles[ifile]);       for DEBUG */
  564.     }
  565.  
  566.     if(!deffcount)
  567.     {
  568.         indeff = FALSE;
  569.         return;
  570.     }
  571.      
  572.     }
  573. }
  574.  
  575.  
  576.  
  577. /************************************************************************/
  578.  
  579.  
  580. readfunct (direntry)            /* read a function (from a library) */
  581.     union ptr direntry;
  582. {
  583.     unsigned start, len;
  584.  
  585.     skip7 (&direntry);
  586.     start = *direntry.w++;
  587.     skip7 (&direntry);
  588.     len = *direntry.w - start;
  589.     if (cseek (&ibuf, start, ABSOLUTE) < 0) Fatal (" -- read error!");
  590.     readobj (len);
  591.     }
  592.  
  593.  
  594. linkmod (fnct, modstart)            /* link in a module */
  595.     struct funct *fnct;
  596.     union ptr    modstart;                    /* loc. of module in memory */
  597.  
  598. {
  599.     union ptr temp,
  600.             jump,                    /* jump table temp */
  601.             body,                    /* loc. of function in memory */
  602.             code,                    /* loc. of code proper in mem. */
  603.             finalloc;                    /* runtime loc. of function */
  604.     unsigned flen, nrelocs, jtsiz, offset;
  605.  
  606.     fnct->flinkedp = LINKED;
  607.     if (phase != DISK2) {
  608.         finalloc.b = codend.b - lspace + buforg;
  609.         if (phase == INMEM) chase (fnct->faddr, finalloc.b);
  610.         fnct->faddr = finalloc.b;
  611.         }
  612.     else finalloc.b = fnct->faddr;
  613.     body.b = modstart.b + strlen(modstart.b) + 3; /* loc. of function body */
  614.     jump.i = body.i + (*modstart.b ? 1 : 0);
  615.     for (temp.b = modstart.b; *temp.b; skip7(&temp)) {
  616.         jump.i->address = intern (temp.b);
  617.         ++jump.i;
  618.         }
  619.     ++temp.b;
  620.     flen = *temp.w;
  621.     code.b = jump.b;
  622.     temp.b = body.b + flen;                /* loc. of reloc parameters */
  623.     nrelocs = *temp.w++;
  624.     jtsiz = code.b - body.b;
  625.     offset = code.b - codend.b;
  626.     if (phase != DISK1)
  627.         while (nrelocs--) relocate (*temp.w++, body.b, jtsiz,
  628.                                finalloc.b, offset, flen);
  629.     flen -= jtsiz;
  630.     if (phase != DISK2) jtsaved += jtsiz;
  631.     if (phase != DISK1) movmem (code.b, codend.b, flen);
  632.     codend.b += flen;
  633.     }
  634.  
  635.  
  636. relocate (param, body, jtsiz, base, offset, flen)    /* do a relocation!! */
  637.     unsigned param, jtsiz, base, offset, flen;
  638.     union ptr body;
  639. {
  640.     union ptr instr,                    /* instruction involved */
  641.             ref;                        /* jump table link */
  642.     struct funct *fnct;
  643.  
  644. /*    if (param == 1) return;                /* don't reloc jt skip */*/
  645.     instr.b = body.b + param - 1;
  646.     if (instr.i->address >= jtsiz)
  647.         instr.i->address += base - jtsiz;            /* vanilla case */
  648.     else {
  649.         ref.b = instr.i->address + body.u;
  650.         if (instr.i->opcode == LHLD) {
  651.             instr.i->opcode = LXIH;
  652.             --ref.b;
  653.             }
  654.         fnct = ref.i->address;
  655.         instr.i->address = fnct->faddr;        /* link in */
  656.         if (!fnct->flinkedp  &&     phase == INMEM)
  657.             fnct->faddr = instr.b + 1 - offset;    /* new list head */
  658.         }
  659.     }
  660.  
  661.  
  662. intern (name)                /* intern a function name in the table */
  663.     char *name;
  664. {
  665.     struct funct *fptr;
  666.  
  667.     if (*name == 0x9D) name = "MAIN";        /* Why, Leor, WHY??? */
  668.     for (fptr = &ftab[nfuncts-1]; fptr >= ftab; --fptr) 
  669.         if (!strcmp7 (name, fptr->fname)) break;
  670.     if (fptr < ftab) {
  671.         if (nfuncts >= maxfuncts)
  672.             Fatal ("Too many functions (limit is %d)!\n", maxfuncts);
  673.         fptr = &ftab[nfuncts];
  674.         strcpy7 (fptr->fname, name);
  675.         str7tont (fptr->fname);
  676.         fptr->flinkedp = FALSE;
  677.         fptr->faddr = NULL;
  678.         ++nfuncts;
  679.         }
  680.     return (fptr);
  681.     }
  682.  
  683.  
  684. dirsearch (name)            /* search directory for a function */
  685.     char *name;
  686. {
  687.     union ptr temp;
  688.  
  689.     for (temp.b = &fdir; *temp.b != 0x80; nextd (&temp))
  690.         if (!strcmp7 (name, temp.b)) return (temp.b);
  691.     return (NULL);
  692.     }
  693.  
  694.  
  695. nextd (ptrp)                /* move this pointer to the next dir entry */
  696.     union ptr *ptrp;
  697. {
  698.     skip7 (ptrp);
  699.     ++(*ptrp).w;
  700.     }
  701.  
  702.  
  703. chase (head, loc)            /* chase chain of refs to function */
  704.     union ptr head;
  705.     unsigned loc;
  706. {
  707.     union ptr temp;
  708.  
  709.     while (head.w) {
  710.         temp.w = *head.w;
  711.         *head.w = loc;
  712.         head.u = temp.u;
  713.         }
  714.     }
  715.  
  716.  
  717. wrtcom()                    /* write out com file (from in-mem link) */
  718. {
  719.     hackccc();
  720.     if (!ovlp) makeext (&outfile, "COM");
  721.     else makeext (&outfile, "OVL");
  722.     printf ("<< Writing  %14s >>\n", &outfile);
  723.     if (!ccreat (&obuf, &outfile) < 0
  724.         ||    cwrite (&obuf, lspace, codend.b - lspace) == -1
  725.         ||    cflush (&obuf) < 0)
  726.         Fatal ("Disk write error!\n");
  727.     cclose (&obuf);
  728.     if (Sflag) prtsyms ();
  729.     stats (STDOUT);
  730.     }
  731.  
  732.  
  733. hackccc()                    /* store various goodies in C.CCC code */
  734. {
  735.     union ptr temp;
  736.     struct funct *fptr;
  737.  
  738.     temp.b = lspace;
  739.     fptr = intern (&mainfunct);
  740.     if (!ovlp) {
  741. #ifdef MARC
  742.         if (!marcp) {
  743. #endif
  744.             if (!Tflag) {
  745.                 temp.i->opcode = LHLD;
  746.                 temp.i->address = origin - 0x100 + 6;
  747.                 (++temp.i)->opcode = SPHL;
  748.                 }
  749.             else {
  750.                 temp.i->opcode = LXISP;
  751.                 temp.i->address = Tval;
  752.                 }
  753.             temp.b = lspace + 0xF;            /* main function address */
  754.             temp.i->address = fptr->faddr;
  755. #ifdef MARC
  756.             }
  757. #endif
  758.         temp.b = lspace + 0x15;
  759.         *temp.w++ = exts.u;
  760.         ++temp.w;
  761.         *temp.w++ = acodend.u;
  762.         *temp.w++ = exts.u + extspc;
  763.         }
  764.     else temp.i->address = fptr->faddr;        /* that's a JMP */
  765. #ifdef MARC
  766.     if (maxmemp) {
  767.         temp.b = lspace + 0x258;
  768.         temp.i->opcode = CALL;
  769.         temp.i->address = 0x50;
  770.         }
  771. #endif
  772.     }
  773.  
  774.  
  775. wrtsyms()                    /* write out symbol table */
  776. {
  777.     int i, fd, compar();
  778.     
  779.     qsort (ftab, nfuncts, sizeof(*ftab), &compar);
  780.     makeext (&progfiles[0], "SYM");
  781.     if (fcreat (&progfiles[0], &symbuf) < 0)
  782.         Fatal ("Can't create .SYM file\n");
  783.     else printf ("<< Writing  %14s >>\n", &progfiles[0]);
  784.     for (i=0; i < nfuncts; ++i) {
  785.         puthex (ftab[i].faddr, &symbuf);
  786.         putc (' ', &symbuf);
  787.         fputs (&ftab[i].fname, &symbuf);
  788.         if (i % 4 == 3) fputs ("\n", &symbuf);
  789.         else {
  790.             if (strlen (&ftab[i].fname) < 3) putc ('\t', &symbuf);
  791.             putc ('\t', &symbuf);
  792.             }
  793.         }
  794.     if (i % 4) fputs ("\n", &symbuf);    
  795.     if (appstatsp) stats (&symbuf);
  796.     putc (CPMEOF, &symbuf);
  797.     fflush (&symbuf);
  798.     fclose (&symbuf);
  799.     if (sepstatsp) {
  800.         makeext (&progfiles[0], "LNK");
  801.         if (fcreat (&progfiles[0], &symbuf) < 0)
  802.             Fatal ("Can't create .LNK file\n");
  803.         else printf ("<< Writing  %14s >>\n", &progfiles[0]);
  804.         stats (&symbuf);
  805.         putc (CPMEOF, &symbuf);
  806.         fflush (&symbuf);
  807.         fclose (&symbuf);
  808.         }
  809.     }
  810.  
  811. prtsyms()                    /* write out symbol table */
  812. {
  813.     int i, compar(), compar2();
  814.     
  815.     if (SAflag)
  816.       qsort (ftab, nfuncts, sizeof(*ftab), &compar2);
  817.     else
  818.       qsort (ftab, nfuncts, sizeof(*ftab), &compar);
  819.     putc ('\n', STDOUT);
  820.     for (i=0; i < nfuncts; ++i) {
  821.         puthex (ftab[i].faddr, STDOUT);
  822.         putc (' ', STDOUT);
  823.         fputs (&ftab[i].fname, STDOUT);
  824.         if (i % 4 == 3) fputs ("\n", STDOUT);
  825.         else {
  826.             if (strlen (&ftab[i].fname) < 3) putc ('\t', STDOUT);
  827.             putc ('\t', STDOUT);
  828.             }
  829.         }
  830.     if (i % 4) putc ('\n', STDOUT);
  831.     }
  832.  
  833.  
  834. compar (f1, f2)            /* compare two symbol table entries by name */
  835.     struct funct *f1, *f2;
  836. {
  837. /*    return (strcmp7 (&f1->fname, &f2->fname));     alphabetical order */
  838.     return (f1->faddr > f2->faddr);            /* memory order */
  839.     }
  840.  
  841. compar2 (f1, f2)        /* compare two symbol table entries by name */
  842.     struct funct *f1, *f2;
  843. {
  844.     return (strcmp7 (&f1->fname, &f2->fname));    /* alphabetical order */
  845. /*    return (f1->faddr > f2->faddr);               memory order */
  846.     }
  847.  
  848.  
  849. #ifdef OVERLAYS
  850. loadsyms()                /* load base symbol table (for overlay) */
  851. {                        /* symbol table must be empty! */
  852.     int nread;
  853.     FLAG done;
  854.     char *c;
  855.     
  856.     makeext (&symsfile, "SYM");
  857.     if (fopen (&symsfile, &symbuf) < 0) 
  858.         Fatal ("Can't open %s.\n", &symsfile);
  859.     else  printf ("<< Loading  %14s >>\n", &symsfile);
  860.     done = FALSE;
  861.     while (!done) {
  862.         nread = fscanf (&symbuf, "%x%s%x%s%x%s%x%s",
  863.                      &(ftab[nfuncts].faddr), &(ftab[nfuncts].fname),
  864.                      &(ftab[nfuncts+1].faddr), &(ftab[nfuncts+1].fname),
  865.                      &(ftab[nfuncts+2].faddr), &(ftab[nfuncts+2].fname),
  866.                      &(ftab[nfuncts+3].faddr), &(ftab[nfuncts+3].fname));
  867.         nread /= 2;
  868.         if (nread < 4) done = TRUE;
  869.         while (nread-- > 0) ftab[nfuncts++].flinkedp = EXTERNAL;
  870.         }
  871.     fclose (&symbuf);
  872.     }
  873. #endif
  874.  
  875.  
  876. stats (chan)                /* print statistics on chan */
  877.     int chan;
  878. {
  879.     unsigned temp, *tptr;
  880.  
  881.     tptr = 6;
  882.     fprintf (chan, "\n\nLink statistics:\n");
  883.     fprintf (chan, "  Number of functions:    %d\n", nfuncts);
  884.     fprintf (chan, "  Code ends at:           0x%x\n", acodend.u);
  885.     fprintf (chan, "  Externals begin at:     0x%x\n", exts.u);
  886.     fprintf (chan, "  Externals end at:       0x%x\n", exts.u + extspc);
  887.     fprintf (chan, "  End of current TPA:     0x%x\n", *tptr);
  888.     fprintf (chan, "  Jump table bytes saved: 0x%x\n", jtsaved);
  889.     temp = lspcend;
  890.     if (phase == INMEM)
  891.         fprintf (chan,
  892.                "  Link space remaining:   %dK\n", (temp - codend.u) / 1024);
  893.     }
  894.  
  895.  
  896. makeext (fname, ext)        /* force a file extension to ext */
  897.     char *fname, *ext;
  898. {
  899. char fbuf [15],*f;
  900.  
  901.  
  902.     f = fname;                /* to use later        */
  903.  
  904.     if(*(fname+1) == ':') defdisk = *fname;
  905.     else if (!indeff && defdisk)        /* only if default exists */
  906.     {
  907.         strcpy7(&fbuf,fname);
  908.         sprintf(fname,"%c:%s",defdisk,&fbuf);
  909.     }
  910.  
  911.     while (*fname && (*fname != '.')) {
  912.         *fname = toupper (*fname);        /* upcase as well */
  913.         ++fname;
  914.         }
  915.     *fname++ = '.';
  916.     strcpy7 (fname, ext);
  917.     while (*f = (*f++ & 0x7f));            /* strip parity */
  918.  
  919.     }
  920.  
  921.  
  922. strcmp7 (s1, s2)            /* compare two bit-7-terminated strings */
  923.     char *s1, *s2;            /* also works for non-null NUL-term strings */
  924. {
  925. /*    char c1, c2, end1, end2;        (These are now global for speed) */
  926.  
  927.     repeat {
  928.         _c1 = *s1++;
  929.         _c2 = *s2++;
  930.         _end1 = (_c1 & 0x80) | !*s1;
  931.         _end2 = (_c2 & 0x80) | !*s2;
  932.         if ((_c1 &= 0x7F) < (_c2 &= 0x7F)) return (-1);
  933.         if (_c1 > _c2  ||  (_end2  &&  !_end1)) return (1);
  934.         if (_end1  &&  !_end2) return (-1);
  935.         if (_end1  &&  _end2) return (0);
  936.         }
  937.     }
  938.  
  939.  
  940. strcpy7 (s1, s2)            /* copy s2 into s1 */
  941.     char *s1, *s2;
  942. {
  943.     do {
  944.         *s1 = *s2;
  945.         if (!*(s2+1)) {                /* works even if */
  946.             *s1 |= 0x80;                /* s2 is null-term */
  947.             ++s1;
  948.             break;
  949.             }
  950.         ++s1;
  951.         } while (!(*s2++ & 0x80));
  952.     *s1 = 0;                    /* additional terminator */
  953.     }
  954.  
  955.  
  956. skip7 (ptr7)                /* move this pointer past a string */
  957.     char **ptr7;
  958. {
  959.     while (!(*(*ptr7)++ & 0x80));
  960.     }
  961.  
  962.  
  963. str7tont (s)                /* add null at end */
  964.     char *s;
  965. {
  966.     while (!(*s & 0x80)) {
  967.         if (!*s) return;        /* already nul term! */
  968.         s++;
  969.         }
  970.     *s = *s & 0x7F;
  971.     *++s = NUL;
  972.     }
  973.  
  974.  
  975. puthex (n, obuf)            /* output a hex word, with leading 0s */
  976.     unsigned n;
  977.     char *obuf;
  978. {
  979.     int i, nyb;
  980.     
  981.     for (i = 3; i >= 0; --i) {
  982.         nyb = (n >> (i * 4)) & 0xF;
  983.         nyb += (nyb > 9) ? 'A' - 10 : '0';
  984.         putc (nyb, obuf);
  985.         }
  986.     }
  987.  
  988.  
  989. Fatal (arg1, arg2, arg3, arg4)    /* lose, lose */
  990.     char *arg1, *arg2, *arg3, *arg4;
  991. {
  992.     printf (arg1, arg2, arg3, arg4);
  993.     exit (1);
  994.     }
  995.  
  996.  
  997. exit (status)                /* exit the program */
  998.     int status;
  999. {
  1000.     if (status == 1) {
  1001. #ifdef SDOS
  1002.         unlink ("a:$$$$.cmd");
  1003. #else
  1004.         unlink ("a:$$$.sub");
  1005. #endif
  1006.         }
  1007.     bios (1);                    /* bye! */
  1008.     }
  1009.  
  1010.  
  1011.  
  1012. /* END OF L2.C */
  1013.