; CHARIO.MAC - 1/17/87 - Character I/O .z80 maclib TNC.LIB entry addcr0,mcmt,getdat,getwt,cmd,cmdlen,cmdtyp entry const,conin,conot entry blink,dtime,itime,@inch,@outch,@prtx entry conmod,dis,gotreq,gotcon,gotlnk,lnkst,discon,prtcmd entry erdone,mdone,erfind,mfind,erprot,mprot entry ercant,mcant,ername,mname,ertime,mtime entry erexst,mexst,erwhat,mwhat entry eofs,leofs,@outn,@outnb,pgst,pghd,pgck,pgdn entry lm3,waitc,pause,cmdtnc,@docmd,wtcmd,tnca,tncb external short,mode,prtpar,btchm,uccnt,ucalls external mcall,scall,ocall,rcall,mtnc,stnc external mhnr,mhdate,mhtime,mhto,mhfrom,mhbbs external bindec,numb,@cmp,@cmpcmd,movcal,@cmp,@wait external date,time,mnr,mcnt,usname,usdate,ustime,usmnr external ncerrs asciictl tncdefs timdef outn macro adr,ct if not nul adr ld hl,adr endif if not nul ct ld b,ct endif call @outn endm outnb macro adr,ct if not nul adr ld hl,adr endif if not nul ct ld b,ct endif call @outnb endm ; BIOS linker. cseg blink: ld hl,(1) inc hl inc hl inc hl ld de,const ld bc,9 ldir ret ; Copy of the BIOS console jumps. dseg const: jp $-$ conin: jp $-$ conot: jp $-$ ; Error/status messages. mdone: ds 2 mfind: ds 2 mprot: ds 2 mcant: ds 2 mname: ds 2 mtime: ds 2 mexst: ds 2 mwhat: ds 2 cseg erdone: prtx mdone jr waitc erfind: prtx mfind jr waitc erprot: prtx mprot jr waitc ercant: prtx mcant jr waitce ername: prtx mname jr waitc ertime: prtx mtime jr waitc erexst: prtx mexst jr waitc erwhat: prtx mwhat jr waitce addcr0: ld (hl),cr inc hl ld (hl),0 ret ; Make TNC on PRINTER port master. tnca: ld a,rbiob ld (stnc),a ld a,raiob ld (mtnc),a ld (iobyte),a ret ; Make TNC on PRINTER port master. tncb: ld a,raiob ld (stnc),a ld a,rbiob ld (mtnc),a ld (iobyte),a ret ; If local user, do xon/xoff pause. ; If local user and long menu, wait for keypress. dseg lm3: ds 2 cseg waitce: ld hl, ncerrs inc (hl) ; Count command errors waitc: cmpm mode,lmode ret nz ; Not local, no wait cmpm short,true ret z ; Short local menu, no wait prtx lm3 jp @inch pause: cmpm iobyte,ciob ret nz call const ret z call @inch ld a,c cp dc3 ret nz call @inch ret ; Screen paging routines. dseg lnmax: ds 1 lncnt: ds 1 pghdr: ds 2 cseg pgst: ld (pghdr),hl ; Save address of header ld a,l or h ; Is a header? ld a,23 ; Page with no header jr z,pgsta ; No ld a,22 ; One less line pgsta: ld (lnmax),a ; Save max ld (lncnt),a ; Init count ret pghd: ld hl,lncnt ; Line we on ld a,(lnmax) ; Lines on screen cp (hl) ; At top? ret nz ; No dtz pghdr ; Is a header? ret z ; No jp @prtx ; Print header pgck: ld hl,lncnt ; Point to line count dec (hl) ; Count line ret nz ; More lines ld a,(lnmax) ld (hl),a ; Reset counter jr pgpaus ; Pause pgdn: ld a,(lncnt) ; Current line ld hl,lnmax ; Lines on screen cp (hl) ; We paused already? ret z ; Yes pgpaus: cmpm iobyte,ciob ; Local user? ret nz ; No prtx lm3 ; Print "Any key to continue" call @inch ; Wait for keypress push bc ; Save response ld c,cr ; Give a CR call @outch pop bc retz ; Zero set, got char ; Print the command line. prtcmd: ld a,(cmdlen) or a jr z,prcme ld b,a ld hl,cmd prcma: ld c,(hl) call @outch inc hl dec b jr nz,prcma prcme: ld c,cr call @outch ret ; Output (B) charcters at (HL). @outn: ld c,(hl) call @outch inc hl dec b jr nz,@outn ret ; Output (B) characters at (HL), except blanks. @outnb: ld a,(hl) cp ' ' jr z,outnba ld c,a call @outch outnba: inc hl dec b jr nz,@outnb ret ; Do a command or string of commands at (HL). dseg docmdc: ds 2 cseg @docmd: ld (docmdc),hl xor a ; Get a zero cp (hl) ; Zero in string? ret z ; Yes, all done ld a,cr ; Get a CR docmda: cp (hl) ; One in string? inc hl ; Point to next char jr nz,docmda ; Not CR, keep looking ld c,(hl) ; Save char after CR ld (hl),0 ; Put 0 after CR push hl ; Save pointer into string push bc ; Save char after CR ld hl,(docmdc) ; Point to start of command call @prtx ; Send it to tnc call wtcmd ; Wait for cmd: from tnc pop bc ; Get char after CR back pop hl ; Get string pointer back ld (hl),c ; Put char after CR back jr @docmd ; Do next command wccmd: db 'cmd:' ; Get TNC to command state. cmdtnc: ld c,etx call @outch ; Wait for TNC to respond to a command. ; Return in A: 0=ok, 1=timeout, 2=command no good. wtcmd: lxim timer,3 ; 3 second wait. ld b,0 ; Assume good status wca: ld de,wccmd wcb: dtz timer jr z,wcd ; TNC did not respond. call const jr z,wcb call @inch ld a,(de) cp c jr nz,wcc ; Looking for cmd: cp ':' jr z,wce inc de jr wcb wcc: ld a,c cp '?' jr nz,wca ld b,2 ; Got EH? jr wca ; Now look for "cmd:" wcd: ld b,1 ; Timeout wce: ld a,b ; Return status in A or a ; Set flags ret ; Character input. ; Character from current console device returned in C. ; Echoed to local console if from a tnc. @inch: push hl call conin pop hl ld c,a ld a,(iobyte) cp ciob ; Console? ret z ; Yes, no echo jr echo ; Character output. ; Character in C output to current console device. ; Echoed to the local console if current device is a tnc. ; Assumes all registers preserved except PSW dseg ctnc: ds 1 cseg @outch: cmpm iobyte,ciob jr z,@co call conot echo: ld a,c cp ff ret z ; No clear screen from tnc movb ctnc,iobyte mvim iobyte,ciob call @co movb iobyte,ctnc ret ; Output (C) to local console. @co: ld a,c cp lf ret z ; Ignore LF, is added after CR. call conot ld a,c cp cr ret nz ld c,lf call conot ld c,cr ret ; Print a string. Expand "variable text" fields. dseg pxpt: ds 2 pxst: ds 2 cseg pxtbl: dw pxa,pxb,pxc,pxd,pxe,pxf,pxg,pxh,pxi,pxj,pxk,pxl,pxm dw pxn,pxo,pxp,pxq,pxr,pxs,pxt,pxu,pxv,pxw,pxx,pxy,pxz @prtx: ld (pxst),hl prtxa: ld (pxpt),hl ld a,(hl) or a ret z ; NUL ends string cp '$' ; Is it a $ ? jr nz,pxok ; No, print it inc hl ; Yes, point to char after $ ld a,(hl) ; Get char after $ cp 'A' jr c,px1 ; Not within A-Z, print $ and char cp 'Z'+1 jr nc,px1 ; Not within A-Z, print $ and char sub 'A' ; To make index into table ld l,a ld h,0 add hl,hl ; Double it, table is word items ld de,pxtbl ; Point to start of table add hl,de ; Add twice index to get to item ld e,(hl) ; Low byte of sub addr inc hl ld d,(hl) ; Hi byte of sub addr ex de,hl jp (hl) ; Go do it px1: ld a,'$' ; Print the $ pxok: ld c,a call @outch ld hl,(pxpt) inc hl jr prtxa pxa: outnb mhbbs,6 jp pxnxt ; Insert bell pxb: ld c,bell call @outch jp pxnxt pxc: ld hl,(mnr) jp pxnum pxd: outn date,6 jp pxnxt ; Insert calls with unread mail pxe: ld hl,(pxpt) ld de,(pxst) or a ; Clear carry sbc hl,de ld a,btchm sub l ld e,a ; Max chars to print ld hl,uccnt ld d,(hl) ld hl,(ucalls) pxeg: ld a,(hl) and 80h ; Is call a bbs? jr nz,pxej ; Yes, dont put in beacon ld b,6 push hl pxeh: ld a,(hl) cp ' ' jr z,pxei ld c,a call @outch inc hl dec e dec b jr nz,pxeh pxei: pop hl dec e ld a,e sub 8 jp c,pxnxt ; No more room ld c,' ' call @outch pxej: push de ld de,6 add hl,de pop de dec d ; Any more calls in list? jr nz,pxeg ; Yes jp pxnxt ; Insert form feed pxf: ld c,ff call @outch jp pxnxt pxg: outnb mhto,6 jp pxnxt ; Pass (ignore) the cr pxh: inxm pxpt jp pxnxt pxi: outnb usname,12 jp pxnxt pxj: outn mhdate,6 jp pxnxt pxk: outn mhtime,4 jr pxnxt pxl: ld hl,(mnr) dec hl jr pxnum pxm: ld hl,(mhnr) jr pxnum pxn: ld hl,(mcnt) jr pxnum pxo: outnb ocall,6 jr pxnxt pxp: outnb mhfrom,6 jr pxnxt pxr: outnb rcall,6 jr pxnxt pxs: outnb scall,6 jr pxnxt pxt: outn time,4 jr pxnxt pxu: outnb mcall,6 jr pxnxt ; Print changable param values. pxv: call prtpar jr pxnxt ; Insert syn pxw: ld c,syn call @outch jr pxnxt pxx: outn usdate,6 jr pxnxt pxy: outn ustime,4 jr pxnxt pxz: ld hl,(usmnr) ; Print the number in (HL) pxnum: call bindec ; Print the previously converted number. pxq: outnb numb,5 ; Move on to the next character pxnxt: ld hl,(pxpt) inc hl inc hl jp prtxa ; Get a line from the console. dseg dtime: ds 2 ; Wait time for disconnect itime: ds 2 ; Timeout waiting for CR otimer: ds 2 ; Save / restore timer value gotreq: ds 1 ; True if got connect request cmdlen: ds 1 ; # chars in buffer cmd: ds cmdmax cmdtyp: ds 1 cseg eofs: db '*** EOF' leofs equ $-eofs conv: db 'CONV',cr,0 cst: db 'C',cr,0 cd: db 'D',cr,0 concmd: db '*** CONNECTED to ' lconcmd equ $-concmd discmd: db '*** DISCONNECTED' ldiscmd equ $-discmd reqcmd: db '*** connect request:' lreqcmd equ $-reqcmd lnkcmd: db '*** LINKED to ' llnkcmd equ $-lnkcmd stat: isdis: db 'Link state is:' lstat equ $-stat db ' DISCONNECTED' lisdis equ $-isdis discon: cmpcmd isdis,lisdis ret ; Get tnc to converse mode conmod: ld hl,conv call @prtx wait convtim ret ; Find out the link state. lnkst: ld hl,cst call @prtx ; Send "C" to tnc lnksta: mvim getwt,false ; Don't wait after con req call getdat ckcmd lnksta,lnkstc,lnkstb cmpcmd stat,lstat jr nz,lnksta lnkstb: call wtcmd ; Eat the cmd: after the C ret lnkstc: call wtcmd ; Eat the cmd: after the discon jr lnksta ; Return zero set if cmd contains a connect. gotcon: cmpcmd concmd,lconcmd ret nz ld c,lconcmd jr mcmt ; Return zero set if cmd contains a link. gotlnk: cmpcmd lnkcmd,llnkcmd ret nz ld c,llnkcmd jr mcmt ; Disconnect dis: call cmdtnc ; Make sure tnc in command mode call lnkst ; Get link state call discon ; We connected? ret z ; No disa: ld hl,cd call @docmd ; Do the disconnect movw timer,dtime ; Start timer disb: call const ; Char from TNC? jr nz,disc ; Yes dtz timer ; No, timed out? jr z,dis ; Yes, disconnect RIGHT NOW jr disb ; Wait some more disc: mvim getwt,false ; No wait if con req call getdat ; Get line from TNC ckcmd disb,disd,disa jr disb ; Not disconnected yet disd: call wtcmd ; Disconnected. ret ; Move command tail to front of cmd buffer. ; (C) = first char in tail. mcmt: ld b,0 ld hl,cmd add hl,bc ld a,(cmdlen) sub c ld (cmdlen),a ret z ; No call... ld c,a ld de,cmd ldir xor a ret ; With zero set dseg getwt: ds 1 cseg getdat: movw otimer,timer ; Save countdown timer movw timer,itime mvim cmdtyp,cdata gtdta: xor a ld (cmdlen),a ld b,cmdmax ld de,cmd gtdtb: call const jr nz,gtdtc cmpm iobyte,ciob jr z,gtdtc dtz timer jr nz,gtdtb mvim cmdtyp,ctimcmd jp gtdtz gtdtc: call @inch ld a,c cp del jr z,gtdtbs ; Treat DEL like BS cp ' ' jr nc,gtdte ; Not CTL char cp cr jr z,gtdtcr cp lf jr z,gtdtlf cp bs jr z,gtdtbs cp ff jr z,gtdte cp bell jr z,gtdte cp tab jr z,gtdte cp eof ; ^Z jr z,gtdte cp linkcmd ; ^W jr z,gtdte jr gtdtb ; Ignore control char ; Char is line feed. gtdtlf: ld a,(cmdlen) or a ld a,c jr nz,gtdtb ; LF in middle of line, ignore jr gtdty ; Initial LF, treat as no data rcvd ; Char is backspace. gtdtbs: ld hl,cmdlen ld a,(hl) or a jr z,gtdtb ; Don't backspace beyond start of line dec (hl) ; One less char in buffer inc b ; Room for one more char in buffer dec de ; Move buffer pointer back cmpm iobyte,ciob ; Local console typing? jr nz,gtdtb ; No, get next char call @outch ; Echo BS SP BS ld c,' ' call @outch ld c,bs call @outch jp gtdtb ; Char is ok, put in buffer gtdte: ld (de),a ; Stick char in buffer inc de ; Point to next buffer location ld hl,cmdlen inc (hl) ; Count the char cmpm iobyte,ciob ; Local console typing? call z,@outch ; Echo char to local console dec b ; Count the room in buffer jp nz,gtdtb ; Room for more char, get one jr xx ; Ran out of buffer ; Got CR, echo it if local console. gtdtcr: cmpm iobyte,ciob call z,@outch ; Is it *** DISCONNECTED? xx: cmpcmd discmd,ldiscmd jr nz,gtdtg mvim cmdtyp,cdiscmd jr gtdtz ; Is it *** connect request ? gtdtg: cmpcmd reqcmd,lreqcmd jr nz,gtdtz ld de,rcall ld hl,cmd+lreqcmd ld a,(cmdlen) sub lreqcmd call movcal ; Save call on con req mvim gotreq,true cmpm getwt,true jp z,gtdta gtdty: mvim cmdtyp,cnull gtdtz: movw timer,otimer ; Restore timer count mvim getwt,true ld a,(cmdtyp) ret end