home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-07-13 | 71.3 KB | 1,363 lines |
- Path: uunet!seismo!sundc!pitstop!sun!amdcad!ames!ll-xn!adelie!necntc!ncoast!allbery
- From: dave@safari.UUCP
- Newsgroups: comp.sources.misc
- Subject: Disk Usage for VAX/VMS
- Keywords: vms, not-shar, not-c
- Message-ID: <4771@ncoast.UUCP>
- Date: 29 Sep 87 20:37:26 GMT
- Sender: allbery@ncoast.UUCP
- Lines: 1350
- Approved: allbery@ncoast.UUCP
- X-Archive: comp.sources.misc/8709/19
-
- This is a program for VAX/VMS users interested in finding out not only
- where their disk space is going, but also where the most significant
- changes are occuring.
-
- -------------------------- Cut Here --------------------------------
-
- .title DISK_USAGE Provides information on disk usage
- ;------------------------------------------------------------------------
- ;
- ; DISK_USAGE 8/87 D.A. Munroe
- ;
- ;
- ; Overview:
- ; ---------
- ; This program shows disk usage in terms of the directory structure.
- ; By the use of comparison files, shows where the most significant
- ; changes are occurring.
- ;
- ; As explained below, this program makes use of a data file produced
- ; by the ANALYZE/DISK_STRUCTURE command and as a result produces two
- ; files: a listing file and a comparison file.
- ;
- ;
- ; The listing file:
- ; -----------------
- ; This file shows how many files and blocks are in use by each directory
- ; and subdirectory. The entries are organized in both an alphabetical
- ; and a heirarchical order which reflects the directory structure. The
- ; file count and block usage information for a parent directory includes
- ; all the files and blocks of its subdirectories. In addition, the
- ; listing file also provides such information as the volume name, owner
- ; name, and the time when the usage data file (from ANALYZE/DISK_STRUCTURE)
- ; was created.
- ;
- ; If a comparison file (described below) was provided as input to this
- ; program, then the listing will also show how much increase or decrease
- ; there was per directory, in terms of blocks allocated. The comparison
- ; file provides a way of showing how much change there has been between
- ; the last time this program has been run and the current run.
- ;
- ; Notes:
- ; 1. If a directory is empty (has no files) it will not appear
- ; in the listing because ANALYZE/DISK_USAGE will not generate
- ; an entry for it in the data file.
- ;
- ; 2. The value for blocks allocated includes those for the file
- ; header, thus this value is larger than what you see from the
- ; DIRECTORY command.
- ;
- ; 3. Files marked for deletion, but which have not actually been
- ; deleted yet, will appear at the top of the listing with no
- ; parent directory.
-
-
- ; The comparison file:
- ; --------------------
- ; Each run of this program generates a comparison file as output which
- ; is intended to be used as input for the next run of this program. If
- ; no input comparison file is available, the program will run normally,
- ; but will not be able to show changes on the listing. This will be the
- ; case on the first run of this program.
- ;
- ; This program will check that the comparison file corresponding to one
- ; disk cannot be used as comparison for an entirely different disk; the
- ; program is able to handle and does take into account addition or deletion
- ; of directories when doing comparisons.
- ;
- ; In order to better keep track of listing and comparison files on systems
- ; with more than one disk, it is recommended that the user of this program
- ; provide descriptive names which override the default file specifications
- ; used by this program.
- ;
- ;
- ; Invoking the program:
- ; ---------------------
- ; In order to run this program you first need to issue the command:
- ;
- ; $ ANALYZE/DISK_STRUCTURE device:/USAGE=filespec
- ;
- ; which will produce a data file file for input to this program (the
- ; default filespec is USAGE.DAT).
- ;
- ; This program is intended to be invoked as a foreign command. If the
- ; program resides in sys$system, you would first enter the definition:
- ;
- ; $ DISK_USAGE := "$SYS$SYSTEM:DISK_USAGE"
- ;
- ; then to run the program, issue the command:
- ;
- ; $ DISK_USAGE [filespec]
- ;
- ; where "USAGE.DAT" is the default filename of a data file created
- ; by ANALYZE/DISK_STRUCTURE. A typical approach in using this
- ; program would be to first do:
- ;
- ; $ ANALYZE/DISK_STRUCTURE _DUA0:/USAGE=DUA0_USAGE
- ; $ DISK_USAGE DUA0_USAGE
- ;
- ; then use a similar sequence with DUA1 and so on. The default
- ; filespec is SYS$MANAGER:USAGE.DAT but may be overridden by a
- ; user provided filespec on the command line.
-
-
- ; Files used (defaults):
- ; ----------------------
- ; inputs:
- ;
- ; sys$manager:usage.dat usage data from ANALYZE/DISK_STRUCTURE
- ; sys$manager:usage.cmp (optional) comparison file, from a prior
- ; run of this program
- ;
- ; outputs:
- ;
- ; sys$manager:usage.lis listing of disk usage information
- ; sys$manager:usage.cmp for use in comparing one run of this
- ; program with the next
- ;
- ;
- ; Additional information:
- ; -----------------------
- ; A complete description of the ANALYZE/DISK_STRUCTURE command and
- ; the format of the USAGE.DAT file is given in the VMS documentation
- ; of the VERIFY utility and in the $USGDEF module of STARLET.MLB .
- ;
- ; Comments, corrections, and suggestions should be sent to:
- ;
- ; David A. Munroe
- ; Capital Cities Communications/ABC
- ; 7818 SE Stark Ave
- ; Portland, Oregon 97215
- ; (503) 251-7533
- ;
- ; uucp: ...tektronix!reed!omen!safari!dave
- ; ...ptsfa!safari!dave
- ; ...ihnp4!safari!dave
- ;
- ;------------------------------------------------------------------------
-
-
- $RMSDEF
- $USGDEF
-
- ; primary definitions
-
- version = 212. ; see .ident and version_msg
-
- cmp_field_size = 8 ; for showing usage difference
- cmp_size = 512. ; record size for USAGE.CMP files
- indent_value = 4 ; spacing before each subdirectory
- lis_size = 80. ; max record size for USAGE.LIS
- max_name_size = 39. ; for file and directory names
- max_nodes = 2000. ; depends on number of .DIR entries
- q_stack_size = 64. ; for comparison tree traversal
-
-
- ;--------------------------------------------------------------------------------
- ; Macros
- ;--------------------------------------------------------------------------------
-
- ; generate general purpose string descriptor
-
- .macro string_dsc buffer,size
- .word size ; output buffer size
- .byte DSC$K_DTYPE_T ; text data type
- .byte DSC$K_CLASS_S ; string descriptor class
- .address buffer ; address of output buffer
- .endm
-
- ; format a value using FA0 and write it to the output file
-
- .macro write_fmt item,fao_p1,fao_p2=#0,?ok
- $fao_s -
- ctrstr = 'item'_fmt,- ; descriptor for format control string
- outlen = fao_outlen,- ; where to store length of formatted output
- outbuf = fao_outbuf,- ; descriptor for formatted output buffer
- p1 = fao_p1,-
- p2 = fao_p2
- blbs r0,ok ; branch if converted ok
- movab 'item'_cvt_msg,r0 ; else set up to write error message
- bsbw write_msg ;
- brw done ;
-
- ok: cvtwb fao_outlen,lis_outlen ; set length of formatted output
- movab lis_outlen,r0 ; .ASCIC format
- bsbw write_msg ; write it
- .endm
-
-
- .ident \v2.12\ ; 10-Sep-1987 D.A. Munroe
- .psect CODE,nowrt,exe
- .entry DISK_USAGE,^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
-
- ;----------------------------------------------------------------
- ; Look at the command line to see if the user provided
- ; anything to override the default file name. If this
- ; program is invoked with a line such as:
- ;
- ; $ DISK_USAGE DUA0
- ;
- ; then the effect of calling lib$get_foreign is to put
- ; "DUA0" in fname_buff (via fname_dsc). This will then
- ; override the "USAGE" default so that we will expect
- ; to work with:
- ;
- ; sys$manager:dua0.dat (the usage data file)
- ; sys$manager:dua0.cmp (optional input comparison file)
- ;
- ; sys$manager:dua0.lis (usage listing file)
- ; sys$manager:dua0.cmp (new output comparison file)
- ;
- ; Similarly, the user could have specified something like:
- ;
- ; $ DISK_USAGE SYS$USER:[DAVE]
- ;
- ; to redirect where the files are placed.
- ;
- ;----------------------------------------------------------------
-
- gcml: pushaw fname_length ; where to put resulting length
- clrl -(sp) ; no prompt string
- pushaq fname_dsc ; descriptor for default name
- calls #3,g^lib$get_foreign ; look at command line
- blbs r0,10$ ; continue if ok
- ret ; else exit w/status in r0
- 10$:
- ;--------------------------------------------------------------------------------
- ; At this point if the user has provided a name, it will be in fname_buff
- ; and r2 will be its length. Otherwise, r2 will be zero and the default
- ; of sys$manager:usage.dat will be used.
- ;--------------------------------------------------------------------------------
-
-
- ;--------------------------------------------------------------------------------
- ; Open files and connect streams.
- ;
- ; The fna field of the data fab is a pointer to the filename
- ; buffer (which may or may not contain "usage" at this time).
- ;--------------------------------------------------------------------------------
-
- open: cvtwb fname_length,data_fab+fab$b_fns ; set filename length
- $open fab = data_fab ; open USAGE.DAT
- blbs r0,5$ ; branch if ok
- brw file_error ;
-
- 5$: $create fab = lis_fab ; create USAGE.LIS
- blbs r0,10$ ; branch if ok
- brw file_error ;
-
- 10$: movb #1,r3 ; assume USAGE.CMP (input) exists
- $open fab = icmp_fab ; try to open USAGE.CMP
- blbs r0,15$ ; branch if it exists
- clrb r3 ; nope
- cmpl r0,#RMS$_FNF ; skip if file not found
- beql 15$ ;
- brw file_error ;
-
- 15$: movb r3,icmp_state ; USAGE.CMP (input) status
- $create fab = ocmp_fab ; create USAGE.CMP (output)
- blbs r0,20$ ; branch if ok
- brw file_error ;
-
- 20$: $connect rab = data_rab ; connect rab for USAGE.DAT
- blbs r0,25$ ; branch if ok
- brw record_error ;
-
- 25$: $connect rab = lis_rab ; connect rab for USAGE.LIS
- blbs r0,30$ ; branch if ok
- brw record_error ;
-
- 30$: tstb r3 ; USAGE.CMP (input) exists?
- beql 35$ ; branch if not
- $connect rab = icmp_rab ; connect rab for USAGE.CMP (input)
- blbs r0,35$ ; branch if ok
- brw record_error ;
-
- 35$: $connect rab = ocmp_rab ; connect rab for USAGE.CMP (output)
- blbs r0,40$ ; branch if ok
- brw record_error ;
-
- 40$:
-
-
- ;--------------------------------------------------------------------------------
- ; The IDENT record should be the first record in the file; we read
- ; it in, verify it, and print the contents of its fields
- ;--------------------------------------------------------------------------------
- ident:
- $get rab = data_rab ; read ident record
- blbs r0,5$ ; branch if ok
- moval data_rab,r2 ;
- brw record_error ;
-
- 5$: movab version_msg,r0 ; show program version
- bsbw write_msg ;
-
- cmpw #USG$C_IDENT_LEN,data_rab+rab$w_rsz ; length ok?
- beql 10$
- movab ident_len_msg,r0 ; print msg if length not ok
- bsbw write_msg ;
- brw done ;
-
- 10$: movab data_buff,r6 ; address of ident record
- cmpb #USG$K_IDENT,USG$B_TYPE(r6) ; record type ok?
- beql 15$ ; branch if ok
- movab not_ident_msg,r0 ;
- bsbw write_msg ;
- brw done ;
-
- ;--------------------------------------------------------------------------------
- ; The write_fmt macro is used to format and and write the contents
- ; of the IDENT record
- ;--------------------------------------------------------------------------------
-
- 15$: write_fmt - ; creation time
- item = time,-
- fao_p1 = #data_buff+USG$Q_TIME
-
- write_fmt - ; volume serial number
- item = serial,-
- fao_p1 = USG$L_SERIALNUM(r6)
-
- write_fmt - ; structure (volume set) name
- item = strucname,-
- fao_p1 = #USG$S_STRUCNAME,-
- fao_p2 = #data_buff+USG$T_STRUCNAME
-
- write_fmt - ; volume name
- item = volname,-
- fao_p1 = #USG$S_VOLNAME,-
- fao_p2 = #data_buff+USG$T_VOLNAME
-
- write_fmt - ; ownername (of volume)
- item = ownername,-
- fao_p1 = #USG$S_OWNERNAME,-
- fao_p2 = #data_buff+USG$T_OWNERNAME
-
- write_fmt - ; file format
- item = format,-
- fao_p1 = #USG$S_FORMAT,-
- fao_p2 = #data_buff+USG$T_FORMAT
-
- bsbw blank_line ; write blank line
-
-
- ;--------------------------------------------------------------------------------
- ; Comparison file initialization.
- ;
- ; The code below does two things:
- ;
- ; - it initializes the data structures for the first part
- ; of the output comparison file
- ;
- ; - if an input comparison file exists, it reads in the
- ; file's IDENT record and checks whether the file can
- ; be used for comparison
- ;
- ; The IDENT record from the USAGE.DAT file is used as the first part of
- ; the output USAGE.CMP file.
- ;
- ; To uniquely identify a comparison file, its USG$B_TYPE field has the
- ; value -USG$K_IDENT (note the negation). The program's version number
- ; is also stored in the comparison file as a check on the integrity of the
- ; file (a comparison file created by a different version of this program
- ; may not have compatible pointer values in the tree structure).
- ;
- ; When a comparison file is read in, we need to do these checks before
- ; we can accept it as a comparison file:
- ;
- ; - we need to make sure it is in fact a comparison file by
- ; checking USG$B_TYPE for the value -USG$K_IDENT
- ;
- ; - we need to make sure it's for the same disk volume
- ;
- ; - we need to check that it was created by the same version
- ; of the program
- ;
- ;--------------------------------------------------------------------------------
- cmp_init:
-
- ; intialize the data structures for the first part of the output .CMP file
-
- mnegb #USG$K_IDENT,USG$B_TYPE(r6) ; identifies .CMP file
- movc3 #USG$C_IDENT_LEN,(r6),tree_ident
- movw #version,tree_version
-
- ; if an input .CMP file exists, do some tests before accepting it
-
- movb icmp_state,r7 ; does it exist?
- bneq 10$ ; branch if yes
- movab no_icmp_msg,r0 ; say no input .CMP
- bsbw write_msg ;
- brw 70$ ;
-
- 10$: movab cmp_tree_ident,r8 ; input address
- movl r8,icmp_rab+rab$l_ubf ;
- movl #cmp_size,icmp_rab+rab$w_usz ; set size
- $get rab = icmp_rab ; read first part
- blbs r0,20$ ; branch if ok
- moval icmp_rab,r2 ;
- brw record_error ;
-
- 20$: cmpb USG$B_TYPE(r8),#-USG$K_IDENT ; really .CMP file?
- beql 25$ ; branch if yes
- movab wrong_type_msg,r0 ;
- brb 40$ ;
- 25$: cmpc3 #USG$S_VOLNAME,- ; volume names match?
- USG$T_VOLNAME(r6),- ;
- USG$T_VOLNAME(r8) ;
- beql 30$ ; branch if yes
- movab wrong_volume_msg,r0 ;
- brb 40$ ;
-
- 30$: cmpw #version,cmp_tree_version ; versions match?
- bneq 35$ ; branch if not
- ; else all is ok
- write_fmt - ; show .CMP creation time
- item = icmp_time,-
- fao_p1 = #cmp_tree_ident+USG$Q_TIME
- brb 70$
-
- 35$: movab wrong_version_msg,r0 ;
- 40$: bsbw write_msg ; report discrepancy
- movb #-1,icmp_state ; set .CMP status
-
- ;-------- we finish with icmp_state set properly --------;
-
- 70$: bsbw blank_line
-
-
- ;--------------------------------------------------------------------------------
- ; If we have a proper input comparison file, we read it in.
- ;--------------------------------------------------------------------------------
- read_cmp: tstb icmp_state ; check status
- bgtr 10$ ; branch if ok
- brw tree_init ; else ignore comparison file
-
- 10$: addl2 #cmp_size,icmp_rab+rab$l_ubf ; set address
- $get rab = icmp_rab ; read first part
- blbs r0,10$ ; loop back if ok
- cmpl r0,#RMS$_EOF ; exit loop if eof
- beql relink ;
- moval icmp_rab,r2 ; else some other error
- brw record_error ;
-
-
- ;--------------------------------------------------------------------------------
- ; Relink comparison tree
- ;
- ; The next_sibling and first_child links for each node in the comparison
- ; tree contain the values that they had when the tree was built. These
- ; values are addresses within "tree" itself and are relative to the DATA
- ; psect. On being read back in, they need to be adjusted to point into
- ; "cmp_tree". Although it is possible to make the links relative to the
- ; base of the tree itself, the extra code that would be needed in every
- ; reference to a link would have made the code for tree building and tree
- ; comparison very awkward. Thus, by not choosing that method and doing
- ; this relinking step instead, the process of tree building and comparison
- ; is straightforward.
- ;
- ; This relinking step does not guarantee comparison files to be compatible
- ; across different versions of this program, however (even if the relative
- ; distance between the two trees remains the same).
- ;
- ; We traverse cmp_tree and adjust all the links by the value of
- ; cmp_tree - tree. Note also that a tree is guaranteed to have at least
- ; one node.
- ;--------------------------------------------------------------------------------
- relink: pushl #0 ; indicates when to stop
- movab cmp_tree,r1 ; used to traverse tree
- subl3 #tree,r1,r2 ; adjustment value
- 10$: movl first_child(r1),r0 ; child exists?
- beql 20$ ; branch if not
- pushl r1 ; else save our place
- addl2 r2,r0 ; adjust child pointer
- movl r0,first_child(r1) ;
- movl r0,r1 ; descend to child
- brb 10$ ; continue
-
- 20$: movl next_sibling(r1),r0 ; sibling exists?
- beql 30$ ; branch if not
- addl r2,r0 ; adjust sibling pointer
- movl r0,next_sibling(r1) ;
- movl r0,r1 ; go to sibling
- brb 10$ ; test for child
-
- 30$: movl (sp)+,r1 ; restore our place
- bneq 20$ ; continue if not done
-
- ; At this point, the comprison file has been read in and relinked
-
-
- ;--------------------------------------------------------------------------------
- ;
- ; Read USAGE.DAT and accumulate usage information
- ;
- ; Here we read the FILE records and build a tree representing the logical
- ; structure of directories on the disk. For every file on the disk there
- ; is a FILE record in the USAGE.DAT file. The FILE record contains, among
- ; other things, the complete file specification and the number of blocks
- ; used and allocated. As part of the tree building process, the usage
- ; information for a file is summed into that file's parent directory and
- ; all subsequent parent directories, including totals for the entire disk.
- ;
- ; Here is a simple overview of the algorithm; specific details and data
- ; structures are given in the appropriate part of the code.
- ;
- ; T1 [initialization] Set totals to 0. Create first node of tree.
- ;
- ; T2 [new file] Read a record from USAGE.DAT. If end-of-file, then the
- ; algorithm terminates. Otherwise add usage data into totals,
- ; set a pointer (p) to the first node, and set current branch name
- ; (bn) to the first branch name in the directory specification.
- ;
- ; T3 [scan for branch] Starting from p and following the next_sibling chain,
- ; scan all nodes for a match with bn. If a match is found, set p and
- ; go to step T5. If a match is not found (either because end of chain
- ; or bn is lexically less than the name in the next node), continue
- ; on with step T4.
- ;
- ; T4 [new sibling] Create a new node, add it to the next_sibling chain, and
- ; set p to it.
- ;
- ; T5 [accumulate] The usage information in the record is added into node p.
- ;
- ; T6 [follow branch name] If there is another branch name in the directory
- ; specification, then set bn to that and go on to the next step.
- ; Otherwise we are done with this file and go back to step T2.
- ;
- ; T7 [descend to child node] If node p has a child node, then set p to
- ; that and go to step T3. Otherwise, create a child node and
- ; set p to that. Go on to step T5.
- ;
- ; Register usage:
- ;
- ; r6 = pointer to data_buff (the current FILE record)
- ; r7 = pointer to found node in the tree
- ; r8 = pointer to first character in a branch name
- ; r9 = length of branch name
- ; r10 = count of available nodes in the tree
- ; r11 = pointer to next available node
- ;--------------------------------------------------------------------------------
-
-
- ;--------------------------------------------------------------------------------
- ; Initialization: set totals to zero, create first node of tree
- ;--------------------------------------------------------------------------------
- tree_init: moval tree_total_files,r0 ; clear totals:
- clrl (r0)+ ; total files
- clrl (r0)+ ; total blocks used
- clrl (r0) ; total blocks allocated
-
- movl #max_nodes,r10 ; ready to create first node
- bgtr 10$ ; should have room for it
- brw no_space ; else error
-
- 10$: movab tree,r11 ; r11 points to node in tree
- clrb branch_name(r11) ; branch name is null: []
- clrb name_length(r11) ; length is 0
- clrl file_count(r11) ; no files
- clrl blocks_used(r11) ; no blocks used
- clrl blocks_allocated(r11) ; no blocks allocated
- clrl next_sibling(r11) ; no sibling nodes
- clrl first_child(r11) ; no child nodes
- addl2 #node_size,r11 ; update ptr to next avail node
- decl r10 ; decrement node count
-
- ;--------------------------------------------------------------------------------
- ; New file: read a record from USAGE.DAT, add usage data into totals,
- ; look at first branch name in the directory specification
- ;--------------------------------------------------------------------------------
- new_file: $get rab = data_rab ; read FILE record
- blbs r0,10$ ; branch if ok
- cmpl r0,#RMS$_EOF ; test and branch if eof
- beql 5$ ;
- moval data_rab,r2 ;
- brw record_error ; else error
-
- 5$: brw print_tree ; on eof, print the tree
-
- 10$: cmpb #USG$K_FILE,USG$B_TYPE(r6) ; record type ok?
- beql 20$ ; branch if ok
- movab not_file_msg,r0 ;
- bsbw write_msg ;
- brw done ;
-
- 20$: moval tree_total_files,r0 ; ready to update totals
- incl (r0)+ ; total files
- addl2 USG$L_USED(r6),(r0)+ ; total used
- addl2 USG$L_ALLOCATED(r6),(r0) ; total allocated
-
- movab tree,r7 ; ptr to first node in tree
-
- ;--------------------------------------------------------------------------------
- ; Setup for first branch name: for a branch name such as "[abc.de.fghij]",
- ; we set r8 to point to "a" and set r9 = 3. We also decrement the count
- ; in USG$W_DIR_LEN in order to simplify things later on.
- ;--------------------------------------------------------------------------------
- movab USG$T_FILESPEC+1(r6),r8 ; ptr to branch name
- cvtwl USG$W_DIR_LEN(r6),r9 ; full directory spec length
- subl2 #2,r9 ; discount "[" and "]"
- subw2 #2,USG$W_DIR_LEN(r6) ;
- beql 40$ ; branch if null name
- locc #^a\.\,r9,(r8) ; scan for "."
- beql 40$ ; branch if not found
- subl2 r0,r9 ; set name length
- decw USG$W_DIR_LEN(r6) ; remove "." from length
- 40$: ; r9 now set properly
- subw2 r9,USG$W_DIR_LEN(r6) ; set remaining length
-
- ;--------------------------------------------------------------------------------
- ; Scan: scan the nodes in the tree looking for a match with the current
- ; branch name. Here we have:
- ;
- ; r7 = node p (name) pointer
- ; r1 = node p name length
- ; r8 = current branch name pointer
- ; r9 = current branch name length
- ;
- ; Note: cmpc5 uses r0..r3, the shorter name is zero-filled
- ;--------------------------------------------------------------------------------
- scan: cvtbw name_length(r7),r1 ; cmpc needs word operand
- cmpc5 r9,(r8),#0,r1,(r7) ; compare current to node p
- beql accumulate ; branch if match
- blss new_sibling ; branch if went too far
-
- ; no match, advance to next node
- movl r7,r5 ; save node pointer
- movl next_sibling(r7),r7 ; advance along node chain
- bneq scan ; branch to test next node
-
- ;----------------------------------------------------------------------------------
- ; New sibling: we arrive here either if the current branch name is lexically
- ; less than the branch name at node p (r7) or if we're at the end of the
- ; node chain. In either case, r5 points to the node to which we will link
- ; a new one. Note that since the initial node has a null name, this also
- ; guarantees at least one pass through the above loop and that r5 will get
- ; a chance to be set to a valid value.
- ;
- ; We fill in the fields of the new node according to the FILE record's
- ; fields. Since filling in the node information encompasses the "accumulate"
- ; step, we can really skip that part.
- ;----------------------------------------------------------------------------------
- new_sibling: decl r10 ; decrement node count
- bgeq 10$ ; branch if we have room
- brw no_space ; else count had been zero
-
- 10$: movl #1,file_count(r11) ; first file in new directory
- movl USG$L_USED(r6),blocks_used(r11) ; set blocks used/allocated
- movl USG$L_ALLOCATED(r6),blocks_allocated(r11)
- movl next_sibling(r5),next_sibling(r11) ; copy from prev node
- movl r11,next_sibling(r5) ; prev node now points here
- clrl first_child(r11) ; no child nodes yet
- movb r9,name_length(r11) ; name length fits in a byte
- movc3 r9,(r8),branch_name(r11) ; movc3 uses r0..r5
- movl r11,r7 ; set node pointer
- addl2 #node_size,r11 ; point to next available node
- brb follow ; we've done "accumulate"
-
- ;----------------------------------------------------------------------------------
- ; Accumulate: usage information for the current FILE record is added into
- ; node p
- ;----------------------------------------------------------------------------------
- accumulate: incl file_count(r7) ; another file in this dir
- addl2 USG$L_USED(r6),blocks_used(r7) ; set blocks used/allocated
- addl2 USG$L_ALLOCATED(r6),blocks_allocated(r7)
-
- ;----------------------------------------------------------------------------------
- ; Follow: if there's another branch name in the directory specification,
- ; we set the current branch name to that in preparation for creating a
- ; child node. Otherwise, we are done with this file.
- ;----------------------------------------------------------------------------------
- follow: addl2 r9,r8 ; possible next branch name
- incl r8 ;
- cvtwl USG$W_DIR_LEN(r6),r9 ; get remaining length
- bneq 10$ ; branch if more to do
- brw new_file ; else done with this file
-
- 10$: locc #^a\.\,r9,(r8) ; scan for "."
- beql 40$ ; branch if not found
- subl2 r0,r9 ; set name length
- decw USG$W_DIR_LEN(r6) ; remove "." from length
- 40$: ; r9 now set properly
- subw2 r9,USG$W_DIR_LEN(r6) ; set remaining length
-
- ;----------------------------------------------------------------------------------
- ; Descend: on following the new branch name, if node p has a child node
- ; we set p to that and go back to scan the child nodes. Otherwise we
- ; create a child node. The code here is very similar to that in creating
- ; a new sibling.
- ;----------------------------------------------------------------------------------
- descend: movl r7,r0 ; point to the parent
- movl first_child(r7),r7 ; child node?
- beql 10$ ; branch if not
- brw scan ; else scan child nodes
-
- 10$: decl r10 ; decrement node count
- bgeq 20$ ; branch if we have room
- brw no_space ; else count had been zero
-
- 20$: movl r11,first_child(r0) ; parent points to new child
- movc3 r9,(r8),branch_name(r11) ; set name of child node
- movb r9,name_length(r11) ; name length fits in a byte
- movl #1,file_count(r11) ; first file in new directory
- movl USG$L_USED(r6),blocks_used(r11) ; set blocks used/allocated
- movl USG$L_ALLOCATED(r6),blocks_allocated(r11)
- clrl next_sibling(r11) ; no siblings yet
- clrl first_child(r11) ; no child nodes yet
- movl r11,r7 ; set node pointer
- addl2 #node_size,r11 ; point to next available node
- brb follow ; we've done "accumulate"
-
-
- ;--------------------------------------------------------------------------------
- ; Compare and print the tree, with indentation to reflect the hierarchy
- ;
- ; If we have an input comparison file, then we traverse both trees
- ; simultaneoulsy and print information on which directories have
- ; changed and by how much.
- ;
- ; Here is a simplified overview of the algorithm used to compare the two
- ; trees:
- ;
- ; Algorithm C [compare trees] We have two trees: the current tree and the
- ; comparison tree. Each node in a tree represents either a directory or
- ; subdirectory. At any given level, all the nodes in that level are linked
- ; in lexical order. We let p be a pointer to a node in the current tree and
- ; let q be the corresponding pointer in the comparison tree. The approach
- ; used is to let p walk through the nodes of p while attempting to track
- ; this movement with q in cmp_tree. In addition, we have two variables,
- ; p_level and q_level, and two stacks, p_stack and q_stack, which are used
- ; in keeping track of our position.
- ;
- ; C1 [initialization] Push a 0 onto p_stack; when this value gets popped
- ; off, the algorithm will terminate. Set both p_level and q_level
- ; to 1, set p to the first node in tree, and q to the first node
- ; in cmp_tree.
- ;
- ; C2 [clear comparison string] Set cmp_string to to blanks. This string
- ; provides the information in the "change" column. If a directory in
- ; tree has no counterpart in cmp_tree, this string remains blank.
- ;
- ; C3 [compare levels] If q_level is greater than p_level, then pop q_stack
- ; to get new values for q and q_level and repeat this step.
- ; Otherwise, if q_level = p_level then go on to step C4, or if
- ; q_level is less than p_level, go on to step C6.
- ;
- ; C4 [compare nodes] If node q does not exist (i.e. has the value 0),
- ; then go on to step C6. Otherwise compare name(q) with name(p).
- ; If name(q) is less than name(p), set q to its next sibling and
- ; repeat this step. If name(q) = name(p) continue with step C5.
- ; If name(q) is greater than name(p), go on to step C6.
- ;
- ; C5 [set difference] Set cmp_string to the difference in blocks_allocated(p)
- ; and blocks_allocated(q).
- ;
- ; C6 [output] Output disk usage information for node p, incorporating the
- ; information in cmp_string.
- ;
- ; C7 [next directory] If node p has any child nodes, go on to step C9.
- ; Otherwise, set p to its next sibling and continue with step C8.
- ;
- ; C8 [check continuation] If node p exists, then continue with step C2.
- ; Otherwise, pop p_stack to get new values for p_level and p.
- ; If p is 0, then the algorithm terminates. Otherwise, go on
- ; with step C2.
- ;
- ; C9 [set p continuation] If node p has a next sibling, push a pointer
- ; to it onto p_stack along with the current value of p_level.
- ;
- ; C10 [descend in tree] Increment p_level and set p to its child node.
- ;
- ; C11 [check q correspondence] If q_level is equal to what p_level was
- ; just recently (e.g. p_level - 1) and node q has a child node,
- ; then go on to the next step, otherwise go to step C2.
- ;
- ; C12 [set q continuation] If node q has a next sibling, push a pointer
- ; to it onto q_stack along with the current value of q_level.
- ;
- ; C13 [descend in cmp_tree] Increment q_level, set q to its child node,
- ; and go to step C2.
- ;
- ; Register usage:
- ;
- ; r0..r3 = scratch, also used by cmpc instruction
- ; r4 = copy of icmp_state
- ; r5 = indentation amount
- ; r6 = p_level
- ; r7 = p
- ; r8 = q_level
- ; r9 = q
- ; r10 = q_stack pointer
- ; r11 = pointer to next available node (we need this for later)
- ;
- ; NOTE: if no input comparison file is being used, we avoid doing anything
- ; with the comparison tree.
- ;--------------------------------------------------------------------------------
-
- print_tree:
- movab heading_msg,r0 ; write heading & blank line
- bsbw write_msg ;
- bsbw blank_line ;
-
- ;--------------------------------------------------------------------------------
- ; Initialization: initialize stacks, levels, and node pointers. The
- ; current indentation amount is also saved on the stack.
- ;--------------------------------------------------------------------------------
- pushl #0 ; mark p_stack top
- cvtbl #1,r6 ; set p_level to 1
- pushl r6 ; save on p_stack
- movab tree,r7 ; set p to walk through tree
- clrl r5 ; indent amount currently 0
- pushl r5 ; save indent amount
- cvtbl icmp_state,r4 ; use comparison tree?
- bleq clear ; branch if not
- movab q_stack_top,r10 ; initialize q_stack pointer
- movl r6,r8 ; set q_level to 1
- movab cmp_tree,r9 ; set q to walk through cmp_tree
-
- ;--------------------------------------------------------------------------------
- ; The "change" column is blank if there's no comparison file, but when
- ; there is one, we want the "change" column to indicate those directories
- ; that are new and have no equivalent in cmp_tree.
- ;--------------------------------------------------------------------------------
-
- movl new_string,blank_string+4
-
- ;--------------------------------------------------------------------------------
- ; Clear: clear comparison string. At this point we can also skip a lot
- ; of comparison code if there is no comparison tree.
- ;--------------------------------------------------------------------------------
- clear: movq blank_string,cmp_string ; set comparison string to blanks
- tstl r4 ; use comparison tree?
- bgtr cmp_levels ; branch if yes
- brw output ; else skip comparisons
-
- ;--------------------------------------------------------------------------------
- ; Compare levels: if we're further down in cmp_tree than in tree, we try
- ; to come back to the same level in cmp_tree. If we're at the same
- ; level, we go on to compare nodes. If we're further up in cmp_tree
- ; (meaning there's no branch in cmp_tree that corresponds to where we are
- ; in tree), then we skip the comparisons.
- ;--------------------------------------------------------------------------------
- cmp_levels: cmpl r8,r6 ; compare q_level to p_level
- bgtr 10$ ;
- beql cmp_nodes ;
- brw output ;
-
- 10$: movl (r10)+,r8 ; pop q_level from q_stack
- movl (r10)+,r9 ; pop q from q_stack
- brb cmp_levels ; compare again
-
- ;--------------------------------------------------------------------------------
- ; Compare nodes: if node q does not exist (e.g. we've reached the end
- ; of its sibling chain at the current q_level), then we can skip this
- ; comparison. Otherwise we scan forward in q until we either find a
- ; name that matches that in p, or until we've gone too far.
- ;--------------------------------------------------------------------------------
- cmp_nodes: tstl r9 ; does node q exist?
- bneq 10$ ; branch if yes
- brw output ;
-
- 10$: cvtbw name_length(r9),r0 ; get word operands
- cvtbw name_length(r7),r2 ;
- cmpc5 r0,(r9),#0,r2,(r7) ; compare names
- beql set_diff ;
- blss 20$ ;
- brw output ;
-
- 20$: movl next_sibling(r9),r9 ; advance q to next sibling
- brb cmp_nodes ; compare again
-
- ;--------------------------------------------------------------------------------
- ; Set difference: set cmp_string to reflect the difference in blocks
- ; allocated between p and q.
- ;--------------------------------------------------------------------------------
- set_diff: subl3 blocks_allocated(r9),- ; r0 = allocation difference
- blocks_allocated(r7),- ;
- r0 ;
-
- $fao_s - ; set new cmp_string
- ctrstr = cmp_fmt,- ; format control string
- outlen = fao_outlen,- ; where to store length
- outbuf = cmp_outbuf,- ; descriptor for cmp_string
- p1 = r0 ; value to convert = difference
- blbs r0,output ; branch if converted ok
- movab cmp_cvt_msg,r0 ; else write error message
- bsbw write_msg ;
- brw done ;
-
- ;--------------------------------------------------------------------------------
- ; Output: here we write a line of information for the file described
- ; by node p. At this time cmp_string has been set to show the allocation
- ; difference. If a comparison file is not being used, or if there is no
- ; file corresponding to that at node p, cmp_string is blank.
- ;--------------------------------------------------------------------------------
-
- output: cvtbl name_length(r7),r0 ; need longword arg for FA0
- $fao_s -
- ctrstr = tree_fmt,- ; descriptor for format control string
- outlen = fao_outlen,- ; where to store length of formatted output
- outbuf = fao_outbuf,- ; descriptor for formatted output buffer
- p1 = r5,-
- p2 = #indent_string,-
- p3 = r0,-
- p4 = r7,-
- p5 = file_count(r7),-
- p6 = blocks_used(r7),-
- p7 = blocks_allocated(r7),-
- p8 = #cmp_field_size,-
- p9 = #cmp_string
-
- blbs r0,10$ ; branch if converted ok
- movab tree_cvt_msg,r0 ; else set up to write error message
- bsbw write_msg ;
- brw done ;
-
- 10$: cvtwb fao_outlen,lis_outlen ; set length of formatted output
- movab lis_outlen,r0 ; .ASCIC format
- bsbw write_msg ; write it
-
- ;--------------------------------------------------------------------------------
- ; Next directory: if node p has any child nodes, then follow that
- ; path. Otherwise, follow the next_sibling chain.
- ;--------------------------------------------------------------------------------
- next_dir: movl first_child(r7),r0 ; any child nodes?
- bneq set_cont ; branch if yes
- movl next_sibling(r7),r7 ; else go to next sibling
- beql 10$ ; branch if none
- brw clear ; else continue on
-
- 10$: movl (sp)+,r5 ; pop indent amount
- movl (sp)+,r6 ; pop p_level
- movl (sp)+,r7 ; pop p
- beql 20$ ; branch if no more
- bsbw blank_line ; blank line when coming up
- brw clear ; continue on
-
- 20$: brw write_totals ; we're done here
-
- ;--------------------------------------------------------------------------------
- ; Set continuation and descend: if node p has a next sibling, push a
- ; pointer to it on the stack and the current value of p_level. We then
- ; increment p_level and descend to the child node (a subdirectory).
- ;
- ; We arrive here with r0 pointing to the child of node p.
- ;--------------------------------------------------------------------------------
-
- set_cont: movl next_sibling(r7),r1 ; look for next sibling
- beql 10$ ; branch if none
- pushl r1 ; save pointer to it
- pushl r6 ; save p_level
- pushl r5 ; save indent amount
- 10$: addl2 #indent_value,r5 ; indent branch name on listing
- movl r6,r1 ; save for reference below
- incl r6 ; indicate one more level down
- movl r0,r7 ; descend to child node
-
- ;--------------------------------------------------------------------------------
- ; If node q has a corresponding child node, we check and set its
- ; continuation point and then descend in cmp_tree also.
- ;--------------------------------------------------------------------------------
-
- tstl r4 ; use comparison tree?
- bgtr 20$ ; branch if yes
- brw clear ; else ignore it
-
- 20$: cmpl r8,r1 ; q_level = p_level?
- beql 30$ ; branch if yes
- brw clear ; else ignore this level
-
- 30$: movl first_child(r9),r0 ; corresponding child?
- bneq 40$ ; branch if yes
- brw clear ; else ignore
-
- 40$: movl next_sibling(r9),r1 ; look for next sibling
- beql 60$ ; branch if none
- cmpl r10,#q_stack ; room in q_stack?
- bgtru 50$ ; branch if yes
- movab q_stack_msg,r0 ; say out of room
- bsbw write_msg ;
- brw done ;
-
- 50$: movl r1,-(r10) ; push next_sibling onto q_stack
- movl r8,-(r10) ; push q_level onto q_stack
- 60$: incl r8 ; down one level in cmp_tree
- movl r0,r9 ; point to child
- brw clear ; continue on
-
-
- ;--------------------------------------------------------------------------------
- ; Write out totals
- ;--------------------------------------------------------------------------------
- write_totals: bsbw blank_line ; write blank line
- clrl r1 ; zero total difference so far
- tstl r4 ; branch if no comparison file
- bleq 10$ ;
- subl3 cmp_tree_total_allocated,- ; get overall difference
- tree_total_allocated,-
- r1
- 10$: $fao_s -
- ctrstr = total_fmt,- ; descriptor for format control string
- outlen = fao_outlen,- ; where to store length of formatted output
- outbuf = fao_outbuf,- ; descriptor for formatted output buffer
- p1 = tree_total_files,-
- p2 = tree_total_used,-
- p3 = tree_total_allocated,-
- p4 = r1
- blbs r0,20$ ; branch if converted ok
- movab total_cvt_msg,r0 ; else set up to write error message
- bsbw write_msg ;
- brw done ;
-
- 20$: cvtwb fao_outlen,lis_outlen ; set length of formatted output
- movab lis_outlen,r0 ; .ASCIC format
- bsbw write_msg ; write it
-
-
- ;--------------------------------------------------------------------------------
- ; Write out the USAGE.CMP file. Since r11 points to the next available
- ; node, it also serves to indicate when to stop writing
- ;--------------------------------------------------------------------------------
- write_cmp:
- movw #cmp_size,ocmp_rab+rab$w_rsz ; set record size
- movab tree_ident,r2 ; where to begin output
- 10$: cmpl r2,r11 ; branch out if done
- blssu 15$ ;
- brw done ;
-
- 15$: movl r2,ocmp_rab+rab$l_rbf ; set output address
- $put rab = ocmp_rab ; write to .CMP file
- blbs r0,20$ ; branch if ok
- moval ocmp_rab,r2 ;
- brw record_error ; else abort out
-
- 20$: addl2 #cmp_size,r2 ; advance pointer
- brb 10$ ;
-
- ;--------------------------------------------------------------------------------
- ; Arrive here if we're unable to allocate nodes in the tree
- ;--------------------------------------------------------------------------------
- no_space: movab no_space_msg,r0
- bsbw write_msg
- brw done
-
-
- ;--------------------------------------------------------------------------------
- ; write_msg
- ;
- ; A routine to write a message to the USAGE.LIS file.
- ; Call with: R0 = address of an .ASCIC string
- ; Exits on error.
- ;--------------------------------------------------------------------------------
- write_msg: cvtbw (r0)+,lis_rab+rab$w_rsz ; set message size
- movl r0,lis_rab+rab$l_rbf ; set message address
- $put rab = lis_rab ; write to list file
- blbs r0,10$ ; branch if ok
- moval lis_rab,r2 ;
- brw record_error ; else abort out
-
- 10$: rsb ; else return
-
-
- ;--------------------------------------------------------------------------------
- ; blank_line
- ;
- ; Prints a blank line
- ;
- ; (we could imbed CR, LF's inside records, but viewing the USAGE.LIS file
- ; in some editors won't handle this properly).
- ;--------------------------------------------------------------------------------
- blank_line: movab blank_msg,r0
- bsbw write_msg
- rsb
-
-
- ;--------------------------------------------------------------------------------
- ; Exit and error handling
- ;
- ; In this section we close any open files and then exit.
- ; The status code associated with the error is in r0.
- ;
- ;--------------------------------------------------------------------------------
-
- record_error: pushl r0 ; save status
- bsbb close_files ;
- movl (sp)+,r0 ; set status
- file_error: ret ; return w/status in r0
-
- done: bsbb close_files ;
- ret ; return w/status in r0
-
- close_files: $close fab = data_fab ; close USAGE.DAT
- $close fab = lis_fab ; close USAGE.LIS
- $close fab = ocmp_fab ; close USAGE.CMP (output)
- tstb icmp_state ; look at USAGE.CMP (input)
- beql 10$ ; branch if not open
- $close fab = icmp_fab ; close USAGE.CMP (input)
- 10$: rsb ;
-
-
- .psect DATA,wrt,noexe,LONG
- ;--------------------------------------------------------------------------------
- ; Access blocks and buffer for USAGE.DAT
- ;
- ; At the time of the $open, any filename components provided by the
- ; user will be reflected in the fna and fns fields of the fab. Any
- ; missing components are provided by the dnm (default name) field of
- ; the fab. As a result of the $open, the resulting file specification
- ; (based on any user input and defaults) is parsed and placed in the
- ; nam block. The file specification components in the nam block are
- ; then used as defaults on subsequent $open or $create calls.
- ;--------------------------------------------------------------------------------
-
- .align long
- data_fab: $fab fna = fname_buff,- ; possibly set by user
- dnm = <sys$manager:usage.dat>,- ; provide default components
- nam = data_nam,- ; point to NAM block
- fac = <get>,- ; GET access only
- shr = <nil>,- ; exclusive access
- fop = sqo ; sequential only
-
- .align long
- data_nam: $nam rsa = data_rsa,- ; NAM used for related filespecs
- rss = nam$c_maxrss ; (maximum resultant string size)
- data_rsa: .blkb nam$c_maxrss ; buffer for filespec components
-
- .align long
- data_rab: $rab fab = data_fab,- ; point to FAB
- rop = rah,- ; read-ahead
- ubf = data_buff,- ; addr of usage data buffer
- usz = data_size ; data buffer size
-
- data_buff: .blkb USG$C_FILE_LEN ; usage data buffer
- data_size = . - data_buff
-
-
- ;--------------------------------------------------------------------------------
- ; Access blocks for USAGE.CMP (optional input file)
- ;--------------------------------------------------------------------------------
-
- .align long
- icmp_fab: $fab fnm = <.cmp>,- ; primary name
- nam = icmp_nam,- ; point to NAM
- fac = <get>,- ; GET access only
- shr = <nil>,- ; exclusive access
- fop = <nam,sqo>,- ; NAM input, sequential only
- rfm = fix,- ; fixed length records
- mrs = cmp_size ; record size
-
- .align long
- icmp_nam: $nam rlf = data_nam ; provide default components
-
- .align long
- icmp_rab: $rab fab = icmp_fab,- ; point to FAB
- rop = rah ; read-ahead
-
-
- ;--------------------------------------------------------------------------------
- ; Access blocks and buffer for USAGE.LIS (created output file)
- ;--------------------------------------------------------------------------------
-
- .align long
- lis_fab: $fab fnm = <.lis>,- ; primary name
- nam = lis_nam,- ; point to NAM
- fac = <put>,- ; PUT access only
- shr = <nil>,- ; exclusive access
- fop = <nam,sqo>,- ; NAM input, sequential only
- mrs = lis_size,- ; max record size
- rat = cr ; implied carriage control
-
- .align long
- lis_nam: $nam rlf = data_nam ; provide default components
-
- .align long
- lis_rab: $rab fab = lis_fab,- ; point to FAB
- rop = wbh ; write-behind
-
- lis_outlen: .blkb ; length of output
- lis_buff: .blkb lis_size ; listing buffer
-
-
- ;--------------------------------------------------------------------------------
- ; Access blocks and buffer for USAGE.CMP (created output file)
- ;--------------------------------------------------------------------------------
-
- .align long
- ocmp_fab: $fab fnm = <.cmp>,- ; primary name
- nam = ocmp_nam,- ; point to NAM
- fac = <put>,- ; PUT access only
- shr = <nil>,- ; exclusive access
- fop = <nam,sqo>,- ; NAM input, sequential only
- rfm = fix,- ; fixed length records
- mrs = cmp_size ; record size
-
- .align long
- ocmp_nam: $nam rlf = data_nam ; provide default components
-
- .align long
- ocmp_rab: $rab fab = ocmp_fab,- ; point to FAB
- rop = wbh ; write-behind
-
-
- ;--------------------------------------------------------------------------------
- ; Messages
- ;--------------------------------------------------------------------------------
-
- version_msg: .ascic \Disk Usage v2.12\
- ident_len_msg: .ascic \invalid record length for IDENT record\
- not_ident_msg: .ascic \first record is not IDENT record\
- time_cvt_msg: .ascic \unable to convert creation time\
- serial_cvt_msg: .ascic \unable to convert serial number\
- strucname_cvt_msg: .ascic \unable to convert volume set name\
- volname_cvt_msg: .ascic \unable to convert volume name\
- ownername_cvt_msg: .ascic \unable to convert owner name\
- format_cvt_msg: .ascic \unable to convert format description\
- not_file_msg: .ascic \record is not a FILE record\
- no_icmp_msg: .ascic \No input comparison file\
- wrong_type_msg: .ascic \input comparison file ignored: incorrect type field\
- wrong_volume_msg: .ascic \input comparison file ignored: wrong volume\
- wrong_version_msg: .ascic \input comparison file ignored: program version mismatch\
- icmp_time_cvt_msg: .ascic \unable to convert comparison time\
- heading_msg: .ascic \Directories File count blk used/allocated change\
- no_space_msg: .ascic \out of room -- please increase max_nodes and reassemble\
- blank_msg: .ascic \\
- total_cvt_msg: .ascic \unable to convert totals\
- cmp_cvt_msg: .ascic \unable to convert difference in block allocation\
- q_stack_msg: .ascic \q_stack overflow -- please increase q_stack_size and reassemble\
- tree_cvt_msg: .ascic \unable to convert name or size information\
-
- ;--------------------------------------------------------------------------------
- ; Data structures for FA0 messages
- ;--------------------------------------------------------------------------------
- fao_outlen: .blkw
- fao_outbuf: string_dsc lis_buff,lis_size
-
- indent_string: .ascic \\
-
- time_fmt: .ascid \Usage file created: !%D\
- serial_fmt: .ascid \Serial number (octal): !OL\
- strucname_fmt: .ascid \Volume set name: !AD\
- volname_fmt: .ascid \Volume name: !AD\
- ownername_fmt: .ascid \Owner name: !AD\
- format_fmt: .ascid \File format: !AD\
- icmp_time_fmt: .ascid \Comparison file dated: !%D\
- total_fmt: .ascid \Total files !SL, blocks used/allocated !SL/!SL, change !SL\
-
- tree_fmt: .ascid \!40<!#AC!AD!> !8SL !8SL/!8<!SL!> !8AD\
-
- ;--------------------------------------------------------------------------------
- ; Data structures used in setting the allocation difference
- ;--------------------------------------------------------------------------------
-
- new_string: .ascii \ new\
- blank_string: .ascii \ \
- cmp_string: .ascii \ \
- cmp_fmt: .ascid \!8SL\
- cmp_outbuf: string_dsc cmp_string,cmp_field_size
-
-
- ;--------------------------------------------------------------------------------
- ; Miscellaneous data structures
- ;
- ; icmp_state reflects the state of the optional USAGE.CMP input file:
- ;
- ; icmp_state < 0 ==> file exists, but is not to be used
- ; icmp_state = 0 ==> file does not exist
- ; icmp_state > 0 ==> file exists and is being used
- ;
- ;--------------------------------------------------------------------------------
-
- icmp_state: .blkb ; state of USAGE.CMP (input)
-
- ; This small stack is used while traversing the comparison tree
-
- q_stack: .blkl q_stack_size
- q_stack_top:
-
-
- ; Data structures for optional name to override default (length is first word in dsc)
-
- fname_buff: .blkb max_name_size
- fname_dsc:
- fname_length: string_dsc fname_buff,max_name_size
-
- ;--------------------------------------------------------------------------------
- ; Data structures for the nodes
- ;--------------------------------------------------------------------------------
-
- ; sizes of elements in the node data structure (in bytes)
-
- branch_name_size = max_name_size ; max size of branch name
- name_length_size = 1 ; since branch name length < 256 chars
- file_count_size = 4 ; longword count
- blocks_used_size = 4 ; longword count
- blocks_allocated_size = 4 ; longword count
- next_sibling_size = 4 ; longword pointer
- first_child_size = 4 ; longword pointer
-
- ; offsets within the node data structure
-
- branch_name = 0
- name_length = branch_name + branch_name_size
- file_count = name_length + name_length_size
- blocks_used = file_count + file_count_size
- blocks_allocated = blocks_used + blocks_used_size
- next_sibling = blocks_allocated + blocks_allocated_size
- first_child = next_sibling + next_sibling_size
-
- node_size = first_child + first_child_size
-
-
- ;--------------------------------------------------------------------------------
- ; Data structures for the trees. The tree built from the USAGE.DAT file
- ; becomes the new comparison file that gets written out. The comparison
- ; file read in (if any) constitutes the comparison tree (cmp_tree).
- ;
- ; To maintain and verify the integrity of the comparison files, the
- ; IDENT record from the USAGE.DAT file which is used to build the tree
- ; is also part of the first record in the comparison file. The contents
- ; of this first record is described in the cmp_init section.
- ;
- ; The comparison file is written out in records of cmp_size bytes. We
- ; want to make sure that storage for the tree (starting with the IDENT
- ; part) is allocated to the nearest multiple of cmp_size. This guarantees
- ; that for whatever amount gets written out (from tree_ident) there will
- ; be room for it when being read back later (into cmp_tree_ident).
- ;
- ; NOTE: various sections of code expect the totals to be grouped together
- ;
- ;--------------------------------------------------------------------------------
- tree_ident: .blkb USG$C_IDENT_LEN ; first part of usage.cmp
- tree_version: .blkw ; for integrity check
- tree_total_files: .blkl ; total files on disk
- tree_total_used: .blkl ; total blocks used
- tree_total_allocated: .blkl ; total blocks allocated
- tree: .blkb max_nodes * node_size ; tree of nodes
- size = . - tree_ident
- blocks = <size + <cmp_size - 1>> / cmp_size
- fill = <blocks * cmp_size> - size
- .blkb fill
-
- cmp_tree_ident: .blkb USG$C_IDENT_LEN ; first part of usage.cmp
- cmp_tree_version: .blkw ; for integrity check
- cmp_tree_total_files: .blkl ; total files on disk
- cmp_tree_total_used: .blkl ; total blocks used
- cmp_tree_total_allocated:.blkl ; total blocks allocated
- cmp_tree: .blkb max_nodes * node_size ; tree of nodes
- .blkb fill
-
- .end DISK_USAGE
-