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-225.ARK / LI.C < prev    next >
Text File  |  1988-05-21  |  37KB  |  1,414 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.
  8.  
  9.     Modified to v2.2.3, 11/27/1982 by David Kirkland
  10.     This is version 2.2 as distributed by BDS C UG, with
  11.     the following modifications:
  12.     -  The c debugger is supported.  This adds the "-NS", "-S", and 
  13.        "-D" command line options.
  14.     -  DEFF3.CRL is scanned, if it is present on disk
  15.     -  New mechanism for default drive selection--the DEF_DRIVE macro added.
  16.     -  Minor changes to messages.
  17.     -  Eliminates need for SCOTT.C by change to fscanf format string
  18.        in function "loadsyms" when reading .SYM file for overlay processing.
  19.     -  Ability to rescan DEFF*.CRL if reply with a carriage return to prompt
  20.        message when functions are missing.
  21.     -  "-I" option, which allows interactive entry of command line 
  22.        arguments.  If the command line ends in a "-i", then L2 treats
  23.        the command line as Incomplete, and prompts the user for more
  24.        arguments.  This is especially useful if you have a replacement
  25.        CCP which does not allow 127 character long command lines
  26.        (e.g., ZCPR).  This option orginally implemented, in a different
  27.        way, by Gil Shapiro.
  28.     Modified to v2.2.4, 03/24/1983 by David Kirkland
  29.     -  "-N" option added to produce .COM files which do not perform a 
  30.        warm boot after execution
  31.        As in clink, if both "-n" and "-t" are specified, "-t" is given
  32.        priority.
  33.     - "-NS" option removed/"-S" option changed.  Now the default is NO
  34.       system library files (see CDB docs for explanation of system 
  35.       library files); system library functions made it impossible to set
  36.       a breakpoint at the return of library functions in certain instances.
  37.  
  38.     Mod. v2.2.5, July 1984 by Greg Lee to read MicroSoft REL files:
  39.     -  Z option added like that of CLINK -- don't zero externals.
  40.     -  E option added to provide default beginning external address.
  41.     -  Program or library files can be entered with extension .REL,
  42.        in which case they are assumed to be REL files with
  43.        a CSEG and/or a DSEG (but no ASEG or COMMON). DSEG's are
  44.        intended to correspond with external data of C-compiled modules.
  45.     -  Function names must be "public" and external functions "ext"
  46.        in the assembler source for M80. All public names are assumed
  47.        to be functions by C-compiled modules, but references
  48.        from one assembled module to data in another are ok. As
  49.        with L80, if external references are not forward, the
  50.        appropriate modules of a library may fail to be loaded on
  51.        the first pass.
  52.     -  One can't do arithmetic with external symbols, such as
  53.        "abra equ cadabra+6" where cadabra is external.
  54.     -  CRL symbols can have 8 characters, but REL file symbols
  55.        only 7, so 7 character long REL file symbols are considered to have
  56.        an 8th wild character ('?') that will match any 8th character in
  57.        a CRL symbol.
  58.     -  DSEG data and addresses are assumed to be offset by the address
  59.        provided with the "-e" option when the main program module
  60.        was compiled or else with the new "-e" option of the linker.
  61.        If no such address was given, and a DSEG is encountered, this
  62.        causes the linker to abort.
  63.     -  If any real data is found in a DSEG (after "db" or "dw"), then
  64.         (1) the Z option is automatically triggered, and
  65.         (2) the COM file written to disk is extended sufficiently
  66.             to include the part of the external area where the
  67.             the (initialization) data was deposited.
  68.     -  Long files requiring disk mode may require DSEG data to be
  69.        loaded last, since the linker cannot write code to disk after
  70.        DSEG data has been written to disk.
  71.     -  The M80 pseudo-op '.REQUEST' is implemented. The requested
  72.        REL files are searched after other library files.
  73.  
  74.     Compilation instructions (assuming l2.com, v2.2.5 is available):
  75.         cc l2 -e5100
  76.         cc chario
  77.         m80 =rdrl
  78.         m80 =chario
  79.         m80 =spr
  80.         l2 l2 rdrl.rel spr.rel chario.rel
  81.     (SPR.MAC is just an assembly language version of the '_spr' library
  82.      function -- it need not be used, but it saves 1/2k of code. Also,
  83.      the C version of CHARIO could be used.)
  84.  
  85.  
  86.     Mod. v2.2.6, November, 1984 by Greg Lee to use the library
  87.        BDSCLIB.REL (instead of DEFF.CRL and DEFF2.CRL)
  88.     -  * option added to load WILD.CCC instead of C.CCC (cf.
  89.        wildccc.doc)
  90.  
  91.     Revised compilation instructions (using v2.2.6 of l2):
  92.         cc l2 -e4900
  93.         cc chario
  94.         m80 =rdrl
  95.         m80 =chario
  96.         l2 l2 rdrl.rel chario.rel
  97.     (The above "-e4900" assumes my revised C.CCC, which is 1/2k
  98.      smaller than the standard version.)
  99.  
  100. *********************************
  101.  
  102. The DEF_DRIVE macro is used to define the drive from which L2 will load C.CCC, 
  103. DEFF.CRL, DEFF2.CRL, and DEFF3.CRL (if it exists). The macro takes as an 
  104. argument the filename and extension, and "returns" the name with whatever drive
  105. designator is needed.  The macro also encloses the name in quotes; thus, the 
  106. argument when the macro is invoked must NOT be within quotes.
  107. That is, to open C.CCC on the proper drive, we use the C code
  108.     if (ERROR==fopen(DEF_DRIVE(C.CCC), iobuf)) .....
  109.  */
  110.  
  111. #define RTRACE    0        /*3 show stuff in rel file    */
  112.  
  113. #define DEF_DRIVE(fn) "fn"      /* Make this "0/A:fn" for, say, user 0 on A */
  114.  
  115. #define SUB_FILE   "$$$.SUB"    /* submit file to delete on error exit...
  116.                  * if you use SDOS, use "a:$$$$.sub"; if you've
  117.                  * hacked your CCP, you may need to change the
  118.                  * drive designator letter */
  119.  
  120. #define RST_NUM          6    /* C debugger RST number. Should be identical
  121.                    to the RSTNUM symbol in CCC.ASM      */
  122.  
  123. #define OVERLAYS        /* comment this out for shorter version */
  124.  
  125. /* These #defines from NOBOOT.C for version 1.50 */
  126. #define SNOBSP 0x0138    /* Location of Set NoBoot SP routine in C.CCC    */
  127. #define NOBRET 0x013B    /* Location of NoBoot RETurn routine in C.CCC    */
  128.  
  129. #define CLREX  0x0141    /*3 location of clear externals vector in C.CCC */
  130.  
  131. /*
  132. #define MARC            /* for MARC cross-linker version
  133.                     (enables the "-marc" option) */
  134. */
  135. #include <bdscio.h>
  136.  
  137. #define NUL        0
  138. #define FLAG        char
  139. #define repeat    while (1)
  140.  
  141. #define STDOUT        1
  142.  
  143. /* Phase control */
  144. #define INMEM        1    /* while everything still fits */
  145. #define DISK1        2    /* overflow; finish building table */
  146. #define DISK2        3    /* use table to do window link */
  147. int phase;
  148.  
  149.  
  150. /* function table */
  151. struct funct {
  152.     char fname[9];
  153.     FLAG flinkedp;        /* in memory already? */
  154.     FLAG fdebug;        /* TRUE unless this routine required
  155.                    only by a lib function after -s */
  156.     char *faddr;        /* address of first ref link if not linked */
  157.     } *ftab;
  158. int nfuncts;            /* no. of functions in    table */
  159. int maxfuncts;            /* table size */
  160.  
  161. #define LINKED        1    /* (flinkedp) function really here */
  162. #define EXTERNAL    2    /* function defined in separate symbol table */
  163.  
  164. char fdir [512];        /* CRL file function directory */
  165.  
  166. /* command line parameters etc. */
  167. int nprogs, nlibs;
  168. char progfiles [30] [15];    /* program file names */
  169. char libfiles [20] [15];    /* library file names */
  170. int deflibindex;        /* index of first default (DEFF*) library */
  171. FLAG symsp,            /* write symbols to .sym file? */
  172.     appstatsp,        /* append stats to .sym file? */
  173.     sepstatsp;        /* write stats to .lnk file? */
  174.  
  175. FLAG Zflag,            /*3 disable zeroing of external area? */
  176.     Wflag;            /*3 use wild expansion? */
  177.  
  178. #ifdef MARC
  179. FLAG maxmemp,            /* punt MARC shell? */
  180.     marcp;            /* uses CM.CCC */
  181. #endif
  182.  
  183. FLAG relflag;            /*3 loading a REL file?        */
  184. FLAG anynotlinked;        /*3 any unlinked symbols after scanlib?    */
  185. int  minlk;            /*3 during scanlib, index before first unlinked
  186.                     symbol    */
  187. FLAG nomorecode;        /*3 cannot accept code after data written */ 
  188. char mainfunct[10];
  189. FLAG ovlp;            /* make overlay? */
  190. char symsfile [15];        /* file to load symbols from (for overlays) */
  191.  
  192. /*  C debugger variables  */
  193. FLAG Dflag;
  194. FLAG SysStat;            /* TRUE if "-s" option given & now active */
  195. int  SysNum;            /* index into libfiles of "-s", or -1 if none */
  196.  
  197. FLAG Tflag;            /* TRUE if "-t" option given    */
  198. FLAG Nflag;            /* TRUE if "-n" option given    */
  199. unsigned Tval;            /* arg to "-t", if present    */
  200.  
  201. /* useful things to have defined */
  202. struct inst {
  203.     char opcode;
  204.     char *address;
  205.     };
  206.  
  207. union ptr {
  208.     unsigned u;        /* an int */
  209.     unsigned *w;        /* a word ptr */
  210.     char *b;        /* a byte ptr */
  211.     struct inst *i;        /* an instruction ptr */
  212.     };
  213.  
  214.  
  215. /* Link control variables */
  216.  
  217. union ptr codend;        /* last used byte of code buffer + 1 */
  218. union ptr loadpt;        /*3 where to put code during REL load */
  219. union ptr datapt;        /*3 where to put data during REL load */
  220. union ptr maxdata;        /*3 max dseg address, to estimate end of
  221.                     of externals when main() is .REL  */
  222. union ptr exts;            /* start of externals */
  223. union ptr acodend;        /* actual code-end address */
  224. unsigned extspc;        /* size of externals */
  225. unsigned origin;        /* origin of code */
  226. unsigned buforg;        /* origin of code buffer */
  227. unsigned jtsaved;        /* bytes of jump table saved */
  228.  
  229. char *lspace;            /* space to link in */
  230. char *lspcend;            /* end of link area */
  231. char *lodstart;            /* beginning of current file */
  232. char *lastdata;            /*3 remember how much of ext. area to save */
  233.  
  234. /*3 external function rdrl reads REL bitstream */
  235. struct rrec {
  236.     char itemtype;
  237.     char segtype;
  238.     char linktype;
  239.     int  dataword;
  240.     char lsymlen;
  241.     char lsymbol[8];
  242.     } *rdrl(), *cd;
  243.  
  244. /*3 REL file address type codes    */
  245. #define    ASEG    0
  246. #define    CSEG    1
  247. #define DSEG    2
  248. #define COMMON    3
  249.  
  250. /*3 character used for 8th char.C of REL external symbols */
  251. #define WILDC    '?'
  252.  
  253. /* i/o buffer */
  254. struct iobuf {
  255.     int fd;
  256.     int isect;        /* currently buffered sector */
  257.     int nextc;        /* index of next char in buffer */
  258.     char buff [128];
  259.     } ibuf, obuf;
  260.  
  261. /* BDS C i/o buffer */
  262. char symbuf[BUFSIZ];
  263.  
  264. /* seek opcodes */
  265. #define ABSOLUTE 0
  266. #define RELATIVE 1
  267.  
  268. #define INPUT 0
  269.  
  270. #define TRUE (-1)
  271. #define FALSE 0
  272. #define NULL 0
  273.  
  274. /* 8080 instructions */
  275. #define LHLD 0x2A
  276. #define LXISP 0x31
  277. #define LXIH 0x21
  278. #define SPHL 0xF9
  279. #define JMP  0xC3
  280. #define CALL 0xCD
  281. #define RET  0xC9
  282.  
  283. #define PARMSIZE    400
  284. char parmtext[PARMSIZE];  /* "-i" command line args go here */
  285. int  parmindex;          /* first unused character in parmtext */
  286.  
  287. /* strcmp7 locals, made global for speed */
  288. char _c1, _c2, _end1, _end2;
  289.  
  290. /**************** End of Globals ****************/
  291.  
  292.  
  293. main (argc, argv)
  294.     int argc;
  295.     char **argv;
  296. {
  297.     char *argvv[40];
  298.  
  299.     puts ("Mark of the Unicorn Linker ver. 2.2.6\n");
  300.     inc_proc(&argc, argv, &argvv);
  301.     setup (argc, argvv);
  302.     linkprog();
  303.     linklibs();
  304.     if (phase == DISK1) rescan();
  305.     else wrtcom();
  306.     if (symsp) wrtsyms();
  307.     }
  308.  
  309.  
  310. inc_proc(count, argv, argvv) int *count; char **argv, **argvv; {
  311.     /* process the "-i" argument by building a new argv vector
  312.      * in argvv.
  313.      */
  314.  
  315.     int i;
  316.  
  317.     for (i=0; i<*count; i++) argvv[i] = argv[i];
  318.  
  319.     while (!strcmp(argvv[*count-1],"-I"))
  320.         buildvec(count, argvv);
  321. }
  322.  
  323. buildvec (count, argvv) int *count; char **argvv; {
  324.     char line[MAXLINE], *p;
  325.  
  326.     puts("Enter continuation\n*");
  327.     gets(line);
  328.  
  329.     for (p=line, --*count; ;) {
  330.         while (isspace(*p)) p++;
  331.         if (!*p) break;
  332.         argvv[(*count)++] = &parmtext[parmindex];
  333.         while (*p && !isspace(parmtext[parmindex] = toupper(*p++)) )
  334.             parmindex++;
  335.         parmtext[parmindex++] = 0;
  336.         }
  337. }
  338.  
  339. setup (argc, argv)        /* initialize function table, etc. */
  340.     int argc;
  341.     char **argv;
  342. {
  343.     symsp = appstatsp = sepstatsp = FALSE;    /* default options */
  344. #ifdef MARC
  345.     marcp = maxmemp = FALSE;
  346. #endif
  347.     ovlp = FALSE;
  348.     nprogs = 0;
  349.     nlibs = 0;
  350.     strcpy (&mainfunct, "MAIN");    /* default top-level function */
  351.     origin = 0x100;            /* default origin */
  352.     maxfuncts = 200;        /* default function table size */
  353.     Zflag = Tflag = Nflag = FALSE;        /* no "-z","-t" or "-n" yet */
  354.     SysNum = -1;
  355.     SysStat = FALSE;
  356.     Dflag = FALSE;
  357.     cmdline (argc, argv);
  358.     ftab = endext();
  359.     lspace = ftab + maxfuncts;
  360.     lspcend = topofmem() - (1024 + 2100);
  361.     if (lspace > lspcend)
  362.         Fatal ("Insufficient memory to do anything at all!\n");
  363.     loadccc();
  364.     nfuncts = 0;
  365. #ifdef OVERLAYS
  366.     if (ovlp) loadsyms();
  367. #endif
  368.     intern (&mainfunct);
  369.     phase = INMEM;
  370.     buforg = origin;
  371.     jtsaved = 0;
  372.     nomorecode = FALSE;    /* no data yet written to disk    */
  373.     maxdata.u =
  374.     lastdata = 0;        /* no data encountered so far    */
  375.     }
  376.  
  377. cmdline (argc, argv)        /* process command line */
  378.     int argc;
  379.     char **argv;
  380. {
  381.     int i, progp;
  382.  
  383.     if (argc == 1) {
  384.         puts ("Usage is:\n");
  385.         puts ("  l2 {program files} [-l {library files} ] ");
  386.         puts ("[-s {library files} ]\n");
  387.         puts ("\t[-m <main_name>] [-f <maxfuncts>] [-org <addr>]");
  388.         puts (" [-t <addr>] [-e <addr>]\n");
  389.         puts ("\t[-d] [-w | -wa | -ws] [-n][-z][-*]\n");
  390. #ifdef OVERLAYS
  391.         puts ("\t[-ovl <rootname> <addr>]");
  392. #endif
  393. #ifdef MARC
  394.         puts ("\t[-marc]");
  395. #endif
  396.         puts ("\t[-i]");
  397.         lexit (1);
  398.         }
  399.     progp = TRUE;
  400.     for (i=1; i < argc; ++i) {
  401.         if (argv[i][0] == '-') {
  402.             if (!strcmp (argv[i], "-F")) {
  403.                 if (++i>=argc) Fatal ("-f argument missing.\n");
  404.                 sscanf (argv[i], "%d", &maxfuncts);
  405.                 }
  406.             else if (!strcmp (argv[i], "-L")) progp = FALSE;
  407.             else if (!strcmp (argv[i], "-S")) {
  408.                 progp = FALSE;
  409.                 SysNum = nlibs;
  410.                 }
  411.             else if (!strcmp (argv[i], "-M")) {
  412.                 if (++i>=argc) Fatal ("-m argument missing.\n");
  413.                 strcpy (&mainfunct, argv[i]);
  414.                 }
  415. #ifdef MARC
  416.             else if (!strcmp (argv[i], "-MARC")) {
  417.                 maxmemp = TRUE;
  418.                 marcp = TRUE;
  419.                 }
  420. #endif
  421.             else if (!strcmp (argv[i], "-ORG")) {
  422.                 if (++i>=argc) Fatal ("-org argument missing.\n");
  423.                 sscanf (argv[i], "%x", &origin);
  424.                 }
  425.             else if (!strcmp (argv[i], "-N")) Nflag = TRUE;
  426.             else if (!strcmp (argv[i], "-Z")) Zflag = TRUE;
  427.             else if (!strcmp (argv[i], "-*")) Wflag = TRUE;
  428.             else if (!strcmp (argv[i], "-T")) {
  429.                 if (++i >= argc)
  430.                     Fatal ("-t argument missing.\n");
  431.                 Tflag = TRUE;
  432.                 sscanf (argv[i], "%x", &Tval);
  433.                 }
  434.             else if (!strcmp (argv[i], "-E")) {
  435.                 if (++i >= argc)
  436.                     Fatal ("-e argument missing.\n");
  437.                 sscanf (argv[i], "%x", &exts.u);
  438.                 }
  439. #ifdef OVERLAYS
  440.             else if (!strcmp (argv[i], "-OVL")) {
  441.                 ovlp = TRUE;
  442.                 if (i + 2 >= argc)
  443.                     Fatal ("-ovl argument missing.\n");
  444.                 strcpy (&symsfile, argv[++i]);
  445.                 sscanf (argv[++i], "%x", &origin);
  446.                 }
  447. #endif
  448.             else if (!strcmp (argv[i], "-D")) Dflag = TRUE; 
  449.             else if (!strcmp (argv[i], "-W")) symsp = TRUE;
  450.             else if (!strcmp (argv[i], "-WA")) 
  451.                 symsp = appstatsp = TRUE;
  452.             else if (!strcmp (argv[i], "-WS")) 
  453.                 symsp = sepstatsp = TRUE;
  454.             else if (!strcmp (argv[i], "-I"))
  455.                 printf("-I ignored, must be last on line\n");
  456.             else printf ("Unknown option: '%s'\n", argv[i]);
  457.             }
  458.         else {
  459.             if (progp) strcpy (&progfiles[nprogs++], argv[i]);
  460.             else strcpy (&libfiles[nlibs++], argv[i]);
  461.             }
  462.         }
  463.     if (ovlp)
  464.         strcpy(&mainfunct, &progfiles[0][2*(progfiles[0][1]==':')] );
  465.     if (Dflag || SysNum!=-1)
  466.         Dflag = symsp = TRUE;
  467.  
  468.     deflibindex = nlibs;
  469. #ifdef MARC
  470. #define NDEFF    3
  471.     strcpy(&libfiles[nlibs++], marcp ? DEF_DRIVE(DEFFM) : DEF_DRIVE(DEFF));
  472.     strcpy(&libfiles[nlibs++], marcp ? DEF_DRIVE(DEFF2M): DEF_DRIVE(DEFF2));
  473.     strcpy(&libfiles[nlibs++], marcp ? DEF_DRIVE(DEFF3M): DEF_DRIVE(DEFF3));
  474. #else
  475. #define NDEFF    4    /*3 deff's + bdsclib*/
  476.     strcpy(&libfiles[nlibs++], DEF_DRIVE(BDSCLIB.REL) );
  477.     strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF) );
  478.     strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF2) );
  479.     strcpy(&libfiles[nlibs++], DEF_DRIVE(DEFF3) );
  480. #endif
  481.     }
  482.  
  483.  
  484. loadccc()            /* load C.CCC (runtime library) */
  485. {
  486.     union ptr temp;
  487.     unsigned len;
  488.  
  489.     codend.b = lspace;
  490.     if (!ovlp) {
  491. #ifdef MARC
  492.         if (copen (&ibuf, 
  493.               marcp ? DEF_DRIVE(CM.CCC) : DEF_DRIVE(C.CCC) ) < 0)
  494. #else
  495.         if (copen (&ibuf, 
  496.               Wflag ? DEF_DRIVE(WILD.CCC) : DEF_DRIVE(C.CCC) ) < 0)
  497. #endif
  498.             Fatal ("Can't open %s\n", DEF_DRIVE(C.CCC) );
  499.         if (cread (&ibuf, lspace, 128) < 128)    /* read a sector */
  500.             Fatal ("C.CCC: read error!\n");
  501.         temp.b = lspace + 0x17;
  502.         len = *temp.w;                /* how long is it? */
  503.         cread (&ibuf, lspace + 128, len - 128);    /* read rest */
  504.         codend.b += len;
  505.         cclose (&ibuf);
  506.         }
  507.     else codend.i++->opcode = JMP;
  508.     }
  509.  
  510.  
  511. linkprog()                /* link in all program files */
  512. {
  513.     int i;
  514.     union ptr dirtmp;
  515.     struct funct *fnct;
  516.  
  517.     for (i=0; i<nprogs; ++i) {
  518.  
  519.         makecrl (&progfiles[i]);
  520.  
  521.         if (copen (&ibuf, progfiles[i]) < 0) {
  522.             printf ("Can't open %s\n", progfiles[i]);
  523.             continue;
  524.             }
  525.         printf ("Loading  %s\n", &progfiles[i]);
  526.  
  527.         if (relflag)
  528.         {    readrel(1);
  529.             relflag = FALSE;
  530.             cclose(&ibuf);
  531.             continue;
  532.         }
  533.  
  534.         readprog (i==0);
  535.  
  536.         for (dirtmp.b=&fdir; *dirtmp.b != 0x80;) {
  537.             fnct = intern (dirtmp.b);    /* for each module */
  538.             skip7 (&dirtmp);        /* in directory */
  539.             if (!fnct->flinkedp)
  540.                 linkmod (fnct, lodstart + *dirtmp.w - 0x205,0);
  541.             else if (phase != DISK2) {
  542.                 puts ("Duplicate program function '");
  543.                 puts (&fnct->fname);
  544.                 puts ("', not linked.\n");
  545.                 }
  546.             dirtmp.w++;
  547.             }                /* intern & link it */
  548.         cclose (&ibuf);
  549.         }
  550.     }
  551.  
  552.  
  553. linklibs()                /* link in library files */
  554. {
  555.     int ifile;
  556.  
  557.     anynotlinked = TRUE;
  558.     minlk = 0;
  559.  
  560.     for (ifile=0; anynotlinked && ifile < nlibs; ++ifile) {
  561.         if (ifile==SysNum) SysStat = TRUE;
  562.         scanlib (ifile);
  563.         }
  564.  
  565.     while (missingp()) {
  566.         anynotlinked = TRUE;
  567.         puts ("Enter the name of a file to be searched or CR: ");
  568.         gets (&libfiles[nlibs]);
  569.         if (libfiles[nlibs][0]) {
  570.             SysStat = FALSE;
  571.             scanlib (nlibs);
  572.             }
  573.         else {
  574.             if (SysNum!=-1)
  575.                 SysStat = TRUE;
  576.             for (ifile=0; anynotlinked && ifile<NDEFF; ++ifile)
  577.                 scanlib (deflibindex + ifile);
  578.             }
  579.         }
  580.     acodend.b = codend.b - lspace + buforg;        /* save that number! */
  581.     if (!exts.b) exts.b = acodend.b;
  582.     }
  583.  
  584.  
  585. missingp()        /* are any functions missing?  print them out */
  586. {
  587.     int i, foundp;
  588.  
  589.     foundp = FALSE;
  590.     for (i=0; i<nfuncts; ++i)
  591.         if (!ftab[i].flinkedp) {
  592.             if (!foundp) puts ("*** Missing functions:\n");
  593.             puts (&ftab[i].fname);
  594.             puts ("\n");
  595.             foundp = TRUE;
  596.             }
  597.     return (foundp);
  598.     }
  599.  
  600.  
  601. rescan()        /* perform second disk phase */
  602. {
  603.     int i;
  604.     
  605.     for (i=0; i < nfuncts; ++i)
  606.         if (ftab[i].flinkedp == LINKED) ftab[i].flinkedp = FALSE;
  607.     phase = DISK2;
  608.     buforg = origin;
  609.     puts ("\n\n**** Beginning second disk pass ****\n");
  610.     if (!ovlp) makeext (&progfiles[0], "COM");
  611.     else makeext (&progfiles[0], "OVL");
  612.     ccreat (&obuf, &progfiles[0]);
  613.     loadccc();
  614.     hackccc();
  615.     linkprog();
  616.     linklibs();
  617.     if (lastdata > codend.b) codend.b = lastdata;
  618.     if (cwrite (&obuf, lspace, codend.b - lspace) == -1
  619.         ||    cflush (&obuf) < 0) Fatal ("Disk write error!\n");
  620.     cclose (&obuf);
  621.     stats (STDOUT);
  622.     }
  623.  
  624.  
  625.  
  626. readprog (mainp)            /* read in a program file */
  627.     FLAG mainp;
  628. {
  629.     char extp;                /* was -e used? */
  630.     char *extstmp;
  631.     union ptr dir;
  632.     unsigned len;
  633.  
  634.     if (cread (&ibuf, &fdir, 512) < 512)        /* read directory */
  635.         Fatal ("-- read error!\n");
  636.     if (phase == INMEM  &&    mainp) {
  637.         cread (&ibuf, &extp, 1);
  638.         cread (&ibuf, &extstmp, 2);
  639.         cread (&ibuf, &extspc, 2);
  640.         if (extp) exts.b = extstmp;
  641.         else exts.b = 0;        /* will be set later */
  642.         }
  643.     else cseek (&ibuf, 5, RELATIVE);
  644.     for (dir.b=&fdir; *dir.b != 0x80; nextd (&dir));  /* find end of dir */
  645.     ++dir.b;
  646.     len = *dir.w - 0x205;
  647.     readobj (len, TRUE);
  648.     }
  649.  
  650.  
  651. readobj (len, crllod)        /* read in an object (program or lib funct) */
  652.     unsigned len;
  653.     FLAG    crllod;    /*3 read CRL? (or just check len for REL load) */
  654. {
  655.     if (phase == DISK1  ||    codend.b + len >= lspcend) {
  656.         if (phase == INMEM) {
  657.             puts("\n** Out of memory--switching to disk mode **\n");
  658.             phase = DISK1;
  659.             }
  660.         if (phase == DISK2) {
  661.             if (cwrite (&obuf, lspace, codend.b - lspace) == -1)
  662.                 Fatal ("Disk write error!\n");
  663.             }
  664.         buforg += codend.b - lspace;
  665.         codend.b = lspace;
  666.         if (codend.b + len >= lspcend)
  667.             Fatal ("Module won't fit in memory at all!\n");
  668.         }
  669.  
  670.     lodstart = codend.b;
  671.     if (crllod && cread (&ibuf, lodstart, len) < len)
  672.         Fatal ("-- read error!\n");
  673.  
  674.     }
  675.  
  676.  
  677. scanlib (ifile)
  678.     int ifile;
  679. {
  680.     int i;
  681.     union ptr dirtmp;
  682.     FLAG morerel;    /*3 keep track of whether have read eof link in REL */
  683.  
  684.     if (minlk >= nfuncts)
  685.     {    anynotlinked = FALSE;
  686.         return;
  687.     }
  688.  
  689.     makecrl (&libfiles[ifile]);
  690.  
  691.     if (copen (&ibuf, libfiles[ifile]) < 0) {
  692.         if (ifile != deflibindex + (NDEFF-1))
  693.             printf ("Can't open %s\n", libfiles[ifile]);
  694.         return;
  695.         }
  696.     printf ("Scanning %s\n", &libfiles[ifile]);
  697.  
  698.     if (!relflag && cread (&ibuf, &fdir, 512) < 512) /* read directory */
  699.         Fatal ("-- Read error!\n");
  700.  
  701.     anynotlinked = FALSE;
  702.  
  703.    if (relflag)
  704.      {    morerel = readrel(FALSE); /* position at first link 0 item */
  705.     i = minlk;
  706.     while (i < nfuncts && morerel)
  707.     {
  708.         if (ftab[i].flinkedp) /* a feeble attempt at opt'n    */
  709.         { if (i == minlk) minlk++; }
  710.  
  711.         else
  712.         {    anynotlinked = TRUE;
  713.              if (!strcmp7(cd->lsymbol,&ftab[i].fname) )
  714.             /* load this module and go back to first unlinked f'n*/
  715.                 {  morerel = readrel(2); i = minlk-1; }
  716.         }
  717.  
  718.         i++;
  719.  
  720.         /* when last unlinked function has been compared,
  721.            scan to next module (if there is one) and go back
  722.            to first unlinked function    */
  723.         if (i == nfuncts)
  724.         {    if (morerel) morerel = readrel(FALSE);
  725.             i = minlk;
  726.         }
  727.     }
  728.     /* make sure to read to end of REL file    */
  729.     while (morerel) morerel = readrel(FALSE);
  730.      }
  731.    else
  732.     for (i=minlk; i<nfuncts; ++i)    /* scan needed functions */
  733.        if (ftab[i].flinkedp)
  734.        { if (i == minlk) minlk++; }
  735.        else
  736.        {    anynotlinked = TRUE;
  737.             if (dirtmp.b = dirsearch (&ftab[i].fname))
  738.             {    readfunct (dirtmp.b);
  739.                 linkmod (&ftab[i], lodstart,0);
  740.             }
  741.        }
  742.  
  743.  
  744.     relflag = FALSE;
  745.     cclose (&ibuf);
  746.  
  747.     }
  748.  
  749.  
  750. readfunct (direntry)            /* read a function (from a library) */
  751.     union ptr direntry;
  752. {
  753.     unsigned start, len;
  754.  
  755.     skip7 (&direntry);
  756.     start = *direntry.w++;
  757.     skip7 (&direntry);
  758.     len = *direntry.w - start;
  759.     if (cseek (&ibuf, start, ABSOLUTE) < 0) Fatal (" -- read error!");
  760.     readobj (len, TRUE);
  761.     }
  762.  
  763. /*3 load or scan a REL file */
  764.     /* loadit = FALSE -- don't load, and stop at link item 0
  765.        loadit = 1     -- load all 'til link item 15 (eof)
  766.        loadit = 2     -- load, but stop at link item 0
  767.     Returns TRUE when stopped at link 0, else FALSE        */
  768. readrel(loadit)
  769. char loadit;
  770. {
  771.     struct funct *fnct;
  772.     union ptr finalloc, raddr, temp;
  773.     char litem, currseg;
  774.     int i;
  775.     unsigned modoffset; /* when loading rel lib, keep track
  776.                 of offset of beginning of module from
  777.                 beginning of lib file    */
  778.  
  779.     lodstart =
  780.     loadpt.b = codend.b;
  781.     modoffset = 0;
  782.     currseg = CSEG;
  783.     finalloc.b = codend.b - lspace + buforg;
  784.  
  785.     litem = 16;    /* assign any value except 15    */
  786.  
  787.     while(litem != 15)
  788.     { cd = rdrl();
  789. #if RTRACE
  790. if (loadit) printf("Load "); else printf("Scan ");
  791. printf("at %04x: ",loadpt.u);
  792. #endif
  793.       switch(cd->itemtype)
  794.        {
  795.         case 0:
  796. #if RTRACE
  797.     printf("code %02x\n", cd->dataword);
  798. #endif
  799.             if (loadit)
  800.             {  if (currseg == DSEG)
  801.                {    dataroom(1);
  802.                 if (phase != DISK1)
  803.                  *datapt.b++ = cd->dataword;
  804.                }
  805.                else    *loadpt.b++ = cd->dataword;
  806.             }
  807.             break;
  808.  
  809.  
  810.         case 1:
  811. #if RTRACE
  812.     printf("addr %04x seg %d\n", cd->dataword,cd->segtype);
  813. #endif
  814.  
  815.           if (loadit)
  816.           {    temp.b = (cd->segtype==DSEG) ? (exts.b + cd->dataword)
  817.                    : cd->dataword + modoffset + finalloc.b;
  818.             if (currseg == CSEG)
  819.              *loadpt.w++ = temp.b;
  820.             else if (currseg == DSEG)
  821.             {    dataroom(2);
  822.                 if (phase != DISK1)
  823.                  *datapt.w++ = temp.b;
  824.             }
  825.            }
  826.  
  827.            break;
  828.  
  829.  
  830.         case 2:    litem = cd->linktype;
  831. #if RTRACE
  832.     printf("link %d : ", litem);
  833.     if (litem >= 5 && litem <= 14)
  834.        printf("addr %x seg %d ", cd->dataword,cd->segtype);
  835.     if (litem <= 7)
  836.       for (i = 0; i < cd->lsymlen; i++ )
  837.         putchar(0x7F & (cd->lsymbol[i]));
  838.     printf("\n");
  839. #endif
  840.  
  841.             if (!loadit)
  842.             {
  843.                 if (litem == 0) return(TRUE);
  844.             }
  845.             else switch(litem)
  846.     {
  847.  
  848.     case 0:    /* PUBLIC SYMBOL */
  849.         modoffset = loadpt.b - lodstart;
  850.         if (loadit > 2)
  851.         {    codend.b = loadpt.b;
  852.             return(TRUE);
  853.         }
  854.         break;
  855.  
  856.     case 7: /* ENTRY POINT */
  857.         fnct = intern(cd->lsymbol);
  858.         linkmod(fnct, lodstart, cd->dataword + modoffset);
  859.         /* during scanlib, signal stop at next link item 0    */
  860.         if (loadit > 1) loadit++;
  861.         break;
  862.  
  863.     case 6:    /* EXTERNAL REFERENCE */
  864.         /* a symbol declared "ext" but not referenced
  865.            will be link item 6, seg 0=ASEG - it should be ignored */
  866.         if (cd->segtype != ASEG)
  867.         {    fnct = intern(cd->lsymbol);
  868.             temp.b =
  869.             raddr.b = lodstart + cd->dataword + modoffset;
  870.             if (!fnct->flinkedp && phase == INMEM)
  871.             {
  872.               /* find end of chain in REL file */
  873.               while (*raddr.w)
  874.               {
  875. #if RTRACE
  876.  printf("*chaining addr %x, contents %x\n", raddr.b, *raddr.w);
  877. #endif
  878.               /* convert to real memory address */
  879.                  *raddr.w = (*raddr.w - modoffset)
  880.                         + (lspace - buforg);
  881.               /* and descend one link    */
  882.                  raddr.b = *raddr.w;
  883.               }
  884.               /* point end of chain to head of old chain */
  885.               *raddr.w = fnct->faddr;
  886.               /* enter here in ftab as new chain head */
  887.               fnct->faddr = temp.b;
  888.             }
  889.  
  890.             else /* put addr in each link of REL chain */
  891.             while (temp.b)
  892.             { temp.b = *raddr.w;
  893.               *raddr.w = fnct->faddr;
  894. #if RTRACE
  895.  printf("*Changed %x from %x to %x\n", raddr.b, temp.b, *raddr.w);
  896. #endif
  897.               raddr.u = (temp.u - modoffset)
  898.                      + (lspace - buforg);
  899.             }
  900.         } /* end of if (cd->segtype == CSEG) */
  901.         break; /* for case litem == 6 */
  902.  
  903.     case 11: /* ORG */
  904.         if ( (currseg = cd->segtype) == CSEG)
  905.             loadpt.b = lodstart + modoffset + cd->dataword;
  906.         else if (currseg == DSEG)
  907.         {    if (!exts.b) Fatal("Need -e<address> for DSEG");
  908.             if (maxdata.u < cd->dataword)
  909.                 maxdata.u = cd->dataword;
  910.             datapt.b = (exts.u + cd->dataword) + (lspace - buforg);
  911.             if (datapt.u < lspace) Fatal("DSEG addr. too low");
  912.         }
  913.         break;
  914.  
  915.     case 13: /* LENGTH OF CODE IN MODULE */
  916.         if (nomorecode)
  917.           Fatal("Cannot write code because of preceding DSEG data");
  918.         if
  919.          (    loadit
  920.              && (phase == DISK1 || loadpt.b + cd->dataword >= lspcend)
  921.          )
  922.         {    codend.b = loadpt.b;
  923.             readobj(cd->dataword, FALSE);
  924.             loadpt.b = codend.b;
  925.             modoffset = 0;
  926.         }
  927.         break;
  928.  
  929.     case  3: /* REQUEST */
  930.         if (loadit && phase != DISK2)
  931.         {    temp.b = &libfiles[nlibs++];
  932.             strcpy7(temp.b, cd->lsymbol);
  933.             str7tont(temp.b);
  934.             *(temp.b+7) = '\0';
  935.             makeext(temp.b,"REL");
  936. #if RTRACE
  937. printf("Requested %s\n", temp.b);
  938. #endif
  939.         }
  940.         break;
  941.  
  942.     /* other cases for possible future use are
  943.         -  9 - offset for external reference
  944.         -  4 - arithmetic with external symbols (1st letter
  945.             of lsymbol gives the operation to perform)
  946.         -  2 - gives module name
  947.         - 10 - gives length of data
  948.     */
  949.     default:
  950.         break;
  951.  
  952.     }    /* end switch(litem)    */
  953.  
  954.             break;
  955.  
  956.         default: Fatal("Illegal code in REL file\n");
  957.             break;
  958.       } /* end switch(cd->itemtype)    */
  959.     } /* end while(litem != 15)    */
  960.  
  961.  
  962.     if (loadit) codend.b = loadpt.b;
  963.     return(FALSE);
  964. }
  965.  
  966. /*3 check room for DSEG data    */
  967. dataroom(len)
  968. char len;
  969. {    if (phase != DISK1 && datapt.b + len >= lspcend)
  970.      if (phase == INMEM) phase = DISK1;
  971.      else
  972.      {    codend.b = datapt.b;
  973.         readobj(len, FALSE);
  974.         datapt.b = codend.b;
  975.         nomorecode = TRUE;
  976.      }
  977.  
  978.     lastdata = datapt.b + len;
  979.     Zflag = TRUE;
  980. }
  981.  
  982.  
  983. /*3 global return value from cread1 */
  984. char rrch ;
  985.  
  986. /*3 called by rdrl to read one byte from REL file */
  987. cread1()
  988. {
  989.     if (cread(&ibuf, &rrch, 1) != 1)
  990.         Fatal("Premature end of REL file\n");
  991.     return(rrch);
  992. }
  993.  
  994.  
  995. linkmod (fnct, modstart, foffset)        /* link in a module */
  996.     struct funct *fnct;
  997.     union ptr modstart;        /* loc. of module in memory */
  998.     unsigned foffset;        /*3 for REL files with late entry pts*/
  999. {
  1000.     union ptr temp,
  1001.             jump,        /* jump table temp */
  1002.             body,        /* loc. of function in memory */
  1003.             code,        /* loc. of code proper in mem. */
  1004.             finalloc;    /* runtime loc. of function */
  1005.     unsigned flen, nrelocs, jtsiz, offset;
  1006.  
  1007.     fnct->flinkedp = LINKED;
  1008.     if (phase != DISK2) {
  1009.         finalloc.b =
  1010.          (relflag && cd->segtype == DSEG)? exts.u + foffset
  1011.             : codend.b - lspace + buforg + foffset;
  1012.         if (phase == INMEM) chase (fnct->faddr, finalloc.b);
  1013.         fnct->faddr = finalloc.b;
  1014.         }
  1015.     else finalloc.b = fnct->faddr;
  1016.  
  1017.     /* REL file relocation already done */
  1018.     if (relflag) return;
  1019.  
  1020.     body.b = modstart.b + strlen(modstart.b) + 3; /* loc. of fn body */
  1021.     jump.i = body.i + (*modstart.b ? 1 : 0);
  1022.     for (temp.b = modstart.b; *temp.b; skip7(&temp)) {
  1023.         jump.i->address = intern (temp.b);
  1024.         ++jump.i;
  1025.         }
  1026.     ++temp.b;
  1027.     flen = *temp.w;
  1028.     code.b = jump.b;
  1029.     temp.b = body.b + flen;        /* loc. of reloc parameters */
  1030.     nrelocs = *temp.w++;
  1031.     jtsiz = code.b - body.b;
  1032.     if (Dflag && fnct->fdebug) {
  1033.         if (phase!=DISK1) {
  1034.             codend.i->opcode = (0307 + (8*RST_NUM));
  1035.             codend.i->address = 0;
  1036.             finalloc.b += 3;
  1037.             }
  1038.         codend.b += 3;
  1039.         }
  1040.     offset = code.b - codend.b;
  1041.     if (phase != DISK1)
  1042.         while (nrelocs--) relocate (*temp.w++, body.b, jtsiz,
  1043.                            finalloc.b, offset, flen);
  1044.     flen -= jtsiz;
  1045.     if (phase != DISK2) jtsaved += jtsiz;
  1046.     if (phase != DISK1) movmem (code.b, codend.b, flen);
  1047.     codend.b += flen;
  1048.     }
  1049.  
  1050.  
  1051. relocate (param, body, jtsiz, base, offset, flen)    /* do a relocation!! */
  1052.     unsigned param, jtsiz, base, offset, flen;
  1053.     union ptr body;
  1054. {
  1055.     union ptr instr,            /* instruction involved */
  1056.             ref;                /* jump table link */
  1057.     struct funct *fnct;
  1058.  
  1059. /*    if (param == 1) return;            /* don't reloc jt skip */*/
  1060.     instr.b = body.b + param - 1;
  1061.     if (instr.i->address >= jtsiz)
  1062.         instr.i->address += base - jtsiz;    /* vanilla case */
  1063.     else {
  1064.         ref.b = instr.i->address + body.u;
  1065.         if (instr.i->opcode == LHLD) {
  1066.             instr.i->opcode = LXIH;
  1067.             --ref.b;
  1068.             }
  1069.         fnct = ref.i->address;
  1070.         instr.i->address = fnct->faddr;        /* link in */
  1071.         if (!fnct->flinkedp  &&  phase == INMEM)
  1072.             fnct->faddr = instr.b + 1 - offset;  /* new list head */
  1073.         }
  1074.     }
  1075.  
  1076.  
  1077. intern (name)            /* intern a function name in the table */
  1078.     char *name;
  1079. {
  1080.     struct funct *fptr;
  1081.  
  1082.     if (*name == 0x9D) name = "MAIN";        /* Why, Leor, WHY??? */
  1083.     for (fptr = &ftab[nfuncts-1]; fptr >= ftab; --fptr)
  1084.         if (!strcmp7 (name, fptr->fname)) break;
  1085.     if (fptr < ftab) {
  1086.         if (nfuncts >= maxfuncts)
  1087.             Fatal("Too many functions (limit is %d)!\n", maxfuncts);
  1088.         fptr = &ftab[nfuncts];
  1089.         strcpy7 (fptr->fname, name);
  1090.         str7tont (fptr->fname);
  1091.         fptr->flinkedp = FALSE;
  1092.         fptr->faddr = NULL;
  1093.         fptr->fdebug = !SysStat;
  1094.         ++nfuncts;
  1095.         }
  1096.     return (fptr);
  1097.     }
  1098.  
  1099.  
  1100. dirsearch (name)            /* search directory for a function */
  1101.     char *name;
  1102. {
  1103.     union ptr temp;
  1104.  
  1105.     for (temp.b = &fdir; *temp.b != 0x80; nextd (&temp))
  1106.         if (!strcmp7 (name, temp.b)) return (temp.b);
  1107.     return (NULL);
  1108.     }
  1109.  
  1110.  
  1111. nextd (ptrp)            /* move this pointer to the next dir entry */
  1112.     union ptr *ptrp;
  1113. {
  1114.     skip7 (ptrp);
  1115.     ++(*ptrp).w;
  1116.     }
  1117.  
  1118.  
  1119. chase (head, loc)        /* chase chain of refs to function */
  1120.     union ptr head;
  1121.     unsigned loc;
  1122. {
  1123.     union ptr temp;
  1124.  
  1125.     while (head.w) {
  1126.         temp.w = *head.w;
  1127.         *head.w = loc;
  1128.         head.u = temp.u;
  1129.         }
  1130.     }
  1131.  
  1132.  
  1133. wrtcom()            /* write out com file (from in-mem link) */
  1134. {
  1135.     hackccc();
  1136.     if (!ovlp) makeext (&progfiles[0], "COM");
  1137.     else makeext (&progfiles[0], "OVL");
  1138.  
  1139.     if (lastdata > codend.b) codend.b = lastdata;
  1140.  
  1141.     if (!ccreat (&obuf, &progfiles[0]) < 0
  1142.         ||    cwrite (&obuf, lspace, codend.b - lspace) == -1
  1143.         ||    cflush (&obuf) < 0)
  1144.         Fatal ("Disk write error!\n");
  1145.     cclose (&obuf);
  1146.     stats (STDOUT);
  1147.     }
  1148.  
  1149.  
  1150. hackccc()            /* store various goodies in C.CCC code */
  1151. {
  1152.     union ptr temp;
  1153.     struct funct *fptr;
  1154.  
  1155.     temp.b = lspace;
  1156.     fptr = intern (&mainfunct);
  1157.     if (!ovlp) {
  1158. #ifdef MARC
  1159.         if (!marcp) {
  1160. #endif
  1161.             if (Tflag) {
  1162.                 temp.i->opcode = LXISP;
  1163.                 temp.i->address = Tval;
  1164.                 }
  1165.             else if (Nflag) {
  1166.                 temp.i->opcode = JMP;
  1167.                 temp.i->address = SNOBSP;
  1168.                 temp.b = lspace + 0x09;
  1169.                 temp.i->opcode = JMP;
  1170.                 temp.i->address = NOBRET;
  1171.                 }
  1172.             else {
  1173.                 temp.i->opcode = LHLD;
  1174.                 temp.i->address = origin - 0x100 + 6;
  1175.                 (++temp.i)->opcode = SPHL;
  1176.                 }
  1177.  
  1178.             if (Zflag)
  1179.             {    temp.b = lspace + 0x41;
  1180.                 temp.i->opcode = RET;
  1181.             }
  1182.  
  1183.             temp.b = lspace + 0xF;        /* main function address */
  1184.             temp.i->address = fptr->faddr;
  1185. #ifdef MARC
  1186.             }
  1187. #endif
  1188.         temp.b = lspace + 0x15;
  1189.         *temp.w++ = exts.u;
  1190.         ++temp.w;
  1191.         *temp.w++ = acodend.u;
  1192.         if (extspc < maxdata.u)
  1193.             extspc = maxdata.u;
  1194.         *temp.w++ = exts.u + extspc;
  1195.         }
  1196.     else temp.i->address = fptr->faddr;        /* that's a JMP */
  1197. #ifdef MARC
  1198.     if (maxmemp) {
  1199.         temp.b = lspace + 0x258;
  1200.         temp.i->opcode = CALL;
  1201.         temp.i->address = 0x50;
  1202.         }
  1203. #endif
  1204.     }
  1205.  
  1206.  
  1207. wrtsyms()                    /* write out symbol table */
  1208. {
  1209.     int i, fd, compar();
  1210.     
  1211.     qsort (ftab, nfuncts, sizeof(*ftab), &compar);
  1212.     makeext (&progfiles[0], "SYM");
  1213.     if (fcreat (&progfiles[0], &symbuf) < 0)
  1214.         Fatal ("Can't create .SYM file\n");
  1215.     for (i=0; i < nfuncts; ++i) {
  1216.         puthex (ftab[i].faddr, &symbuf);
  1217.         putc (' ', &symbuf);
  1218.         fputs (&ftab[i].fname, &symbuf);
  1219.         if (i % 4 == 3) fputs ("\n", &symbuf);
  1220.         else {
  1221.             if (strlen (&ftab[i].fname) < 3) putc ('\t', &symbuf);
  1222.             putc ('\t', &symbuf);
  1223.             }
  1224.         }
  1225.     if (i % 4) fputs ("\n", &symbuf);    
  1226.     if (appstatsp) stats (&symbuf);
  1227.     putc (CPMEOF, &symbuf);
  1228.     fflush (&symbuf);
  1229.     fclose (&symbuf);
  1230.     if (sepstatsp) {
  1231.         makeext (&progfiles[0], "LNK");
  1232.         if (fcreat (&progfiles[0], &symbuf) < 0)
  1233.             Fatal ("Can't create .LNK file\n");
  1234.         stats (&symbuf);
  1235.         putc (CPMEOF, &symbuf);
  1236.         fflush (&symbuf);
  1237.         fclose (&symbuf);
  1238.         }
  1239.     }
  1240.  
  1241.  
  1242. compar (f1, f2)            /* compare two symbol table entries by name */
  1243.     struct funct *f1, *f2;
  1244. {
  1245. /*    return (strcmp (&f1->fname, &f2->fname));    alphabetical order */
  1246.     return (f1->faddr > f2->faddr);            /* memory order */
  1247.     }
  1248.  
  1249.  
  1250. #ifdef OVERLAYS
  1251. loadsyms()            /* load base symbol table (for overlay) */
  1252. {                    /* symbol table must be empty! */
  1253.     int nread;
  1254.     FLAG done;
  1255.     char *c;
  1256.     
  1257.     makeext (&symsfile, "SYM");
  1258.     if (fopen (&symsfile, &symbuf) < 0)
  1259.         Fatal ("Can't open %s.\n", &symsfile);
  1260.     done = FALSE;
  1261.     while (!done) {
  1262.         nread = 
  1263.            fscanf (&symbuf, "%x %s\t%x %s\t%x %s\t%x %s\n", 
  1264.                &(ftab[nfuncts].faddr), &(ftab[nfuncts].fname),
  1265.                &(ftab[nfuncts+1].faddr), &(ftab[nfuncts+1].fname),
  1266.                &(ftab[nfuncts+2].faddr), &(ftab[nfuncts+2].fname),
  1267.                &(ftab[nfuncts+3].faddr), &(ftab[nfuncts+3].fname));
  1268.         nread /= 2;
  1269.         if (nread < 4) done = TRUE;
  1270.         while (nread-- > 0) ftab[nfuncts++].flinkedp = EXTERNAL;
  1271.         }
  1272.     fclose (&symbuf);
  1273.     }
  1274. #endif
  1275.  
  1276.  
  1277. stats (chan)                /* print statistics on chan */
  1278.     int chan;
  1279. {
  1280.     unsigned temp, *tptr;
  1281.  
  1282.     tptr = 6;
  1283.     fprintf (chan, "\n\nLink statistics:\n");
  1284.     fprintf (chan, "  Number of functions: %d\n", nfuncts);
  1285.     fprintf (chan, "  Code ends at: 0x%x\n", acodend.u);
  1286.     fprintf (chan, "  Externals begin at: 0x%x\n", exts.u);
  1287.     fprintf (chan, "  Externals end at: 0x%x\n", exts.u + extspc);
  1288.     fprintf (chan, "  End of current TPA: 0x%x\n", *tptr);
  1289.     fprintf (chan, "  Jump table bytes saved: 0x%x\n", jtsaved);
  1290.     temp = lspcend;
  1291.     if (phase == INMEM)
  1292.         fprintf (chan,
  1293.            "  Link space remaining: %dK\n", (temp - codend.u) / 1024);
  1294.     }
  1295.  
  1296. /*3 force extension to .CRL unless is .REL    */
  1297. makecrl(fname) char *fname;
  1298. {
  1299.     /*3 keep REL extension and raise flag */
  1300.     if
  1301.     (    index(fname,".REL") > 0
  1302.         ||  index(fname,".rel") > 0
  1303.     ) relflag = TRUE;
  1304.     else
  1305.     {    makeext (fname, "CRL");
  1306.         relflag = FALSE;
  1307.     }
  1308. }
  1309.  
  1310. makeext (fname, ext)        /* force a file extension to ext */
  1311.     char *fname, *ext;
  1312. {
  1313.     while (*fname && (*fname != '.')) {
  1314.         *fname = toupper (*fname);        /* upcase as well */
  1315.         ++fname;
  1316.         }
  1317.     *fname++ = '.';
  1318.     strcpy (fname, ext);
  1319.     }
  1320.  
  1321.  
  1322. strcmp7(s1, s2) char *s1, *s2; {
  1323.  
  1324.     /* compare two strings, either bit-7-terminated or null-terminated */
  1325.  
  1326.     for (; (_c1 = *s1) == *s2; s1++, s2++)
  1327.         if ( (0x80 & _c1) || !_c1) return 0;
  1328.  
  1329.      /*3 8th char of REL symbol is wild */
  1330.     if ( (_c1 &= 0x7F) == WILDC || (_c2 = 0x7F & *s2) == WILDC ) return 0;
  1331.  
  1332.  
  1333. /*    if ((_c1 &= 0x7F) < (_c2 = 0x7F & *s2)) return -1;*/
  1334.     if (_c1 < _c2) return -1;
  1335.     if (_c1 > _c2) return  1;
  1336.  
  1337.     _end1 = (*s1 & 0x80) || !*(s1+1) || *(s1+1) == WILDC;
  1338.     _end2 = (*s2 & 0x80) || !*(s2+1) || *(s2+1) == WILDC;
  1339.     if (_end2  &&  !_end1) return 1;
  1340.     if (_end1  &&  !_end2) return -1;
  1341.  
  1342.     /* if (_end1  &&  _end2) */
  1343.      return 0;
  1344.  
  1345. }
  1346.  
  1347. strcpy7 (s1, s2)            /* copy s2 into s1 */
  1348.     char *s1, *s2;
  1349. {
  1350.     do {
  1351.         *s1 = *s2;
  1352.         if (!*(s2+1)) {            /* works even if */
  1353.             *s1 |= 0x80;            /* s2 is null-term */
  1354.             break;
  1355.             }
  1356.         ++s1;
  1357.         } while (!(*s2++ & 0x80));
  1358.     }
  1359.  
  1360.  
  1361. skip7 (ptr7)                /* move this pointer past a string */
  1362.     char **ptr7;
  1363. {
  1364.     while (!(*(*ptr7)++ & 0x80));
  1365.     }
  1366.  
  1367.  
  1368. str7tont (s)                /* add null at end */
  1369.     char *s;
  1370. {
  1371.     while (!(*s & 0x80)) {
  1372.         if (!*s) return;        /* already nul term! */
  1373.         s++;
  1374.         }
  1375.     *s = *s & 0x7F;
  1376.     *++s = NUL;
  1377.     }
  1378.  
  1379.  
  1380. puthex (n, obuf)            /* output a hex word, with leading 0s */
  1381.     unsigned n;
  1382.     char *obuf;
  1383. {
  1384.     int i, nyb;
  1385.     
  1386.     for (i = 3; i >= 0; --i) {
  1387.         nyb = (n >> (i * 4)) & 0xF;
  1388.         nyb += (nyb > 9) ? 'A' - 10 : '0';
  1389.         putc (nyb, obuf);
  1390.         }
  1391.     }
  1392.  
  1393.  
  1394. Fatal (arg1, arg2, arg3, arg4)    /* lose, lose */
  1395.     char *arg1, *arg2, *arg3, *arg4;
  1396. {
  1397.     printf (arg1, arg2, arg3, arg4);
  1398.     lexit (1);
  1399.     }
  1400.  
  1401.  
  1402. lexit (status)                /* exit the program */
  1403.     int status;
  1404. {
  1405.     if (status == 1)
  1406.         unlink (SUB_FILE);
  1407.     exit();        /* bye! */
  1408.     }
  1409.  
  1410.  
  1411.  
  1412. /* END OF L2.C */
  1413.  
  1414.