home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
ZCPR2
/
MKDIR.MQC
/
MKDIR.MAC
Wrap
Text File
|
2000-06-30
|
21KB
|
1,050 lines
;
; PROGRAM: MKDIR
; VERSION: 1.2
; AUTHOR: RICHARD CONN
; DATE: 17 Jan 83
; PREVIOUS VERSIONS: 1.1 (15 Jan 83), 1.0 (14 Jan 83)
;
VERS EQU 12
;
; MKDIR is used to create named directory files. It allows the user
; to read and edit them. It is fully integrated into the ZCPR2 system.
;
; Forms of the MKDIR command are:
; MKDIR <-- Enter System
; MKDIR // <-- Get Help
; MKDIR filename.typ <-- Enter System with selected file
;
;
; CP/M Constants
;
cpm equ 0 ; base
bdose equ cpm+5
fcb equ cpm+5ch
tbuff equ cpm+80h
cr equ 0dh
lf equ 0ah
;
; SYSLIB Routines
;
ext print,zgpins,putud,getud,logud,retud,zfname,moveb
ext cin,cout,crlf,caps,compb
ext fi0$open,f0$get,fi0$close
ext fo0$open,f0$put,fo0$close
ext bbline,padc,initfcb,cline,zpfind,codend
ext sort
;
; This program is Copyright (c) 1982, 1983 by Richard Conn
; All Rights Reserved
;
; ZCPR2 and its utilities, including this one, are released
; to the public domain. Anyone who wishes to USE them may do so with
; no strings attached. The author assumes no responsibility or
; liability for the use of ZCPR2 and its utilities.
;
; The author, Richard Conn, has sole rights to this program.
; ZCPR2 and its utilities may not be sold without the express,
; written permission of the author.
;
;
; Branch to Start of Program
;
jmp start
;
;******************************************************************
;
; SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format
;
; This data block precisely defines the data format for
; initial features of a ZCPR2 system which are required for proper
; initialization of the ZCPR2-Specific Routines in SYSLIB.
;
;
; EXTERNAL PATH DATA
;
EPAVAIL:
DB 0FFH ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES)
EPADR:
DW 40H ; ADDRESS OF EXTERNAL PATH IF AVAILABLE
;
; INTERNAL PATH DATA
;
INTPATH:
DB 0,0 ; DISK, USER FOR FIRST PATH ELEMENT
; DISK = 1 FOR A, '$' FOR CURRENT
; USER = NUMBER, '$' FOR CURRENT
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0 ; DISK, USER FOR 8TH PATH ELEMENT
DB 0 ; END OF PATH
;
; MULTIPLE COMMAND LINE BUFFER DATA
;
MCAVAIL:
DB 0FFH ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE?
MCADR:
DW 0FF00H ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE
;
; DISK/USER LIMITS
;
MDISK:
DB 4 ; MAXIMUM NUMBER OF DISKS
MUSER:
DB 31 ; MAXIMUM USER NUMBER
;
; FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK
;
DOK:
DB 0FFH ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES)
UOK:
DB 0FFH ; ALLOW USER CHANGE? (0=NO, 0FFH=YES)
;
; PRIVILEGED USER DATA
;
PUSER:
DB 10 ; BEGINNING OF PRIVILEGED USER AREAS
PPASS:
DB 'chdir',0 ; PASSWORD FOR MOVING INTO PRIV USER AREAS
DS 41-($-PPASS) ; 40 CHARS MAX IN BUFFER + 1 for ending NULL
;
; CURRENT USER/DISK INDICATOR
;
CINDIC:
DB '$' ; USUAL VALUE (FOR PATH EXPRESSIONS)
;
; DMA ADDRESS FOR DISK TRANSFERS
;
DMADR:
DW 80H ; TBUFF AREA
;
; NAMED DIRECTORY INFORMATION
;
NDRADR:
DW 00000H ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY
NDNAMES:
DB 64 ; MAX NUMBER OF DIRECTORY NAMES
DNFILE:
DB 'NAMES ' ; NAME OF DISK NAME FILE
DB 'DIR' ; TYPE OF DISK NAME FILE
;
; REQUIREMENTS FLAGS
;
EPREQD:
DB 0FFH ; EXTERNAL PATH?
MCREQD:
DB 000H ; MULTIPLE COMMAND LINE?
MXREQD:
DB 0FFH ; MAX USER/DISK?
UDREQD:
DB 000H ; ALLOW USER/DISK CHANGE?
PUREQD:
DB 000H ; PRIVILEGED USER?
CDREQD:
DB 0FFH ; CURRENT INDIC AND DMA?
NDREQD:
DB 0FFH ; NAMED DIRECTORIES?
Z2CLASS:
DB 0 ; CLASS 0
DB 'ZCPR2'
DS 10 ; RESERVED
;
; END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA
;
;******************************************************************
;
;
; Start of Program
;
start:
lxi h,0 ; save stack
dad sp
shld stack
xra a ; A=0
sta chflag ; set no changes
sta flflag ; set no file loaded
sta ecount ; set no entries
call zgpins ; set up environ
call print
db 'MKDIR Version '
db vers/10+'0','.',(vers mod 10)+'0',0
lda fcb+1 ; check for help
cpi '/'
jnz start1
call print ; print help message
db cr,lf,' MKDIR is used to read and edit named directory files.'
db cr,lf,'It is invoked by the following forms --'
db cr,lf
db cr,lf,' MKDIR <-- Enter System'
db cr,lf,' MKDIR dir:filename.typ <-- Define File First'
db cr,lf,' MKDIR // <-- Print this Help'
db cr,lf,0
ret
start1:
call putud ; save current dir for quick return
call retud ; get current user and disk
mov a,b ; save disk
sta cdisk
mov a,c
sta cuser
lxi h,dnfile ; set default file name
lxi d,dfcb+1 ; copy into fcb
mvi b,11 ; 11 chars
call moveb
lxi h,tbuff ; save command line as string
call cline
call sblank ; skip to non-blank
ora a ; no entry?
jz mkdir ; enter system
;
; Main Entry Point for Loading a File
;
loadfile:
lxi sp,stack ; set stack
lxi d,dfcb ; set up default file name
call zfname ; extract info
jnz start2
call print
db cr,lf,'Error in Disk or User -- Ignoring',0
lda cdisk ; set current values
mov b,a
lda cuser
mov c,a
jmp start3
start2:
mov a,b ; check for current disk
cpi 0ffh ; current?
jnz cutst
lda cdisk ; get current disk
mov b,a
inr b ; add 1 for following decrement
cutst:
dcr b ; adjust disk to 0 to n-1
mov a,c ; check for current user
cpi 0ffh ; current?
jnz start3
lda cuser ; get current user
mov c,a
start3:
call logud ; log into UD to begin search
;
; Entry Point for Loading File in DFCB
;
ffile:
lxi sp,stack ; reset stack
mvi b,0ffh ; search current first
lxi d,dfcb ; pt to FCB
call initfcb ; init it
call zpfind ; look for file
jnz start4
call print
db cr,lf,'File ',0
lxi h,dfcb+1 ; print name
call prfn
call print
db ' Not Found',0
jmp mkdir
start4:
call logud ; log into dir of file
lxi d,dfcb
call initfcb
call fi0$open ; open file for input
call codend ; pt to scratch buffer
lda ndnames ; get max entry count
mov b,a ; ... in B
readf:
call getch ; get disk letter from file
sui 'A' ; convert to number from 0 to n-1
mov m,a ; store disk number
inx h ; pt to user number
call getch ; get user number
mov m,a ; store user number
inx h ; pt to next
mvi c,8 ; store dir name
readn:
call getch ; get char
ora a ; done?
jz readn1
mov m,a ; store char if not done
inx h ; pt to next
dcr c ; count down
jnz readn
jmp readn2
readn0:
call getch ; flush char
readn1:
mvi m,' ' ; store spaces now
inx h ; pt to next
dcr c ; count down
jnz readn0
readn2:
call getch ; flush 9th char
dcr b ; count down
jnz readf ; continue reading file entries
call fi0$close ; close input file
call getud ; return to current dir
call dirpack ; pack dir
mvi a,0ffh ; set file loaded flag
sta flflag
jmp mkdir1
;
; Enter MKDIR System and Init Environ
; Enter at MKDIR if no file loaded, enter at MKDIR1 if file loaded
;
mkdir:
call dinit0 ; init directory
xra a ; A=0
sta ecount ; set no entries present
sta flflag ; set no file loaded
sta chflag ; set no changes
mkdir1:
lxi sp,stack ; set stack
call print
db cr,lf,'MKDIR Command (? for Help)? ',0
call cin ; get command
call caps ; capitalize
call cout ; echo
lxi d,mkdir1 ; set ret address
push d
lxi h,ctable ; scan command table for it
mov c,a ; command in C
mkdir2:
mov a,m ; get command letter
ora a ; end of table?
jz mkdirh
cmp c ; match?
jz mkdir3
inx h ; skip over address
inx h
inx h
jmp mkdir2
mkdir3:
inx h ; get address in HL
mov a,m ; low
inx h
mov h,m
mov l,a ; HL is address of routine
pchl ; "call" routine
;
; Print MKDIR Command Help
;
mkdirh:
call print
db cr,lf,'MKDIR Commands are --'
db cr,lf,' C -- Change Directory (Add/Rename/Delete Entries)'
db cr,lf,' I -- Initialize Directory'
db cr,lf,' P -- Print Directory'
db cr,lf,' R -- Read Directory File'
db cr,lf,' S -- Status of MKDIR Environment'
db cr,lf,' W -- Write Directory File'
db cr,lf,' X -- Exit Program'
db cr,lf,0
ret
;
; Command Table
;
ctable:
db 'C' ; change directory
dw change
db 'I' ; init directory
dw dinit
db 'P' ; print directory
dw dprint
db 'R' ; read file
dw read
db 'S' ; status
dw status
db 'W' ; write file
dw write
db 'X' ; exit
dw exit
db 0 ; end of table
;
; Status
;
status:
call print
db cr,lf,'** MKDIR Status **',cr,lf,cr,lf,0
lda ecount ; print entry count
mov b,a ; ... count in B for later
call padc
call print
db ' Entries in Directory',cr,lf,0
lda ndnames ; get limit
sub b ; subtract amount taken so far
call padc
call print
db ' Empty Entries Remaining'
db cr,lf
db cr,lf,'Working File Name: ',0
lxi h,dfcb+1
call prfn
call crlf ; new line
call crlf
lda chflag ; changes made?
ora a
jnz stat1
call print
db 'No ',0
stat1:
call print
db 'Changes made to Directory since Startup'
db cr,lf,0
lda flflag ; file loaded?
ora a ; 0=no
jnz stat2
call print
db 'No ',0
stat2:
call print
db 'File has been loaded',cr,lf,0
ret
;
; Init Directory
;
dinit:
call print
db cr,lf,' Are you sure you want to Initialize the Directory '
db '(Y/N/<CR>=N)? ',0
call cin ; get response
call caps
call cout
call crlf
cpi 'Y' ; Yes is only valid reply
rnz
dinit0:
xra a ; A=0
sta ecount
mvi a,0ffh
sta chflag ; set change flag
call codend ; pt to directory
lda ndnames ; get entry count
mov b,a ; ... in B
dinit1:
mvi m,0 ; set double zero
inx h
mvi m,0
inx h ; pt to name
mvi c,8 ; 8 chars
dinit2:
mvi m,' ' ; store space
inx h ; pt to next
dcr c ; count down
jnz dinit2
dcr b ; count down
jnz dinit1
ret
;
; Read File
;
read:
call getfname ; get file name
ora a ; none?
jz ffile ; just find default file and load it
jmp loadfile ; parse entry and load file
;
; Get File Name from User
;
getfname:
call print
db cr,lf,'Name of File (<RETURN> = ',0
lxi h,dfcb+1 ; print default name
call prfn
call print
db ')? ',0
mvi a,0ffh ; capitalize
call bbline ; get user input
call sblank ; skip to non-blank
ora a ; default?
ret
;
; Write File
;
write:
call getfname
jz write1
lxi d,dfcb ; parse into DFCB
call zfname ; parse file name
jnz write0
call print
db cr,lf,'Invalid Disk or User -- Using Current Directory',0
jmp write1
write0:
mov a,b ; current disk?
cpi 0ffh
jnz wutst
lda cdisk ; select current disk
mov b,a
inr b ; add 1 for following decrement
wutst:
dcr b ; adjust disk to 0 to n-1
mov a,c ; current user?
cpi 0ffh
jnz wlog
lda cuser ; select current user
mov c,a
wlog:
call logud ; log into new dir
write1:
lxi d,dfcb ; open file for output
call initfcb
call fo0$open ; open file
ora a ; OK?
jnz werr ; write error and abort
call print
db cr,lf,'Writing Directory to Disk ... ',0
lda ndnames ; save dir as loaded
mov b,a ; count in B
call codend ; pt to start of buffer
writef:
mov a,m ; get disk
adi 'A' ; convert to letter
call putch ; write char
inx h ; pt to user
mov a,m ; get user
call putch ; write char
inx h ; pt to next
mvi c,8 ; write dir name to disk
wf1:
mov a,m ; get char
cpi ' ' ; done?
jz wf2
inx h ; pt to next
call putch ; write char to disk
dcr c ; count down
jnz wf1
jmp wf3
wf2:
xra a ; write zeroes
inx h ; skip next char
call putch
dcr c ; count down
jnz wf2
wf3:
xra a ; write 9th zero
call putch
dcr b ; count down
jnz writef
call fo0$close ; close file
call getud ; go home
xra a ; A=0
sta chflag ; set no changes flag
call print
db 'Done',0
ret
;
; Exit from MKDIR
;
exit:
lda chflag ; check for any changes
ora a ; 0=No
jz exit1
call print
db cr,lf
db cr,lf,'Directory has changed since last Write'
db cr,lf,'Do you want to write Directory to Disk first '
db '(Y/N/<CR>=Y)?',0
call cin ; get response
call caps
call cout
call crlf ; new line
cpi 'N' ; no?
cnz write ; write if not No
exit1:
lhld stack ; return to OS
sphl
ret
;
; Print Directory to User
;
dprint:
lda ecount ; any entries?
ora a ; 0=none
jnz dpr1
call print
db cr,lf,'Empty Directory',0
ret
dpr1:
call codend ; pt to first element
lda ecount ; get entry count
mov b,a ; ... in B
mvi c,'A'-1 ; set disk type
prloop:
inr c ; next disk
call print
db cr,lf,'Disk ',0
mov a,c ; print disk letter
call cout
call print
db ' --',0
mvi a,0ffh ; set line count
sta crcnt
prl1:
mov a,m ; get next disk
adi 'A' ; convert to alpha
cmp c ; same as current?
jnz prloop ; loop to next if not
lda crcnt ; increment entry count
inr a
sta crcnt
ani 3 ; new line?
cz crlf
call print
db ' ',0 ; space over
inx h ; pt to user
mov a,m ; get user number
call padc ; print user number
call print
db ': ',0
inx h ; pt to name
mvi d,8 ; 8 chars
prl2:
mov a,m ; get char
inx h ; pt to next
call cout ; print char
dcr d ; count down
jnz prl2
prl3:
dcr b ; count down
jnz prl1
call crlf ; new line
lda ecount
call padc
call print
db ' Entries in Directory',0
ret
;
; Change Directory Contents
;
change:
call print
db cr,lf,'** MKDIR Change Mode **',0
ch0:
call print
db cr,lf,'Directory Entry (?<RETURN> for Help)? ',0
mvi a,0ffh ; caps
call bbline ; get user input
call sblank ; skip to non-blank
ora a ; no input?
jz chprint ; done, so print directory
mov a,m ; get first char
cpi 'X' ; Exit?
jz dsort ; if so, sort and then exit
cpi '?' ; help?
jnz ch1
call print
db cr,lf
db cr,lf,'MKDIR Change Mode --'
db cr,lf,' You may issue the following commands at this point:'
db cr,lf
db cr,lf,' DU:dirname <-- Create/Rename Dir Entry'
db cr,lf,' DU: <-- Delete Dir Entry'
db cr,lf,' <RETURN> <-- Print Directory'
db cr,lf,' X <-- Exit'
db cr,lf,' ? <-- Print this Help'
db cr,lf,0
jmp ch0
chprint:
call dsort ; use dsort routine
call dprint ; use dprint routine
jmp ch0 ; continue
ch1:
lxi d,tfcb ; extract user and disk info as well as name
call zfname ; get info
jnz ch2
call print
db cr,lf,'Error in Disk or User',0
jmp ch0
ch2:
mov a,b ; current disk?
cpi 0ffh
jnz ch3
lda cdisk ; set disk
mov b,a
inr b ; add 1 for following decrement
ch3:
dcr b ; adjust disk to 0 to n-1
mov a,c ; current user?
cpi 0ffh
jnz ch4
lda cuser ; set user
mov c,a
ch4:
mov a,b ; save as temp disk and user
sta tdisk
mov a,c
sta tuser
;
; Scan Directory for Temp Disk and User
;
lda ndnames ; get entry count
mov b,a ; ... in B
call codend ; pt to first entry
scanud:
inx h ; pt to name
inx h
mov a,m ; get first char of name
dcx h
dcx h ; pt to disk
cpi ' ' ; deleted entry?
jz scanud1
mov d,m ; get disk
lda tdisk ; compare it
cmp d
jnz scanud1
inx h ; pt to user
mov a,m ; get user
dcx h ; pt back
cmp c ; compare it
jz udfound
scanud1:
lxi d,10 ; pt to next
dad d
dcr b ; count down
jnz scanud
lda tfcb+1 ; delete?
cpi '?' ; ? if so
jnz addname
call print
db cr,lf,' -- DU not found for Delete -- No Change Made',0
jmp ch0
;
; Found Possible Directory Entry
;
udfound:
inx h ; found existing entry
inx h ; pt to name
lda tfcb+1 ; delete?
cpi '?' ; ? if so
jz delname
;
; Rename Function
;
xra a ; clear add flag
sta addflg
call print
db cr,lf,' Renaming ',0
mvi b,8 ; 8 chars
push h ; save ptr
call prfn1 ; print name
pop h ; get ptr
mvi m,' ' ; space fill
jmp putname
;
; Add Function
;
addname:
mvi a,0ffh ; set add flag
sta addflg
call print
db cr,lf,' Adding ',0
lxi h,tfcb+1
mvi b,8
call prfn1
lda ecount ; increment entry count
inr a
sta ecount
putname:
lda ndnames ; get entry count
mov c,a ; ... in C
call codend ; pt to first entry
inx h ; pt to name
inx h
etest:
lxi d,tfcb+1 ; pt to new name
mvi b,8 ; 8 chars
call compb ; compare
jnz etest1
call print
db cr,lf,' -- Error -- Duplicate Name Exists -- No Change Made',0
lda addflg ; add?
ora a ; 0=no
jz ch0
lda ecount ; count down
dcr a
sta ecount
jmp ch0
etest1:
lxi d,10 ; pt to next entry
dad d
dcr c ; count down
jnz etest
mvi a,0ffh ; change made
sta chflag
lda ndnames ; get entry count
mov b,a ; ... in B
call codend ; pt to first
inx h ; pt to name
inx h
putn1:
mov a,m ; valid entry?
cpi ' ' ; empty?
jnz putn2
dcx h ; pt to disk
dcx h
lda tdisk
mov m,a
inx h
lda tuser
mov m,a
inx h
lxi d,tfcb+1 ; pt to new name
xchg
mvi b,8 ; 8 chars
call moveb
call print
db ' -- ',0
lda ecount ; print count
mov b,a ; ... in B
call padc
call print
db ' Entries in Directory, Room for ',0
lda ndnames
sub b
call padc
call print
db ' More',0
jmp ch0 ; continue
putn2:
lxi d,10 ; skip to next entry
dad d
dcr b ; count down
jnz putn1
call print
db cr,lf,'** Directory Full **',0
lda addflg ; adding?
ora a ; 0=no
jz ch0
lda ecount ; count down
dcr a
sta ecount
jmp ch0
;
; Delete Function
;
delname:
mvi a,0ffh ; change made
sta chflag
call print
db cr,lf,' Deleting ',0
mvi b,8 ; 8 chars
push h ; save ptr
call prfn1
pop h ; get ptr
mvi m,' ' ; space fill
call dirpack ; pack directory
call print
db ' -- ',0
lda ecount ; print remaining count
call padc
call print
db ' Entries Remaining',0
jmp ch0 ; continue
;
; Sort Directory
;
dsort:
call dirpack ; pack directory
lda ecount ; number of elements
ora a ; any?
rz ; done if none
sta ssbcnt ; set count
call codend ; pt to first element
shld ssbstrt ; set starting address
lxi d,ssb ; pt to sort specifiction block
call sort ; sort
ret
;
; Sort Compare Routine
;
compare:
push h ; don't change regs
push d
ldax d ; compare disk
cmp m
jnz comp1
inx h ; pt to user
inx d
ldax d ; compare user
cmp m
comp1:
pop d ; restore regs
pop h
ret
;
; Utilities
;
;
; Read and Write Chars to Disk
;
getch:
call f0$get ; get char
rz ; OK since no error
call print
db cr,lf,'File Read Error -- Aborting',0
jmp mkdir1 ; goto command level
putch:
call f0$put ; put char
rz ; OK since no error
werr:
call print
db cr,lf,'Disk Write Error -- Aborting',0
call getud ; return home
jmp mkdir1
;
; Pack Memory-Based Directory
;
dirpack:
call codend ; get address of first entry
mov d,h ; DE pts to it also
mov e,l
lda ndnames ; get max count
mov b,a ; ... in B
mvi c,0 ; set entry count
dirp0:
push b ; save counts
inx h ; pt to name
inx h
mov a,m ; get char
dcx h ; pt back to disk
dcx h
cpi ' ' ; no entry if space
jz dirp1
mvi b,10 ; copy 10 bytes
dirpm:
mov a,m ; copy HL to DE for B bytes
stax d
inx h ; pt to next
inx d
dcr b ; count down
jnz dirpm
pop b ; get counts
inr c ; 1 more entry
jmp dirp2
dirp1:
push d ; save new entry ptr
lxi d,10 ; pt to next entry
dad d
pop d
pop b ; get counts
dirp2:
dcr b ; count down
jnz dirp0
mov a,c ; save count
sta ecount
lda ndnames ; make rest empty
sub c ; number of entries remaining
mov b,a ; ... in B
ora a ; none?
rz
xchg ; HL pts to next entry
inx h ; pt to name
inx h
lxi d,10 ; prep to add 10
dirp3:
mvi m,' ' ; set space as first char
dad d ; pt to next
dcr b ; count down
jnz dirp3
ret
;
; Skip until non-blank encountered
;
sblank:
mov a,m ; get char
inx h ; pt to next
cpi ' ' ; skip space
jz sblank
dcx h ; pt to char
ret
;
; Print file name pted to by HL
;
prfn:
push b ; save regs
push h
mvi b,8 ; 8 chars
call prfn1
mvi a,'.'
call cout
mvi b,3 ; 3 chars
call prfn1
pop h ; get regs
pop b
ret
prfn1:
mov a,m ; print chars
inx h ; pt to next
call cout
dcr b ; count down
jnz prfn1
ret
;
; Sort Specification Block
;
ssb:
ssbstrt:
ds 2 ; start address of dir
ssbcnt:
dw 0 ; number of records to sort
dw 10 ; 10 bytes/record
dw compare ; compare routine
dw 0 ; no ptr table
db 0,0 ; don't use ptrs
;
; Buffers
;
cdisk:
ds 1 ; current disk
cuser:
ds 1 ; current user
tdisk:
ds 1 ; temp disk
tuser:
ds 1 ; temp user
flflag:
ds 1 ; file loaded flag
chflag:
ds 1 ; dir changed flag
ecount:
ds 1 ; entry count
addflg:
ds 1 ; add/rename flag
crcnt:
ds 1 ; new line count
tfcb:
ds 36 ; temp FCB
dfcb:
ds 36 ; Default FCB
ds 50 ; 25-elt stack
stack:
ds 2 ; original stack ptr
end