; RZMPLOG.Z80 ; ;v4.0 - equate ver4 true makes rzmplog compatible with new userin.lib ; routine. ver4 false is the same as rzmplog3. Version 4 gets the ; upload category from the userin.lib insert via a low memory location ; at 4ah. If KMD is true, then the FOR file header info will show the ; drive and user that the file is uploaded to. ;v3.0 - provide patch point at KMD: to turn off du,size,date in FOR ; header line. Set to FF for KMD format. ; fixed bug in filename routine if no file extent. rkr ; ;v2.4 - please report problems or suggestions to ; Houston N/W Znode TXHOU (713)- 937-8886 ; Performs log function for RZMP ; Rzmp16 writes a text file consisting of a list of names received or ; sent. Rzmp then chains to RZMPLOG, which reads the RZMP.OUT file left ; by Rzmp. ; To test this program offline, set TEST equ true and drive to store ; files on and assemble. A RZMP.OUT file must be located in the test ; directory. Format for the 0:00 b0:filename.ext 3k ; | | ; xfer time size ; ; Run by typing RZMPLOG R or RP ; or RZMPLOG S or SP ; ; Assembly requires SYSLIB.REL, preferably version 4.0. ; ; Using SLRASM and SLRNK+ ; SLRASM RZMPLOG/6 ; SLRNK RZMPLOG/N,/P:100,RZMPLOG,SYSLIB/S,/E ; ; Called by RZMP, which leaves 'R' or 'S' in fcb1 depending on ; whether files were received or sent. Files transferred are in ; a file called RZMP.OUT, with data on file length and transmission ; time. ; ; Started with RZMPLOG.MAC from RZMP16.LBR ; Added FOR file descriptions with code borrowed from KMD23. ; handles single or batch uploads and downloads. ; Puts DU:, filesize, and date in the header in the format ; of Gene Nolan's UFOR program. ; ; Private uploads will not have FOR entries requested. ; Zmodem tranfers can be determined by a large K in the filesize ; as opposed to a lowercase k for KMD or ZMD. ; ; set equates for test and filenames below. ; FOR name is at end of program. version equ 40 false equ 0 true equ not false yes equ true no equ 0 ver4 equ true ;* set false if userin.lib is not used. test equ false ; true for test mode to run without BYE ; using fake data mspeed equ 003ch ; Address of mspeed byte cseg .z80 dma equ 080h cr equ 0dh lf equ 0ah fcb1 equ 5ch bdos equ 5 ; SYSLIB routines used: ext print, putud, getud, fname, retud, logud ext setdma, initfcb, ialloc, alloc, f$open ext f$exist, f$make, f$appl, f$write, f$read ext f$close, capstr, argv, caps, eval10, mhldc ext cout, f$delete, isalpha ; rzmplog: jp start db 'Z3ENV' ; In case of ZCPR3 db 1 ; External environment z3env: dw 0 db 0,0,0 ;filler descrb: db 0ffh ;set to zero if descriptions not wanted kmd: db 0h ;set to nonzero if kmd style FOR entries ;ie no DU:,size, or date. lognam: db 'A14:KMD.LOG',0 ; du: and name of .LOG file ds 16 - ($ - lognam) lcname: db 'A14:LASTCALR',0 ds 16 - ($ - lcname) dausa: db 'DATEUSA>' dateusa: db 0ffh ; flag: 0ffh for USA-style date ds 16 - ($ - dausa) ; MHZ: DB 4 ; *Clock speed, use integer (2,4,5,8, etc.) DRIVE: DB 'A' ; Drive to store FOR file USER: DB 14 ; User area of FOR file ; ; File categories, this will be shown when a file upload description is ; needed. ; FILDES: DB CR,LF,' [A] - Zcpr3 ' DB CR,LF,' [B] - Generic Cp/m ' DB CR,LF,' [C] - Modem,BBS,Rcp/m ' DB CR,LF,' [D] - Technical ' DB CR,LF,' [E] - Text & Information ' DB CR,LF,' [F] - Games & Basic ' DB CR,LF,' [G] - Wdproc & Printer ' DB CR,LF,' [H] - Pascal ' DB CR,LF,' [I] - Cstuf ' DB CR,LF,' [J] - Machine Specific ' DB CR,LF,' [K] - Business & Database ' DB CR,LF,' [L] - Msdos communication ' DB CR,LF,' [M] - Msdos Disk Utility ' DB CR,LF,' [N] - Msdos Utility ' DB CR,LF,' [O] - Msdos Game ' DB CR,LF,' [P] - Msdos Business ' DB CR,LF,' [Q] - Msdos O.S enhancement ' DB CR,LF,' [R] - Msdos Wdprocessing ' DB CR,LF,'$' ; GUIDE EQU 'S' ; Maximun category letter + 1 ;..... start: ld (stack),sp ld sp,stack ; call print db cr,lf,'RZMPLOG v',version / 10 + '0' db '.', version mod 10 + '0',cr,lf,0 call putud ; save current du: if not test ld c,32 ; is BYE running? ld e,241 call bdos cp 77 ; A has 77 if so jr z,byeok call print db 'BYE not running -- aborted.',cr,lf,0 jp quit endif ; not test byeok: ld a,(fcb1+2) ;save P for later use ld (pvtopt),a ld a,(fcb1+1) ; get direction cp 'R' ; must be R or S jr z,dirok cp 'S' jr z,dirok call print db 'Must use R or S.',cr,lf,0 jp quit dirok: ld (direct),a xor a ; use all of memory call ialloc jr nz,stkok jp stkok memerr: call print db 'Memory allocation error.',cr,lf,0 jp quit stkok: ld de,128 ; 128 bytes for inbuf call alloc jr z,memerr ld (inbuf),hl ld de,128 ; 128 for outbuf call alloc jr z,memerr ld (outbuf),hl ld de,128 call alloc jr z,memerr ld (lcbuf),hl ; 128 for lastcalr buffer ld de,24*128 ; 3k bytes for names buffer call alloc jr z,memerr ld (nambuf),hl ld de,128*128 ; 16k for disk buffer call alloc jr z,memerr ld (dbuf),hl if not test ld c,81 ; get mxtime ld e,255 call bdos push af ; save ld c,81 ; set to zero ld e,0 call bdos ld c,79 ; get rtcbuf address call bdos else ld hl,fakertc ; use fake data for test endif ; not test ld de,rtcbuf ; transfer it ld bc,13 ldir if not test pop af ; restore old mxtime LD e,a ld c,81 call bdos endif ld hl,lcname ; parse LASTCALR name ld de,lcfcb call fname jr nz,lcfok call print db 'Invalid LASTCALR filename.',cr,lf,0 jp quit lcfok: call newdu ; go to new du: ld hl,(lcbuf) ; set dma call setdma ld de,lcfcb ; try to open LASTCALR file call f$open or a jr nz,lcerr ; error call f$read ; read it or a jr nz,lcerr ; error ld hl,(lcbuf) ; Check the file ld b,128 ; max 128 bytes lcck1: ld a,(hl) ; ignore leading non-alpha call isalpha jr z,lcck2 inc hl djnz lcck1 jr lcerr ; error lcck2: ld (lcnam1),hl ; save address of first name inc hl lcck3: ld a,(hl) ; look for separator for second name call isalpha jr nz,lcck4 inc hl djnz lcck3 jr lcerr ; overrun lcck4: ld (hl),0 ; terminate inc hl ; point to second name ld (lcnam2),hl ; save it lcck5: ld a,(hl) ; look for end or a ; either zero, jr z,lcck6 cp cr ; or cr jr z,lcck6 cp lf ; or lf jr z,lcck6 cp ' ' ; or space jr z,lcck6 cp 01ah ; or 1a jr z,lcck6 inc hl djnz lcck5 lcck6: ld (hl),0 ; terminate jr lclrok ; ok lcerr: call print db 'LASTCALR file error.',cr,lf,0 jp quit lclrok: ld hl,dma ; reset dma call setdma ld hl,lognam ; parse filename ld de,outfcb call fname jr nz,fnok ; ok if nz call print db 'Invalid .LOG filename.',cr,lf,0 jp quit fnok: call newdu ; go to new du: ld hl,innam ; move input file name ld de,infcb+1 ; to its fcb ld bc,11 ldir ld de,infcb call initfcb ; initialise call f$open ; open it or a jr z,iook ; ok if Z call print db 'Input file not found.',cr,lf,0 jp quit iook: ld a,128 ; set input file counter ld (incnt),a ld de,outfcb ; is output file there? call f$exist jr nz,outex ; yes if nz call f$make ; else make it cp 0ffh ; ok? jr nz,makeok call print db 'Error in creating output file.',cr,lf,0 jp quit makeok: ld hl,(outbuf) ; set output pointer ld (outpnt),hl xor a ; and counter ld (outcnt),a jr outset outex: ld hl,(outbuf) ; set dma call setdma ld de,outfcb call f$appl ; open file for append jr z,oldok ; ok if zero cp 3 ; 3 means file empty jr z,makeok ; so same as new file call print db 'Error in opening output file.',cr,lf,0 jp quit oldok: ld a,01ah ; look for closing 1a ld hl,(outbuf) ld bc,128 cpir jp po,oldnf ; parity odd means not found dec hl ; found it, point to it ld (outpnt),hl ; use as pointer ld bc,(outbuf) ; calculate count or a sbc hl,bc ld a,l ld (outcnt),a jr outset oldnf: ld de,outfcb ; not found: must be full buffer call f$write ; so write it or a jp nz,wrerr ;At this point, the output counter and pointer are set. Now we read each ; line from the input file and construct an output line for it. outset: ld hl,(nambuf) LD (forpnt),HL call print db 'Logging ',0 ld a,(direct) ; print 'up' or 'down' cp 'R' jr nz,outs1 call print db 'up',0 jr outs2 outs1: call print db 'down',0 outs2: call print db 'loads to disk',0 ;Loop here for each file mloop: call readln ; read a line jr nz,linok ; ok if nz ld a,01ah ; else terminate in 1a call putbyt call flush ; write any output record ld de,outfcb ; close it call f$close IF NOT TEST ld de,infcb ; delete input file call f$delete ENDIF ld a,(direct) ; see if uploads cp 'R' jp nz,quit call getud ld a,(gotone) ; see if we got at least one or a jp z,quit jp ask ; got one, get description linok: ld hl,inline ; parse input line ld de,inftok ld a,0ffh ; null-terminate call argv ld a,(infnum) ; must have at least 3 cp 3 jr nc,rlinok call print db 'Error in input line format.',cr,lf,0 jp quit rlinok: ld a,1 ld (gotone),a ; show we have one ld a,'.' ; do a dot call cout ld a,(pvtopt) cp 'P' jr nz,rlin1 call putbyt ; put P into logfile instead of R or S jr z,rlin2 rlin1: ld a,(direct) ; send R or S call putbyt rlin2: ld a,(mspeed) ; modem speed add a,'0' ; in ascii call putbyt ld a,' ' ; space call putbyt ld ix,(inftim) ; look at transmission time ld a,(ix+1) ; if <10, cp ':' jr nz,sendtim ld a,'0' ; do leading zero call putbyt sendtim: ld hl,(inftim) ; rest of transmission time call putstr ld a,' ' ; space call putbyt ld hl,(inffil) ; get filename call capstr ; capitalised ld a,(hl) ; send drive call putbyt inc hl push hl pop ix ; user area < 10? ld a,(ix+1) cp ':' jr nz,sendfn ld a,'0' ; leading zero if so call putbyt sendfn: ld a,(hl) ; send next inc hl cp ':' ; done user area when : jr z,sfn1 call putbyt jr sendfn sfn1: ld a,':' call putbyt ld b,8 ; 8 chars in filename sfn2: ; tranfer filename ld a,(hl) inc hl or a ; done if zero jr z,sfn2a cp '.' ; or . jr z,sfn3 call putbyt call putfor ; djnz sfn2 ; do all 8 jr sfn4 sfn2a: ld a,1 ld (tmpflg),a sfn3: ld a,' ' ; pad with space call putbyt call putfor ; djnz sfn3 sfn4: ld a,(hl) ; skip dot cp '.' jr nz,sfn5 inc hl sfn5: ld b,3 ; 3 bytes more ld a,(tmpflg) or a jp nz,sfn7 sfn6: ld a,(hl) or a ; done if zero jr z,sfn7 cp ' ' jr z,sfn7 call putbyt call putfor ; inc hl djnz sfn6 jr sfn8 sfn7: ld a,' ' ; pad with spaces call putbyt call putfor djnz sfn7 sfn8: ld a,' ' ; 11 x space (no library files!) ld b,11 rlsplp: call putbyt djnz rlsplp xor a ld (tmpflg),a ld a,' ' call putfor ld hl,(infsiz) ; get filesize call eval10 ; convert to binary ex de,hl ld de,numbuf ; convert to ascii call mhldc xor a ; zero-terminate ld (de),a ld hl,numbuf ; and send to buffer call putstr ld hl,numbuf call forstr ; ld a,'K' ; use uppercase so we know its from rzmp call putbyt call putfor ; ld a,' ' call putbyt call putfor ; space over to date call putfor call putfor call putfor ld ix,rtcbuf ; now do date/time ld a,(dateusa) ; American date? or a jr nz,dusa ; yes if nz ld a,(ix+6) ; day call putbcd ld a,(ix+6) call forbcd ; ld a,'/' call putbyt call putfor ; ld a,(ix+5) ; month call putbcd ld a,(ix+5) call forbcd ; jr dyear dusa: ld a,(ix+5) ; month call putbcd ld a,(ix+5) call forbcd ; ld a,'/' call putbyt call putfor ; ld a,(ix+6) ; day call putbcd ld a,(ix+6) call forbcd ; dyear: ld a,'/' call putbyt call putfor ; ld a,(ix+4) ; year call putbcd ld a,(ix+4) call forbcd ; ld a,cr call putfor ld a,lf call putfor ; ld a,' ' call putbyt ld a,(ix) ; hours call putbcd ld a,':' call putbyt ld a,(ix+1) ; minutes call putbcd ld a,' ' call putbyt ld hl,(lcnam1) ; first name call capnam call putstr ld a,' ' call putbyt ld hl,(lcnam2) ; second name call capnam call putstr ld a,cr ; cr/lf call putbyt ld a,lf call putbyt LD A,(filcnt) INC A LD (filcnt),A jp mloop ; then read next line ;Come here when finished quit: ld hl,(stack) ld sp,hl call getud ; restore original du: jp 0 ; back to system: MUST do warm boot ;Read a line from the input file. Exit with Z set if eof. readln: ld b,40 ; max = 40 ld hl,inline ; set pointer rlnlp: call getbyt ; get a byte ret z ; eof encountered cp cr ; don't store cr jr z,rlnlp cp lf ; lf = end jr z,rln1 ld (hl),a ; else store it inc hl ; bump pointer djnz rlnlp ; loop till full rln1: ld (hl),0 ; zero terminate xor a ; ensure nz dec a ret ; done ;Get a byte from the input file. Read new record if necessary. Exit with ;Z set if eof getbyt: push de ; save de, hl push hl ld a,(incnt) ; need to read new record? cp 128 jr c,gb1 ld hl,(inbuf) ; yes, set dma call setdma ld de,infcb call f$read ; and read it or a ; ok if z jr nz,gbeof ; else eof ld (incnt),a ; clear count ld hl,(inbuf) ; set pointer ld (inpnt),hl gb1: inc a ; bump counter ld (incnt),a ld hl,(inpnt) ; get pointer ld a,(hl) ; get the byte inc hl ; bump pointer ld (inpnt),hl cp 01ah ; 1a = eof jr nz,gb2 gbeof: xor a ; eof, so set Z gb2: pop hl pop de ret ;Pretty up a name string in (hl) by capitalising the first character ;and setting the rest to lower case. capnam: push af push hl ld a,(hl) ; do first or a jr z,capnex ; quit if null call caps ; make it a capital ld (hl),a ; and store it capnlp: inc hl ld a,(hl) or a ; done when zero jr z,capnex cp 'A' ; A-Z --> a-z jr c,capnlp cp 'Z'+1 jr nc,capnlp or 20h ld (hl),a ; store it back jr capnlp capnex: pop hl pop af ret ;Write a string in (hl) to the output buffer. putstr: ld a,(hl) inc hl or a ret z ; done if zero call putbyt ; else send it jr putstr forstr: ld a,(hl) inc hl or a ret z call putfor jr forstr ;Convert a BCD value in A to 2-byte ASCII and store in the output buffer. putbcd: push af ; save it rra rra ; do hi nybble rra rra call pbcd1 pop af ; then low nybble pbcd1: and 0fh ; mask off add a,'0' ; add ascii part call putbyt ; and store ret forbcd: push af rra rra rra rra call pbcd2 pop af pbcd2: and 0Fh add A,'0' call putfor ret ;Write a byte to the output buffer. Write buffer to disk if necessary. putbyt: push af push hl ld hl,(outpnt) ; get pointer ld (hl),a ; store in buffer inc hl ; bump pointer ld (outpnt),hl ld a,(outcnt) ; and counter inc a ld (outcnt),a cp 128 ; flush if 128 bytes written call z,flush pop hl pop af ret putfor: push af push hl ld hl,(forpnt) ; get pointer ld (hl),a ; store in buffer inc hl ; bump pointer ld (forpnt),hl pop hl pop af ret ;Flush output buffer and reset pointers flush: push af push de push hl ; preserve all regs ld hl,(outbuf) call setdma ; set dma ld de,outfcb call f$write ; write it or a jr nz,wrerr ; error ld (outcnt),a ; clear counter ld hl,(outbuf) ; and set pointer ld (outpnt),hl pop hl pop de pop af ret wrerr: call print db 'Error in writing output file.',cr,lf,0 jp quit ;Log into du: in bc parsed by fname. Correct for unentered drive or user. newdu: push bc ; save parsed du: pop hl call retud ; and get current one ld a,l ; was user area specified? cp 0ffh jr z,nousr ld c,a ; yes, set it nousr: ld a,h ; was drive specified? cp 0ffh jr z,nodisk dec a ; yes, subtract 1 ld b,a ; and set it nodisk: call logud ; go to correct du: ret ;end of rzmplog ; ; FOR FILE ROUTINES ; ; ; Asks user to add description of an uploaded file ; ASK: LD A,(DESCRB) ;descriptions wanted? OR A RET Z LD A,(PVTOPT) ; Sending to "private area"? CP 'P' RET Z ; If yes, do not ask for description LD HL,(DBUF) ; LD (BCHADR),HL ;init buffer pointers LD (BUFADR),HL LD (OUTADR),HL LD HL,(NAMBUF) LD (NBSAVE),HL ; set counter to first filename CALL BCHDCR ; get the filname ; ASK1: if not ver4 CALL SHONM ; Show the file name CALL PRINT DEFB ' - this file is for:',13,10,0 LD C,9 ; Display the file descriptors LD DE,FILDES CALL 5 CALL PRINT DEFB 13,10,'Select a category: ',0 ASK1A: CALL INPUT ; Get a character CALL UCASE CP 'A' JP C,ASK1A CP GUIDE JP NC,ASK1A CALL TYPE LD (KIND),A endif ;not ver4 ; ASK2: CALL PRINT DEFB 13,10,13,10 DEFB 'Please describe this file in 7 lines or less. ' DEFB 13,10,13,10,0 ; ; ; Get the file name from FCB, skip any blanks ; LD HL,HLINE ; Store short line with dashes CALL DSTOR1 ; Store and show LD A,CR CALL OUTCHR LD A,LF CALL OUTCHR XOR A LD (LNCNTR),A LD B,8 ; Get FILENAME LD DE,NEWNAM ;source LD HL,OLINE ;destination CALL LOPFCB LD A,(DE) CP 32 ; Any file extent? JP Z,AFIND1 ; If not, skip the period and extent LD A,46 LD (HL),A ; Separate FILENAME and EXTENT CALL TYPE INC HL LD B,3 ; Get EXTENT name CALL LOPFCB if not ver4 AFIND1: LD A,(KIND) ; Get the answer else afind1: ld a,(4ah) ;passed category selection from userin. cp 'A' jp c,afinda ;make sure it's in range cp (guide) jp c,afind2 afinda: call print db 'No category selected',cr,lf,0 ret endif ;userin fildes and rzmplog fildes should match afind2: SUB 40H ; Convert to binary LD C,A ; Store for now LD DE,FILDES ; ALOOP: LD A,(DE) CP '$' JP Z,ASK1 CP 10 ; New line yet? INC DE JP NZ,ALOOP ; Look for a LF DEC C ; One less line to go JP NZ,ALOOP INC DE ; move past [A] in categories INC DE INC DE INC DE CALL DKIND ; move category in de to oline in hl ; CALL DSTOR ; copy oline to FOR buffer and show ; add B0: and size and date here ;at this point lncntr has number of characters at end of category. ;we will count from there and fill spaces up to 46 where DU: will be put ;in. ld a,(kmd) ;see if its kmd format or a jp nz,alignf ;yes, so skip du,size,date align: ld a,(lncntr) ;current position ld b,a ld a,46 ;location of DU: for UFOR style sub b ;b now has # of spaces to fill ld b,a align1: ld a,' ' call outchr ;not there yet so put in space call type djnz align1 ;new routines for RZMPLOG4 ld hl,(inffil) ; get filename call capstr ; capitalised ld a,(hl) ; send drive call outchr inc hl push hl pop ix ; user area < 10? sndfn: ld a,(hl) ; send next inc hl cp ':' ; done user area when : jr z,sn1 call outchr jr sndfn sn1: ld a,':' call outchr ;------- ld a,' ' call outchr call outchr ld hl,newnam ;put file size and date ld de,12 ;add offset add hl,de call dstor1 alignf: ld a,cr ;end of line call outchr call type ld a,lf call outchr call type CALL print DEFB 13,10,'0: ---------1---------2---------3' DEFB '---------4---------5---------6---------',13,10,0 XOR A LD (ANYET),A ; Reset the flag for no information yet LD C,48 EXPLN: INC C LD A,C CP 56 JP NC,EXPL1 CALL TYPE LD A,32 CALL OUTCHR CALL OUTCHR CALL OUTCHR CALL print DEFB ': ',0 CALL DESC ; Get a line of information CALL DSTOR ; LD A,CR CALL OUTCHR LD A,LF CALL OUTCHR JP EXPLN ; EXPL1: LD A,13 ; All finished, put in an extra CR-LF CALL OUTCHR LD A,10 CALL OUTCHR XOR A CALL OUTCHR CALL print DEFB 13,10,' Repeating to verify:',13,10,13,10,0 LD HL,(BUFADR) ; Get starting address of description ; EXPL1A: LD A,(HL) ; Get the character OR A ; Is it a '0' to terminate? JP Z,EXPL1B ; If yes, exit CALL TYPE ; Show character on CRT, send to modem INC HL ; Next location JP EXPL1A ; Go do next charcter ; EXPL1B: LD HL,(OUTPTR) DEC HL ; Skip the '0' LD (OUTPTR),HL ; Store address at end of this entry ; EXPL2: CALL print DEFB 13,'Is this ok (Y/N)? ',0 CALL INPUT AND 5FH ; Change to upper case CP 'Y' JP Z,EXPL4 ; Exit if this description was ok CP 'N' JP NZ,EXPL2 CALL TYPE ; EXPL3: LD HL,(BCHPTR) ; Else restart at beginning of text LD (OUTPTR),HL ; Start over at this address JP ASK2 ; Go do this one again ;... ; ; ; See if any more batch files need descriptions ; EXPL4: CALL TYPE LD A,(FILCNT) ; Any more file names left in buffer? OR A JP Z,EXPL5 ; If not, all finished LD HL,(BCHADR) ; Get the current output address LD (BUFADR),HL ; Store for next verify LD HL,(OUTPTR) ; Get end of current description LD (BCHPTR),HL ; Store for start of next one JP ASK1-3 ; Get the next file description ; ; ; Now open the file and put this at the beginning ; EXPL5: LD A,(0004H) ; Get current drive/user LD (DRUSER),A ; Store ; ; ; Set drive/user to the area listed above ; LD A,(USER) ; Get requested user number LD C,32 LD E,A ; Put user number into 'E' register CALL 5 LD A,(DRIVE) ; Get requested drive SUB 65 LD C,14 LD E,A CALL 5 ; ; ; Open source file ; CALL PRINT DEFB 13,10,0 LD C,15 LD DE,FILE ; Open FOR text file CALL 5 INC A ; Check for no open JP NZ,OFILE ; File exists, exit LD C,22 ; None exists, make a new file LD DE,FILE CALL 5 INC A JP Z,NOROOM ; Exit if cannot open new file ; OFILE: LD HL,FILE ; Otherwise use same filename LD DE,DEST ; With .$$$ extent for now LD B,9 CALL MOVE ; ; ; Open the destination file ; XOR A LD (DEST+12),A LD (DEST+32),A LD HL,16*1024 ; Size of output buffer LD (OUTSIZ),HL ; Set for comparison LD C,19 ; Delete any existing file that name LD DE,DEST CALL 5 LD C,22 ; Now make a new file that name LD DE,DEST CALL 5 ; INC A JP Z,NOROOM ; Cannot open file, no directory room CALL print DEFB 13,10,'wait a moment...',0 ; ; ; Read sector from source file ; READLP: LD C,26 LD DE,DMA CALL 5 LD C,20 LD DE,FILE ; Read from FOR text file CALL 5 OR A ; Read ok? JP NZ,RERROR LD HL,DMA ; Read buffer address ; ; ; Write sector to output file (with buffering) ; WRDLOP: LD A,(HL) ; Get byte from read buffer AND 127 ; Strip parity bit CP 127 ; Del (rubout)? JP Z,NEXT ; Yes, ignore it CP 26 ; End of file marker? JP Z,TDONE ; Transfer done, close, exit CALL OUTCHR ; NEXT: INC L ; Done with sector? JP Z,READLP ; If yes get another sector JP WRDLOP ; No, get another byte ;..... ; ; ; Handle a backspace character while entering a character string ; BCKSP: CALL TYPE LD A,B ; Get position on line OR A JP NZ,BCKSP1 ; Exit if at initial column LD A,' ' ; Delete the character JP BCKSP3 ; BCKSP1: DEC B ; Show one less column used DEC HL ; Decrease buffer location LD A,' ' LD (HL),A ; Clear memory at this point CALL TYPE ; Backspace the "CRT" ; BCKSP2: LD A,8 ; Reset the "CRT" again ; BCKSP3: JP TYPE ; Write to the "CRT", done ;..... ; ; ; Asks for line of information ; DESC: XOR A LD (FIRST),A LD B,A LD HL,OLINE ; DESC1: CALL INPUT ; Get keyboard character CP CR JP Z,DESC5 CP 9 JP Z,DESC7 CP 8 ; Backspace character? JP Z,DESC2 CP 127 ; Delete character? JP NZ,DESC3 ; DESC2: CALL BCKSP JP DESC1 ; Get the next character ; DESC3: CP ' ' ; Space character? JP C,DESC1 ; If non-printing character, ignore JP NZ,DESC4 LD A,(FIRST) ; Any non-space characters yet? OR A JP Z,DESC1 ; If not, ignore this space LD A,' ' ; Restore the value ; DESC4: LD (ANYET),A ; Show a character has been sent now LD (FIRST),A LD (HL),A CALL TYPE ; Display the character INC HL INC B LD A,B CP 70 ; Do not exceed line length JP C,DESC1 CALL BCKSP2 CALL BCKSP1 ; Do not allow a too-long line JP DESC1 ; DESC5: LD A,(ANYET) ; Any text typed on first line yet? OR A JP NZ,DESC6 ; If yes, exit POP HL JP EXPL3 ; Ask again for a description ; DESC6: LD (HL),CR LD A,(HL) CALL TYPE INC HL ; Ready for next character LD (HL),LF LD A,(HL) CALL TYPE ; Display the line feed INC HL LD A,B ; See if at first of line OR A RET NZ ; If not, ask for next line POP HL ; Clear "CALL" from stack JP EXPL1 ; DESC7: LD A,B ; At end of line now? CP 68 JP NC,DESC1 ; If yes, disregard LD (HL),32 LD A,(HL) CALL TYPE INC HL INC B LD A,B AND 7 JP NZ,DESC7 JP DESC1 ; Ask for next character ;..... ; ; ; Print message then exit to CP/M ; DEXIT: LD C,9 ; Print message POP DE ; Get message address CALL 5 JP RESET ; Reset the drive/user, then finished ;..... ; DKIND: LD A,(DE) ; Get the character from the string CALL TYPE ; Otherwise display the character LD (HL),A ; Put in the buffer CP LF RET Z INC DE ; Next position in the string INC HL ; Next postion in the buffer JP DKIND ; Keep going until a LF ;..... ; ; DSTOR: LD HL,OLINE ; DSTOR1: LD A,(HL) CP CR RET Z CALL OUTCHR INC HL LD A,(LNCNTR) ;bump position counter INC A LD (LNCNTR),A JP DSTOR1 ;..... UCASE: CP 97 RET C CP 123 RET NC AND 95 RET ; ; ; Disk is full, save original file, erase others. ; FULL: LD C,19 LD DE,DEST CALL 5 CALL DEXIT DEFB 13,10,'++ DISK FULL, ABORTING, SAVING ORIGINAL FILE','$' ;..... ; ; ; Get a character, if none ready wait up to 3 minutes, then exit from ; the program. ; INPUT: PUSH HL ; Save current values PUSH DE PUSH BC LD A,3 ; Wait up to 3 minutes ADD A,A ; Double the number, bell each 30 sec. LD H,A ; Put in 'H' for 1/2 minute loops ; INPUT1: LD DE,300 ; Outer loop count 600 loops per min. INPUT2: LD A,(MHZ) ; Get the clock speed LD L,A ; Put in 'L' for 'clock loops' ; INPUT3: ; INPUT4: PUSH HL PUSH DE ; Save the outer delay count PUSH BC ; Save the inner delay count LD C,6 ; Get console character, if any LD E,255 CALL 5 AND 127 ; Remove any parity POP BC ; Restore the inner delay count POP DE ; Restore the outer delay count POP HL ; Restore the Number of minutes count OR A ; Have a character yet? JP NZ,INPUT5 ; If yes, exit and get it ; DEC BC LD A,C ; See if inner loop is finished OR B JP NZ,INPUT4 ; If not loop again ; DEC L ; One less clock loop to go JP NZ,INPUT3 ; DEC DE LD A,E OR D JP NZ,INPUT2 ; If not reset inner loop and go again ; ; ; No character received, ding the bell each 1/2 minute ; PUSH HL call print db 7,0 POP HL DEC H JP NZ,INPUT1 ; ; ; Out of time, no character so abort ; LD A,13 CALL OUTCHR LD A,10 CALL OUTCHR LD SP,STACK ; Restore the stack CALL EXPL5 ; Finish appending previous information JP EXIT ; File is closed, return to CP/M ; INPUT5: POP BC POP DE POP HL RET ; Got a character, return with it ;..... ; ; ; Stores the Filename/extent in the buffer temporarily ; LOPFCB: LD A,(DE) ; Get FCB FILENAME/EXT character CP 33 ; Skip any blanks JP C,LOPF1 LD (HL),A ; Store in OLINE area CALL TYPE ; Display on CRT INC HL ; Next OLINE position ; LOPF1: INC DE ; Next FCB position DEC B ; One less to go JP NZ,LOPFCB ; If not done, get next one RET ;..... ; ; BCHDCR: LD A,(FILCNT) DEC A LD (FILCNT),A BCHD1: LD HL,(NBSAVE) ; Get address of next batch filename LD DE,NEWNAM ; Where to put it LD B,32 CALL MOVE LD (NBSAVE),HL ; Store address for next filename RET ; ;-------------------------- DONE: ; Finished, clean up and return to CP/M EXIT: ; ; Restore original drive/user area ; EXIT2: LD HL,DMA CALL SETDMA ; EXIT3: XOR A ; Clear the register and carry bit LD HL,(STACK) ; Get original return adress back LD SP,HL ; Put on the stack pointer jp 0 ; ;..... ; MOVE: LD A,(HL) ; Get a byte LD (DE),A ; Put at new home INC DE ; Bump pointers INC HL DEC B ; Decrement byte count JP NZ,MOVE ; If more, do it RET ; If not, return ;..... ; ; ; No room to open a new file ; NOROOM: CALL DEXIT DEFB 13,10,'NO DIR SPACE: OUTPUT','$' ;..... ; ; ; Output error - cannot close destination file ; OERROR: CALL DEXIT DEFB 13,10,'CANNOT CLOSE OUTPUT','$' ;..... ; ; ; See if there is room in the buffer for this character ; OUTCHR: PUSH HL PUSH AF ; Store the character for now LD HL,(OUTSIZ) ; Get buffer size EX DE,HL ; Put in 'DE' LD HL,(OUTPTR) ; Now get the buffer pointers LD A,L ; Check to see if room in buffer SUB E LD A,H SBC A,D JP C,OUT3 ; If room, go store the character LD HL,0 ; Otherwise reset the pointers LD (OUTPTR),HL ; Store the new pointer address ; OUT1: EX DE,HL ; Put pointer address into 'DE' LD HL,(OUTSIZ) ; Get the buffer size into 'HL' LD A,E ; See if buffer is max. length yet SUB L ; By subtracting 'HL' from 'DE' LD A,D SBC A,H JP NC,OUT2 ; If less, exit and keep going ; ; ; No more room in buffer, stop and transfer to destination file ; LD HL,(OUTADR) ; Get the buffer address ADD HL,DE ; Add pointer value ; EX DE,HL ; Put into 'DE' CALL SETDMA LD C,21 EX DE,HL ;kr LD DE,DEST CALL 5 OR A JP NZ,FULL ; Exit with error, if disk is full now LD DE,128 LD HL,(OUTPTR) ADD HL,DE LD (OUTPTR),HL JP OUT1 ; OUT2: LD HL,DMA CALL SETDMA LD HL,0 LD (OUTPTR),HL ; OUT3: EX DE,HL LD HL,(OUTADR) ADD HL,DE EX DE,HL POP AF ; Get the character back LD (DE),A ; Store the character EX DE,HL LD (BCHADR),HL LD HL,(OUTPTR) ; Get the buffer pointer INC HL ; Increment them LD (OUTPTR),HL ; Store the new pointer address POP HL RET ;..... ; ; RERROR: CP 1 ; File finished? JP Z,TDONE ; Exit, then LD C,19 ; Erase destination file, keep original LD DE,DEST CALL 5 CALL DEXIT DEFB '++ SOURCE FILE READ ERROR ++$' ;..... ; ; ; Reset the Drive/User to original ; RESET: LD A,(DRUSER) ; Get original drive/user area back RRA RRA RRA RRA AND 15 ; Just look at the user area LD C,32 LD E,A CALL 5 LD A,(DRUSER) ; Get the original drive/user back AND 15 ; Just look at the drive for now LD C,14 ; Restore original drive LD E,A CALL 5 CALL PRINT ; Print CRLF before quitting DEFB 13,10,0 JP EXIT ;..... ; ; ; Shows the Filename/extent ; SHONM: CALL print DEFB 13,10,13,10,0 LD HL,NEWNAM ; SHONM1: LD B,8 ; Maximum size of file name CALL SHONM2 LD A,(HL) ; Get the next character CP 32 ; Any file extent? RET Z ; If not, finished LD A,46 CALL CTYPE LD B,3 ; Maximum size of file extent ; SHONM2: LD A,(HL) ; Get FCB FILENAME/EXT character CP 32 ; Skip any blanks CALL NZ,CTYPE INC HL ; Next FCB position DEC B ; One less to go JP NZ,SHONM2 ; If not done, get next one RET ;..... ; ; ; Transfer is done - close destination file ; TDONE: LD HL,(OUTPTR) LD A,L AND 127 JP NZ,TDONE1 LD (OUTSIZ),HL ; TDONE1: LD A,26 ; Fill remainder of record with ^Z's PUSH AF CALL OUTCHR POP AF JP NZ,TDONE LD C,16 ; Close FOR text file LD DE,FILE CALL 5 LD C,16 ; Close FOR.$$$ text file LD DE,DEST CALL 5 INC A JP Z,OERROR ; ; ; Rename both files as no destination file name was specified ; LD HL,FILE+1 ; Prepare to rename old file to new LD DE,DEST+17 LD B,16 CALL MOVE LD C,19 ; Delete original FOR text file LD DE,FILE CALL 5 LD C,23 LD DE,DEST ; Rename FOR.$$$ to FOR text file CALL 5 JP RESET ; Reset the drive/user, finished ;..... ; ; ; Send character in 'A' register to console ; TYPE: PUSH BC PUSH DE PUSH HL PUSH AF LD C,2 ; Write to console LD E,A ; Character to 'E' for CP/M CALL 5 POP AF POP HL POP DE POP BC RET ;..... ; ; end of file description area ;----------------------------------------------------------------------- ; ; CTYPE: PUSH BC ; Save all registers PUSH DE PUSH HL LD E,A ; Character to 'E' in case BDOS (normal) LD C,2 ; BDOS console output, to CRT and modem CALL 5 ; Since 'BYE' intercepts the char. POP HL ; Restore all registers POP DE POP BC RET ;..... ; ; Restore the old user area and drive from a received file ; RECARE: LD E,A ; Stuff it in E LD C,32 ; Tell BDOS what we want to do JP 5 ; Now do it ;..... ;data innam: db 'RZMP OUT' ; input filename ; Fake strings for test mode if test fakertc: db 20h,20h,34h,19h,89h,06h,07h,02h,00h,14h,14h,14h,12h endif ; test ;Token pointer table for input line inftok: db 3 ; 3 tokens infnum: ds 1 ; # found by argv inftim: ds 2 ; pointer to transmission time inffil: ds 2 ; pointer to filename infsiz: ds 2 ; pointer to filesize direct: ds 1 ; 'R' or 'S' inbuf: ds 2 ; pointer to input buffer outbuf: ds 2 ; pointer to output buffer lcbuf: ds 2 ; pointer to LASTCALR buffer lcnam1: ds 2 ; address of first name in LASTCALR lcnam2: ds 2 ; address of second name in LASTCALR incnt: ds 1 ; input file counter inpnt: ds 2 ; input file pointer outcnt: ds 1 ; output file counter outpnt: ds 2 ; output file pointer numbuf: ds 6 ; number conversion buffer outfcb: ds 36 ; FCB for .LOG file infcb: ds 36 ; FCB for input file lcfcb: ds 36 ; FCB for LASTCALR file inline: ds 41 ; input line from file rtcbuf: ds 15 ; RTC buffer from BYE lncntr: ds 1 ; count postion in FOR header line tmpflg: ds 1 ; flag to indicate no file extent pvtopt: ds 1 ; is it a private upload gotone: ds 1 ; show we have at least one upload ; FILE: DEFB 0,'FOR ',0,0,0,0,0,0,0 DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0 DEST: DEFB 0,' $$$',0,0,0,0,0,0,0 DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; FORPNT: DS 2 NEWNAM: ds 80 ; ; Batch stuff ; BCHADR: DEFW 0 ; For multiple descriptions BCHPTR: DEFW 0 BUFADR: DEFW 0 ; For multiple file display ; ; FILCNT: DEFB 0 ; # of files in batch mode NBSAVE: DS 2 ; Start address in NAMBUF for next file ; ANYET: DEFB 0 ; Any description typed yet? DRUSER: DEFB 0 ; Original drive/user, for return FIRST: DEFB 0 ; Used in file description KIND: DEFB 0 ; Asks what kind of file this is OLDDRV: DEFB 0 ; Save the original drive number OLDUSR: DEFB 0 ; Save the original user number OUTADR: DW 0 OUTPTR: DEFW 0 OUTSIZ: DEFW 16*1024 ;kr was 16 Size of buffer (use caution) ; ; HLINE: DEFB '----',13,10 OLINE: DEFS 80 ; Temporary buffer to store line DEFS 100 ; Area for stack STACK: DW 0 NAMBUF: ds 2 ; Allow room for 256 batch filenames DBUF: ds 2 ; 16k disk buffer ; ; END ;