home *** CD-ROM | disk | FTP | other *** search
- .title 'pubpatch.asm 4-13-84 (c) 1984 Plu*Perfect Systems'
- .settim 16:19:00
- .setdat 11/18/84
- .setwid 90
- .setlen 60
-
- ;11/18/84 minor change to published DDJ version to produce
- ;relocatable object file, to be relocated using HXRLOAD
-
- .remark ~
- -- PUBPATCH --
-
- A CP/M 2.2 BDOS modification to support the PUBlic filetype.
-
- --------------------------------------------
- Copyright (c) 1984 -- All rights reserved.
-
- Plu*Perfect Systems
- P. O. Box 1494
- Idyllwild CA 92349
- --------------------------------------------
-
- Attribute bit 2 of a filename signifies a PUBlic file,
- accessible by its unambiguous filename from all user
- numbers.
-
- PUBlic files are not accessible via the usual ambiguous
- filenames (e.g. *.* or ABC.D?F), to prevent unintentional
- erasure and avoid directory clutter.
-
- Directory entries for PUBlic files are, however, accessible
- via ambiguous filenames by using the BDOS search-for-first,
- search-for-next functions with a '?' in the drive-byte of the
- fcb. Extended versions of SD and DISK7 displays PUBlic files.
-
- To erase a PUBlic file, use "ERA unambiguous-filename". Or use
- DISK7. Or change it to a private file and then erase with a
- wildcard erase command.
-
- The PUBLIC.COM utility is available to make files either
- PUBlic or private and to list the current PUBlic files.
-
- If another utility is used to set the PUBlic attribute bit,
- avoid creating multiple files with the same name on the same
- drive, unless all of them are private. (PUBLIC.COM checks
- for this situation and prevents a conflict.)
-
- The REName command removes all attributes, so RENaming a
- PUBlic file will make it private, R/W, DIR in its original
- user number.
- ~
- .page
- .remark ~
- --- TO INSTALL ---
-
- 1a. Determine the BIOSBASE address of your system in memory
- by subtracting 3 from the warm-boot address in memory:
- DDT
- L0
- subtract 3 ==> BIOSBASE address
- 1b. Subtract 1600H to determine the CCPBASE_MEMORY address.
- 1c. Assemble PUBPATCH for these addresses.
-
- Either: use CDL's MACROIII assembler:
-
- MACROIII PUBPATCH A:DHK
-
- Or: convert the pseudo-opcodes to your assembler's
- pseudo-ops and assemble into a HEX file.
- e.g. .loc ==> org
- = ==> set
- =\ ==> ????, etc.
-
- 2. Create a system image for the SYSGEN operation.
- There are two ways to get the image:
-
- a. Either use SYSGEN to extract a system image from a disk
- in the usual manner --
- SYSGEN
- source drive? A
- destination drive? <CR>
- SAVE pp ORIG.SYS. Use pp=50 pages or so to get
- the entire BIOS.
-
- b. Or generate a new system --
- MOVCPM ss * where ss=64 for a 64K system,
- SAVE pp ORIG.SYS or whatever you are running.
-
- 3. Find the base address of the Command Processor in the image
- DDT ORIG.SYS
- Look for the command processor at 980H:
- You recognize it by two JMP instructions, followed by
- the command buffer (containing a Digital Research
- copyright notice, in the case of the original CCP):
- L980
- D980
- Call that address CCPBASE_IMAGE (normally 980H).
- (If you don't find it, you have a non-standard system, and
- your user's manual should have a memory map. See, e.g.,
- the Compupro Disk 1 Controller manual, sec. 6.4).
-
- 4. Calculate the offset needed to cause the PUBPATCH.HEX file to
- load on top of the BDOS image. 'offset' will satisfy:
-
- CCPBASE_IMAGE = CCPBASE_MEMORY + offset
-
- 5. Create a new system image containing the patch:
-
- DDT ORIG.SYS
- IPUBPATCH.HEX
- Roffset
- G0
- SAVE pp NEWSYS.SYS
-
- 6. Finally, put the new system on a FLOPPY disk for testing:
-
- SYSGEN NEWSYS.SYS
- <CR>
- destination_drive
-
-
- ------------------------------------------------
- Code also corrects a CP/M 2.2 bug that caused
- Rename, Set Attribute, and Delete File functions
- to return 0 status on success instead of 0,1,2,3
- per CP/M 2.2 Installation Guide.
- ------------------------------------------------
- ~
- .page
- .phex
-
- bdosbase = .
-
- ; Internal BDOS locations:
- ;
- FINDNXT = bdosbase+072Dh
- NXENTRY = bdosbase+0605h
- CKFILPOS = bdosbase+05F5h
- MOREFLS = bdosbase+057Fh
- FCB2HL = bdosbase+055Eh
- SAMEXT = bdosbase+0707h
- STFILPOS = bdosbase+05FEh
- SETSTAT = bdosbase+0301h
- SAVEFCB = bdosbase+0DD9h
- COUNTER = bdosbase+0DD8h
- FILEPOS = bdosbase+0DEAh
- STATUS = bdosbase+0345h
- FNDSTAT = bdosbase+0DD4h
- CHKWPRT = bdosbase+0554h
- CHKROFL = bdosbase+0544h
- FINDFST = bdosbase+0718h
- SETFILE = bdosbase+066bh
- DIRWRITE = bdosbase+05c6h
- CKFILPOS = bdosbase+05f5h
- DELFILE = bdosbase+0cd7h
- EXTMASK = bdosbase+0dc5h
- CLOSEFLG = bdosbase+0dd2h
- RDWRTFLG = bdosbase+0dd3h
- GETEMPTY = bdosbase+0924h
- OPENIT1 = bdosbase+085ah
- STRDATA = bdosbase+04bbh
- SETSTAT = bdosbase+0301h
- IOERR1 = bdosbase+0305h
- SETS2B7 = bdosbase+0578h
- ;
- .page
- .loc FINDNXT
-
- fnxt0: lxi h,0
- shld pflag ;initialize PUBlic & wildcard flags
- mov c,h ;0
- call NXENTRY
- call CKFILPOS
- jrz nomatch ;if done
- lhld SAVEFCB
- xchg ;de=user-fcb
- ldax d
- cpi 0E5h ;if Getempty fn wants first
- jrz fnxt1 ;..deleted file slot in directory
- push d
- call MOREFLS
- pop d
- jrnc nomatch ;if no more files
- ;
- fnxt1: call FCB2HL ;hl=directory fcb
- lda COUNTER
- mov b,a ;b=count
- mvi c,0 ;c=byte #
- ora a ;COUNTER=0 ==> Search fn
- jrz matched ;..so match every entry
- ;
- fnxt2: mov a,c ;get byte #
- cpi 13
- jrz nxtbyte ;omit S1 byte
- ldax d ;get user-fcb char
- cpi '?'
- jrnz fnxt3
- sta qflag ;flag wildcard
- jr nxtbyt
- ;
- fnxt3: mov a,m ;get directory-fcb char
- cpi 0E5h ;check for blank/deleted file
- mov a,c ;A = byte #
- jrz chkext ;if a deleted file, omit user # check
- ora a
- jrnz chkext ;or if not user # byte
- inx h ;else check for PUBlic file
- inx h
- bit 7,m ;..at attribute bit 2
- dcx h
- dcx h
- jrz chkext ;if not PUBlic, match on user #
- ;
- ; the file is PUBlic
- ; -- but is BDOS looking for an empty directory slot?
- mov a,b ;if COUNTER=1, this is a Getempty request
- dcr a ;
- jrz fnxt0 ;..so go to next file
- sta pflag ;else flag the file PUBlic,
- jr nxtbyt ;..and omit matching user #
- ;
- chkext: cpi 12 ; (A=byte #)
- ldax d
- jrz tstext ;extent byte(#12) is special case
- sub m ;compare the characters
- ani 07fh ;..excluding attribute bits
- jr extdone
- tstext: push b ;check for same extent
- mov c,m
- call SAMEXT
- pop b
- extdone:jrnz fnxt0 ;if mismatch, get next file
- ;
- nxtbyt: inx d ;chars match, bump to next byte
- inx h
- inr c ;byte # ++
- djnz fnxt2 ;count--
- ;
- ; here if-- COUNTER > 1 and filenames match
- ;
- ;Test for PUBlic file and wild-card combination:
- ; ;flags initially = 0, but
- pflag = .+1 ; = COUNTER-1 if PUBlic
- qflag = .+2 ; = '?'(3Fh) if '?' in fcb+1...
- lxi h,.-.
- mov a,l ;if file is PUBlic
- ana h ;..and there's a wildcard
- ;(3Fh & 1...n) ==> NZ
- jrnz fnxt0 ;..get next directory entry
- ;
- ; here if--
- ; (a) non-PUBlic filenames match,
- ; or (b) find-all-files (searchfirst/searchnext functions
- ; with drive byte = '?')
- ; or (c) delete unambiguous PUBlic-filename.
- ;
- matched:jmp PATCH1
- ;
- nomatch:call STFILPOS
- mov a,l ;l=0ffh
- jmp SETSTAT
- ;
- .page
- ; the ERASE FILE routine -- in a new location
- ;
- ; Routine is split, with remainder stuffed
- ; into free bytes at end of BDOS.
- ;
- ERAFILE:call CHKWPRT ;write-protect aborts
- mvi c,12
- call FINDFST
- eraf1: call CKFILPOS ;check for 'E5' case
- rz
- call CHKROFL ;read-only file aborts
- call FCB2HL
- jmp PATCH2
- LAST1 = . ;must be <= bdosbase+07BEh
- ;
- ;
-
-
- ;Remainder of ERASE routine goes at end of BDOS
- ;
- .loc bdosbase+0deeh ;there are 18 spare bytes
-
- PATCH2:
- eraf2: mvi m,0E5h ;install erase mark
- mvi c,0
- call SETFILE ;clear file's space in bitmap
- call DIRWRITE ;write directory sector
- eraf3: call FINDNXT ;look for next entry
- jmp eraf1
- LAST2 = . ;must be <= bdosbase+0E00h
- ;
- .page
- ;rewrite last part of bdos GETNEXT routine to gain space
- ;
- .LOC bdosbase+0971h
- ;
- gnxt0: jrz gnxt1 ;( overlaying jz gtnext1)
- mov b,a ;extent byte
- lda EXTMASK
- ana b
- lxi h,CLOSEFLG
- ana m
- jrz gnxt2 ;must read next extent
- gnxt3: call OPENIT1 ;open current extent
- gnxt4: call STRDATA ;update rec#, extent#,...
- xra a
- jsetst: jmp SETSTAT
- ;
- ; have overflowed normal extent, check s2 byte
- gnxt1: inx h ;shorter code, replacing
- inx h ;lxi b,2 & dad b
- inr m ;bump s2 byte
- mov a,m
- ani 0fh
- jrz gnxt5 ;error if too many extents
- gnxt2: mvi c,15 ;open the next extent
- call FINDFST
- call CKFILPOS
- jrnz gnxt3
- lda RDWRTFLG ;no extant extent
- inr a ;..if reading, can't open one
- jrz gnxt5
- call GETEMPTY ;writing, so get next free entry
- call CKFILPOS
- jrnz gnxt4 ;and if no error, save the data
- gnxt5: call IOERR1 ;set error &
- jmp SETS2B7 ;..don't close file
- ;
- ;
- ; use space (14 bytes) for fragment from FINDNXT routine:
- ;
- PATCH1: lda FILEPOS
- ani 03h
- sta STATUS ;save its directory buffer index
- lxi h,FNDSTAT
- ;
- .remark ~
- The original CP/M 2.2 code removed below is erroneous, and
- causes BDOS Erasefile, Renamefile, Setattribute functions
- to return A=0 on success rather than the directory index
- (0,1,2 or 3) specified in the Interface Guide.
-
- ;; mov a,m
- ;; ral
- ;; rnc
- ;; xra a
- ~
- ;
- mov m,a ;also save it for use
- ret ;..by Erase,Rename,Set Attribute fns
- ;
- LAST3 = . ;must be <= bdosbase+09BCh
- ;
- ;
- ;patch ERAFILE reference to its new location
- ;
- .loc (DELFILE+3)
- CALL ERAFILE
- ;
- .end