[comp.sys.m6809] New, improved Makdir utility

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 --/

-------------------------------