2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
5 List the contents of a directory.
7 /*****************************************************************************
15 List [(dir | pattern | filename)] [ PAT (pattern)] [KEYS] [DATES]
16 [NODATES] [TO (name)] [SUB (string)] [SINCE (date)] [UPTO (date)]
17 [QUICK] [BLOCK] [NOHEAD] [FILES] [DIRS] [LFORMAT (string)] [ALL]
21 DIR/M,P=PAT/K,DATES/S,NODATES/S,TO/K,SUB/K,SINCE/K,UPTO/K,QUICK/S,BLOCK/S,NOHEAD/S,FILES/S,DIRS/S,LFORMAT/K,ALL/S
29 Lists detailed information about the files and directories in the
30 current directory or in the directory specified by DIR.
32 The information for each file or directory is presented on a separate
33 line, containing the following information:
42 DIR -- The directory to list. If left out, the current
43 directory will be listed.
44 PAT -- Display only files matching 'string'
45 KEYS -- Display the block number of each file or directory
46 DATES -- Display the creation date of files and directories
47 NODATES -- Don't display dates
48 TO (name) -- Write the listing to a file instead of stdout
49 SUB (string) -- Display only files, a substring of which matches
50 the substring 'string'
51 SINCE (date) -- Display only files newer than 'date'
52 UPTO (date) -- Display only files older than 'date'
53 QUICK -- Display only the names of files
54 BLOCK -- File sizes are in blocks of 512 bytes
55 NOHEAD -- Don't print any header information
56 FILES -- Display files only
57 DIRS -- Display directories only
58 LFORMAT -- Specify the list output in printf-style
59 ALL -- List the contents of directories recursively
61 The following attributes of the LFORMAT strings are available
64 %B -- size of file in blocks rather than bytes
69 %K -- file key block number
70 %L -- size of file in bytes
71 %M -- file name without extension
74 %S -- superceded by %N and %P; obsolete
79 Standard DOS return codes.
84 Directory "C:" on Wednesday 12-Dec-99
85 AddBuffers 444 --p-rwed 02-Sep-99 11:51:31
86 Assign 3220 --p-rwed 02-Sep-99 11:51:31
87 Avail 728 --p-rwed 02-Sep-99 11:51:31
88 Copy 3652 --p-rwed 02-Sep-99 11:51:31
89 Delete 1972 --p-rwed 02-Sep-99 11:51:31
90 Execute 4432 --p-rwed 02-Sep-99 11:51:31
91 List 5108 --p-rwed 02-Sep-99 11:51:31
92 Installer 109956 ----rwed 02-Sep-99 11:51:31
93 Which 1068 --p-rwed 02-Sep-99 11:51:31
94 9 files - 274 blocks used
104 ******************************************************************************/
107 #include <aros/debug.h>
109 #include <clib/macros.h>
110 #include <exec/memory.h>
111 #include <proto/exec.h>
112 #include <dos/datetime.h>
114 #include <dos/exall.h>
115 #include <dos/dosasl.h>
116 #include <dos/datetime.h>
117 #include <proto/dos.h>
118 #include <proto/alib.h>
119 #include <utility/tagitem.h>
127 const TEXT version
[] = "$VER: List 41.5 (3.12.2000)\n";
129 #define ARG_TEMPLATE "DIR/M,P=PAT/K,KEYS/S,DATES/S,NODATES/S,TO/K,SUB/K,SINCE/K,UPTO/K,QUICK/S,BLOCK/S,NOHEAD/S,FILES/S,DIRS/S,LFORMAT/K,ALL/S"
138 typedef struct _Statistics
167 #define MAX_PATH_LEN 1024
169 #define BLOCKSIZE 512
171 int printDirHeader(STRPTR dirname
, BOOL noHead
)
175 char datestr
[LEN_DATSTRING
];
176 char dow
[LEN_DATSTRING
];
180 DateStamp((struct DateStamp
*)&dt
);
181 dt
.dat_Format
= FORMAT_DEF
;
184 dt
.dat_StrDate
= datestr
;
185 dt
.dat_StrTime
= NULL
;
188 Printf("Directory \"%s\" on %s %s:\n", dirname
, dow
, datestr
);
195 /* Possible printf-type switches
197 %A -- file attributes
198 %B -- size of file in blocks rather than bytes
203 %K -- file key block number
204 %L -- size of file in bytes
205 %M -- file name without extension
214 struct AnchorPath
*ap
;
226 #define roundUp(x, bSize) ((x + bSize - 1)/bSize)
228 int printLformat(STRPTR format
, struct lfstruct
*lf
)
230 STRPTR filename
= FilePart(lf
->filename
);
233 while ('\0' != (c
= *format
++))
237 switch (toupper(*format
++))
254 /* File size in blocks of BLOCKSIZE bytes */
262 ULONG tmp
= roundUp(lf
->size
, BLOCKSIZE
);
264 /* File is 0 bytes? */
277 /* Path incl. volume name*/
282 if (NameFromLock(lf
->ap
->ap_Current
->an_Lock
, buf
, 256))
289 if ((len
> 0) && (buf
[len
- 1] != ':') && (buf
[len
- 1] != '/'))
298 /* File attributes (flags) */
305 Printf("[%ld]", lf
->key
);
322 Printf("%lu", lf
->size
);
328 /* File name without extension */
331 STRPTR lastPoint
= strrchr(filename
, '.');
333 if (lastPoint
!= NULL
)
340 /* Resurrect filename in case we should print it once
342 if (lastPoint
!= NULL
)
360 STRPTR extension
= strrchr(filename
, '.');
362 if (extension
!= NULL
)
370 /* Path name, but without volume */
373 STRPTR end
= FilePart(lf
->filename
);
378 Printf(lf
->filename
);
380 /* Restore pathname */
391 Printf("%%%lc", *format
);
405 int printFileData(struct AnchorPath
*ap
,
406 BOOL showFiles
, BOOL showDirs
, STRPTR parsedPattern
,
407 ULONG
*files
, ULONG
*dirs
, ULONG
*nBlocks
, STRPTR lFormat
,
408 BOOL quick
, BOOL dates
, BOOL noDates
, BOOL block
,
409 struct DateStamp
*sinceDate
, struct DateStamp
*uptoDate
,
410 BOOL doSince
, BOOL doUpto
, STRPTR subpatternStr
,
413 STRPTR filename
= ap
->ap_Buf
;
414 BOOL isDir
= (ap
->ap_Info
.fib_DirEntryType
>= 0);
415 struct DateStampe
*ds
= &ap
->ap_Info
.fib_Date
;
416 ULONG protection
= ap
->ap_Info
.fib_Protection
;
417 ULONG size
= ap
->ap_Info
.fib_Size
;
418 STRPTR filenote
= ap
->ap_Info
.fib_Comment
;
419 LONG diskKey
= ap
->ap_Info
.fib_DiskKey
;
421 int error
= RETURN_OK
;
423 UBYTE date
[LEN_DATSTRING
];
424 UBYTE time
[LEN_DATSTRING
];
429 /* Do the file match the time interval we are looking for?
430 (ARG_SINCE and ARG_UPTO) -- any combination of these may be
432 if ((doSince
&& (CompareDates(sinceDate
, ds
) < 0)) ||
433 (doUpto
&& (CompareDates(uptoDate
, ds
) > 0)))
438 /* Does the filename match a certain pattern? (ARG_PAT) */
439 if (parsedPattern
!= NULL
&&
440 !MatchPatternNoCase(parsedPattern
, FilePart(filename
)))
445 /* Does a substring of the filename match a certain pattern? (ARG_SUB) */
446 if (subpatternStr
!= NULL
&&
447 !MatchPatternNoCase(subpatternStr
, FilePart(filename
)))
452 CopyMem(ds
, &dt
.dat_Stamp
, sizeof(struct DateStamp
));
453 dt
.dat_Format
= FORMAT_DOS
;
454 dt
.dat_Flags
= DTF_SUBST
;
455 dt
.dat_StrDay
= NULL
;
456 dt
.dat_StrDate
= date
;
457 dt
.dat_StrTime
= time
;
458 DateToStr(&dt
); /* returns 0 if invalid */
460 /* Convert the protection bits to a string */
461 flags
[0] = protection
& FIBF_SCRIPT
? 's' : '-';
462 flags
[1] = protection
& FIBF_PURE
? 'p' : '-';
463 flags
[2] = protection
& FIBF_ARCHIVE
? 'a' : '-';
465 /* The following flags are high-active! */
466 flags
[3] = protection
& FIBF_READ
? '-' : 'r';
467 flags
[4] = protection
& FIBF_WRITE
? '-' : 'w';
468 flags
[5] = protection
& FIBF_EXECUTE
? '-' : 'e';
469 flags
[6] = protection
& FIBF_DELETE
? '-' : 'd';
478 struct lfstruct lf
= { ap
, isDir
, date
, time
, flags
, filename
,
479 filenote
, size
, diskKey
};
481 printLformat(lFormat
, &lf
);
488 D(bug("Found file %s\n", filename
));
490 Printf("%-25s ", FilePart(filename
));
494 Printf(" <Dir> %7s ", flags
);
497 if (!noDates
&& (!quick
|| dates
))
499 Printf("%-11s %s", date
, time
);
512 struct lfstruct lf
= { ap
, isDir
, date
, time
, flags
, filename
,
513 filenote
, size
, diskKey
};
515 printLformat(lFormat
, &lf
);
519 *nBlocks
+= roundUp(size
, BLOCKSIZE
);
523 Printf("%-25s ", FilePart(filename
));
531 int i
; /* Loop variable */
533 sprintf(key
, "%ld", diskKey
);
534 fill
= 7 - strlen(key
) - 2;
536 for (i
= 0; i
< fill
; i
++)
541 Printf("[%ld] ", diskKey
);
548 block
? roundUp(size
, BLOCKSIZE
) : size
);
556 Printf("%7s ", flags
);
559 if (!noDates
&& (!quick
|| dates
))
561 Printf("%-11s %s", date
, time
);
564 if (!quick
&& (*filenote
!= 0))
566 Printf("\n: %s", filenote
);
571 *nBlocks
+= roundUp(size
, BLOCKSIZE
);
579 /* Print directory summary information */
580 void printSummary(int files
, int dirs
, int nBlocks
, BOOL noHead
, BOOL PrintEmpty
)
587 if ((files
== 0) && (dirs
== 0) && PrintEmpty
)
589 Printf("Directory is empty\n");
595 Printf("%ld files - ", files
);
600 Printf("%ld directories - ", dirs
);
603 Printf("%ld bytes used\n", nBlocks
* BLOCKSIZE
);
608 int listFile(STRPTR filename
, BOOL showFiles
, BOOL showDirs
,
609 STRPTR parsedPattern
, BOOL noHead
, STRPTR lFormat
, BOOL quick
,
610 BOOL dates
, BOOL noDates
, BOOL block
, struct DateStamp
*sinceDate
,
611 struct DateStamp
*uptoDate
, BOOL doSince
, BOOL doUpto
,
612 STRPTR subpatternStr
, BOOL all
, BOOL keys
, Statistics
*stats
)
614 struct AnchorPath
*ap
;
615 struct List DirList
, FreeDirNodeList
;
616 struct DirNode
*dirnode
, *prev_dirnode
= NULL
;
624 NewList(&FreeDirNodeList
);
628 ap
= AllocVec(sizeof(struct AnchorPath
) + MAX_PATH_LEN
, MEMF_CLEAR
);
635 ap
->ap_Strlen
= MAX_PATH_LEN
;
637 error
= MatchFirst(filename
, ap
);
639 /* Explicitely named directory and not a pattern? --> enter dir */
643 if (!(ap
->ap_Flags
& APF_ITSWILD
))
645 if (ap
->ap_Info
.fib_DirEntryType
>= 0)
647 //error = printDirHeader(filename, noHead);
648 ap
->ap_Flags
|= APF_DODIR
;
652 error
= MatchNext(ap
);
662 ap
->ap_BreakBits
= SIGBREAKF_CTRL_C
;
663 if (FilePart(ap
->ap_Buf
) == ap
->ap_Buf
)
665 ap
->ap_Flags
&= ~APF_DirChanged
;
671 ** There's something to show.
673 if (!(ap
->ap_Flags
& APF_DIDDIR
))
675 if (ap
->ap_Flags
& APF_DirChanged
)
680 if (!first
) printSummary(files
, dirs
, nBlocks
, noHead
, TRUE
);
682 /* Update global statistics for (possiblr) ALL option */
683 stats
->nFiles
+= files
;
684 stats
->nDirs
+= dirs
;
685 stats
->nBlocks
+= nBlocks
;
691 p
= PathPart(ap
->ap_Buf
);
695 error
= printDirHeader(ap
->ap_Buf
, noHead
);
701 error
= printFileData(ap
,
720 if (all
&& (ap
->ap_Info
.fib_DirEntryType
>= 0))
722 if ((dirnode
= malloc(sizeof(struct DirNode
))))
724 if ((dirnode
->dirname
= strdup(ap
->ap_Buf
)))
726 Insert(&DirList
, (struct Node
*)dirnode
,
727 (struct Node
*)prev_dirnode
);
729 prev_dirnode
= dirnode
;
739 error
= MatchNext(ap
);
743 } while (0 == error
);
750 if (error
== ERROR_BREAK
)
752 PrintFault(error
, NULL
);
755 if (error
== ERROR_NO_MORE_ENTRIES
)
760 if ((error
== 0) || (error
== ERROR_BREAK
))
762 printSummary(files
, dirs
, nBlocks
, noHead
, TRUE
);
765 /* Update global statistics for (possiblr) ALL option */
766 stats
->nFiles
+= files
;
767 stats
->nDirs
+= dirs
;
768 stats
->nBlocks
+= nBlocks
;
777 dirnode
= (struct DirNode
*)RemHead(&DirList
);
781 filename
= dirnode
->dirname
;
786 /* do not free() dirnode, as we reference dirnode->dirname! */
788 AddTail(&FreeDirNodeList
, (struct Node
*)dirnode
);
792 while ((dirnode
= (struct DirNode
*)RemHead(&FreeDirNodeList
)))
794 free(dirnode
->dirname
);
806 IPTR args
[NOOFARGS
] =
808 (IPTR
) NULL
, // ARG_DIR
809 (IPTR
) NULL
, // ARG_PAT
812 FALSE
, // ARG_NODATES
813 (IPTR
) NULL
, // ARG_TO
814 (IPTR
) NULL
, // ARG_SUB
815 (IPTR
) NULL
, // ARG_SINCE
816 (IPTR
) NULL
, // ARG_UPTO
822 FALSE
, // ARG_LFORMAT
825 static const STRPTR
*default_directories
[] = {"", 0};
828 LONG error
= RETURN_OK
;
829 STRPTR parsedPattern
= NULL
;
830 STRPTR subpatternStr
= NULL
;
831 BPTR oldOutput
= NULL
;
833 Statistics stats
= { 0, 0, 0 };
835 rda
= ReadArgs(ARG_TEMPLATE
, args
, NULL
);
839 STRPTR
*directories
= (STRPTR
*)args
[ARG_DIR
];
840 STRPTR lFormat
= (STRPTR
)args
[ARG_LFORMAT
];
841 STRPTR pattern
= (STRPTR
)args
[ARG_PAT
];
842 STRPTR toFile
= (STRPTR
)args
[ARG_TO
];
843 STRPTR subStr
= (STRPTR
)args
[ARG_SUB
];
844 STRPTR since
= (STRPTR
)args
[ARG_SINCE
];
845 STRPTR upto
= (STRPTR
)args
[ARG_UPTO
];
846 BOOL files
= (BOOL
)args
[ARG_FILES
];
847 BOOL dirs
= (BOOL
)args
[ARG_DIRS
];
848 BOOL noDates
= (BOOL
)args
[ARG_NODATES
];
849 BOOL dates
= (BOOL
)args
[ARG_DATES
];
850 BOOL quick
= (BOOL
)args
[ARG_QUICK
];
851 BOOL noHead
= (BOOL
)args
[ARG_NOHEAD
];
852 BOOL block
= (BOOL
)args
[ARG_BLOCK
];
853 BOOL all
= (BOOL
)args
[ARG_ALL
];
854 BOOL keys
= (BOOL
)args
[ARG_KEYS
];
856 struct DateTime sinceDatetime
;
857 struct DateTime uptoDatetime
;
859 ULONG i
; /* Loop variable */
863 sinceDatetime
.dat_StrDate
= since
;
864 sinceDatetime
.dat_StrTime
= NULL
;
865 sinceDatetime
.dat_Format
= FORMAT_DEF
;
866 sinceDatetime
.dat_Flags
= 0;
867 if (StrToDate(&sinceDatetime
) == DOSFALSE
)
870 Printf("*** Illegal 'SINCE' parameter\n");
878 uptoDatetime
.dat_StrDate
= upto
;
879 uptoDatetime
.dat_StrTime
= NULL
;
880 uptoDatetime
.dat_Format
= FORMAT_DEF
;
881 uptoDatetime
.dat_Flags
= 0;
883 if (StrToDate(&uptoDatetime
) == DOSFALSE
)
886 Printf("*** Illegal 'UPTO' parameter\n");
894 STRPTR subStrWithPat
;
895 ULONG length
= (strlen(subStr
) + sizeof("#?#?"))*2 + 2;
897 subStrWithPat
= AllocVec(length
, MEMF_ANY
);
899 if (subStrWithPat
== NULL
)
902 PrintFault(IoErr(), "List");
907 strcpy(subStrWithPat
, "#?");
908 strcat(subStrWithPat
, subStr
);
909 strcat(subStrWithPat
, "#?");
911 subpatternStr
= AllocVec(length
, MEMF_ANY
);
913 if (subpatternStr
== NULL
||
914 ParsePatternNoCase(subStrWithPat
, subpatternStr
, length
) == -1)
916 FreeVec(subStrWithPat
);
918 PrintFault(IoErr(), "List");
923 FreeVec(subStrWithPat
);
929 ULONG length
= strlen(pattern
)*2 + 2;
931 parsedPattern
= AllocVec(length
, MEMF_ANY
);
933 if (parsedPattern
== NULL
||
934 ParsePatternNoCase(pattern
, parsedPattern
, length
) == -1)
936 FreeVec(subpatternStr
);
945 BPTR file
= Open(toFile
, MODE_NEWFILE
);
949 FreeVec(subpatternStr
);
950 FreeVec(parsedPattern
);
952 PrintFault(IoErr(), "List");
956 oldOutput
= SelectOutput(file
);
965 /* if (!dates && !noDates)
975 if ((directories
== NULL
) || (*directories
== NULL
))
977 directories
= default_directories
;
980 for (i
= 0; directories
[i
] != NULL
; i
++)
982 error
= listFile(directories
[i
], files
, dirs
, parsedPattern
,
983 noHead
, lFormat
, quick
, dates
, noDates
,
984 block
, &sinceDatetime
.dat_Stamp
,
985 &uptoDatetime
.dat_Stamp
, since
!= NULL
,
986 upto
!= NULL
, subpatternStr
, all
, keys
,
989 if (error
!= RETURN_OK
)
1004 if ((BOOL
)args
[ARG_ALL
] && (stats
.nFiles
|| stats
.nDirs
))
1006 Printf("\nTOTAL: %ld files - %ld directories - %ld blocks used\n",
1007 stats
.nFiles
, stats
.nDirs
, stats
.nBlocks
);
1011 if (error
!= RETURN_OK
)
1013 if (error
== ERROR_BREAK
)
1015 error
= RETURN_WARN
;
1019 PrintFault(error
, "List");
1020 error
= RETURN_FAIL
;
1024 if (parsedPattern
!= NULL
)
1026 FreeVec(parsedPattern
);
1029 if (subpatternStr
!= NULL
)
1031 FreeVec(subpatternStr
);
1034 if (oldOutput
!= NULL
)
1036 Close(SelectOutput(oldOutput
));