$ TITLE('CP/M 3.0 --- SUBMIT') sub: do; $include (copyrt.lit) /* Revised: 26 July 79 for CP/M 2.0 01 July 82 for CP/M 3.0 by John Knight 23 Aug 82 for CP/M 3.0 by Doug Huskey 11 Sept 82 for CP/M 3.0 by Doug Huskey 1 Nov 82 for CP/M 3.0 by Doug Huskey */ /* generation procedure seteof submit.plm seteof copyrt.lit is14 asm80 mcd80a.asm debug asm80 getf.asm debug asm80 parse.asm debug plm80 submit.plm pagewidth(100) debug optimize link mcd80a.obj,submit.obj,parse.obj,getf.obj,plm80.lib to submit.mod locate submit.mod code(0100H) stacksize(100) era submit.mod cpm objcpm submit rmac getrsx xref getrsx link getrsx[op] era get.rsx ren get.rsx=getrsx.prl gencom submit.com get.rsx */ declare plm label public; /********************************* * * * B D O S I N T E R F A C E * * * *********************************/ declare sfcb(33) byte external, /* default fcb */ buff(128) byte external; /* default buffer */ declare cmdrv byte external; /* command drive */ declare fcb (1) byte external; /* 1st default fcb */ declare fcb16 (1) byte external; /* 2nd default fcb */ declare pass0 address external; /* 1st password ptr */ declare len0 byte external; /* 1st passwd length */ declare pass1 address external; /* 2nd password ptr */ declare len1 byte external; /* 2nd passwd length */ declare tbuff (1) byte external; /* default dma buffer */ mon1: procedure(f,a) external; declare f byte, a address; /* bdos interface, no returned value */ end mon1; mon2a: procedure(f,a) external; declare f byte, a byte; /* bdos interface, no returned value */ end mon2a; mon2: procedure(f,a) byte external; declare f byte, a address; /* bdos interface, return byte value */ end mon2; mon3: procedure(func,info) address external; declare func byte; declare info address; end mon3; parse: procedure (pfcb) address external; declare pfcb address; end parse; getf: procedure (input$type) external; /* does submit file processing */ declare input$type address; end getf; /************************************ * * * L I T E R A L S * * * ************************************/ declare lit literally 'literally', dcl lit 'declare', proc lit 'procedure', addr lit 'address', ctll lit '0ch', lca lit '110$0001b', /* lower case a */ lcz lit '111$1010b', /* lower case z */ endfile lit '1ah', /* cp/m end of file */ sysin$endfile lit '0ffh', true literally '1', false literally '0', forever literally 'while true', cr literally '13', lf literally '10', what literally '63', temp$file$drive$offset literally '50h', con$type literally '0', cpmversion literally '30h', ctrli literally '09h'; /**************************************** * * * G L O B A L V A R I A B L E S * * * ****************************************/ declare ln(9) byte initial('00001 : $'), ln1 byte at(.ln(0)), ln2 byte at(.ln(1)), ln3 byte at(.ln(2)), ln4 byte at(.ln(3)), ln5 byte at(.ln(4)), dfcb(36) byte initial(0,'SYSIN $$$',0,0,0), drec byte at(.dfcb(32)), /* current record */ drrec address at(.dfcb(33)), /* random record */ drr2 byte at(.dfcb(35)), /* random record byte 3 */ dcnt byte, get$init$pb byte initial(128), /* getrsx sub-functions */ get$kill$pb byte initial(129), get$fcb$pb byte initial(130), sstring(128) byte, /* substitute string */ sbp byte, /* source buffer pointer */ ssbp byte, /* sub string buffer pointer */ ver address, a address, /* calling program's stack pointer */ prog$flag based a address; declare scbpd structure (offset byte, set byte, value address); declare parse$fn structure (buff$adr address, fcb$adr address); declare subpb structure (io$type byte, echo$flag byte, filtered$flag byte, program$flag byte) initial (con$type,true,true,false); declare ctrlc literally '3', ctrlx literally '18h', bksp literally '8', submit$file$drv literally '15'; /**************************************** * * * B D O S F U N C T I O N C A L L S * * * ****************************************/ printchar: procedure(char); declare char byte; call mon1(2,char); end printchar; conin: procedure byte; return mon2(6,0fdh); end conin; print: procedure(a); declare a address; /* print the string starting at address a until the next dollar sign is encountered */ call mon1(9,a); end print; read$console$buf: procedure (buffer$address,max) byte; declare buffer$address address; declare new$max based buffer$address address; declare max byte; new$max = max; call mon1(10,buffer$address); buffer$address = buffer$address + 1; return new$max; /* actually number of characters input */ end read$console$buf; version: procedure address; /* returns current cp/m version */ return mon3(12,0); end version; open: procedure(fcb) address; declare fcb address; return (mon3(15,fcb)); end open; close: procedure(fcb); declare fcb address; dcnt = mon2(16,fcb); end close; delete: procedure(fcb); declare fcb address; call mon1(19,fcb); end delete; diskread: procedure(fcb) byte; declare fcb address; return mon2(20,fcb); end diskread; diskwrite: procedure(fcb) byte; declare fcb address; return mon2(21,fcb); end diskwrite; ranread: procedure(fcb) byte; declare fcb address; return mon2(33,fcb); end ranread; make: procedure(fcb); declare fcb address; dcnt = mon2(22,fcb); end make; setdma: procedure(dma); declare dma address; call mon1(26,dma); end setdma; errormode: procedure(mode); declare mode byte; call mon2a(45,mode); end errormode; getscbbyte: procedure (offset) byte; declare offset byte; scbpd.offset = offset; scbpd.set = 0; return mon2(49,.scbpd); end getscbbyte; setscbbyte: procedure (offset,value); declare offset byte; declare value byte; scbpd.offset = offset; scbpd.set = 0ffh; scbpd.value = double(value); call mon1(49,.scbpd); end setscbbyte; rsx$call: procedure (rsxpb) address; /* call Resident System Extension */ declare rsxpb address; return mon3(60,rsxpb); end rsx$call; /************************************************* * * * M A I N S U B R O U T I N E S * * * *************************************************/ move: procedure(s,d,n); declare (s,d) address, n byte; declare a based s byte, b based d byte; do while (n := n - 1) <> 255; b = a; s = s + 1; d = d + 1; end; end move; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ crlf: proc; call printchar(cr); call printchar(lf); end crlf; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ bad$file: proc; call print(.('Invalid file name $')); call mon1(0,0); end bad$file; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* fill string @ s for c bytes with f */ fill: procedure(s,f,c); declare s address; declare (f,c) byte; declare a based s byte; do while (c:=c-1) <> 255; a=f; s=s+1; end; end fill; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ error: procedure(a); declare a address; call crlf; call print(.('Error On Line $')); call print(.ln1); call print(a); call move(.dfcb(0),.sfcb(0),33); call delete(.sfcb(0)); /* cleanup before exit */ call mon1(0,0); /* return to ccp */ end error; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ucase: procedure (char) byte; declare char byte; if char >= 'a' then if char < '{' then return (char-20h); return char; end ucase; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ getucase: procedure byte; declare c byte; c = ucase(conin); return c; end getucase; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ getpasswd: procedure; declare (i,c) byte; call crlf; call crlf; call print(.('Enter Password: $')); retry: call fill(.fcb16,' ',8); do i=0 to 7; nxtchr: if (c:=getucase) >= ' ' then fcb16(i)=c; if c = cr then return; if c = ctrlx then go to retry; if c = bksp then do; if i < 1 then goto retry; else do; fcb16(i := i - 1) = ' '; goto nxtchr; end; end; if c = 3 then call mon1(0,0); end; end getpasswd; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ deblankparm: procedure; /* clear to next non-blank substitute string */ do while (sstring(ssbp) = ' ' or sstring(ssbp) = ctrli); ssbp = ssbp + 1; end; end deblankparm; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ try$open: procedure; declare error$code address; call fill(.fcb16,' ',8); /* blank storage for password */ if len0 <> 0 then call move(pass0,.fcb16,len0); call error$mode(0feh); call setdma(.fcb16); /* set dma to password */ error$code = open(.sfcb); if low(error$code) = 0ffh then if high(error$code) = 7 then do; call getpasswd; call crlf; call setdma(.fcb16); call error$mode(0); error$code=open(.sfcb); end; else do; if high(error$code) = 0 then call print(.('ERROR: No ''SUB'' File Found$')); call mon1(0,0); end; call setdma(.buff(0)); call error$mode(0); end try$open; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ setup: procedure; declare no$chars byte; declare pstatus address; declare b byte; /* move buffer to substitute string */ call move(.buff(1),.sstring(0),127); sstring(buff(0))=0; /* mark end of string */ /* check to see if there are parameters */ ssbp = 0; call deblankparm; /* skip over leading spaces */ if sstring(ssbp) = 0 then do; /* no sub file, prompt for it */ call print(.('CP/M 3 SUBMIT Version 3.0',cr,lf,'$')); call print(.('Enter File to SUBMIT: $')); no$chars = read$console$buf(.buff(0),40); buff(no$chars+2)=0; /* mark end of input */ call crlf; parse$fn.buff$adr = .buff(2); parse$fn.fcb$adr = .sfcb(0); pstatus = parse(.parse$fn); if pstatus = 0FFFFh then call bad$file; call move(.buff(2),.sstring(0),127); end; call move(.('SUB'),.sfcb(9),3); /* set file type to SUB */ if sfcb(0) = 0 then if (b:=getscbbyte(submit$file$drv)) > 0 then do; sfcb(0)=b; /* set file drive to that saved by CCP */ call setscbbyte(submit$file$drv,0); end; call try$open; do while (sstring(ssbp) <> ' ' and sstring(ssbp) <> 0 and sstring(ssbp) <> ctrli); ssbp = ssbp + 1; /* skip over file name */ end; call deblankparm; /* skip over any spaces */ b = sstring(ssbp); /* File is open if this point reached */ sbp = 128; /* causes read below */ end setup; getsource: procedure byte; /* read the next source character */ declare b byte; if sbp > 127 then do; if diskread(.sfcb(0)) <> 0 then return endfile; sbp = 0; end; if (b := buff((sbp:=sbp+1)-1)) = cr then do; /* increment line */ if (ln5:=ln5+1) > '9' then do; ln5 = '0'; if (ln4:=ln4+1) > '9' then do; ln4 = '0'; if (ln3:=ln3+1) > '9' then do; ln3 = '0'; if (ln2:=ln2+1) > '9' then do; ln2 = '0'; ln1 = ln1 + 1; end; end; end; end; end; return b; end getsource; writebuff: procedure; /* write the contents of the buffer to disk */ if diskwrite(.dfcb) <> 0 then /* error */ call error(.('Disk Write Error$')); end writebuff; declare rbuff(2048) byte, /* jcl buffer */ rbp address, /* jcl buffer pointer */ rlen byte; /* length of current command */ fillrbuff: procedure; declare s byte; /* sub string buffer pointer */ notend: procedure byte; /* look at next character in sstring, return true if not at the end of the string - char passed back in 's' */ if not ((s := sstring(ssbp)) = ' ' or s = 0) then do; ssbp = ssbp + 1; return true; end; return false; end notend; write$rbuff: procedure; declare j byte; declare i address; rbp=0; i=0; do while (i < 2048); do j=0 to 127; if rbuff(i+j)=sysin$endfile then goto close$file; end; call setdma(.rbuff(i)); call writebuff; i=i+128; end; call setdma(.buff(0)); return; close$file: call setdma(.rbuff(i)); call writebuff; call setdma(.buff(0)); drrec, drr2 = 0; /* set to 1st record in file */ dcnt = ranread(.dfcb); /* read to position at start */ if dcnt <> 0 then call error(.('Random Read $')); goto exit$from$process; end write$rbuff; putrbuff: procedure(b); declare b byte; if (rbp > last(rbuff)) then do; call print(.('.$')); call write$rbuff; end; rbuff(rbp) = b; if b = sysin$endfile then call write$rbuff; rbp = rbp + 1; end putrbuff; declare (reading,b,newline,progline) byte; /* fill the jcl buffer */ rbp = 0; reading = true; do while reading; rlen = 0; /* reset command length */ newline,progline = true; do while (b:=getsource) <> endfile and b <> cr; if b <> lf then do; if b = sysin$endfile then call error(.('Invalid ASCII Character$')); if newline then do; /* program input begins with < */ newline = false; if b <> '<' then progline = false; end; if b = '$' then /* copy substitute string */ do; if (b:=getsource) = '$' then /* $$ replaced by $ */ call putrbuff(b); else if (b := b - '0') > 9 then call error(.('Parameter Error$')); else do; /* find string 'b' in sstring */ ssbp = 0; call deblankparm; /* ready to scan string */ do while b <> 0; b = b - 1; /* clear next parameter */ do while notend; end; call deblankparm; end; /* ready to copy substitute string from position ssbp */ do while notend; call putrbuff(s); end; end; end; else /* not a '$' */ if b = '^' then do; /* possible control character */ b=getsource; if b = '^' then call putrbuff('^'); /* '^^' ==> '^' */ else do; if b < '@' then /* number symbols */ call putrbuff(b-' '); else if b < '`' then /* upper case */ call putrbuff(b-'@'); else call putrbuff(b-'`'); /* lower case */ end; end; /* check for multiple commands !! */ else if b = '!' and not progline then do; call putrbuff(cr); /* mark eoln with cr, lf */ call putrbuff(lf); end; else /* not $ or ^ */ call putrbuff(b); end; end; /* of line or input file - compute length */ reading = b = cr; call putrbuff(cr); /* mark eoln with cr, lf */ call putrbuff(lf); end; /* entire file has been read and processed */ rbp = rbp - 2; /* back up; too many cr,lf's on last line */ call putrbuff(sysin$endfile); /* mark end of file */ end fillrbuff; makefile: procedure; declare i byte; declare rsxadr addr; declare rsxbase based rsxadr addr; rsxadr = rsx$call(.get$init$pb); i = high(rsxbase); /* rsxbase = addr of kill flag */ i = shr(i,2); dfcb(6) = i/10 + '0'; dfcb(7) = i mod 10 + '0'; call errormode(0ffh); /* set to return errors */ drec = 0; /* zero the next record to write */ call make(.dfcb); if dcnt = 255 then do; call delete(.dfcb); /* file might exist */ call errormode(0); call make(.dfcb); /* try make again */ if dcnt = 255 then do; call print(.('ERROR: Directory Full$')); call mon1(0,0); end; end; call errormode(0); end makefile; /************************************************* * * * M A I N P R O G R A M * * * *************************************************/ plm: ver = version; if (low(ver) < cpmversion) or (high(ver) = 1) then do; call print(.('Requires CP/M 3.0 $')); call mon1(0,0); end; dfcb(0)=getscbbyte(temp$file$drive$offset); call setup; call makefile; call fillrbuff; exit$from$process: /* check if GET is above us and about to abort */ a = rsx$call(.get$fcb$pb); if a <> 0ffh then do; a = a - 2; if prog$flag then a = rsx$call(.get$kill$pb); end; call move(.dfcb(0),.sfcb(0),33); /* move to fcb @ 5ch */ call getf(.subpb); /* GETF also does submit processing */ end sub;