$title ('PUTF - CP/M 3.0 Output Redirection - August 1982') ;****************************************************************** ; ; PUT 'Redirection Initializer' version 3.0 ; ; 11/30/82 - Doug Huskey ;****************************************************************** ; ; ; Copyright (c) 1982 ; Digital Research ; P.O. Box 579 ; Pacific Grove, Ca. ; 93950 ; ; ; generation procedure ; ; seteof put.plm ; seteof getscan.dcl ; seteof putf.asm ; seteof getscan.plm ; seteof parse.asm ; is14 ; asm80 putf.asm debug ; asm80 mcd80a.asm debug ; asm80 parse.asm debug ; plm80 put.plm pagewidth(100) debug optimize ; link mcd80a.obj,put.obj,parse.obj,putf.obj,plm80.lib to put.mod ; locate put.mod code(0100H) stacksize(100) ; era put.mod ; cpm ; objcpm put ; rmac putrsx ; link putrsx[op] ; era put.rsx ; ren put.rsx=putrsx.prl ; gencom put.com ; gencom put.com put.rsx ; ; ; This module is called as an external routine by the ; PL/M program PUT. The address of a the following ; structure is passed: ; ; declare putpb structure ; (output$type byte, ; echo$flag byte, ; filtered$flag byte, ; system$flag byte); ; ; output$type = 0 > console output (default) ; = 1 > auxiliary output ; = 2 > list output ; = 3 > console input ; ; echo = true > echo output to real device ; (default) ; = false > don't echo output (input is ; still echoed) ; filtered = true > convert control characters ; to a printable form ; preceeded by an ^ ; = false > no character conversions ; program = true > continue until user uses ; PUT command to revert to ; console ; = false > active only until program ; termination public putf extrn mon1,fcb,memsiz ; ; true equ 0ffffh false equ 00000h ; biosfunctions equ true ;intercept BIOS list or conout ; ; ; low memory locations ; wboot equ 0000h wboota equ wboot+1 ; ; equates for non graphic characters ; cr equ 0dh ; carriage return lf equ 0ah ; line feed ; ; BDOS function equates ; cinf equ 1 ;read character coutf equ 2 ;output character crawf equ 6 ;raw console I/O creadf equ 10 ;read buffer cstatf equ 11 ;status lchrf equ 5 ;list character pbuff equ 9 ;print buffer resetf equ 13 ;disk reset selectf equ 14 ;select disk openf equ 15 ;open file closef equ 16 ;close file delf equ 19 ;delete file dreadf equ 20 ;disk read makef equ 22 ;make file dmaf equ 26 ;set dma function curdrv equ 25 ;get current drive dpbf equ 31 ;get dpb address userf equ 32 ;set/get user number resdvf equ 37 ;reset drive scbf equ 49 ;set/get system control block word rsxf equ 60 ;RSX function call resalvf equ 99 ;reset allocation vector pblkf equ 111 ;print block to console lblkf equ 112 ;print block to list device ginitf equ 128 ;GET initialization sub-function no. gkillf equ 129 ;GET delete sub-function no. gfcbf equ 130 ;GET file display sub-function no. pinitf equ 132 ;PUT initialization sub-funct no. pckillf equ 133 ;PUT CON: delete sub-function no. pcfcbf equ 134 ;return PUT CON: fcb address plkillf equ 137 ;PUT LST: delete sub-function no. plfcbf equ 138 ;return PUT LST:fcb address jinitf equ 140 ;JOURNAL initialization sub-funct no. jkillf equ 141 ;JOURNAL delete sub-function no. jfcbf equ 142 ;return JOURNAL fcb address skillf equ 144 ;SUBMIT delete sub-function no. sfcbf equ 145 ;SUBMIT fcb address function svkillf equ 160 ;SAVE delete sub-function no. ; ; System Control Block definitions ; scba equ 03ah ;offset of scbadr from SCB base ccpflg1 equ 0b3h ;offset of ccpflags word from page boundary submit equ 040h ;mask for active submit or get test errflg equ 0aah ;offset of error flag from page boundary conmode equ 0cfh ;offset of console mode from page boundary listcp equ 0d4h ;offset of ^P flag from page boundary common equ 0f9h ;offset of common memory base from pg. bound wbootfx equ 068h ;offset of warm boot jmp from page. bound constfx equ 06eh ;offset of constat jmp from page. bound coninfx equ 074h ;offset of conin jmp from page. bound conoufx equ 07ah ;offset of conout jmp from page. bound listfx equ 080h ;offset of list jmp from page. bound cstjmp equ 003h ;offset of console status jmp from warm boot cinjmp equ 006h ;offset of console input jmp from warm boot coujmp equ 009h ;offset of console output jmp from warm boot lstjmp equ 00ch ;offset of list output jmp from warm boot ; ; Restore mode equates (used with inr a, rz, rm, ret) ; norestore equ 0ffh ;no BIOS interception biosonly equ 07fh ;restore BIOS jump table only everything equ 0 ;restore BIOS jump table and jmps in ;RESBDOS (default mode) ; ; Instructions ; lxih equ 21h ;LXI H, instruction jmpi equ 0c3h ;jump instruction ; ;****************************************************************** ; START OF INITIALIZATION CODE ;****************************************************************** cseg putf: ;get parameters mov h,b mov l,c ;HL = .(parameter block) mov a,m ;output type 0=con:,1=aux:,2=lst:,3=conin: cpi 1 ;is it aux? jz notimp ;error if so cpi 3 ;is it console input only jnz setlst sta input ;non-zero => console input xra a setlst: sta list ;non-zero => list device inx h mov a,m ;echo/noecho mode sta echo inx h mov a,m ;cooked/raw mode sta cooked inx h mov a,m ;system/program mode sta program ; ;check if enough memory ; lhld memsiz mov a,h cpi 20h lxi d,memerr jc error ; ;check if drive specified lxi h,fcb mov a,m ;drive code dcr a ;drive specified? jp movfcb ;jump if so ; ;set to current drive, if not ; mvi c,curdrv push h ;save .fcb call mon1 pop h ;a=current drive, hl=.fcb mov m,a ;set fcb to force drive select inr m ;must be relative to 1 ; movfcb: ;copy default fcb up into data area for move to RSX ; mov e,a mvi c,selectf ;make sure drive is selected push h ;save .fcb call mon1 ;so we get the right DPB pop h lxi d,putfcb lxi b,32 ;length of fcb call ldir ;move it to putfcb ; ;initialize other variables to be moved to RSX ; call getusr ;get current user number sta putusr ;save for redirection file I/O call getscbadr shld scbadr ;System Control Block address ; ;initialize records per block (BLM) ; mvi c,dpbf call mon1 ;HL = .disk parameter block inx h inx h inx h ;HL = .blm mov a,m sta blm ; ;initialize function table (functions to be intercepted) ; lda list ora a lxi b,funcend-functbl ;count lxi d,functbl ;destination lxi h,pcfcbf*256+pckillf ;rsx function codes jz ckinput lxi h,listfunc ;list function table call ldir mvi a,lchrf sta bdosfunc ;use list output for bios trap mvi a,listfx sta resoff ;offset of fixup for bios list mvi a,lstjmp sta biosoff ;offset of bios lst jmp lxi h,plfcbf*256+plkillf jmp getrsxadr ckinput: lda input ora a jz getrsxadr lxi h,inputfunc call ldir mvi a,cinf sta bdosfunc ;use console input mvi a,coninfx sta resoff ;offset of fixup for bios conin mvi a,cinjmp sta biosoff sta echo ;must be non-zero for input lhld scbadr mvi l,ccpflg+1 mov a,m ani submit ;SUBMIT or GET active? lxi d,noget jnz error ;error if so lxi h,jfcbf*256+jkillf ; ;get address of initialization table in RSX ; getrsxadr: shld rsxfun mvi c,rsxf ;PUT is not compatible with SAVE.RSX lxi d,savkill ;as both SAVE & PUT trap warm starts call mon1 ;eliminate SAVE.RSX if active mvi c,rsxf lxi d,rsxinit call mon1 ;call PUT.RSX initialization routine push h ;save address of destination for move mov e,m inx h mov d,m ;DE = .kill flag push d ;save for later set ; if biosfunctions ; inx h inx h inx h ;HL = .(.(bios entry in RSX)) push h ;save for getting RSX entry point ;later (in trap:) ;check if BIOS jump table looks valid (jmp in right places) check: lhld biosoff xchg lhld wboota mov a,m cpi jmpi ;should be a jump dad d ;HL = .(jmp address) mov a,m cpi jmpi ;should be a jump jnz bioserr ;skip bios redirection if not ; ;fix up RESBDOS to do BIOS calls to intercepted functions ; lhld scbadr mvi l,common+1 mov a,m ;get high byte of common base ora a jnz fix0 ;high byte = zero if non-banked mvi a,biosonly sta biosmode jmp trap ;skip code that fixes resbdos ;fix warmboot BIOS jmp in resbdos fix0: mvi l,wbootfx ;HL = .warm boot fix in SCB shld wmfix ;save for RSX restore at end mov a,m cpi jmpi ;is it a jump instruction? jz fix1 ;jump if so mvi a,biosonly ;whoops already traped sta biosmode fix1: mvi m,lxih ;change jump to an lxi h, ;fix list bios jmp in resbdos lda resoff mov l,a shld biosfix mov a,m cpi jmpi ;is it a jump instruction? jz biosck ;jump if so mvi a,biosonly ;whoops already changed sta biosmode ;restore jump table only fix3: mvi m,lxih ; ;get address of list entry point ; trap: pop h ;.(.(bios entry point in RSX)) mov c,m inx h mov b,m push h lhld biosoff xchg lhld wboota dad d ;HL = .(jmp address) inx h ;move past jmp instruction shld biosjmp ;save for RSX restore at end mov e,m mov m,c inx h mov d,m ;DE = bios routine address mov m,b ;BIOS jmp jumps to RSX xchg shld biosout ;save bios routine address ;get addresses of RSX bios trap pop h inx h mov c,m ;HL = .(.(bios warm start in RSX)) inx h mov b,m ;BC = .bios warmstart entry in RSX ; ;patch RSX wmboot entry into BIOS jump table ;save real wmboot address in RSX exit table ; lhld wboota inx h shld wmjmp ;save for RSX restore at end mov e,m mov m,c inx h mov d,m mov m,b xchg shld wmsta ;save real bios warm start routine endif ; ;move data area to RSX ; rsxmov: pop h ;HL = .(kill flag = 0FFh) inr m ;set to zero for redirection active lxi h,movstart pop d ;RSX data area address lxi b,movend-movstart call ldir jmp wboot ; ; auxiliary redirection ; notimp: lxi d,notdone error: mvi c,pbuff call mon1 mvi c,closef lxi d,fcb call mon1 mvi c,delf lxi d,fcb call mon1 jmp wboot if biosfunctions ; ; check if warm boot was fixed up by someone ; and list or console output was not ; biosck: lda biosmode cpi biosonly jnz fix3 ;warm boot not fixed up ; ; can't do BIOS redirection ; bioserr: lxi d,nobios mvi c,pbuff call mon1 lxi h,biosmode mvi m,norestore pop h ;throw away stacked bios entry jmp rsxmov endif ; ; get/set user number ; getusr: mvi a,0ffh ;get current user number setusr: mov e,a ;set current user number (in A) mvi c,userf jmp mon1 ; ; get system control block address ; (BDOS function #49) ; ; exit: hl = system control block address ; getscbadr: mvi c,scbf lxi d,data49 jmp mon1 ; data49: db scba,0 ;data structure for getscbadd ; ; ; copy memory bytes (emulates z80 ldir instruction) ; ldir: mov a,m ;get byte stax d ;store it at destination inx h ;advance pointers inx d dcx b ;decrement byte count mov a,c ;loop if non-zero ora b jnz ldir ret ; ;****************************************************************** ; DATA AREA ;****************************************************************** ; ; equates function table ; eot equ 0ffh ; end of function table skipf equ 0feh ; skip this function ; listfunc: db lchrf, lblkf, coutf, cstatf, crawf db pbuff, cinf, creadf, resetf, resdvf db resalvf, pblkf, eot ; Note that the list routines precede the console ; routines so that the CKLIST: routine in PUTRSX ; can distinquish list functions from console ; functions. inputfunc: ;preset for console input db skipf, skipf, skipf, skipf, crawf db skipf, cinf, creadf, resetf, resdvf db resalvf, eot, skipf ; savkill: db svkillf rsxinit: db Pinitf nobios: db cr,lf,'WARNING: Cannot redirect from BIOS',cr,lf,'$' notdone: db cr,lf db 'ERROR: Auxiliary device redirection not implemented',cr,lf,'$' memerr: db cr,lf db 'ERROR: Insufficient Memory',cr,lf,'$' noget: db cr,lf db 'ERROR: You cannot PUT INPUT to a file',cr,lf db ' when using GET or SUBMIT.',cr,lf,'$' resoff: db conoufx biosoff: dw coujmp aux: db 0 ; ;****************************************************************** ; Following variables are initialized by PUT.COM ; and moved to the PUT RSX - Their order must not be changed ;****************************************************************** ; ; movstart: inittable: ;addresses used by PUT.COM for scbadr: dw 0 ;address of System Control Block ; if biosfunctions ;PUT.RSX initialization ; gobios: mov c,e db jmpi biosout: dw 0 ;set to real BIOS routine ; ;restore only if changed when removed. biosjmp: dw 0 ;address of bios jmp initialized by COM biosfix: dw 0 ;address of jmp in resbdos to restore db jmpi wmsta: dw 0 ;address of real warm start routine wmjmp: dw 0 ;address of jmp in bios to restore wmfix: dw 0 ;address of jmp in resbdos to restore bdosfunc: db coutf biosmode: db 0 ;0FFh = no bios restore, 07fh = restore ;only bios jmp, 0 = restore bios jump and ;resbdos jmp when removed. endif functbl: ;preset for console output db skipf, skipf, coutf, cstatf, crawf, pbuff db cinf, creadf, resetf, resdvf, resalvf, pblkf, eot funcend: ; input: db 0 ;non-zero if putting input to a file list: db 0 ;TRUE if list output redirection echo: db 1 ;echo output to device cooked: ;must be next after echo db 0 ;TRUE if ctrl chars displayed with ^ rsxfun: pkillf: db 255 ;put abort routine code pfcbf: db 255 ;put FCB display function no. ; ********** remaining variables must be in this order record: db 0 ;counts down records to block boundary blm: db 0 ;block mask = records per block (rel 0) program: ;This must be @ .putfcb-2 db 0 putusr: db 0 ;user number for redirection file putfcb: db 1 ;a db 'SYSOUT ' db '$$$' db 0,0 putmod: db 0 putrc: db 0 ds 16 ;map putcr: db 0 ; cbufp: db 0 movend: ;******************************************************************* end