home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug077.arc
/
SETATT.ASM
< prev
next >
Wrap
Assembly Source File
|
1979-12-31
|
21KB
|
714 lines
; SETATT
;
; A file attribute change utility for CP/M 80
;
; Copyright: Ian Ashdown
; byHeart Software
; 2 - 2016 West 1st Avenue
; Vancouver, B.C. V6J 1G8
; Canada
;
; Version 1.0 15 December 1983 -- published in 'Microcomputing'
; vol VIII no. 5 May 1984
;
; Version 1.1 10 June 1985 -- modified by Peter Martin to cover
; the 'archive' attribute (t3')
;
; NOTICE: This program has been released into the public
; domain for non-commercial use. As this
; assembly-language listing forms the only
; documentation for the use of SETATT, it is
; requested that any copies of SETATT.COM made
; for redistribution include this listing.
;
; This version: 1.1 of 10 June 1985
;
;
; USE: 'SETATT' is designed to replace CP/M's 'STAT' utility for
; setting the READ-ONLY, SYSTEM and 'ARCHIVE' attributes of
; a file.
;
; The command line syntax expected by SETATT is:
;
; SETATT filename.typ (specifier)
;
; where (specifier) can be one of:
;
; R/W to reset files to Read/Write
; R/O to set files to Read-Only
; DIR to reset files to Directory
; SYS to set files to System
; NRC to reset files to 'non-archived'
; ARC to set files to 'Archived'
;
; The following example indicates how to use SETATT
; to set a group of files to R/O. The symbol (x)
; denotes that the operator has typed the character
; 'x' at the console as a response. Note that the
; wild card characters '?' and '*' are permitted to
; specify ambiguous file names. Also (not shown)
; typing ^C in response to any question will termin-
; ate the program without changing any file attrib-
; utes.
;
;
; Example:
;
; A>SETATT PRO*.??? R/O
;
; SETATT - Version 1.1 Copyright 1983
;
; File Name: READ Status: SYSTEM Status: ARCHIVE Status: Make READ-ONLY ?
;
; A: PROG .TXT READ/WRITE DIRECTORY NOT ARCHIVED ? (Y) Yes
; A: PROG .ASM READ/WRITE DIRECTORY NOT ARCHIVED ? (N) No
; A: PROG .001 READ/ONLY SYSTEM NOT ARCHIVED Already READ-ONLY
; A: PROGRESS.BAS READ/WRITE DIRECTORY ARCHIVED ? (Y) Yes
; A: PROG .TXT READ/WRITE DIRECTORY ARCHIVED ? (Y) Yes
;
; O.K. to change [Y/N] ? (Y) Yes
;
; **** DEFINITIONS ****
BOOT EQU 0000H ; warm start vector
BDOS EQU 0005H ; fdos entry vector
FCB1 EQU 005CH ; default file control block #1 address
FCB2 EQU 006CH ; default file control block #2 address
DFDMA EQU 0080H ; default DMA address
CONOUT EQU 02H ; bdos console output function
DIRCIO EQU 06H ; bdos direct console i/o function
PSTRNG EQU 09H ; bdos print string function
SRCHF EQU 11H ; bdos search first function
SRCHN EQU 12H ; bdos search next function
DSKNO EQU 19H ; bdos return current disk function
SETFAT EQU 1EH ; bdos set file attributes function
BELL EQU 07H ; ASCII bell
CR EQU 0DH ; ASCII carriage return
LF EQU 0AH ; ASCII line feed
RWATT EQU 1 ; read/write flag
ROATT EQU 2 ; read-only flag
DIRATT EQU 3 ; directory flag
SYSATT EQU 4 ; system flag
NRCATT EQU 5 ; non-archived flag
ARCATT EQU 6 ; archived flag
; ********** MAIN PROGRAM ************
org 0100h
lxi sp,Stack ; set stack pointer to local stack
lxi d,Head1 ; print first part of program heading
call Print
call Init ; initialise variables
lxi h,FNBA ; store address of start of File Name Buffer
shld Buff ; Array in pointer Buff
call GetAttrib ; get attribute type from default FCB #2
jz AttribOK ; jump to AttribOK if attribute type is valid
lxi d,AttError ; else print 'ATTRIBUTE ERROR' message if
call Print ; invalid or missing attribute type
jmp BOOT ; and then return to cp/m
AttribOK:
call SerchFirst ; search for the first file match
call QueryFind ; check to see if a match was found
jnz FileFound ; jump to FileFound if match found
lxi d,NoFileMsg ; else print 'NO FILE' message
call Print
jmp BOOT ; and exit
FileFound:
call MovName ; move file name to current File Name Buffer
call IncBuff ; increment buffer pointer
call SerchNext ; search for next file match
call QueryFind ; see if any found
jnz FileFound ; yes? loop for another...
lxi h,FNBA ; reset buffer pointer to start
shld Buff ; and store that away
call SaveCount ; then save copy of file count
call QueryDisk ; find out what disk we're on
call PrintHedder ; print remainder of program heading
NextFile:
call TestFAtt ; test existing file attributes
lda AttReg ; get Attribute Type Register contents
cpi RWATT ; Is it R/W we have to change ?
jz RwDirNrc ; jump to RWDIRNRC
cpi DIRATT ; Is it DIR we have to change?
jz RwDirNrc ; go to same place
cpi NRCATT ; Is it NRC we have to change?
jz RwDirNrc ;.. and again
call TestFAttCh ; else (r/o,sys,arc) -- test one to be changed...
jnz NextFile2 ; if found set, skip past
jmp NextFile1 ; else set flags and check with query
RwDirNrC:
call TestFAttCh ; test attribute in non-set group
jnz NextFile1 ; skip over check/count if r/w or dir already
mvi a,0ffh
sta AlreadyFlag
jmp NextFile1a
NextFile1:
mvi a,0ffh ; set File Found flag
sta FoundFlag
NextFile1a:
call PrintFN ; show file name
call PrintAtt ; show current att setting
lda AlreadyFlag ; see if file set already
inr a
jnz NextFile1b ; no -- go do query
call AlreadyOut ; else say already set and move on
jmp NextFile2
NextFile1b:
call QueryChange ; ask if attribute is to be changed
NextFile2:
call IncBuff ; increment file buffer pointer to next
lxi h,DirFileCnt; point to directory file counter
dcr m ; and decrement it.
jnz NextFile ; and loop if not finished....
lda FoundFlag ; check file-found flag
inr a ; is it set?
jnz AllOK ; if not, exit -- none need changing
lda QueryFlag ; check if queries confirmed a change
inr a
jnz BOOT ; exit if they didn't
lxi h,FNBA ; pointer to start of filename buffer
shld Buff ; stored again for run-down
call QueryOK ; do the end query bit
cc DoChanges ; if that's confirmed, do the changes
jmp BOOT ; and close down.
;
; ********** SUBROUTINES *********
; Initialize variables
Init:
xra a ; clear Accumulator and with it
sta DirFileCnt ; clear our counts and flags
sta FoundFlag
sta QueryFlag
sta AlreadyFlag
ret
; Get attribute type from Default FCB #2
GetAttrib:
lxi h,RW ; point to the 'R/W' string
mvi a,RWATT ; put corresponding value in Acc (RWATT=0)
call CmpAtt ; call comparison routine
rz ; and return if match found
lxi h,RO ; do same for 'R/O'
mvi a,ROATT ;
call CmpAtt
rz
lxi h,DIR ; ... and for 'DIR'
mvi a,DIRATT
call CmpAtt
rz
lxi h,SYS ; ... and 'SYS'
mvi a,SYSATT
call CmpAtt
rz
lxi h,NRC ; ... and 'NRC'
mvi a,NRCATT
call CmpAtt
rz
lxi h,ARC ; ... and 'ARC'
mvi a,ARCATT
call CmpAtt
ret
; Compare attribute type to string
CmpAtt:
sta AttReg ;store value in A as variable AttReg
mvi b,3 ; set character count to 3
lxi d,FCB2+1 ; set DE to point to first char
NextCh:
ldax d ; get char into Acc
cpi '/' ; is it the slash ?
jz NextCh1
ani 5fh ; toupper
NextCh1:
cmp m ; same as one laid down?
rnz ; no? return-- we have a mismatch
inx d ; else move along to next
inx h
dcr b ; and decrement counter
jnz NextCh ; loop if not done
ret ; else return Z flag set for full match
; Search for first file
SerchFirst:
lxi d,FCB1 ; bdos preparation
mvi c,SRCHF
call BDOS
ret
; Search for next file
SerchNext:
lxi d,FCB1 ; bdos preparation
mvi c,SRCHN
call BDOS
ret
; Determine if file found
QueryFind:
inr a ; if ERROR, 0ffh returned. test
rz ; by incrementing. zero means ERROR
dcr a ; else restore value
lxi h,DirFileCnt ; else increment count of finds
inr m
ret
; Move filename from default DMA to current file name buffer
MovName:
lhld Buff
xchg ; buffer pointer into DE
lxi h,DFDMA ; while HL=> DMA buffer base
add a ; use offset from search functions
add a ; *32 to make HL=> file found
add a
add a
add a
add l
mov l,a
lda FCB1 ; get disk number from default FCB #1
mov m,a ; store it as first item in buffer
mvi b,15 ; set up counter in b
NextChar:
mov a,m ; get char into Acc from DMA buffer
stax d ; and store in our buffer
inx h ; incrementing pointers
inx d
dcr b ; and decrementing char count
jnz NextChar; looping until all done
; NOTE -- byte following filename in our new buffer is used as a flag
; for changing of attributes. zero means no change, -1 means change.
inx h
xra a
mov m,a
ret
; Increment file name buffer pointer
IncBuff:
lhld Buff
lxi d,16
dad d
shld Buff
ret
; Save copy of directory file count
SaveCount:
lda DirFileCnt
sta DirFileCnt1
ret
; Determine name of specified disk
QueryDisk:
lda FCB1
ora a ; none specified ?
cz Current ; then get current...
adi 40h ; and adjust to ASCII
sta Disk ; saving it...
ret
Current:
mvi c,DSKNO
call BDOS
adi 1
ret
; Print remainer of program heading
PrintHedder:
lxi d,Head2 ; output the heading
call Print
lda AttReg ; check which we have to change
dcr a ; get it to zero base
mov c,a ; use value as an offset
mvi b,0 ; in BC for a pointer to the right
lxi h,HeadMsgs ; query message held in table
call TablePrint ; go and print it in another routine
ret
; Test existing file attributes
TestFAtt:
lhld Buff ; get current pointer to current filename
lxi d,9 ; offset to point to 1st char in 'typ'
dad d
mov a,m ; get that character in
ani 80h ; mask off its READ bit
rlc ; and move it round into bit 0
mov b,a ; storing temporarily in B
inx h ; while we look at the next
mov a,m
ani 80h ; and mask for its SYSTEM bit
rlc ; moving it around
rlc ; into bit 1
add b ; and combining results with addition
mov b,a ; saving again
inx h ; for another turn on the merry-go-round
mov a,m
ani 80h
rlc
rlc
rlc
add b
sta FAtt
ret
; Test for file attribute to be changed
TestFAttCh:
lda AttReg
cpi NRCATT
jc TestFC1
lda FAtt
ani 04
ret
TestFC1:
cpi DIRATT
jc TestFC2
lda FAtt
ani 02
ret
TestFC2
lda FAtt
ani 01
ret
; Print File Name
PrintFN:
lda Disk ; print disk name....
mov e,a
mvi c,CONOUT
call BDOS
lxi d,Colon ; followed by colon
call Print
lhld Buff ; point to filename in buffer
inx h
mvi b,8 ; counter for chars in filename
NextN2:
push h ; output 8 chars
push b
mov a,m
ani 7fh
mov e,a
mvi c,CONOUT
call BDOS
pop b
pop h
inx h
dcr b
jnz NextN2
push h
mvi e,'.' ; put in delimiter for filename
mvi c,CONOUT
call BDOS
pop h
mvi b,3 ; now counter for filetyp
NextT2:
push h
push b
mov a,m
ani 7fh
mov e,a
mvi c,CONOUT
call BDOS
pop b
pop h
inx h
dcr b
jnz NextT2
mvi e,' ' ; and a space at end
mvi c,CONOUT
call BDOS
ret
; Print existing (unchanged) file attribute
PrintAtt:
lda FAtt
mov c,a ; make it into offset in BC
mvi b,0
lxi h,ComboMsgs
call TablePrint
ret
;
; Signal a file already set for attribute wanted
AlreadyOut:
lxi d,Already ; say 'Already...'
call Print
lda AttReg
dcr a
mov c,a
mvi b,0
lxi h,NoFCM ; and the setting
call TablePrint
xra a ; reset flag for next time through
sta AlreadyFlag
ret
; Ask if attribute is to be changed
QueryChange:
lxi d,Ask
call Print
call Charin
cpi 03 ; was it a ctrl-C ?
jz Exit ; yes? then go away
ani 5fh ; else toupper
cpi 'Y'
jz CheckAtt
lxi d,No
call Print
ret
CheckAtt:
lhld Buff
lxi d,15 ; (clears D to 00)
dad d ; pointer set to byte at end of filename
mvi a,0ffh ; and Acc set to -1
mov m,a ; put it in there
lhld Buff ; reset HL to point to start of buffer
lda AttReg ; get attribute we have to change
cpi NRCATT ; nrc or arc ?
jc CheckAtt1 ; no? -- press on
mvi e,0bh ; load offset to 3rd char in typ
jmp CheckAtt3
CheckAtt1:
cpi DIRATT
jc CheckAtt2 ; not dir or system? -- press on
mvi e,0ah ; else load offset to 2nd char in typ
jmp CheckAtt3
CheckAtt2:
mvi e,09h ; load offset to r/o;r/w -- 1st char in typ
CheckAtt3:
dad d ; apply the offset
mov a,m ; get the character in
xri 80h ; toggle bit 7 as required
mov m,a ; and put result back
mvi a,0ffh ; get -1 into A
sta QueryFlag ; and set the query flag
lxi d,Yes ; and acknowledge response
call Print
ret
Exit:
lxi d,ExitMsg ; tell em 'You asked for it...'
call Print ; and go away.
jmp BOOT
; Return to CP/M if specified files already have desired attributes
AllOK:
lxi d,NoFC1 ; Print 'Specified files are already...'
call Print
lda AttReg
dcr a
mov c,a ; do offset bit for message
mvi b,0
lxi h,NoFCM ; from NoFCM base
call TablePrint
jmp BOOT
; Ask if attributes of indicated files should be changed
QueryOK:
lxi d,OKChange
call Print
call Charin
ani 5fh
cpi 'Y'
jz ChangeYes
lda AttReg
cpi NRCATT
jc QueryOk1
lxi d,NoAB3 ; says 'No -- ARCHIVE attributes NOT CHANGED'
call Print
jmp QueryOk3
QueryOk1:
cpi DIRATT
jc QueryOk2
lxi d,NoAB2 ; says 'No -- SYSTEM attributes NOT CHANGED'
call Print
jmp QueryOk3
QueryOk2:
lxi d,NoAB1 ; says 'No -- READ attributes NOT CHANGED'
call Print
QueryOk3:
ora a ; clear Cy flag as 'not changed' indicator
ret
ChangeYes:
lxi d,Yes
call Print
stc ; set Cy
ret
; Change attributes of indicated files
DoChanges:
lda DirFileCnt1 ; restore original file count from saved byte
mov b,a ; get count of files to be done in B
NextFC:
lhld Buff ; get pointer over buffer
lxi d,15 ; and offset to flag for change on each file
dad d
mov a,m ; check change status byte
inr a
jnz NoChange
push b ; save counter
lhld Buff ; get back pointer
xchg ; into DE
mvi c,SETFAT ; and leave it to bdos
call BDOS
pop b ; restoring counter
NoChange:
call IncBuff ; increment pointer to next file
dcr b ; and decrement counter of files
jnz NextFC ; looping as required
ret
; Table-driven print message routine -- HL=> base, BC= offset of message
TablePrint:
dad b
dad b ; two-byte arrays
mov e,m ; get address into DE
inx h
mov d,m
call Print
ret
; Print String Routine
Print:
mvi c,PSTRNG
call BDOS
ret
;
; Direct input of character routine
Charin:
mvi e,0ffh ; code for bdos
mvi c,DIRCIO
call BDOS
ora a
jz Charin ; loop till character ready
ret
;
; ********** DATA STATEMENTS AND TABLES *********
Ask: db ' ? $'
AttError: db BELL,'The command line syntax expected by SETATT is:',CR,LF,LF
db ' SETATT <filename.typ> (specifier) ',CR,LF,LF
db ' WHERE (specifier) can be one of:',CR,LF,LF
db ' R/W to reset files to READ/WRITE',CR,LF
db ' R/O to set files to READ-ONLY',CR,LF
db ' DIR to reset files to DIRECTORY',CR,LF
db ' SYS to set files to SYSTEM',CR,LF
db ' NRC to reset files to NON-ARCHIVED',CR,LF
db ' ARC to set files to ARCHIVED',CR,LF,LF
db ' e.g. -- SETATT FILE.TYP R/O',CR,LF,'$'
Colon: db ': $'
ExitMsg: db BELL,CR,LF,LF,'SETATT terminated at your request -- '
db 'NO ATTRIBUTES CHANGED',CR,LF,'$'
Head1: db CR,LF, 'SETATT -- version 1.1 1985'
db ' Copyright 1983 byHeart Software',CR,LF,LF,'$'
Head2: db 'Filename: '
db ' READ Status: SYSTEM Status: ARCHIVE Status: Make $'
Combo0: db ' READ/WRITE DIRECTORY NON-ARCHIVED$'
Combo1: db ' READ-ONLY DIRECTORY NON-ARCHIVED$'
Combo2: db ' READ/WRITE SYSTEM NON-ARCHIVED$'
Combo3: db ' READ-ONLY SYSTEM NON-ARCHIVED$'
Combo4: db ' READ/WRITE DIRECTORY ARCHIVED $'
Combo5: db ' READ-ONLY DIRECTORY ARCHIVED $'
Combo6: db ' READ/WRITE SYSTEM ARCHIVED $'
Combo7: db ' READ-ONLY SYSTEM ARCHIVED $'
Head3: db 'READ/WRITE?',CR,LF,LF,'$'
Head4: db 'READ-ONLY?',CR,LF,LF,'$'
Head5: db 'DIRECTORY?',CR,LF,LF,'$'
Head6: db 'SYSTEM?',CR,LF,LF,'$'
Head7: db 'NON-ARCHIVED?',CR,LF,LF,'$'
Head8: db 'ARCHIVED?',CR,LF,LF,'$'
No: db 'No',CR,LF,'$'
NoAB1: db BELL,'No -- READ attributes NOT CHANGED',CR,LF,'$'
NoAB2: db BELL,'No -- SYSTEM attributes NOT CHANGED',CR,LF,'$'
NoAB3: db BELL,'No -- ARCHIVE attributes NOT CHANGED',CR,LF,'$'
NoFileMsg: db BELL,'Sorry -- specified file(s) could not be found',CR,LF,'$'
NoFC1: db BELL,'Specified files are already $'
Already: db ' Already $'
NoFC2A: db 'READ/WRITE',CR,LF,'$'
NoFC2B: db 'READ-ONLY',CR,LF,'$'
NoFC2C: db 'DIRECTORY',CR,LF,'$'
NoFC2D: db 'SYSTEM',CR,LF,'$'
NoFC2E: db 'NON-ARCHIVED',CR,LF,'$'
NoFC2F: db 'ARCHIVED',CR,LF,'$'
OkChange: db CR,LF,LF,'O.K. to change ? [Y/N] $'
RW: db 'R/W$'
RO: db 'R/O$'
DIR: db 'DIR$'
SYS: db 'SYS$'
NRC: db 'NRC$'
ARC: db 'ARC$'
YES: db 'Yes',CR,LF,'$'
;
; ****** POINTER TABLE *******
;
ComboMsgs: dw Combo0
dw Combo1
dw Combo2
dw Combo3
dw Combo4
dw Combo5
dw Combo6
dw Combo7
HeadMsgs: dw Head3
dw Head4
dw Head5
dw Head6
dw Head7
dw Head8
NoFCM:
dw NoFC2A
dw NoFC2B
dw NoFC2C
dw NoFC2D
dw NoFC2E
dw NoFC2F
; ****** RESERVED DATA AREA ******
AttReg: ds 1
Buff: ds 2
DirFileCnt: ds 1
DirFileCnt1: ds 1
Disk: ds 1
FAtt: ds 1
QueryFlag: ds 1
FoundFlag: ds 1
AlreadyFlag: ds 1
ds 8
Stack
FNBA EQU $
END