home *** CD-ROM | disk | FTP | other *** search
/ norge.freeshell.org (192.94.73.8) / 192.94.73.8.tar / 192.94.73.8 / pub / computers / cpm / alphatronic / DRIPAK.ZIP / CPM_3-0 / SOURCES / GENCOM.PLM < prev    next >
Text File  |  1982-12-31  |  63KB  |  2,000 lines

  1. $ TITLE('CPM 3.0 --- GENCOM 1.0')
  2. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  3.  
  4.  
  5.                        * * *  GENCOM  * * *
  6.  
  7.  
  8.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  9.  
  10.  
  11. gencomer:
  12. do;
  13.  
  14.  
  15. declare
  16.     mpmproduct literally '01h', /* requires mp/m */
  17.     cpmversion literally '30h'; /* requires 3.0 cp/m */
  18.  
  19.  
  20. declare plm label public;
  21.  
  22. declare copyright (*) byte data (
  23.   ' Copyright (c) 1982, Digital Research ');
  24.  
  25. declare version (*)     byte data('11/02/82');
  26.  
  27. /*
  28.             Digital Research
  29.             Box 579
  30.             Pacific Grove, Ca
  31.             93950
  32. */
  33. $ eject
  34. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  35.  
  36.  
  37.                    * * *  CP/M INTERFACE * * *
  38.  
  39.  
  40.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  41.  
  42.  
  43. declare
  44.         maxb      address external,     /* addr field of jmp BDOS */
  45.         fcb (33)  byte external,        /* default file control block */
  46.         fcb16(33) byte external,        /* default fcb 2 */
  47.         buff(128) byte external,        /* default buffer */
  48.         buffa     literally '.buff',    /* default buffer */
  49.         fcba      literally '.fcb',     /* default file control block */
  50.  
  51.         cr              literally '13',
  52.         lf              literally '10';
  53.         
  54.                                         /* reset drive mask */
  55.     declare reset$mask (16) address data (
  56.       0000000000000001b,
  57.       0000000000000010b,
  58.       0000000000000100b,
  59.       0000000000001000b,
  60.       0000000000010000b,
  61.       0000000000100000b,
  62.       0000000001000000b,
  63.       0000000010000000b,
  64.       0000000100000000b,
  65.       0000001000000000b,
  66.       0000010000000000b,
  67.       0000100000000000b,
  68.       0001000000000000b,
  69.       0010000000000000b,
  70.       0100000000000000b,
  71.       1000000000000000b );
  72.  
  73. mon1: procedure(f,a) external;
  74.     declare f byte, a address;
  75.     end mon1;
  76.  
  77. mon2: procedure(f,a) byte external;
  78.     declare f byte, a address;
  79.     end mon2;
  80.  
  81. declare mon3 literally 'mon2a';
  82.  
  83. mon3: procedure(f,a) address external;
  84.     declare f byte, a address;
  85.     end mon3;
  86.  
  87.     /********** SYSTEM FUNCTION CALLS *********************/
  88.  
  89. printchar: procedure(char);
  90.     declare char byte;
  91.     call mon1(2,char);
  92. end printchar;
  93.  
  94. printb: procedure;
  95.                                 /* print blank character */
  96.     call printchar(' ');
  97. end printb;
  98.  
  99. printx: procedure(a);
  100.     declare a address;
  101.     declare s based a byte;
  102.         do while s <> 0;
  103.                 call printchar(s);
  104.                 a = a + 1;
  105.         end;
  106. end printx;
  107.  
  108. check$con$stat: procedure byte;
  109.     return mon2(11,0);          /* console ready */
  110. end check$con$stat;
  111.  
  112. crlf: procedure;
  113.     call printchar(cr);
  114.     call printchar(lf);
  115.     if check$con$stat then do; 
  116.         call mon1 (1,0);        /* read character */
  117.         call mon1 (0,0);        /* system reset */
  118.     end;
  119. end crlf;
  120.  
  121. print: procedure(a);
  122.     declare a address;
  123.                         /* print the string starting at address a until the
  124.                            next 0 is encountered */
  125.     call crlf;
  126.     call printx(a);
  127. end print;
  128.  
  129. get$version: procedure address;
  130.                         /* returns current cp/m version # */
  131.     return mon3(12,0);
  132. end get$version;
  133.  
  134.  
  135. conin: procedure byte;
  136.     return mon2(6,0fdh);
  137. end conin;
  138.  
  139.  
  140. open: procedure(fcb) byte;
  141.     declare fcb address;
  142.     return mon2(15,fcb);
  143. end open;
  144.  
  145. close: procedure(fcb) byte;
  146.         declare fcb     address;
  147.         return mon2(16,fcb);
  148. end close;
  149.  
  150. make: procedure(fcb) byte;
  151.         declare fcb     address;
  152.         return mon2(22,fcb);
  153. end make;
  154.  
  155.         declare ioflag  address,
  156.                  nrecs  byte;
  157.  
  158. mread: procedure(fcb);           /* multi sector read - returns # recs*/
  159.         declare fcb     address;
  160.  
  161.         ioflag = mon3(20,fcb);
  162.         readflag = low(ioflag);         /* if = 255 then error */
  163.         nrecs = high(ioflag);           /* if 0 -> multi sector count */
  164.  
  165. end mread;
  166.  
  167.  
  168. setmulti: procedure(nsects);            /* set multi sector count */
  169.         declare nsects  byte;
  170.  
  171.         flag = mon2(44,nsects);
  172.  
  173. end setmulti;
  174.  
  175.  
  176. readsq: procedure(fcb) byte;
  177.         declare fcb     address;
  178.         return mon2(20,fcb);
  179. end readsq;
  180.  
  181. writesq: procedure(fcb) byte;
  182.         declare fcb     address;
  183.         return mon2(21,fcb);
  184. end writesq;
  185.  
  186. rename: procedure(fcb) byte;
  187.         declare fcb     address;
  188.         return mon2(23,fcb);
  189. end rename;
  190.  
  191. delete: procedure(fcb) byte;
  192.         declare fcb     address;
  193.         return mon2(19,fcb);
  194. end delete;
  195.  
  196. setdma: procedure(dma);
  197.     declare dma address;
  198.     call mon1(26,dma);
  199. end setdma;
  200.  
  201. return$errors:                  /* 0ff => return BDOS errors */
  202.     procedure(mode);
  203.     declare mode byte;
  204.       call mon1 (45,mode);      
  205. end return$errors;
  206.  
  207. /******************************************************/
  208.  
  209. terminate: procedure;
  210.     call crlf;
  211.     call mon1 (0,0);
  212. end terminate;
  213.  
  214. parse: procedure(pfcb) address external;
  215.         declare pfcb address;
  216.  
  217. end parse;
  218.  
  219. $eject
  220.  
  221.         declare
  222.  
  223.                 options(*) byte data
  224.                              ('NULL0LOADER0SCB',0FFH),
  225.                 off$opt(*) byte data(0,5,12,15),
  226.                 end$list        byte data (0ffh),
  227.                 end$of$string   byte data (0),
  228.  
  229.                 delimiters(*) byte data (0,'[]=, :;<>%\|"()/#!@&+-*?',0,0ffh),
  230.                 SPACE           byte data(5),   /* delim        space */
  231.                 COMMA           byte data(4),   /*    "         comma */
  232.                 LPAREN          byte data(14),  /*    "         left paren */
  233.  
  234.                 opt$map(23)     byte,
  235.  
  236.                 j               byte initial(0),
  237.                 buf$ptr         address,
  238.                 opt$index       byte,
  239.                 endbuf          byte,
  240.                 delimiter       byte;
  241. $ eject
  242.  
  243.  
  244.         declare
  245.                 true            literally '1',
  246.                 false           literally '0',
  247.                 punchSCB        byte initial (false),
  248.                 COMonly         byte initial (false),
  249.                 revert          byte initial (false),
  250.                 build           byte initial (false),
  251.                 replace         byte initial (false),
  252.                 empty           byte initial (false),
  253.                 hex             byte initial (false),
  254.  
  255.                 oldSCB          byte initial (false),
  256.  
  257.                 incount         byte initial (0),
  258.                 ret$inst        byte data (0c9h),
  259.                 BLANK           byte data (020h),
  260.                 (readflag,writeflag)    byte,
  261.                 flag            byte,
  262.                 (rsx,old,fill)  byte,
  263.                 maxrcd          byte data(32),
  264.  
  265.                 deletes         byte,
  266.                 which(15)       byte,
  267.  
  268.                 comoff          address,
  269.                 comsize         address,
  270.                 totbyte         address,
  271.                 rsxrec          address,
  272.                 oldrsx          address,
  273.                 offsets(15)     address,
  274.                 length$rsx(15)  address,
  275.                 testvers        address,
  276.  
  277.                 comtype(3)      byte data ('COM'),
  278.                 hextype(3)      byte data ('HEX'),
  279.                 rsxtype(3)      byte data ('RSX'),
  280.  
  281.                 tempfcb(33)     byte initial(0,'TEMP    $$$',0,0,0,0,0),
  282.                 errfcb(14)      byte,
  283.  
  284.               files(16)       structure ( pass(8) byte),
  285.                 len$pass(16)    byte,
  286.  
  287.                 parse$struc     structure(
  288.                    name$addr    address,
  289.                    fcb$addr     address),
  290.  
  291.                 optmark         based buf$ptr byte,
  292.                 NULL            byte initial(0),
  293.                 LOAD            byte initial(0),
  294.                 SCB             byte initial(0),
  295.  
  296.                 fcbs(16)        structure(
  297.                    file(33)       byte),
  298.  
  299.                 test$ptr        address,
  300.                 allfcbs(16)     address,
  301.                 fcbp            address,
  302.                 comptr          address,
  303.                 comfcb          based comptr (1) byte,
  304.                 testfcb         based test$ptr (1) byte,
  305.                 gen$fcb         based fcbp (1) byte;
  306.  
  307. /*              RSX COM FILE HEADER FORMAT              */
  308.  
  309.         declare
  310.                 head$ptr        address,
  311.                 head            based head$ptr structure(
  312.                  retinst        byte,   /* return instruction 0C9h */
  313.                  progsize       address,/* program size:orig com prog */
  314.                  SCBjmp         byte,
  315.                  SCBaddr        address,
  316.                  RESERVED2(7)   byte,
  317.                  LOADER         byte,
  318.                  nscb           byte,
  319.                  nrsx           byte);  /* number of RSX modules in file */
  320.  
  321.         declare
  322.                 subptr          address,
  323.                 rsx$sub$head    based subptr structure(
  324.                  off            address,
  325.                  len            address,
  326.                  NONBANK        byte,
  327.                  RESERVED3      byte,
  328.                  name(8)        byte,
  329.                  RESERVED4      address),
  330.  
  331.                 scbvect         based subptr structure(
  332.                   pad1          byte,
  333.                   smark         byte,
  334.                   pad2          address,
  335.                   svect(12)     byte),
  336.  
  337.                 head$byte       based head$ptr byte,
  338.  
  339.                 head$buffer(384)        byte,
  340.                 iobuff(4096)            byte,
  341.  
  342.                 nextptr         address,
  343.                 next            based nextptr structure(
  344.                  off            address,
  345.                  len            address,
  346.                  NONBANK        byte,
  347.                  RESERVED3      byte,
  348.                  name(8)        byte,
  349.                  RESERVED4      address),
  350.  
  351.                 nbank(16)       byte initial(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
  352.                 newoff(16)      address,
  353.                 newlen(16)      address,
  354.                 actlen(15)      address,
  355.                 new(15)         structure(
  356.                   name(8)       byte),
  357.  
  358.                 soff(20)        byte,
  359.                 sval(20)        byte,
  360.                 nscbs           byte initial(0);
  361.  
  362.         declare
  363.                 SCBbuff(256)    byte,
  364.                 SCBcode(23)     byte data(011h,018h,00,0d5h,0eh,031h,0cdh,5,0,
  365.                                           0e1h,23h,23h,23h,7eh,0feh,
  366.                                           0ffh,0e5h,0ebh,0c2h,4,0,0e1h,0c9h),
  367.                 SCBpos          address;
  368. $eject
  369.  
  370.         declare
  371.                 ERRORM(*)               byte data ('ERROR: ',0),
  372.                 FILEM(*)                byte data ('FILE: ',0),
  373.                 err$notfnd(*)           byte data ('File not found.',0),
  374.                 err$msg$make(*)         byte data ('No directory space.',0),
  375.                 err$msg$parse(*)        byte data ('Invalid file name.',0),
  376.                 err$msg$first(*)        byte data ('First submitted file must be
  377.  
  378.  a COM file.',0),
  379.                 err$msg$dup1(*)         byte data ('Duplicate input RSX...',0),
  380.                 err$msg$dup2(*)         byte data ('Duplicate RSX in header.',
  381.                                                     ' Replacing old by new.',0),
  382.  
  383.                 err$msg$rsxval(*)       byte data ('Invalid RSX type.',0),
  384.                 err$msg$no$rsx(*)       byte data ('No more RSX files to be used
  385.  
  386. .',0),
  387.                 err$msg$copy(*)         byte data ('Error on copy.',0),
  388.                 err$msg$rsx$slot(*)     byte data ('There are not enough availab
  389.  
  390. le RSX slots.',0),
  391.                 err$msg$read(*)         byte data ('Disk read.',0),
  392.                 err$msg$write(*)        byte data ('Disk write.',0),
  393.                 err$msg$toobig(*)       byte data ('Total file size exceeds 64K.
  394.  
  395. ',0),
  396.                 err$NULL(*)     byte data ('COM file found and NULL option.',0),
  397.  
  398.                 errSTRIP(*)     byte data ('No header or RSXs to strip.',0),
  399.  
  400.                 errIFCB(*)      byte data ('Invalid FCB.',0),
  401.                 errMEDIA(*)     byte data ('Media change occurred.',0),
  402.                 errDIO(*)       byte data ('Disk I/O error.',0),
  403.                 errDRIVE(*)     byte data ('Invalid drive error.',0),
  404.  
  405.                 errscboff(*)    byte data ('Invalid SCB offset',0),
  406.                 errscbclose(*)  byte data('Missing right parenthesis.',0),
  407.                 errscbnoval(*)  byte data ('Missing SCB value.',0),
  408.                 errscbpar(*)    byte data ('Missing left parenthesis.',0),
  409.                 err$unrecopt(*) byte data ('Unrecognized option.',0),
  410.                 err$notscb(*)   byte data ('No modifier for this option.',0);
  411.  
  412.  
  413.  
  414. closeall: procedure;
  415.         declare i       byte;
  416.  
  417.         do i = 0 to incount;
  418.                 readflag = close(allfcbs(i));   /* close input files */
  419.         end;
  420.         readflag = close(.tempfcb);
  421.         readflag = delete(.tempfcb);
  422.  
  423. end closeall;
  424.  
  425. get$errfcb: procedure;
  426.         declare (i,j)   byte;
  427.  
  428.         do i = 1 to 14;
  429.                 errfcb(i) = 0;
  430.         end;
  431.         errfcb(0) = 9;                  /* tab */
  432.  
  433.         i = 1;
  434.         j = 1;
  435.         do while i < 9 and gen$fcb(j) <> 32;            /* 32 = space */
  436.                 errfcb(i) = gen$fcb(j);
  437.                 i = i + 1;
  438.                 j = j + 1;
  439.         end;
  440.  
  441. ge1:    errfcb(i) = 46;                 /* dot */
  442.         j = 9;
  443.         do while i < 12 and gen$fcb(j) <> 32;
  444.                 i = i + 1;
  445.                 errfcb(i) = gen$fcb(j);
  446.                 j = j + 1;
  447.         end;
  448. end get$errfcb;
  449.  
  450.  
  451. e$print1: procedure(message);
  452.         declare message address;
  453.  
  454.         call get$errfcb;
  455.         call print(.ERRORM);
  456.         call printx(message);
  457.  
  458. end e$print1;
  459.  
  460. e$print2: procedure;
  461.  
  462.         call print(.FILEM);
  463.         call printx(.errfcb);
  464.         call crlf;
  465.  
  466. end e$print2;
  467.  
  468.  
  469. err$print: procedure(message);
  470.         declare message address;
  471.  
  472.         call e$print1(message);
  473.         call e$print2;
  474.  
  475.         call closeall;
  476.         call terminate;
  477.  
  478. end err$print;
  479.  
  480.  
  481.  
  482. bdoserr: procedure;
  483.         declare (lflag,hflag)   byte;
  484.  
  485.         lflag = low(ioflag);
  486.         hflag = high(ioflag);
  487.  
  488.         if lflag = 9 then call err$print(.errIFCB);
  489.         if lflag = 10 then call err$print(.errMEDIA);
  490.         if lflag = 255 then do;
  491.                 if hflag = 1 then call err$print(.errDIO);
  492.                 if hflag = 4 then call err$print(.errDRIVE);
  493.         end;
  494.  
  495. end bdoserr;
  496. $ eject
  497.  
  498.  
  499. $eject
  500. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  501.  
  502.  
  503.                     * * *  Option scanner  * * *
  504.  
  505.  
  506.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  507.  
  508.  
  509. separator: procedure(character) byte;
  510.  
  511.                                         /* determines if character is a 
  512.                                            delimiter and which one */
  513.         declare k       byte,
  514.                 character       byte;
  515.  
  516.         k = 1;
  517. loop:   if delimiters(k) = end$list then return(0);
  518.         if delimiters(k) = character then return(k);    /* null = 25 */
  519.                 k = k + 1;
  520.                 go to loop;
  521.  
  522. end separator;
  523.  
  524. opt$scanner:    procedure(list$ptr,off$ptr,idx$ptr);
  525.                                         /* scans the list pointed at by idxptr
  526.                                            for any strings that are in the 
  527.                                            list pointed at by list$ptr.
  528.                                            Offptr points at an array that 
  529.                                            contains the indices for the known
  530.                                            list. Idxptr points at the index 
  531.                                            into the list. If the input string
  532.                                            is unrecognizable then the index is
  533.                                            0, otherwise > 0.
  534.  
  535.                                         First, find the string in the known
  536.                                         list that starts with the same first 
  537.                                         character.  Compare up until the next
  538.                                         delimiter on the input. if every input
  539.                                         character matches then check for 
  540.                                         uniqueness.  Otherwise try to find 
  541.                                         another known string that has its first
  542.                                         character match, and repeat.  If none
  543.                                         can be found then return invalid.
  544.  
  545.                                         To test for uniqueness, start at the 
  546.                                         next string in the knwon list and try
  547.                                         to get another match with the input.
  548.                                         If there is a match then return invalid.
  549.  
  550.                                         else move pointer past delimiter and 
  551.                                         return.
  552.  
  553.                                 P.Balma         */
  554.  
  555.         declare
  556.                 buff            based buf$ptr (1) byte,
  557.                 idx$ptr         address,
  558.                 off$ptr         address,
  559.                 list$ptr        address;
  560.  
  561.         declare
  562.                 i               byte,
  563.                 j               byte,
  564.                 list            based list$ptr (1) byte,
  565.                 offsets         based off$ptr (1) byte,
  566.                 wrd$pos         byte,
  567.                 character       byte,
  568.                 letter$in$word  byte,
  569.                 found$first     byte,
  570.                 start           byte,
  571.                 index           based idx$ptr byte,
  572.                 save$index      byte,
  573.                 (len$new,len$found)     byte,
  574.                 valid           byte;
  575.  
  576. /*****************************************************************************/
  577. /*                      internal subroutines                                 */
  578. /*****************************************************************************/
  579.  
  580. check$in$list: procedure;
  581.                                 /* find known string that has a match with 
  582.                                    input on the first character.  Set index
  583.                                    = invalid if none found.   */
  584.                         
  585.         declare i       byte;
  586.  
  587.         i = start;
  588.         wrd$pos = offsets(i);
  589.         do while list(wrd$pos) <> end$list;
  590.                 i = i + 1;
  591.                 index = i;
  592.                 if list(wrd$pos) = character then return;
  593.                 wrd$pos = offsets(i);
  594.         end;
  595.                         /* could not find character */
  596.         index = 0;
  597.         return;
  598. end check$in$list;
  599.  
  600. setup:  procedure;
  601.         character = buff(0);
  602.         call check$in$list;
  603.         letter$in$word = wrd$pos;
  604.                         /* even though no match may have occurred, position
  605.                            to next input character.  */
  606.         i = 1;
  607.         character = buff(1);
  608. end setup;
  609.  
  610. test$letter:    procedure;
  611.                         /* test each letter in input and known string */
  612.  
  613.         letter$in$word = letter$in$word + 1;
  614.  
  615.                                         /* too many chars input? 0 means
  616.                                            past end of known string */
  617.         if list(letter$in$word) = end$of$string then valid = false;
  618.         else
  619.         if list(letter$in$word) <> character then valid = false;
  620.  
  621.         i = i + 1;
  622.         character = buff(i);
  623.  
  624. end test$letter;
  625.  
  626. skip:   procedure;
  627.                                         /* scan past the offending string;
  628.                                            position buf$ptr to next string...
  629.                                            skip entire offending string;
  630.                                            ie., falseopt=mod, [note: comma or
  631.                                            space is considered to be group 
  632.                                            delimiter] */
  633.         character = buff(i);
  634.         delimiter = separator(character);
  635.         do while ((delimiter <> 2) and (delimiter <> 4) and (delimiter <> 5)
  636.                    and (delimiter <> 25));
  637.                 i = i + 1;
  638.                 character = buff(i);
  639.                 delimiter = separator(character);
  640.         end;
  641.         endbuf = i;
  642.         buf$ptr = buf$ptr + endbuf + 1;
  643.         return;
  644. end skip;
  645.  
  646. eat$blanks: procedure;
  647.  
  648.         declare charac  based buf$ptr byte;
  649.  
  650.  
  651.         do while(delimiter := separator(charac)) = SPACE;
  652.                 bufptr = buf$ptr + 1;
  653.         end;
  654.  
  655. end eat$blanks;
  656.  
  657. /*****************************************************************************/
  658. /*                      end of internals                                     */
  659. /*****************************************************************************/
  660.  
  661.  
  662.                                         /* start of procedure */
  663.         call eat$blanks;
  664.         start = 0;
  665.         call setup;
  666.  
  667.                                         /* match each character with the option
  668.                                            for as many chars as input 
  669.                                            Please note that due to the array
  670.                                            indices being relative to 0 and the
  671.                                            use of index both as a validity flag
  672.                                            and as a index into the option/mods
  673.                                            list, index is forced to be +1 as an
  674.                                            index into array and 0 as a flag*/
  675.  
  676.         do while index <> 0;
  677.                 start = index;
  678.                 delimiter = separator(character);
  679.  
  680.                                         /* check up to input delimiter */
  681.  
  682.                 valid = true;           /* test$letter resets this */
  683.                 do while delimiter = 0;
  684.                         call test$letter;
  685.                         if not valid then go to exit1;
  686.                         delimiter = separator(character);
  687.                 end;
  688.  
  689.                 go to good;
  690.  
  691.                                         /* input ~= this known string;
  692.                                            get next known string that 
  693.                                            matches */
  694. exit1:          call setup;
  695.         end;
  696.                                         /* fell through from above, did
  697.                                            not find a good match*/
  698.         endbuf = i;                     /* skip over string & return*/
  699.         call skip;
  700.         return;
  701.  
  702.                                         /* is it a unique match in options
  703.                                            list? */
  704. good:   endbuf = i;
  705.         len$found = endbuf;
  706.         save$index = index;
  707.         valid = false;
  708. next$opt:
  709.                 start = index;
  710.                 call setup;
  711.                 if index = 0 then go to finished;
  712.  
  713.                                         /* look at other options and check
  714.                                            uniqueness */
  715.  
  716.                 len$new = offsets(index + 1) - offsets(index) - 1;
  717.                 if len$new = len$found then do;
  718.                         valid = true;
  719.                         do j = 1 to len$found;
  720.                                 call test$letter;
  721.                                 if not valid then go to next$opt;
  722.                         end;
  723.                 end;
  724.                 else go to nextopt;
  725.                                         /* fell through...found another valid
  726.                                            match --> ambiguous reference */
  727.         index = 0;
  728.         call skip;              /* skip input field to next delimiter*/
  729.         return;
  730.  
  731. finished:                       /* unambiguous reference */
  732.         index = save$index;
  733.         buf$ptr = buf$ptr + endbuf;
  734.         call eat$blanks;
  735.         if delimiter <> 0 then  buf$ptr = buf$ptr + 1;
  736.         else delimiter = SPACE;
  737.  
  738. end opt$scanner;
  739.  
  740. error$prt:      procedure;
  741.         declare i       byte,
  742.                 t       address,
  743.                 char    based t byte;
  744.  
  745.         t = buf$ptr - endbuf - 1;
  746.         do i = 1 to endbuf;
  747.                 call printchar(char);
  748.                 t = t + 1;
  749.         end;
  750.  
  751. end error$prt;
  752.  
  753. $eject
  754.  
  755. e$print3: procedure(message);
  756.  
  757.         declare message address;
  758.  
  759.         call print(.ERRORM);
  760.         call printx(message);
  761.         call terminate;
  762.  
  763. end e$print3;
  764.  
  765.  
  766. aschex: procedure(ahbyte,albyte) byte;
  767.  
  768.         declare (ahbyte,albyte) address,
  769.                 hbyte           based ahbyte byte,
  770.                 lbyte           based albyte byte;
  771.  
  772.  conv: procedure(abyte);
  773.         declare abyte   address,
  774.                 b       based abyte byte;
  775.  
  776.         if b > 39h then b = b - 37h;
  777.         else b = b - 30h;
  778.  
  779.  end conv;
  780.  
  781.         call conv(ahbyte);
  782.         call conv(albyte);
  783.         hbyte = shl(hbyte,4);
  784.  
  785.         return(hbyte or lbyte);
  786.  
  787. end aschex;
  788.  
  789. /**************************************************************************/
  790.  
  791. valoff: procedure(high,low,achar);
  792.         declare (high,low)      byte,
  793.                 achar           address,
  794.                 char            based achar byte;
  795.  
  796.         if (char > high) or (char < low) then
  797.                 call e$print3(.errscboff);
  798.  
  799. end valoff;
  800.  
  801. /**************************************************************************/
  802.  
  803. /**************************************************************************/
  804.  
  805. getoption: procedure;
  806.  
  807.         declare char            based buf$ptr byte,
  808.                 bufptr1         address,
  809.                 nextchar        based bufptr1 byte,
  810.                 index           byte,
  811.                 zero            byte;
  812.  
  813.         /************************************************/
  814.  
  815. getscbval: procedure;
  816.  
  817.         bufptr1 = buf$ptr + 1;
  818.  
  819.         if (delimiter := separator(nextchar)) = 0 then do;
  820.                 sval(nscbs) = aschex(buf$ptr,buf$ptr1);         /* 2 chars */
  821.                 buf$ptr = buf$ptr + 2;
  822.         end;
  823.         else do;
  824.                 sval(nscbs) = aschex(.zero,buf$ptr);            /* 1 char */
  825.                 buf$ptr = bufptr1;
  826.         end;
  827.  
  828.         nscbs = nscbs + 1;
  829.  
  830.         if (delimiter := separator(char)) <> 15 then            /* ) */
  831.                 call e$print3(.errscbclose);
  832.  
  833.         buf$ptr = buf$ptr + 1;
  834.  
  835.         delimiter = separator(char);                    /* set delimiter */
  836.         if delimiter <> 0 then buf$ptr = buf$ptr + 1;
  837.  
  838. end getscbval;
  839.  
  840.         /******************************************************/
  841.  
  842. checkval: procedure;
  843.  
  844.         delimiter = separator(char);
  845.         if delimiter = SPACE then go to cv0;
  846.         if delimiter <> COMMA then
  847.                 call e$print3(.err$scbnoval);
  848.  
  849. cv0:    buf$ptr = buf$ptr + 1;
  850.  
  851. end checkval;
  852.  
  853.         /******************************************************/
  854.  
  855.  
  856. getscboff: procedure;
  857.  
  858.         if (delimiter := separator(char)) = LPAREN then do;
  859.  
  860.                 buf$ptr = buf$ptr + 1;
  861.                 call valoff(39h,30h,buf$ptr);           /* valid char ? */
  862.  
  863.                 bufptr1 = buf$ptr + 1;
  864.  
  865.                 delimiter = separator(nextchar);
  866.  
  867.                 if delimiter = SPACE then go to gs1;
  868.                 if delimiter = COMMA then go to gs1;
  869.                                                         /* 2 char input */
  870.                         call valoff(36h,30h,buf$ptr);
  871.                         call valoff(46h,30h,bufptr1);   /* valid ? */
  872.                         soff(nscbs) = aschex(buf$ptr,bufptr1);
  873.                         buf$ptr = buf$ptr + 2;
  874.                         call checkval;
  875.                         return;
  876.  
  877.                                                         /* single char in */
  878. gs1:                    soff(nscbs) = aschex(.zero,buf$ptr);
  879.                         buf$ptr = bufptr1 + 1;
  880.         end;
  881.         else call e$print3(.errscbpar);
  882.  
  883. end getscboff;
  884.  
  885.         /******************************************************/
  886.  
  887.         zero = 30h;
  888.         delimiter = 1;
  889.         index = 0;
  890.         buf$ptr = buf$ptr + 1;          /* move off [ delimiter */
  891.  
  892.                                         /* while not eos */
  893.  
  894. gto0:           call opt$scanner(.options,.off$opt,.index);
  895.                 if index = 0 then do;
  896.                         call print(.ERRORM);
  897.                         call printx(.err$unrecopt);
  898.                         call print(.('OPTION: ',0));
  899.                         call error$prt;
  900.                 end;
  901.  
  902.                 if index = 1 then NULL = true;
  903.                 else if index = 2 then LOAD = true;
  904.  
  905.                 if delimiter = 2 then return;
  906.                 if delimiter = 25 then return;
  907.  
  908.                         if delimiter = 3 then do;               /* = */
  909.                                 if index <> 3 then do;
  910.                                         call print(.ERRORM);
  911.                                         call printx(.err$notscb);
  912.                                         call opt$scanner(.options,.offopt,
  913.                                                          .index);
  914.                                         go to gto1;
  915.                                 end;
  916.  
  917.                                 call getscboff;         /* buf$ptr -> value */
  918.                                 call getscbval;
  919.                                 SCB = true;
  920.                         end;
  921.  
  922. gto1:   if delimiter = 0 then return;
  923.         if delimiter = 2 then return;
  924.         if delimiter = 25 then return;
  925.  
  926.         go to gto0;
  927.  
  928. end getoption;
  929.  
  930. $ eject
  931.  
  932.  
  933. opener: procedure(fcb);
  934.         declare fcb     address;
  935.  
  936.         if open(fcb) > 3 then do;
  937.                 fcbp = fcb;
  938.                 call err$print(.err$notfnd);
  939.         end;
  940.  
  941. end opener;
  942.  
  943.  
  944. closer: procedure(fcb);
  945.         declare fcb     address;
  946.  
  947.         if close(fcb) > 3 then do;
  948.                 fcbp = fcb;
  949.                 call err$print(.err$notfnd);
  950.         end;
  951. end closer;
  952.  
  953. maker: procedure(fcb);
  954.         declare fcb     address;
  955.  
  956.         flag = make(fcb);
  957.         if flag > 3 then do;
  958.                 fcbp = fcb;
  959.                 call err$print(.err$msg$make);
  960.         end;
  961.  
  962. end maker;
  963.  
  964. deleter: procedure;
  965.  
  966.         if (comfcb(8) and 80h) = 80h then return;       /* user 0 file ? */
  967.  
  968.         if delete(comptr) > 0 then do;
  969.                 fcbp = comptr;
  970.         end;
  971.  
  972. end deleter;
  973.  
  974.  
  975. parser: procedure(fcb$ptr);
  976.  
  977.         declare fcb$ptr address;
  978.  
  979.         parse$struc.name$addr = buf$ptr;
  980.         parse$struc.fcb$addr = fcb$ptr;
  981.         test$ptr = buf$ptr;
  982.  
  983. pa1:    buf$ptr = parse(.parse$struc);  /* parse command tail */
  984.  
  985. pa2:    if buf$ptr = 0ffffh then do;
  986.                 fcbp = test$ptr;
  987.                 call err$print(.err$msg$parse);
  988.         end;
  989.  
  990. end parser;
  991.  
  992.  
  993. copypass$dma: procedure(index);
  994.         declare index   byte,
  995.                 i       byte;
  996.  
  997.         do i = 0 to 7;
  998.                 buff(i) = files(index).pass(i);
  999.         end;
  1000.  
  1001. end copypass$dma;
  1002.  
  1003. renamer: procedure;
  1004.  
  1005.         declare
  1006.                 (i,j)           byte,
  1007.                 renbuf(32)      byte;
  1008.  
  1009.         do i = 12 to 15;
  1010.                 j = i + 16;
  1011.                 renbuf(i) = 0;
  1012.                 renbuf(j) = 0;
  1013.         end;
  1014.  
  1015.         do i = 0 to 11;         /* set up buffer */
  1016.                 j = i + 16;
  1017.                 renbuf(i) = tempfcb(i);
  1018.                 renbuf(j) = comfcb(i);
  1019.         end;
  1020.  
  1021. re1:    flag = rename(.renbuf);
  1022.  
  1023.         if flag > 0 then do;    
  1024.                 fcbp = allfcbs(0);              /*GLITCH?????????*/
  1025.         end;
  1026. end renamer;
  1027.  
  1028. clearfcb: procedure(fcb);
  1029.  
  1030.         declare fcb     address,
  1031.                 f       based fcb (1) byte,
  1032.                 i       byte;
  1033.  
  1034.         do i = 12 to 33;
  1035.                 f(i) = 0;
  1036.         end;
  1037.  
  1038. end clearfcb;
  1039.  
  1040.  
  1041. /****************************************************************************/
  1042.  
  1043.  
  1044. copy: procedure(recsize);
  1045.         declare recsize                 address;
  1046.         declare recs                    based recsize address;
  1047.         declare 
  1048.                 i                       byte,
  1049.                 flag                    address;
  1050.  
  1051.         call setmulti(maxrcd);
  1052.         call mread(fcbp);
  1053.  
  1054. co2:            if readflag <> 0 then do;
  1055.                         if readflag = 1 then do;
  1056.                            if nrecs = 0 then  return;    /* EOF */
  1057.                         end;
  1058.                         else call bdoserr;
  1059.                 end;
  1060.  
  1061.                 i = maxrcd;
  1062.                 if nrecs <> 0 then do;          /* read less than maxrcd */
  1063.                         call setmulti(nrecs);
  1064.                         i = nrecs;
  1065.                 end;
  1066.  
  1067.                 writeflag = writesq(.tempfcb);
  1068.  
  1069.                 do while i <> 0;
  1070.                         recs = recs + 128;      /* this is in bytes */
  1071.                         i = i - 1;
  1072.                 end;
  1073.                                                 /* record count <= 64K */
  1074.                 if recs > 0ffffh then call err$print(.err$msg$toobig);
  1075.  
  1076.                 if nrecs <> 0 then return;
  1077.  
  1078.                 call mread(fcbp);
  1079.  
  1080.                 go to co2;
  1081.  
  1082. end copy;
  1083.  
  1084.  
  1085. /*************************************************************************/
  1086.  
  1087.  
  1088. copy2: procedure(nrcds,skip);
  1089.                                         /* read/write in min(maxrcd,nrcds)
  1090.                                            units. */
  1091.  
  1092.         declare nrcds   address,
  1093.                 skip    byte,
  1094.                 set     byte,
  1095.                 savin   address;
  1096.  
  1097.         savin = nrcds;
  1098.  
  1099. cp20:   if savin > maxrcd then set = maxrcd;
  1100.         else set = savin;
  1101.  
  1102.         call setmulti(set);
  1103.         flag = readsq(comptr);                          /* get nrcds units */
  1104.  
  1105. cp21:   if skip = 0 then flag = writesq(.tempfcb);     /* while savin > 0 */
  1106.         savin = savin - set;
  1107.  
  1108.         if savin = 0 then return;
  1109.  
  1110.         if savin > maxrcd then set = maxrcd;
  1111.         else set = savin;
  1112.  
  1113.         call setmulti(set);
  1114.         flag = readsq(comptr);
  1115.  
  1116.         go to cp21;
  1117.  
  1118. end copy2;
  1119.  
  1120.  
  1121. /****************************************************************************/
  1122.  
  1123.  
  1124. reopen$temp: procedure;
  1125.         declare i       byte;
  1126.  
  1127.         call closer(.tempfcb);
  1128.         call clearfcb(.tempfcb);
  1129.         call opener(.tempfcb);
  1130.  
  1131.         call setmulti(2);
  1132.  
  1133.         readflag = readsq(.tempfcb);
  1134.  
  1135. end reopen$temp;
  1136.  
  1137.  
  1138. /***************************************************************************/
  1139.  
  1140.  
  1141. get$off: procedure(xrecs,index);
  1142.         declare index   byte,
  1143.                 xrecs   address,
  1144.                 i       based xrecs address;
  1145.         declare (temp,sum)      address;
  1146.  
  1147. gt0:    temp = offsets(index - 1);
  1148.         sum = temp + i;
  1149. gt1:    if sum < temp then call err$print(.err$msg$toobig);
  1150.  
  1151.         offsets(index) = sum;
  1152.  
  1153. end get$off;
  1154.  
  1155. zapRSX: procedure;
  1156.  
  1157.         declare dRSX    based subptr (16) byte,
  1158.                 i       byte;
  1159.  
  1160.         do i = 0 to 15;
  1161.                 dRSX(i) = 0;
  1162.         end;
  1163.  
  1164.         subptr = subptr + 16;
  1165.  
  1166. end zapRSX;
  1167.  
  1168.  
  1169. /************************************************************************/
  1170.  
  1171.  
  1172. addrsx: procedure;
  1173.         declare i               byte,
  1174.                 prlptr          address,
  1175.                 rsxlen          based prlptr address;
  1176.  
  1177.                 i = 1;
  1178. next$rsx:       fcbp = allfcbs(i);              /* while i <= incount */
  1179.  
  1180.                 call setmulti(2);               /* get header */
  1181.                 readflag = readsq(fcbp);
  1182.                 prlptr = .iobuff(1);            /* get program length */
  1183. ad1:            length$rsx(i) = rsxlen;
  1184.  
  1185.                 call setmulti(1);
  1186.                 readflag = readsq(fcbp);
  1187.  
  1188.                 if iobuff(15) <> 0 then iobuff(14) = 0ffh;
  1189.                 nbank(i) = iobuff(15);          /* only non-banked ? */
  1190.                 iobuff(10) = 6;
  1191.                 iobuff(12) = 7;
  1192.                 iobuff(24) = 0;
  1193.  
  1194.                 writeflag = writesq(.tempfcb);
  1195.  
  1196.                 rsxrec = 128;
  1197.                 call copy(.rsxrec);
  1198.  
  1199. ad2:            totbyte = totbyte + rsxrec;
  1200.  
  1201.                 i = i + 1;
  1202.  
  1203.                 if i > incount then go to fini;
  1204.  
  1205.                 call get$off(.rsxrec,i);
  1206.                 go to next$rsx;
  1207.  
  1208. fini:   end addrsx;
  1209.  
  1210.  
  1211. /*****************************************************************************/
  1212.  
  1213.  
  1214. putSCBcode: procedure(ptrfcb);
  1215.         declare (i,j)   byte,
  1216.                 ptrfcb  address,
  1217.                 fixup   address,
  1218.                 fa      based fixup address;
  1219.  
  1220.         if not SCB  and not oldSCB then return;
  1221.  
  1222.         totbyte = totbyte + 256;        /* rel to 100h */
  1223.  
  1224.         call setdma(.SCBbuff);
  1225.         call setmulti(2);
  1226.  
  1227.         if oldscb then i = SCBbuff(23); /* next open slot */
  1228.         else if SCB then do;            /* must initialze buffer with code */
  1229.  
  1230.                 do i = 0 to 255;
  1231.                         SCBbuff(i) = 0ffh;
  1232.                 end;
  1233.  
  1234. ps0:            fixup = .SCBcode(1);
  1235.                 fa = fa + totbyte;
  1236.                 fixup = .SCBcode(19);
  1237.                 fa = fa + totbyte;
  1238.  
  1239. ps1:            call move(23,.SCBcode,.SCBbuff(0));
  1240.                 i = 24;
  1241.         end;
  1242.  
  1243. ps2:    if nscbs > 0 then do;
  1244.            do j = 0 to nscbs-1;
  1245.                 SCBbuff(i) = soff(j);
  1246.                 SCBbuff(i+2) = sval(j);
  1247.                 i = i + 3;
  1248.            end;
  1249.         end;
  1250.  
  1251.         SCBbuff(23) = i;                /* next available scb init */
  1252.  
  1253. ps3:    if oldSCB then 
  1254.                 if ptrfcb = comptr then comfcb(32) = comfcb(32) - 2;
  1255.  
  1256.         writeflag = writesq(ptrfcb);
  1257.         call setdma(.iobuff);
  1258.  
  1259. end putSCBcode;
  1260.  
  1261. /***************************************************************************/
  1262.  
  1263.  
  1264. update$head: procedure;
  1265.         declare (i,j,k)         byte,
  1266.                 (olds,temp)     byte;
  1267.  
  1268.  
  1269.  possub: procedure;
  1270.  
  1271.         subptr = .iobuff(16);           /* start of RSX info in header */
  1272.  
  1273.         i = 1;                          /* skip old rsx heads */
  1274.         do while i <= old;
  1275.                 subptr = subptr + 16;
  1276.                 i = i + 1;
  1277.         end;
  1278. end possub;
  1279.  
  1280.         /************************************************************/
  1281.  
  1282.  
  1283.         call possub;                    /* set subptr to end of RSX */
  1284.         head$ptr = .iobuff;
  1285.  
  1286.         if not COMonly then do;
  1287.                 if build then head.progsize = comsize;
  1288. up1:            k = old;
  1289.  
  1290.                 do i = 1 to incount;
  1291.                         k = k + 1;
  1292.                         rsx$sub$head.off = offsets(i);
  1293.                         rsx$sub$head.len = length$rsx(i);
  1294.                         rsx$sub$head.NONBANK = nbank(i);
  1295.                         fcbp = allfcbs(i);
  1296.                         do j = 0 to 7;
  1297.                                 rsx$sub$head.name(j) = gen$fcb(j + 1);
  1298.                         end;
  1299.  
  1300.                         subptr = subptr + 16;
  1301.                 end;
  1302.         end;                            /* COMonly... */
  1303.         else head.progsize = comsize;
  1304.  
  1305. up2:    if LOAD then head.LOADER = 1;
  1306.         if SCB or oldSCB then call move(2,.totbyte,.iobuff(4));
  1307.  
  1308.         tempfcb(32) = 0;                        /* backup CR to re-write rcd */
  1309.  
  1310.         writeflag = writesq(.tempfcb);
  1311.         call closer(.tempfcb);
  1312.  
  1313.         if not NULL then call deleter;          /* erase old file */
  1314.         call renamer;
  1315.  
  1316. end update$head;
  1317.  
  1318.  
  1319. /***********************************************************************/
  1320.  
  1321.  
  1322. tear$down: procedure;
  1323.  
  1324.                                         /* remove header from file */
  1325.         head$ptr = .iobuff(0);
  1326.         comsize = head.progsize/128;
  1327.  
  1328. tr1:    call copy2(comsize,0);          /* copies com to temp */
  1329.  
  1330.         call closer(comptr);
  1331.         call closer(.tempfcb);
  1332.                                         /* set up pass if any */
  1333.         if len$pass(0) > 0 then call copypass$dma(0);
  1334.         call deleter;                   /* delete com file*/
  1335.         call renamer;
  1336.  
  1337. end tear$down;
  1338.  
  1339.  
  1340. /***************************************************************************/
  1341.  
  1342. create2: procedure;
  1343.  
  1344.  
  1345.         if not COMonly then do;
  1346.  
  1347.                 offsets(0) = 256;               /* starting pos in bytes */
  1348. cr4:            call get$off(.comsize,1);
  1349.                 call addrsx;                    /* copy RSX to temp */
  1350.         end;
  1351.  
  1352.         call putSCBcode(.tempfcb);
  1353.  
  1354.         call reopen$temp;
  1355.  
  1356. cr5:    old = 0;
  1357.         call update$head;
  1358.  
  1359. end create2;
  1360.  
  1361.  
  1362. /***************************************************************************/
  1363.  
  1364.  
  1365. create: procedure;
  1366.         declare i       byte;
  1367.  
  1368.         do i = 0 to 384;                        /* clear the header buffer */
  1369.                 head$buffer(i) = 0;
  1370.         end;
  1371.         do i = 0 to incount;                    /* clear offsets */
  1372.                 offsets(i) = 0;
  1373.         end;
  1374.  
  1375.         head$ptr = .head$buffer;
  1376.         head.retinst = ret$inst;
  1377.         if not SCB then head.SCBjmp = ret$inst;
  1378.         else head.SCBjmp = 0c3h;
  1379.  
  1380.         head.nrsx = incount;
  1381.  
  1382.         totbyte = 256;
  1383.         if NULL then do;
  1384.                 head$buffer(256) = ret$inst;
  1385.                 call setmulti(3);
  1386.         end;
  1387.  
  1388. cr1:    call setdma(head$ptr);                  /* move dma to header */
  1389.         writeflag = writesq(.tempfcb);
  1390.         if writeflag > 0 then do;
  1391.                 fcbp = .tempfcb;
  1392.                 call err$print(.err$msg$write);
  1393.         end;
  1394.  
  1395.         call setdma(.iobuff);
  1396.  
  1397.         if not NULL then do;
  1398.  
  1399.                 if readflag <> 1 then do;               /* if size of COM = 1
  1400.                                                            then read in setup
  1401.                                                            found EOF, no need
  1402.                                                            to copy; if flag > 1
  1403.                                                            then setup catches */
  1404.  
  1405.                         writeflag = writesq(.tempfcb);  /* first 2 COM rcds */
  1406.  
  1407.                         fcbp = comptr;
  1408.                         comsize = 256;
  1409. cr2:                    call copy(.comsize);            /* COM->temp */
  1410.                 end;
  1411.                 else do;
  1412.                         call setmulti(1);
  1413.                         writeflag = writesq(.tempfcb);
  1414.                         comsize = 128;
  1415.                 end;
  1416.         end;
  1417.         else comsize = 128;
  1418.  
  1419.         totbyte = totbyte + comsize;
  1420.  
  1421.         call create2;
  1422.  
  1423. end create;
  1424.  
  1425. /*****************************************************************************/
  1426.  
  1427.  
  1428. SCBget: procedure(skip);
  1429.         declare  skip   byte;
  1430.                                         /* where in record units is beginning
  1431.                                            of SCB initialization code?
  1432.                                            Record numbering is rel to 0 */
  1433.  
  1434.                 comsize = shr(SCBpos,7) - 4;
  1435.                 call copy2(comsize,skip);  /* do not copy SCB code */
  1436.                 totbyte = shl(comsize,7);
  1437.  
  1438.                 readflag = readsq(comptr);
  1439.                 call move(256,.iobuff,.SCBbuff);
  1440.  
  1441. end SCBget;
  1442.  
  1443. /*****************************************************************************/
  1444.  
  1445.  
  1446. remover: procedure;
  1447.                                         /* remove old RSX in gencommed file */
  1448.  
  1449. getname: procedure(j);
  1450.  
  1451.         declare (j,k)   byte;
  1452.  
  1453.         do k = 0 to 7;
  1454.                 new(j).name(k) = rsx$sub$head.name(k);
  1455.         end;
  1456. end getname;
  1457.  
  1458.  
  1459.         declare (i,j,k,l)       byte,
  1460.                 zeroes          based subptr (1) byte,
  1461.                 tot             address;
  1462.  
  1463.  
  1464.         fcbp = comptr;
  1465. rp1:    subptr = .iobuff(16);                   /* prepare to collapse header..
  1466.                                                    compute actual lengths,
  1467.                                                    & save start bit map */
  1468.         nextptr = .iobuff(32);
  1469.         do j = 1 to old;
  1470.                 newlen(j) = rsx$sub$head.len;   /* save len & name */
  1471.                 call getname(j);
  1472.                 actlen(j) = next.off - rsx$sub$head.off;
  1473.                 nbank(j) = rsx$sub$head.NONBANK;
  1474.  
  1475.                 subptr = nextptr;
  1476.                 nextptr = nextptr + 16;
  1477.         end;
  1478.         actlen(old) = 0;
  1479.  
  1480. rp2:    subptr = .iobuff(16);                   /* start copying current COM
  1481.                                                    file, skipping dup entries*/
  1482.         writeflag = writesq(.tempfcb);          /* header */
  1483.         tot = shr(head.progsize,7);             /* # 80h units to copy */
  1484.         call copy2(tot,0);                      /* copies COM to temp */
  1485.         tot = tot + 2;
  1486.  
  1487. rp3:    j = 1;                                  /* now copy each valid RSX */
  1488.         do i = 1 to old;
  1489.                 comsize = shr(actlen(i),7);     /* convert to 80h units */
  1490.                 if which(i) = i then do;        /* duplicate */
  1491.                         if i <> old then        /* don't skip last */
  1492.                           call copy2(comsize,1);
  1493.                 end;
  1494.                 else do;                        /* copy RSX & setup new offsets
  1495.                                                    lengths */
  1496. rpx:                    newoff(j) = shl(tot,7);
  1497.                         nbank(j) = nbank(i);
  1498.                                                 /* if last RSX then we have no
  1499.                                                    way of knowing the actual 
  1500.                                                    length...so write until EOF,
  1501.                                                    else write comsize # rcds */
  1502.                         if i = old then call copy(.tot);
  1503.                         else do;
  1504.                                 tot = tot + comsize;
  1505.                                 call copy2(comsize,0);
  1506.                         end;
  1507.  
  1508.                         newlen(j) = newlen(i);          /* i > j always */
  1509.                         do k = 0 to 7;
  1510.                                 new(j).name(k) = new(i).name(k);
  1511.                         end;
  1512.                         j = j + 1;
  1513.                 end;
  1514.         end;
  1515.  
  1516.                                                 /* now rebuild header */
  1517.         call reopen$temp;
  1518.  
  1519.         j = j - 1;
  1520.         subptr = .iobuff(16);
  1521.         do i = 1 to j;                     /* j = # good RSX */
  1522.                 rsx$sub$head.off = newoff(i);
  1523.                 rsx$sub$head.len = newlen(i);
  1524.                 rsx$sub$head.NONBANK = nbank(i);
  1525.                 nbank(i) = 0;
  1526.                 do k = 0 to 7;
  1527.                         rsx$sub$head.name(k) = new(i).name(k);
  1528.                 end;
  1529.                 subptr = subptr + 16;
  1530.         end;
  1531.  
  1532.         do i = j + 1 to old;                    /* clear out header */
  1533.                 call zapRSX;
  1534.         end;
  1535.  
  1536. rp4:    head.nrsx = j;
  1537.         old = j;
  1538.  
  1539.         tempfcb(32) = 0;                        /* CR = 0 */
  1540.         flag = writesq(.tempfcb);
  1541.  
  1542.         call closer(.tempfcb);                  /* close and rename */
  1543.         call deleter;                           /* delete com file */
  1544.         call renamer;
  1545.  
  1546.         call clearfcb(comptr);
  1547.         call clearfcb(.tempfcb);
  1548.         call maker(.tempfcb);
  1549. rp9:    call opener(comptr);                    /* prepare return to concat */
  1550. rp7:    readflag = readsq(comptr);
  1551.  
  1552. end remover;
  1553.  
  1554.  
  1555. /***************************************************************************/
  1556.  
  1557.  
  1558. dup$RSX: procedure byte;
  1559.                                         /* check for duplications in header and
  1560.                                            input.  Remove old entry if found,
  1561.                                            or if all are duplicated then strip
  1562.                                            everything off. */
  1563.  
  1564.         declare (i,j,k,l)       byte,
  1565.                 temp            address;
  1566.  
  1567.         subptr = .iobuff(16);
  1568.         deletes = 0;
  1569.  
  1570.         do i = 1 to old;
  1571.                 which(i) = 0;
  1572.  
  1573.                 do j = 1 to incount;            /* compare names */
  1574.                         fcbp = allfcbs(j);
  1575.                         do k = 0 to 7;
  1576.                                 if rsx$sub$head.name(k) <> gen$fcb(k+1)
  1577.                                         then go to dp1;
  1578.                         end;
  1579.                                                 /* duplicate RSX's */
  1580.                         which(i) = i;
  1581.                         deletes = deletes + 1;
  1582.  
  1583.                         call e$print1(.err$msg$dup2);
  1584.                         call e$print2;
  1585.  
  1586.                         go to dp2;              /* no need to scan rest of
  1587.                                                    input names- checked input
  1588.                                                    for dups already */
  1589. dp1:            end;
  1590. dp2:            subptr = subptr + 16;
  1591.         end;
  1592.  
  1593.         if deletes = 0 then return(false);
  1594. dp4:    if deletes >= old then do;              /* replace all ? */
  1595.                 subptr = .iobuff(16);
  1596.                 do i = 1 to old;
  1597.                         call zapRSX;
  1598.                 end;
  1599.  
  1600.                 temp = head.progsize;           /* get size of COM in rcds */
  1601.  
  1602.                 if oldSCB then do;
  1603.                         call SCBget(1);
  1604.                         comfcb(32) = 0;
  1605.                         call setmulti(2);
  1606.                         readflag = readsq(comptr);
  1607.                 end;
  1608.  
  1609.                 comsize = shr(temp,7);
  1610.                 writeflag = writesq(.tempfcb);  /* copy header to temp */
  1611.                 call copy2(comsize,0);          /* copy COM file */
  1612.  
  1613.                 comsize = temp;                 /* back to byte count */
  1614.                 call create2;
  1615.  
  1616.                 return(true);
  1617.         end;
  1618.  
  1619.         call remover;                           /* selective replace */
  1620.  
  1621.         return(false);                          /* return and add new RSX */
  1622.  
  1623. end dup$RSX;
  1624.  
  1625.  
  1626. /***************************************************************************/
  1627.  
  1628.  
  1629. concat: procedure;
  1630.                                         /* add new, replace old */
  1631.  
  1632.         declare i       byte;
  1633.  
  1634.         head$ptr = .iobuff;
  1635.         if (old := head.nrsx) <> 0 then do;
  1636. yy:             if dup$RSX then return;         /* true  : did a create
  1637.                                                    false : add new RSX,
  1638.                                                            might have collapsed
  1639.                                                            old header...*/
  1640.  
  1641.         end;
  1642.  
  1643.         head.nrsx = head.nrsx + incount;
  1644.         fcbp = comptr;
  1645.  
  1646. cc1:    if head.nrsx > 15 then
  1647.                 call err$print(.err$msg$rsx$slot);
  1648.  
  1649.         flag = writesq(.tempfcb);       /* write header */
  1650.  
  1651.         if oldSCB then call SCBget(0);
  1652.         else do;                        /* no SCB...copy to EOF */
  1653.                 comsize = 256;
  1654.                 call copy(.comsize);
  1655.         end;
  1656.  
  1657.                                         /* comsize = size of file in bytes
  1658.                                            +1 = offset of first new RSX */
  1659.         offsets(0) = 0;
  1660.         call getoff(.comsize,1);
  1661.  
  1662.         totbyte = comsize;
  1663.  
  1664.         call closer(fcbp);              /*close old file */
  1665.  
  1666.         call addrsx;
  1667.  
  1668.         call putSCBcode(.tempfcb);
  1669.  
  1670.         call reopen$temp;
  1671.         call update$head;
  1672.  
  1673. end concat;
  1674.  
  1675.  
  1676. /***********************************************************************/
  1677.  
  1678. setSCB: procedure;
  1679.  
  1680.                                 /* read in gencommed file and set scb values
  1681.                                    from command line */
  1682.  
  1683.         head$ptr = .iobuff;
  1684.  
  1685.         fcbp = comptr;
  1686.         totbyte = 2;
  1687.  
  1688.         if LOAD then do;                /* write out loader flag */
  1689.                 if oldSCB or not SCB then do;
  1690.                         iobuff(13) = 1;
  1691.                         comfcb(32) = 0;
  1692.                         writeflag = writesq(.comfcb);
  1693.                         if writeflag <> 0 then call err$print(.err$msg$write);
  1694.                         totbyte = 0;
  1695.                 end;
  1696.         end;
  1697.  
  1698.         if SCB then do;
  1699.                 if oldSCB then call SCBget(1);
  1700.                 else do;
  1701.                      if readflag <> 1 then do;          /* 1 rcd com file ? */
  1702.                         call setmulti(32);
  1703.                         call mread(comptr);
  1704.                         do while readflag <> 1;
  1705.                                 totbyte = totbyte + nrecs;
  1706.                                 call mread(comptr);
  1707.                         end;
  1708.                      end;
  1709.  
  1710.                         totbyte = totbyte + nrecs;
  1711.                         totbyte= shl(totbyte,7);        /* change to bytes */
  1712.                 end;
  1713.  
  1714.                 call putSCBcode(comptr);
  1715.  
  1716.                 if not oldSCB then do;                  /* must update header
  1717.                                                            for new SCB's */
  1718.                         call closer(comptr);
  1719.                         call setmulti(1);
  1720.                         call clearfcb(comptr);
  1721.                         call opener(comptr);
  1722.                         readflag = readsq(comptr);
  1723.                         call move(2,.totbyte,.iobuff(4));
  1724.                         if LOAD then iobuff(13) = 1;
  1725.                         iobuff(3) = ret$inst;
  1726.                         comfcb(32) = 0;
  1727.                         writeflag = writesq(.comfcb);
  1728.                         if writeflag <> 0 then call err$print(.err$msg$write);
  1729.                 end;
  1730.         end;
  1731.  
  1732.         call closer(comptr);
  1733.  
  1734. end setSCB;
  1735.  
  1736.  
  1737. /***********************************************************************/
  1738.  
  1739.  
  1740. setuper: procedure;
  1741.  
  1742.                                 /*      1. get each file (process passwords)
  1743.                                         2. check for proper type
  1744.                                         3. check for duplicate RSX on input
  1745.                                         4. open files and make temp
  1746.                                 */
  1747.  
  1748.         declare (i,j,k,l)       byte;
  1749.  
  1750. init:   procedure;
  1751.  
  1752.         fcbp,allfcbs(i) = .fcbs(i).file(0);
  1753.         do j = 0 to 32;
  1754.                 fcbs(i).file(j) = 0;
  1755.         end;
  1756. end init;
  1757.  
  1758. RSX$errprint: procedure;
  1759.  
  1760.  
  1761.         call e$print1(.('This file was not used.',0));
  1762.         call e$print2;
  1763.         call crlf;
  1764.  
  1765.         which(deletes) = i;
  1766.         deletes = deletes + 1;
  1767.  
  1768. end RSX$errprint;
  1769.  
  1770. fill$type: procedure(typea);
  1771.         declare typea   address,
  1772.                 type    based typea (1) byte;
  1773.  
  1774.         k = 0;
  1775.         do l = 9 to 11;
  1776.                 gen$fcb(l) = type(k);
  1777.                 k = k + 1;
  1778.         end;
  1779.  
  1780. end fill$type;
  1781.  
  1782.  
  1783. checktype: procedure(typea) byte;
  1784.         declare typea   address,
  1785.                 type    based typea (1) byte;
  1786.  
  1787.         if gen$fcb(9) = BLANK then              /* any type ? */
  1788.                 call fill$type(typea);
  1789.  
  1790.         else do;                                /* check input type */
  1791.                 k = 0;
  1792.                 do l = 9 to 11;
  1793.                         if gen$fcb(l) <> type(k) then return(false);
  1794.                         k = k + 1;
  1795.                 end;
  1796.         end;
  1797.  
  1798.         return(true);
  1799.  
  1800. end checktype;
  1801.  
  1802.  
  1803.  
  1804.         buf$ptr = .buff(1);                     /* get files */
  1805.         i = 0;
  1806.         do while buf$ptr <> 0;
  1807.                 call init;
  1808.                 call parser(fcbp);
  1809.  
  1810.                 if optmark = '[' then go to sb1;/* no more names, options */
  1811.  
  1812.                                                 /* any PASSWORDS !!!! */
  1813.                 k = gen$fcb(26);                /* length of password */
  1814.                 if k > 0 then do;
  1815.                         l = 16;                 /* start of password */
  1816.                         do j = 0 to k - 1;
  1817.                                 files(i).pass(j) = gen$fcb(l);
  1818.                                 l = l + 1;
  1819.                         end;
  1820.                         len$pass(i) = k;
  1821.                 end;
  1822.                 i = i + 1;
  1823.         end;
  1824.  
  1825. sb1:    incount = i - 1;
  1826.  
  1827.         if optmark = '[' then do;
  1828.                 incount = i;
  1829.                 call getoption;
  1830.         end;
  1831.  
  1832.         comptr = allfcbs(0);
  1833.                                                         /* check COM */
  1834. sb2:            fcbp = comptr;
  1835.                 if not checktype(.comtype) then do;     /* bad input */
  1836.                   if not NULL then do;    
  1837.                         call print(.err$msg$first);
  1838.                         call terminate;
  1839.                   end;
  1840.                 end;
  1841.  
  1842.                 if len$pass(0) > 0 then call copypass$dma(0);
  1843.                 if open(fcbp) > 3 then do;             /* something awry */
  1844.                   if not NULL then do;
  1845.                         call err$print(.err$notfnd);
  1846.                         call e$print1(.err$msg$first);
  1847.                         call terminate;
  1848.                   end;
  1849.                 end;
  1850.                 else
  1851.                 if NULL then 
  1852.                 if (comfcb(8) and 80h) <> 80h then
  1853.                         call err$print(.err$NULL); /* NULL and COM file*/
  1854.  
  1855.                 if NULL then do;
  1856. sb3:            i = (incount := incount + 1);   /* move fcbs up */
  1857.                 allfcbs(i) = .fcbs(i);
  1858.                 do j = 0 to incount - 1;
  1859.                         do k = 0 to 32;
  1860.                                 fcbs(i).file(k) = fcbs(i-1).file(k);
  1861.                         end;
  1862.                         i = i - 1;
  1863.                 end;
  1864.                                                 /* dummy COM name = 1st RSX */
  1865.                 call fill$type(.comtype);
  1866.                 fcbp = allfcbs(1);              /* restore type to RSX */
  1867.                 call fill$type(.rsxtype);
  1868.         end;
  1869.  
  1870. sb4:   if incount > 0 then do;
  1871.                 deletes = 0;                    /* now check RSX's */
  1872.                 do i = 1 to incount;
  1873.                         fcbp = allfcbs(i);      /* point to RSX fcb */
  1874.  
  1875.                         if not checktype(.rsxtype) then do;
  1876.                                 call e$print1(.err$msg$rsxval);
  1877.                                 call RSX$errprint;
  1878.                         end;
  1879.  
  1880.                         else do;                /* try to open file */
  1881.                                 if len$pass(i) > 0 then
  1882.                                    call copypass$dma(i);
  1883.  
  1884.                                 flag = open(fcbp);
  1885.                                 if flag > 3 then do;
  1886.                                         call e$print1(.err$notfnd);
  1887.                                         call RSX$errprint;
  1888.                                 end;
  1889.                                 else            /* Duplicate input RSX ? */
  1890.                                      do j = i+1 to incount;
  1891.                                         test$ptr = allfcbs(j);
  1892.                                         do l = 1 to 8;
  1893.                                            if genfcb(l) <> testfcb(l)
  1894.                                                 then go to sb5;
  1895.                                         end;
  1896.                                         call e$print1(.err$msg$dup1);
  1897.                                         call RSX$errprint;
  1898. sb5:                                 end;
  1899.                         end;
  1900.                 end;                            /* ends i = incount...*/
  1901.  
  1902.                                                 /* have any RSX's left? */
  1903.                 if deletes >= incount then do;
  1904.                    call print(.err$msg$no$rsx);
  1905.                    call terminate;
  1906.                 end;
  1907.  
  1908.                 i = 0;
  1909. sb6:            do while i < deletes;   /* collapse allfcbs */
  1910.                         j = which(i);
  1911.                         incount = incount - 1;
  1912.         
  1913.                         do l = j to incount;
  1914.                                 allfcbs(l) = allfcbs(l + 1);
  1915.                         end;
  1916.  
  1917.                         i = i + 1;
  1918.                 end;
  1919.  
  1920.                 rsx = true;
  1921.         end;                            /* if incount> 0...*/
  1922.  
  1923. sb7:
  1924.         call setdma(.iobuff);
  1925.         call setmulti(2);                       /* read header if any */
  1926.  
  1927.         if not NULL then do;
  1928.                 fcbp = comptr;
  1929.                 call mread(comptr);
  1930.                 if readflag > 1 then call err$print(.err$msg$read);
  1931.  
  1932.                                                 /* is this already gencommed*/
  1933. sb8:            if iobuff(0) = ret$inst then do;
  1934.                                                 /* first byte = return */
  1935.                         if rsx then replace = true;
  1936.                         else do;
  1937.                                 if SCB or LOAD then punchSCB = true;
  1938.                                 else revert = true;
  1939.                         end;
  1940.  
  1941.                                                 /* do we need to move old SCB
  1942.                                                    initialization code ? */
  1943.                         if iobuff(3) <> 0c9h then do;
  1944.                                 oldSCB = true;
  1945.                                 call move(2,.iobuff(4),.SCBpos);
  1946.                         end;
  1947.                 end;
  1948.                 else do;
  1949.                         if rsx then build = true;
  1950.                         else if SCB or LOAD then COMonly = true;
  1951.                         else call err$print(.errSTRIP);
  1952.                 end;
  1953.         end;
  1954.         else build = true;
  1955.  
  1956. sb9:    if not punchSCB then do;
  1957.                 call clearfcb(.tempfcb);
  1958.                 flag = delete(.tempfcb);
  1959.                 tempfcb(0) = comfcb(0);         /* init temp drive */
  1960. sb0:            call maker(.tempfcb);
  1961.         end;
  1962.  
  1963. end setuper;
  1964.  
  1965.  
  1966.  
  1967. /*                      MAIN PROGRAM                    */
  1968.  
  1969.  
  1970. plm:
  1971.  
  1972.         testvers = get$version;
  1973.         if high(testvers) = 1 then go to err$vers;
  1974.         if low(testvers) < 30h then go to err$vers;
  1975.  
  1976.         call return$errors(254);
  1977.  
  1978.         call setuper;
  1979.  
  1980.         if revert then call tear$down;
  1981.         else
  1982.         if build then call create;
  1983.         else
  1984.         if punchSCB then call setscb;
  1985.         else if COMonly then call create;
  1986.         else call concat;
  1987.  
  1988.         call closeall;
  1989.  
  1990.         call print(.('GENCOM completed.',0));
  1991.         call terminate;
  1992.  
  1993. err$vers:
  1994.         call print(.ERRORM);
  1995.         call printx(.('Requires CP/M 3 or higher.',0));
  1996.         call terminate;
  1997.  
  1998.  
  1999. end gencomer;
  2000.