home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / BDSC / BDSC-2 / L2.C < prev    next >
Text File  |  2000-06-30  |  20KB  |  825 lines

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