dml@loral.UUCP (11/18/86)
This one fixes something that's bothered me for a long time. Whenever
you make a directory, OS-9 allocates it 8 sectors, which is enough
space for 62 entries. Most of the time this is a waste; a lot of
directories never get more than 10 or 12 entries. Two sectors would be
plenty of room. Then again, sometimes it's not enough. My main system
disk has 87 entries in its CMDS directory now, and I keep writing more.
I mentioned this to Jim Omura a while ago and he said he always wanted
a Makdir that would automatically put the directory name in uppercase.
That sounded like a good idea, so I incorporated that into this program
too. The Root directory looked like it would be a problem, since Format
puts that on, but it turned out to be simple -- just skip the code that
creates the directory.
This program DOES NOT fix, or set, directory size. It merely changes
how many sectors are allocated for the directory's first segment. If
you put in more entries than will fit in the first segment, OS-9 will
still allocate more storage for them. However, if there are no free
sectors adjacent to the initial segment, your directory will become
fragmented, just like it would before if you put in 63 or more entries.
Also, pay heed to the warnings in the program header. If you deallocate
a sector that contains active directory entries, OS-9 can and probably
will write over them. The next time you try to use those files, anything
could happen.
It won't let you set the size to zero sectors.
There's also a good general-purpose numeric input routine built into
the program. It's hard-coded for decimal input here, but it's easy to
change. Just make a variable and store your base in it, and change the
two LDA #10 instructions to LDA NUMBASE. To process hex base (or
larger), make all a-z uppercase, SUBB #7, go to NOTNUMBR if the result
is < $A, and compare the number to NUMBASE. If >= NUMBASE, it's NOTNUMBR.
The routine works like this:
Entry conditions: X --> first character of numeric string
("-->" means "points to")
Exit conditions : X --> first unconvertable character
D = 16-bit converted number
Error conditions: CCR carry bit set if first character is not valid
It's recursive so give it some leeway on the stack. It only needs two
bytes per loop, though - it carries the interim sum in the D register.
For a disk containing sources and binaries of this and a whole lot of
other OS-9 programs, send $10.00 to:
Dave Lewis
4417 Idaho apt 4
San Diego CA 92116
If the program assembles properly, the Ident should be:
Header for: Makdir
Module size: $01F9 #505
Module CRC: $09990E (Good)
Hdr parity: $D3
Exec. off: $0067 #103
Data Size: $00F9 #249
Edition: $02 #2
Ty/La At/Rv: $11 $82
Prog mod, 6809 obj, re-en, R/O
*****************************************************************
*
* Makdir (improved) -- now puts directory name in uppercase and
* allows user to specify how much space to allocate for the
* directory. Defaults to 8 sectors, the same as the standard.
*
* Makdir [-l] [-s#] [-n#] [-r] pathname
*
* -l: Allows lowercase letters in directory name
* -s: Allocates "#" sectors for directory. "#" represents a
* decimal number. Overrides "N" option if both are present.
* -n: Allocates enough space for at least "#" user entries.
* Space for "." and ".." is automatically added.
* -r: Operates on an existing directory, such as the root
* directory of an empty disk. Use this option with extreme
* caution, as it can set up a disk to clobber itself at
* some random time in the future. To be safe, use it only
* on empty directories.
*
* Options must precede the pathname; the option processing
* routine stops looking for them after it finds the path. The
* "-" (minus sign) is required on each option entry.
*
*****************************************************************
*
NAM Makdir
TTL Create Directory
*
* Copyright 1986 by Dave Lewis
* 4417 Idaho apt 4
* San Diego CA 92116
*
IFP1
USE /D0/DEFS/OS9Defs
USE /D0/DEFS/SCFDefs
USE /D0/DEFS/RBFDefs
ENDC
*
REV EQU 2
TYPE EQU PRGRM+OBJCT
ATTR EQU REENT+REV
*
MOD SIZE,NAME,TYPE,ATTR,EXEC,STORG
NAME FCS 'Makdir'
FCB 2 Version number
*
MEMORG RMB 2 Data area origin address
OPTL RMB 1 Upper or upper/lower case
SECTORS RMB 1 Number of sectors in directory
OPTS RMB 1 Nonzero if "S" option
OPTR RMB 1 Nonzero if "R" option
DIRPATH RMB 1 Directory path number
ATPATH RMB 1 Disk @ path number
BMAPOFST RMB 2 Offset to first sector byte
BMAPBIT RMB 1 Bit representing first sector
DIRFDLSN RMB 3 LSN of directory file descriptor
FIRSTSEG RMB 5 First segment entry in FD
SCRATCH EQU . Scratch memory
RMB 180 Stack space
RMB 50 Command line arguments
STORG EQU .
*
ERRMSG FCC 'ERROR: bad arguments'
FCB C$CR
*
GETNUMBR CLRA Start with a zero
CLRB
GETNUMB1 PSHS D Save old sum
LDB ,X+ Get next character
SUBB #'0 Subtract ASCII bias
BLO NOTNUMBR Not a digit if less than $30
CMPB #9 Highest decimal digit
BHI NOTNUMBR Not a digit if over 9
CLRA Make a 16-bit number
PSHS D Save new digit
LDB 3,S Get old LSB
LDA #10 Load base 10
MUL Multiply old LSB
ADDD ,S Add in new digit
STD ,S Save partial product
LDB 2,S Get old MSB
LDA #10 Load base again
MUL Multiply old MSB
TFR B,A Move up 8 bits
CLRB Zero out LSB
ADDD ,S Add partial product
LEAS 4,S Adjust the stack
BSR GETNUMB1 Go get the next digit
ANDCC #^CARRY Clear error condition
RTS Return to caller
NOTNUMBR COMA Set carry for error
LEAX -1,X Point back to invalid char
PULS D,PC Pull current number and return
*
ARGERROR LEAX <ERRMSG,PCR Point to error message
ERROR LDA #2 Write to standard error path
LDY #40 Write 40 bytes maximum
OS9 I$WRITLN Display error message
BRA QUIT Go terminate
*
EXEC STU MEMORG Save pointer to memory area
CLRA Initialize variables to zero
CLRB
STD OPTL Store default values
STD OPTS in all option variables
FINDARGS LDA ,X+ Get next character of args
CMPA #C$SPAC Is it space?
BEQ FINDARGS Keep looking if so
CMPA #C$CR Is it <CR>?
BEQ ARGERROR No pathname if so
CMPA #'- Is it "-"?
BNE MAIN Not an option, must be path
LDA ,X+ Get option identifier
ANDA #$5F Make upper case
CMPA #'L Is it "L"?
BNE NOT.L Try others if not
STA OPTL Set upper/lower case mode
BRA FINDARGS Look for more arguments
NOT.L CMPA #'S Is it "S"?
BNE NOT.S Check for others if not
BSR GETNUMBR Read the number
BCS ARGERROR Error if not at least 1 digit
INC OPTS Indicate "S" option used
TSTB Did some bozo enter 0?
BNE FINDARG2 Number is OK, use it
INCB Make it semi-idiot-proof
FINDARG2 STB SECTORS Store new sector size
BRA FINDARGS Look for more arguments
NOT.S CMPA #'N Is it "N"?
BNE NOT.N Try "R" if not
BSR GETNUMBR Read the number
BCS ARGERROR Error if no number
TST OPTS Was "S" used to set size?
BNE FINDARGS Disregard this one if so
ADDD #9 Add two entries for "." and
LSRA "..", seven for the three
RORB bits that get shifted out,
LSRA and then divide by eight
RORB for the eight entries that
LSRA fit in one sector
RORB
BRA FINDARG2 Store sector count like "S"
NOT.N CMPA #'R Is it "R"? (last chance!)
BNE ARGERROR Oooops!
STA OPTR Set the "R" flag
BRA FINDARGS Look for more arguments
*
MAIN LEAX -1,X Point back to start of path
PSHS Y,X Save memory end and path pointers
TST OPTR Is option "R" on?
BNE SETSIZE Skip directory create if so
TST OPTL Is option "L" on?
BNE CREATE Skip uppercase conversion if so
CASELOOP LDA ,X+ Get next pathlist character
ANDA #$5F Make it uppercase if alpha
CMPA #'A Test for alpha, low bound
BLO TESTEOM Not alpha if less than "A"
CMPA #'Z Test high bound
BHI TESTEOM Not alpha if more than "Z"
STA -1,X Store character if alpha
TESTEOM CMPX 2,S Test for end of memory
BLO CASELOOP Continue if not at end
CREATE LDX ,S Retrieve pathlist pointer
LDB #$AF Attributes: d-e-rewr
OS9 I$MAKDIR Create a new directory
BCS QUIT Abort if error
TST SECTORS If directory size has been
BNE SETSIZE specified, go set it up
CLRB Return no error
QUIT OS9 F$EXIT Terminate the process
*
FRAGERR LEAX <FRAGMSG,PCR Point to error message
LBRA ERROR Print it out and quit
*
FRAGMSG FCC 'ERROR: Directory fragmented'
FCB C$CR
*
SETSIZE PULS X Retrieve pathlist pointer
LDA #DIR.+READ. Access mode: d------r
OS9 I$OPEN Open path to new directory
BCS QUIT Abort if error
STA DIRPATH Save path number
LDS ,S Recover the argument space
LDB #SS.OPT Get Option getstat code
LEAX SCRATCH+1,U Point to free memory
OS9 I$GETSTT Get path options
BCS QUIT Abort if error
LDD #"/D Create "/D#@" string from
STD ,-X the drive number
LDD #"0@ Make the drive number ASCII
ADDA 2,X and tack on the "@"
STD 2,X Store it
LDA #C$CR Terminate the line
STA 4,X with a <CR>
LDA #UPDAT. Access mode: ------wr
OS9 I$OPEN Open the entire disk
BCS QUIT Abort if error
STA ATPATH Save /D#@ path number
LDB SCRATCH+21 Get the directory's file
LDX SCRATCH+22 descriptor's LSN
STB DIRFDLSN Save it for later
STX DIRFDLSN+1 All 24 bits of it
BSR SEEKSEG1 Point to first segment entry
OS9 I$READ Read first two entries
BCS QUIT Abort if error
LDD SCRATCH+3 Get size of second segment
BNE FRAGERR Already fragmented if nonzero
LDD FIRSTSEG Get MSB's of LSN
STD SCRATCH Stick in scratch area
LDB FIRSTSEG+2 Move the LSB too
STB SCRATCH+2
CLRA Initialize bit counter
LDB #3 Initialize loop index
FINDBIT LSR SCRATCH Divide the LSN by 8, catching
ROR SCRATCH+1 the remainder in ACC A
ROR SCRATCH+2 This finds the byte and bit
RORA representing the file's
DECB first sector
BNE FINDBIT Repeat if not zero
*
* Normalize the remainder, which now looks like:
*
* ACC A 7654 3210 C (carry bit)
* bbb0 0000 X bbb = rem X = don't care
*
LSLA bb00 0000 b
ROLA b000 000b b
ROLA 0000 00bb b
ROLA 0000 0bbb 0
STA BMAPBIT Save bit number
LDD SCRATCH+1 Get byte number
INCA Add $100 for sector 0
STD BMAPOFST Save absolute offset on disk
*
* Get ten bytes from the disk sector allocation map,
* starting with the byte containing the bit that
* represents the first sector in the directory (the
* one containing the "." and ".." entries).
* This represents space for at least 582 entries.
*
BSR SEEKMAP Point into allocation map
OS9 I$READ Read the allocation data
BCS QUIT2 Abort if error
CLRA Make MSB zero
LDB SECTORS Get new directory size
SUBB FIRSTSEG+4 Subtract current size
BMI REDUCE If negative go make it smaller
TFR D,Y Number of sectors to Y
LDB BMAPBIT Get sector offset in byte
ADDB FIRSTSEG+4 Add sectors in file
LEAU 9,X Point to end of data
PSHS D Save start point
OS9 F$SCHBIT Find free sectors
BCS CANTEXP Error: no room to expand
CMPD ,S++ Can it be extended in one
BNE CANTEXP continuous segment?
OS9 F$ALLBIT If so, allocate the space
EXIT BCS QUIT2 Abort if error
BSR SEEKMAP Point to where data came from
OS9 I$WRITE Write updated map back
BCS QUIT2 Abort if error
LDX DIRFDLSN+1 Get LSB's of sector number
BSR SEEKSEG1 Point to first segment
LEAY -5,Y Only 5 bytes this time
LDB SECTORS Get new directory size
STB FIRSTSEG+4 Update segment entry
CLRB Prevent pesky error message
OS9 I$WRITE Write the new entry back
QUIT2 LBRA QUIT The end, error or no error
*
REDUCE NEGB How much smaller?
TFR D,Y Put reduction in Y
LDB BMAPBIT Get offset to sector 1
ADDB SECTORS Add in desired size
OS9 F$DELBIT Deallocate excess sectors
BRA EXIT Go finish up
*
SEEKSEG1 LDB #16 Offset 16 into file descriptor
PSHS B Store file position LSB
LDB DIRFDLSN Get MSB of sector number
PSHS X,B Push three bytes on the stack
PULS X,U Pull it off realigned
OS9 I$SEEK Seek to the descriptor
BCS QUIT2 Abort if error
LDU MEMORG Point to start of memory
LEAX FIRSTSEG,U Point to segment buffer
BRA SEEKMAP2 Steal LDY - it's big
*
SEEKMAP LDU BMAPOFST It's needed in register U
LDX #0 Zero out upper 16 bits
LDA ATPATH Get /D#@ path number
OS9 I$SEEK Seek to file's bit map
BCS QUIT2 Abort if error
LDU MEMORG Point to memory area
LEAX SCRATCH,U Point to data buffer
SEEKMAP2 LDY #10 Transfer ten bytes
RTS
*
CANTEXP LEAX <EXPMSG,PCR Point to error message
LBRA ERROR Complain and quit
*
EXPMSG FCC 'ERROR: can't expand directory'
FCB C$CR
*
EMOD Insert CRC bytes
SIZE EQU * Total size of module
END
-------------------------------
Dave Lewis Loral Instrumentation San Diego
hp-sdd --\ ihnp4 --\
sdcrdcf --\ bang --\ kontron -\
csndvax ---\ calmasd -->-->!crash --\
celerity --->------->!sdcsvax!sdcc3 --->--->!loral!dml (uucp)
dcdwest ---/ gould9 --/
-------------------------------