home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.update.uu.se
/
ftp.update.uu.se.2014.03.zip
/
ftp.update.uu.se
/
pub
/
rainbow
/
msdos
/
decus
/
RB125
/
attrib.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-06-04
|
26KB
|
1,165 lines
PROGRAM FileAttributes;
{$G128,P128,D-} {010,001}
CONST
ProgramVersion = '1.0';
(***********************************************************************
This software has been placed into the public domain by Digital
Equipment Corporation.
DISCLAIMER:
The information herein is subject to change without notice and should
not be construed as a commitment by Digital Equipment Corporation.
Digital Equipment Corporation assumes no responsibility for the use or
reliability of this software. This software is provided "as is,"
without any warranty of any kind, express or implied. Digital Equipment
Corporation will not be liable in any event for any damages including
any loss of data, profit, or savings, claims against the user by any
other party, or any other incidental or consequential damages arising
out of the use of, or inability to use, this software, even if Digital
Equipment Corporation is advised of the possibility of such damage.
DEFECT REPORTING AND SUGGESTIONS:
Please send reports of defects or suggestions for improvement directly
to the author:
Brian Hetrick
Digital Equipment Corporation
110 Spit Brook Road ZKO1-3/J10
Nashua NH 03062-2698
Do NOT file a Software Performance Report on this software, call the
Telephone Support Center regarding this software, contact your Digital
Field Office regarding this software, or use any other mechanism
provided for Digital's supported and warranted software.
FACILITY:
MS-DOS user utilities
ABSTRACT:
Manipulates attributes of files
ENVIRONMENT:
MS-DOS V2.0 or later compiled with Borland International's TURBO
Pascal V3.0 or later
AUTHOR: Brian Hetrick, CREATION DATE: 24 November 1986.
MODIFIED BY:
Brian Hetrick, 24-Nov-86: Version Y1.0-0
000 - Original creation of module.
Released to selected Easynet sites for beta test on 24 November
1986.
Brian Hetrick, 02-Dec-86: Version Y1.0-8
001 - Add Gn, Pn compiler directives for compilation on IBM PC clones.
002 - Modify IsPrefix routine to PrefixLength for command qualifiers
starting with same letter.
003 - Parse command qualifiers before and after parsing file spec, as
bad command qualifier with no file spec prompts for file spec
before detecting bad command qualifer.
004 - Add /CLEAR and /REMOVE synonyms for /RESET.
005 - Add help message if no command line given.
006 - Allow multiple wild card specs.
007 - Make path specifications absolute before reporting.
008 - List file names on left side of display.
Released to selected Easynet sites for beta test on 2 December
1986.
Brian Hetrick, 16-Dec-86: Version Y1.0-14
009 - Use CtlCTrap package to trap CTRL/C, as TURBO Pascal's CTRL/C
is not as desired. The undesired behavior (waiting for a Read
or ReadLn to abort the program) appears to occur only on MS-DOS
or PC-DOS V2.x. The PC-DOS specific TURBO Pascal had this un-
desired behavior all along, but MS-DOS generic TURBO Pascals be-
fore version 3.02A did not have this behavior on the Rainbow
(due to a bug in how the TURBO CTRL/C handler was set up), where
most testing occurred. The undesired behavior was noticed by a
beta test site using ATTRIB Y1.0-8, the first release compiled
with TURBO Pascal 3.02A, when it was impossible to CTRL/C out of
listings that were hit with the performance bug handled in edit
011.
010 - Construct print lines as a whole and omit trailing spaces. Add
the D- compiler directive and Flush (Output) to speed things up.
This also makes all program-generated text finally go to the MS-
-DOS standard output: even with Pn, TURBO will use IBM PC ROM
BIOS calls if the standard output is the console.
011 - Retain attribute from wild card lookup. This considerably
improves performance in highly fragmented directories.
012 - CTRL/C entered in response to the ReadLn in CLA.PAS does *NOT*
abort the program at least under PC-DOS V2.10. Apparently,
using the Gn,Pn,D- set of compiler directives entirely defeats
^C detection. So use the ^C package even for command line pars-
ing.
013 - Detect CTRL/Z entered in response to ReadLn in CLA.PAS.
014 - Reorder attributes in listing to put Arc and Dir, the most pop-
ular attributes, first.
Released to selected Easynet sites for beta test on 17 December
1986.
Brian Hetrick, 30-Jan-87: Version Y1.0-16
015 - Introduce /HELP switch to give long help message; if no command
line given, give short message and assume *.*. Remove prompting
for command parameters as there is now a 'reasonable' default.
016 - Make help text less dense, as it is now explicitly requested and
the user is presumably ready to deal with it.
Brian Hetrick, 30-Jan-87: Version 1.0
017 - Delete internal use only notice, copyright notice, etc., and set
version number to have no prefix or edit suffix, as will be re-
leased to DECUS Program Library.
Released to Easynet sites and DECUS Program Library 30 January
1987.
***********************************************************************)
{.PA}
(*
* INCLUDE FILES:
*)
{$I CtlCTrap.Pas} {009}
{$I CLA.PAS}
{$I WildExpa.Pas}
{$I MakeAbs.Pas} {007}
{$I BaseName.Pas} {008}
(*
* LABEL DECLARATIONS:
*)
(*
* CONSTANT DECLARATIONS:
*)
CONST
AttrMaskReadOnly = 1;
AttrMaskHidden = 2;
AttrMaskSystem = 4;
AttrMaskSubDirectory = 16;
AttrMaskArchive = 32;
(*
* TYPE DECLARATIONS:
*)
TYPE
PathSpec = WildExpandPathSpec; {011}
(*
* OWN STORAGE:
*)
VAR
Logging : BOOLEAN;
HelpDesired : BOOLEAN; {015}
OptionSpecified : BOOLEAN; {005}
ResetMask : INTEGER;
SetMask : INTEGER;
(*
* TABLE OF CONTENTS:
*)
{.PA}
PROCEDURE PrintHelp; {005}
(***********************************************************************{005}
FUNCTIONAL DESCRIPTION: {005}
Writes a description of the program on the standard output. {005}
FORMAL PARAMETERS: {005}
None. {005}
RETURN VALUE: {005}
None. {005}
IMPLICIT INPUTS: {005}
None. {005}
IMPLICIT OUTPUTS: {005}
None. {005}
SIDE EFFECTS: {005}
None. {005}
***********************************************************************){005}
BEGIN {005}
WriteLn; {016}
WriteLn ('Command line: ATTRIB filespec [qualifier]...'); {005}
WriteLn; {016}
WriteLn ('''filespec'' is a path specification possibly with wild card characters'); {005}
WriteLn (' in the last component'); {005}
WriteLn; {016}
WriteLn ('''qualifier'' is one of /[NO]HELP, /[NO]LOG, /SET:value, /RESET:value,'); {005}
WriteLn (' /CLEAR:value, /REMOVE:value'); {005}
WriteLn; {016}
WriteLn (' /SET grants attributes'); {016}
WriteLn (' /RESET, /CLEAR, and /REMOVE remove attributes'); {016}
WriteLn; {016}
WriteLn ('''value'' is either name or (name[,name]...)'); {005}
WriteLn; {016}
WriteLn ('''name'' is one of ARCHIVE, HIDDEN, SYSTEM, READ_ONLY'); {005}
WriteLn; {016}
WriteLn ('All keywords may be uniquely abbreviated') {005}
END; {005}
{.PA}
FUNCTION PrefixLength {002}
( Str1 : PathSpec;
Str2 : PathSpec) : INTEGER; {002}
(***********************************************************************
FUNCTIONAL DESCRIPTION:
Determines whether one string is a prefix of another, ignoring the
case of letters.
FORMAL PARAMETERS:
TestString.rt.v - The string which may be a prefix of TargetString.
TargetString.rt.v - The string of which TestString may be a prefix.
RETURN VALUE:
Zero: TestString is not a prefix of TargetString. {002}
n>0: TestString is a prefix of TargetString and has n characters. {002}
IMPLICIT INPUTS:
None.
IMPLICIT OUTPUTS:
None.
SIDE EFFECTS:
None.
***********************************************************************)
VAR
Chr1 : CHAR;
Chr2 : CHAR;
Index : INTEGER;
BEGIN
IF Length (Str1) <= Length (Str2)
THEN
BEGIN
(*
* Test string is no longer than target string, so check char-
* acters
*)
PrefixLength := Length (Str1); {002}
FOR Index := 1 TO Length (Str1)
DO
BEGIN
Chr1 := UpCase (Str1 [Index]);
Chr2 := UpCase (Str2 [Index]);
IF Chr1 <> Chr2
THEN
BEGIN {002}
(*
* A mismatch was found, test string is not a prefix of
* target string
*)
PrefixLength := 0; {002}
Exit {002}
END {002}
END
END
ELSE
(*
* Test string is longer than target string and so cannot be a
* prefix
*)
PrefixLength := 0 {002}
END;
{.PA}
PROCEDURE Pad {010,008}
(VAR StringText : PathSpec; {010,008}
PadLength : INTEGER); {010,008}
(***********************************************************************{008}
FUNCTIONAL DESCRIPTION: {008}
Adjusts a string by truncating the rightmost characters or padding{008}
on the right with spaces to be a specified length. {008}
FORMAL PARAMETERS: {008}
StringToPad.rt.v - The string to be adjusted. {008}
DesiredLength.rg.v - The length of the result string. {008}
RETURN VALUE: {008}
None. {010}
IMPLICIT INPUTS: {008}
None. {008}
IMPLICIT OUTPUTS: {008}
None. {008}
SIDE EFFECTS: {008}
None. {008}
***********************************************************************){008}
VAR {008}
StuffIndex : INTEGER; {008}
BEGIN {008}
(* {008}
* Pad on the right with blanks {008}
*) {008}
FOR StuffIndex := Length (StringText) + 1 TO PadLength {008}
DO {008}
StringText [StuffIndex] := ' '; {010,008}
(* {008}
* Adjust the length {008}
*) {008}
StringText [0] := Chr (PadLength) {010,008}
END; {008}
{.PA}
PROCEDURE AppendString {010}
( InsertString : PathSpec; {010}
VAR TargetString : PathSpec); {010}
(***********************************************************************{010}
FUNCTIONAL DESCRIPTION: {010}
Appends one string to another. {010}
FORMAL PARAMETERS: {010}
StringToAdd.rt.v - The string to be appended to TargetString. {010}
TargetString.mt.r - The string to which StringToAdd is to be ap- {010}
pended. {010}
RETURN VALUE: {010}
None. {010}
IMPLICIT INPUTS: {010}
None. {010}
IMPLICIT OUTPUTS: {010}
None. {010}
SIDE EFFECTS: {010}
None. {010}
***********************************************************************){010}
BEGIN {010}
Insert (InsertString, TargetString, Length (TargetString) + 1) {010}
END; {010}
{.PA}
PROCEDURE SetKeywordBit
( KeywordText : PathSpec;
VAR OptionMask : INTEGER);
(***********************************************************************
FUNCTIONAL DESCRIPTION:
Sets the bit in an attribute mask designated by a keyword. The key-
word is any of ARCHIVE, HIDDEN, READ_ONLY, or SYSTEM, or any leading
abbreviation of one of these keywords.
FORMAL PARAMETERS:
Keyword.rt.v - The keyword designating an attribute.
AttributeMask.mg.r - The attribute mask in which the bit correspond-
ing to the keyword is to be set.
RETURN VALUE:
None.
IMPLICIT INPUTS:
None.
IMPLICIT OUTPUTS:
None.
SIDE EFFECTS:
If Keyword is not an abbreviation of one of the valid keywords, an
error mesage is written to the standard output and the program is
terminated.
***********************************************************************)
BEGIN
(*
* Check against list and set appropriate bit
*)
IF PrefixLength (KeywordText, 'HIDDEN') > 0 {002}
THEN
OptionMask := OptionMask OR AttrMaskHidden
ELSE IF PrefixLength (KeywordText, 'SYSTEM') > 0 {002}
THEN
OptionMask := OptionMask OR AttrMaskSystem
ELSE IF PrefixLength (KeywordText, 'READ_ONLY') > 0 {002}
THEN
OptionMask := OptionMask OR AttrMaskReadOnly
ELSE IF PrefixLength (KeywordText, 'ARCHIVE') > 0 {002}
THEN
OptionMask := OptionMask OR AttrMaskArchive
ELSE
BEGIN
WriteLn ('Invalid argument value: "', KeywordText, '"');
Halt
END
END;
{.PA}
PROCEDURE DoSetArgument
( ArgumentText : PathSpec;
VAR OptionMask : INTEGER);
(***********************************************************************
FUNCTIONAL DESCRIPTION:
Parses the value to the /SET or /RESET option. The syntax of these
values is:
keyword
(keyword[,keyword]...])
where 'keyword' is one of ARCHIVE, HIDDEN, READ_ONLY, or SYSTEM, or
a unique leading abbreviation of one of these.
FORMAL PARAMETERS:
ValueText.rt.v - The text of the value to be parsed.
AttributeMask.mg.r - The attribute mask in which the bits cor-
responding to the keywords are to be set.
RETURN VALUE:
None.
IMPLICIT INPUTS:
None.
IMPLICIT OUTPUTS:
None.
SIDE EFFECTS:
May write a message to the standard output and halt program execut-
ion under the following circumstances:
- ValueText consists only of '(';
- ValueText starts with '(' but does not end with ')';
- ValueText has ')' before the end of the string;
- ValueText has two adjacent commas.
***********************************************************************)
VAR
KeyWord : PathSpec;
SearchIndex : INTEGER;
BEGIN
(*
* See whether single keyword or bundle
*)
IF ArgumentText [1] = '('
THEN
BEGIN
(*
* Is a bundle. Do each word individually
*)
Delete (ArgumentText, 1, 1);
WHILE Length (ArgumentText) > 0
DO
BEGIN
(*
* Isolate the keyword
*)
SearchIndex := 1;
WHILE (SearchIndex <= Length (ArgumentText)) AND
(ArgumentText [SearchIndex] <> ',') AND
(ArgumentText [SearchIndex] <> ')')
DO
SearchIndex := SearchIndex + 1;
IF SearchIndex > Length (ArgumentText)
THEN
BEGIN
WriteLn ('Invalid unterminated argument value');
Halt
END;
IF SearchIndex = 1
THEN
BEGIN
WriteLn ('Invalid null argument value');
Halt
END;
Keyword := Copy (ArgumentText, 1, SearchIndex - 1);
(*
* Set the appropriate bit
*)
SetKeywordBit (Keyword, OptionMask);
(*
* Ensure proper separator format
*)
IF SearchIndex = Length (ArgumentText)
THEN
BEGIN
IF ArgumentText [SearchIndex] <> ')'
THEN
BEGIN
WriteLn ('Invalid unterminated argument value');
Halt
END
END
ELSE
BEGIN
IF ArgumentText [SearchIndex] <> ','
THEN
BEGIN
WriteLn ('Invalid argument value after termination');
Halt
END
END;
Delete (ArgumentText, 1, SearchIndex)
END
END
ELSE
(*
* Argument value is single keyword
*)
SetKeywordBit (ArgumentText, OptionMask)
END;
{.PA}
PROCEDURE ParseCommandQualifiers; {003}
(***********************************************************************
FUNCTIONAL DESCRIPTION:
Parses the command line for the ATTRIB program.
The command line has the format:
ATTRIB wildspec [option]...
The ATTRIB token is typed by the user but is not part of the command
line tail retained by MS-DOS, and so does not participate in this
parse.
Wildspec is a single path specification which may contain wild card
characters in the last component. Any single token not starting
with the option character is accepted in this position. This is not{003}
parsed by this routine. {003}
Option is one of:
/SET:value
/RESET:value or /CLEAR:value or /REMOVE:value {004}
/[NO]LOG
where 'value' is as accepted by the DoSetArgument routine above.
The keywords SET, CLEAR, REMOVE, and LOG may be abbreviated to any{004}
unique leading substring; the keywords RESET and REMOVE may be ab-{004}
breviated all the way to R, permitted in this case as they are syn-{004}
onyms. {004}
An equal sign (=) may be used in place of the colon.
FORMAL PARAMETERS:
None.
RETURN VALUE:
None.
IMPLICIT INPUTS:
The command line tail at CS:0080. [Actually, this is an implicit
input of the CLA package which this routine uses.]
ResetMask - The mask of attribute bits to be reset.
SetMask - The mask of attribute bits to be set.
IMPLICIT OUTPUTS:
OptionSpecifed - The flag determining whether any options were
specified on the command line.
ResetMask - The mask of attribute bits to be reset.
SetMask - The mask of attribute bits to be set.
SIDE EFFECTS:
May write a message to the standard output and terminate program
execution under the following circumstances:
- A null option (slash with no other characters) is present in the
command
- An unrecognized option (slash followed by something other than a
unique abbreviation of [NO]LOG, RESET, or SET) is present in the
command
- A value is specified with [NO]LOG
- No value is specified with RESET or SET
- The attributes specified with /SET and /RESET are not disjoint.
***********************************************************************)
VAR
DummyArg : PathSpec;
Keyword : PathSpec;
SearchIndex : INTEGER;
TargetMask : ^ INTEGER;
ValueType : INTEGER;
BEGIN
(*
* Get all switches {003}
*)
DummyArg := CommandLineArgument ('', '', TRUE);
WHILE Length (DummyArg) > 0
DO
BEGIN
(*
* Delete the leading slash
*)
Delete (DummyArg, 1, 1);
IF Length (DummyArg) = 0
THEN
BEGIN
WriteLn ('Invalid null option');
Halt
END;
(*
* Extract the keyword
*)
SearchIndex := 1;
WHILE (SearchIndex <= Length (DummyArg)) AND
(DummyArg [SearchIndex] <> ':') AND
(DummyArg [SearchIndex] <> '=')
DO
SearchIndex := SearchIndex + 1;
Keyword := Copy (DummyArg, 1, SearchIndex - 1);
(*
* Delete all but the keyword value
*)
IF SearchIndex > Length (DummyArg)
THEN
SearchIndex := Length (DummyArg);
Delete (DummyArg, 1, SearchIndex);
(*
* Try to match the keyword to a possible keyword
*)
IF PrefixLength (Keyword, 'LOG') > 0 {002}
THEN
BEGIN
Logging := TRUE;
ValueType := 0
END
ELSE IF PrefixLength (Keyword, 'NOLOG') > 2 {002}
THEN
BEGIN
Logging := FALSE;
ValueType := 0
END
ELSE IF PrefixLength (Keyword, 'SET') > 0 {002}
THEN
BEGIN
TargetMask := Addr (SetMask);
ValueType := 1
END
ELSE IF (PrefixLength (Keyword, 'RESET') > 0) OR {004,002}
(PrefixLength (Keyword, 'CLEAR') > 0) OR {004}
(PrefixLength (Keyword, 'REMOVE') > 0) {004}
THEN
BEGIN
TargetMask := Addr (ResetMask);
ValueType := 1
END
ELSE IF PrefixLength (Keyword, 'HELP') > 0 {015}
THEN {015}
BEGIN {015}
HelpDesired := TRUE; {015}
ValueType := 0 {015}
END {015}
ELSE IF PrefixLength (Keyword, 'NOHELP') > 2 {015}
THEN {015}
BEGIN {015}
HelpDesired := FALSE; {015}
ValueType := 0 {015}
END {015}
ELSE
BEGIN
WriteLn ('Invalid switch: "', Keyword, '"');
Halt
END;
(*
* Parse the switch value
*)
IF ValueType = 0
THEN
BEGIN
IF Length (DummyArg) > 0
THEN
BEGIN
WriteLn ('/LOG switch does not take value');
Halt
END
END
ELSE
BEGIN
IF Length (DummyArg) = 0
THEN
BEGIN
WriteLn ('/SET and /RESET require value');
Halt
END;
DoSetArgument (DummyArg, TargetMask ^)
END;
(* {005}
* Note option parsed {005}
*) {005}
OptionSpecified := TRUE; {005}
(*
* Get next switch
*)
DummyArg := CommandLineArgument ('', '', TRUE)
END;
(*
* Check for non-interference of set and reset masks
*)
IF (SetMask AND ResetMask) <> 0
THEN
BEGIN
WriteLn ('Same attribute specified for both /SET and /RESET');
Halt
END
END;
{.PA}
(***********************************************************************
FUNCTIONAL DESCRIPTION:
Manipulates attributes of files.
FORMAL PARAMETERS:
None.
RETURN VALUE:
None.
IMPLICIT INPUTS:
Logging - The flag showing whether attribute messages are to be
written to the standard output.
ResetMask - The mask of attribute bits to be reset in the files sel-
ected by WildSpec.
SetMask - The mask of attribute bits to be set in the files select-
ed by WildSpec.
IMPLICIT OUTPUTS:
None.
SIDE EFFECTS:
May write messages to the standard output.
May modify attributes of files.
***********************************************************************)
TYPE
RegPack = RECORD
CASE INTEGER OF
0: (AX, BX, CX, DX, DP, SI, DI, DS, ES, Flags : INTEGER);
1: (AL, AH, BL, BH, CL, CH, DL, DH : BYTE)
END;
VAR
FileSpec : PathSpec;
NewAttr : INTEGER;
OldAttr : INTEGER;
OutLine : PathSpec; {010}
Registers : RegPack;
WildSpec : PathSpec; {003}
BEGIN
(* {012}
* Set up Control/C trapping for program {012}
*) {012}
CtrlCSetup; {012,009}
(*
* Print banner
*)
WriteLn ('ATTRIB version ', ProgramVersion);
Flush (Output); {012}
(*
* Parse the command line
*)
Logging := TRUE; {003}
OptionSpecified := FALSE; {005}
HelpDesired := FALSE; {015}
ResetMask := 0; {003}
SetMask := 0; {003}
ParseCommandQualifiers; {003}
WildSpec := CommandLineArgument ('', '', FALSE); {005}
IF (Length (WildSpec) = 0) AND NOT OptionSpecified {005}
THEN {005}
BEGIN {005}
(* {015}
* A totally blank command line. Assume *.* and give short mes-{015}
* sage. {015}
*) {015}
WildSpec := '*.*'; {015}
WriteLn; {015}
WriteLn ('Use /HELP qualifier for help') {015}
END; {005}
(* {015}
* If help requested, give it {015}
*) {015}
IF HelpDesired {015}
THEN {015}
PrintHelp; {015}
(* {006}
* Scan with each wild card specification {006}
*) {006}
WHILE (NOT CtrlCOccurred) AND (Length (WildSpec) > 0) {009,006}
DO {006}
BEGIN {006}
(* {007}
* Append *.* if path ends in : or \ {007}
*) {007}
IF WildSpec [Length (WildSpec)] IN [':', '/', '\'] {007}
THEN {007}
Insert ('*.*', WildSpec, Length (WildSpec) + 1); {007}
(* {007}
* Make the wild card path absolute {007}
*) {007}
MakePathAbsolute (WildSpec); {007}
(* {008}
* Log the specification {008}
*) {008}
IF Logging {008}
THEN {008}
BEGIN {008}
WriteLn; {008}
WriteLn (WildSpec, ':') {008}
END; {008}
(*
* Initialize the wild card scan
*)
IF NOT WildExpandInitialize (WildSpec, $17)
THEN
BEGIN
IF Logging {008}
THEN {008}
WriteLn (' No files found') {008}
ELSE {008}
WriteLn ('No files found for ', WildSpec) {008}
END {008}
ELSE {006}
BEGIN {006}
WildExpandContinue (FileSpec, OldAttr); {011}
WHILE (NOT CtrlCOccurred) AND (Length (FileSpec) > 0) {009}
DO
BEGIN
(*
* Append NUL for MS-DOS
*)
FileSpec [Length (FileSpec) + 1] := #$00;
(*
* Obtain changed attributes
*)
NewAttr := (OldAttr OR SetMask) AND NOT ResetMask;
(*
* Modify attributes
*)
IF NewAttr <> OldAttr
THEN
BEGIN
Registers . AH := $43;
Registers . AL := $01;
Registers . CX := NewAttr AND NOT AttrMaskSubDirectory;
Registers . DS := Seg (FileSpec [1]);
Registers . DX := Ofs (FileSpec [1]);
MsDos (Registers)
END
ELSE {010}
Registers . Flags := 0; {010}
IF (Registers . Flags AND 1) <> 0
THEN
WriteLn ('Cannot change attributes for ', FileSpec) {008}
ELSE
BEGIN
(*
* List new attributes and file name
*)
IF Logging
THEN
BEGIN
OutLine := ' '; {010}
AppendString (BaseName (FileSpec), OutLine); {010}
IF (NewAttr AND AttrMaskArchive) <> 0
THEN
BEGIN {010}
Pad (OutLine, 16); {014,010}
AppendString ('Arc', OutLine) {010}
END; {010}
IF (NewAttr AND AttrMaskSubDirectory) <> 0
THEN
BEGIN {010}
Pad (OutLine, 20); {014,010}
AppendString ('Dir', OutLine) {010}
END; {010}
IF (NewAttr AND AttrMaskReadOnly) <> 0
THEN
BEGIN {010}
Pad (OutLine, 24); {014,010}
AppendString ('R/O', OutLine) {010}
END; {010}
IF (NewAttr AND AttrMaskHidden) <> 0
THEN
BEGIN {010}
Pad (OutLine, 28); {014,010}
AppendString ('Hid', OutLine) {010}
END; {010}
IF (NewAttr AND AttrMaskSystem) <> 0
THEN
BEGIN {010}
Pad (OutLine, 32); {014,010}
AppendString ('Sys', OutLine) {010}
END; {010}
WriteLn (OutLine); {010,008}
Flush (Output) {009}
END
END;
WildExpandContinue (FileSpec, OldAttr) {011}
END {006}
END;
WildSpec := CommandLineArgument ('', '', FALSE) {006}
END {006}
END.