2 Copyright © 1995-2015, 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,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
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 -- Always display the full modification date of files
47 and directories instead of a day name.
48 NODATES -- Don't display dates
49 TO (name) -- Write the listing to a file instead of stdout
50 SUB (string) -- Display only files, a substring of which matches
51 the substring 'string'
52 SINCE (date) -- Display only files newer than 'date'
53 UPTO (date) -- Display only files older than 'date'
54 QUICK -- Display only the names of files
55 BLOCK -- File sizes are in blocks of 512 bytes
56 NOHEAD -- Don't print any header information
57 FILES -- Display files only
58 DIRS -- Display directories only
59 LFORMAT -- Specify the list output in printf-style
60 ALL -- List the contents of directories recursively
63 The following attributes of the LFORMAT strings are available
66 %B -- size of file in blocks rather than bytes
68 %D -- modification date
70 %F -- absolute file path, with volume label
71 %K -- file key block number
72 %L -- size of file in bytes
73 %M -- file name without extension
76 %S -- superseded by %N and %P; obsolete
77 %T -- modification time
80 Additionally, the following modifiers, each optional, can be used,
81 in this order, following the % character:
83 left-justify -- minus sign
84 field width minimum -- value
85 value width maximum -- dot value
87 Value width maximum is not available for all numeric fields.
91 Standard DOS return codes.
96 Directory "c:" on Wednesday 12/18/14:
97 Assign 6548 ---rwed Saturday 01:12:16
98 Copy 17772 ---rwed Saturday 01:12:24
99 AddBuffers 5268 ---rwed Saturday 01:14:46
100 Avail 8980 ---rwed Saturday 01:14:51
101 Delete 8756 ---rwed Saturday 01:14:59
102 Install 13024 ---rwed Saturday 01:15:09
103 List 20228 ---rwed Today 12:06:38
104 Which 7840 ---rwed Saturday 01:16:09
105 8 file - 167 blocks used
107 1> List C: lformat "[%10.5M] -- >%-4b<"
126 Current lformat interpretation requires re-interpretation of the format for each entry.
129 ******************************************************************************/
132 #include <aros/debug.h>
134 #include <clib/macros.h>
135 #include <exec/memory.h>
136 #include <proto/exec.h>
137 #include <dos/datetime.h>
139 #include <dos/exall.h>
140 #include <dos/dosasl.h>
141 #include <dos/datetime.h>
142 #include <proto/dos.h>
143 #include <proto/alib.h>
144 #include <proto/utility.h>
145 #include <utility/tagitem.h>
147 const TEXT version
[] = "$VER: List 41.13 (18.12.2014)\n";
149 #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"
158 typedef struct _Statistics
187 #define MAX_PATH_LEN 1024
189 #define BLOCKSIZE 512
191 #define DIRTEXT "Dir"
192 #define EMPTYTEXT "empty"
195 /* UQUAD2string: Helper function to generate a decimal string representation for a UQUAD value.
196 Arguments: Value; a UBYTE buffer large enough to hold the string; length of the buffer.
197 Returns: Pointer to string inside the buffer. (String is end-aligned in the buffer!)
198 Note: Just a helper: Not safe with incorrect input!
201 UBYTE
*UQUAD2string( UQUAD value
, UBYTE
*buffer
, int buflen
)
203 buffer
[ --buflen
] = '\0';
207 buffer
[ --buflen
] = '0' + (value
% 10);
211 return buffer
+buflen
;
216 int printDirHeader(STRPTR dirname
, BOOL noHead
)
220 char datestr
[LEN_DATSTRING
];
221 char dow
[LEN_DATSTRING
];
225 DateStamp((struct DateStamp
*)&dt
);
226 dt
.dat_Format
= FORMAT_DEF
;
229 dt
.dat_StrDate
= datestr
;
230 dt
.dat_StrTime
= NULL
;
233 Printf("Directory \"%s\" on %s %s:\n", dirname
, dow
, datestr
);
240 /* Possible lformat switches
242 %A -- file attributes
243 %B -- size of file in blocks rather than bytes
247 %F -- absolute file path, with volume label
248 %K -- file key block number
249 %L -- size of file in bytes
250 %M -- file name without extension
253 %S -- file name or file path
256 %F used to be documented as just volume name. Though not Amiga-compatible, volume and path separate might indeed be useful.
261 struct AnchorPath
*ap
;
273 #define roundUp(x, bSize) ((x + bSize - 1)/bSize)
276 int printLformat(STRPTR format
, struct lfstruct
*lf
)
278 STRPTR filename
= FilePart(lf
->filename
);
279 STRPTR temp
= format
;
280 LONG substitutePath
= 0;
282 UBYTE fbuf
[ 260]; // 256 plus 3 characters format string plus '\0'.
286 Whether the path or the filename is substituted for an occurrence
287 of %S depends on how many occurrences are in the LFORMAT line, and
288 their order, as follows:
290 Occurrences of %S 1st 2nd 3rd 4th
293 3 path filename filename
294 4 path filename path filename
296 For 5 or more occurences: As with 4, with occurences beyond the 4th the filename.
299 while ( ( substitutePath
< 4 ) && ( '\0' != (c
= *temp
++) ) )
302 if ( 'S' == ToUpper(*temp
++) )
305 if ( substitutePath
== 3 )
309 while ('\0' != (c
= *format
++))
311 if ('%' == c
) // Character introducing a format switch in lformat.
313 /* Try for modifiers */
316 fbuf
[ fbufindex
++]= '%'; // Introducing a format type for PrintF.
318 while ((c
= *format
++))
320 if (c
== '-') // Left align
322 fbufindex
= 1; // Only the last one counts
323 dot
= 0; // Reset max value width as well
325 else if (c
== '.') // Max value width.
329 fbufindex
= dot
; // Only the last one counts.
333 dot
= fbufindex
; // Max value width starts after the dot
336 else if ( c
< '0' || '9' < c
) // It's not a digit either ==> end of modifiers
340 if (fbufindex
< 256) // Leave room for a three character format string plus \0.
342 fbuf
[ fbufindex
++]= c
;
343 } // Squeezes out any overflow silently. Not a likely event, but is it acceptable? Desperado 20141217
347 /* Interpret argument */
348 switch (cu
= ToUpper(c
))
352 strcpy( fbuf
+fbufindex
, "s");
353 D(bug("[List] rawFormat = [%s]", fbuf
));
354 Printf( fbuf
, lf
->comment
);
357 /* Modification date */
359 strcpy( fbuf
+fbufindex
, "s");
360 D(bug("[List] rawFormat = [%s]", fbuf
));
361 Printf( fbuf
, lf
->date
);
364 /* Modification time */
366 strcpy( fbuf
+fbufindex
, "s");
367 D(bug("[List] rawFormat = [%s]", fbuf
));
368 Printf( fbuf
, lf
->time
);
373 /* File size in blocks of BLOCKSIZE bytes */
378 strcpy( fbuf
+fbufindex
, "s");
379 D(bug("[List] rawFormat = [%s]", fbuf
));
380 Printf( fbuf
, DIRTEXT
);
384 UQUAD size
= ( cu
== 'B' ? roundUp(lf
->size
, BLOCKSIZE
) : lf
->size
); // Blocks or bytes.
386 /* File has no content? */
389 strcpy( fbuf
+fbufindex
, "s");
390 D(bug("[List] rawFormat = [%s]", fbuf
));
391 Printf( fbuf
, EMPTYTEXT
);
395 UBYTE buf
[ 256]; // Should be UQUADSTRSIZE +1, but this will suffice.
396 UBYTE
*quadstr
= UQUAD2string( size
, buf
, 256);
398 strcpy( fbuf
+fbufindex
, "s"); // Should we implement a '%q' type?
399 D(bug("[List] rawFormat = [%s]", fbuf
));
400 Printf( fbuf
, quadstr
);
401 } // Side effect of converting uquad to string: User can even maxsize numbers, if wanted.
406 /* Path incl. volume name*/
409 UBYTE buf
[257]; // 256 + room for an extra '/'.
411 if (NameFromLock(lf
->ap
->ap_Current
->an_Lock
, buf
, 256))
413 int len
= strlen(buf
); // For checking the end of the string
415 if ((len
> 0) && (buf
[len
- 1] != ':') && (buf
[len
- 1] != '/')) // We need a separator:
417 strcpy( buf
+len
, "/"); // Add an /.
420 strcpy( fbuf
+fbufindex
, "s");
421 D(bug("[List] rawFormat = [%s]", fbuf
));
428 /* File attributes (flags) */
430 strcpy( fbuf
+fbufindex
, "s");
431 D(bug("[List] rawFormat = [%s]", fbuf
));
432 Printf( fbuf
, lf
->flags
);
437 strcpy( fbuf
+fbufindex
, "lu");
438 D(bug("[List] rawFormat = [%s]", fbuf
));
439 Printf( fbuf
, lf
->key
);
442 /* File name without extension */
445 STRPTR lastPoint
= strrchr(filename
, '.');
447 if (lastPoint
!= NULL
)
452 strcpy( fbuf
+fbufindex
, "s");
453 D(bug("[List] rawFormat = [%s]", fbuf
));
454 Printf( fbuf
, filename
);
456 /* Resurrect filename in case we need to print it again */
457 if (lastPoint
!= NULL
)
465 /* Filename or Path name */
467 D(bug("[List] substitutePath = %d\n", substitutePath
));
468 if ( (--substitutePath
== 3) || (substitutePath
== 1) )
470 STRPTR end
= FilePart(lf
->filename
);
475 strcpy( fbuf
+fbufindex
, "s");
476 D(bug("[List] rawFormat = [%s]", fbuf
));
477 Printf( fbuf
, lf
->filename
);
479 /* Restore pathname */
486 strcpy( fbuf
+fbufindex
, "s");
487 D(bug("[List] rawFormat = [%s]", fbuf
));
488 Printf( fbuf
, filename
);
494 STRPTR extension
= strrchr(filename
, '.');
496 if (extension
!= NULL
)
498 strcpy( fbuf
+fbufindex
, "s");
499 D(bug("[List] rawFormat = [%s]", fbuf
));
500 Printf( fbuf
, ++extension
); // Skip the dot.
506 /* File path as specified */
509 STRPTR end
= FilePart(lf
->filename
);
514 strcpy( fbuf
+fbufindex
, "s");
515 D(bug("[List] rawFormat = [%s]", fbuf
));
516 Printf( fbuf
, lf
->filename
);
518 /* Restore pathname */
524 /* Unexpected end of format */
526 fbuf
[ fbufindex
]= '\0'; // Just add end to the string.
527 Printf( "%s", fbuf
); // We never found the switch, so print as text.
531 /* Unrecognised %-sequence */
533 fbuf
[ fbufindex
]= '\0'; // Just add end to the string.
534 Printf("%s%lc", fbuf
, c
); // Print interpreted format part as text.
548 int printFileData(struct AnchorPath
*ap
,
549 BOOL showFiles
, BOOL showDirs
, STRPTR parsedPattern
,
550 ULONG
*files
, ULONG
*dirs
, ULONG
*nBlocks
, STRPTR lFormat
,
551 BOOL quick
, BOOL dates
, BOOL noDates
, BOOL block
,
552 struct DateStamp
*sinceDate
, struct DateStamp
*uptoDate
,
553 BOOL doSince
, BOOL doUpto
, STRPTR subpatternStr
,
556 STRPTR filename
= ap
->ap_Buf
;
557 BOOL isDir
= (ap
->ap_Info
.fib_DirEntryType
>= 0);
558 struct DateStamp
*ds
= &ap
->ap_Info
.fib_Date
;
559 ULONG protection
= ap
->ap_Info
.fib_Protection
;
560 UQUAD size
= ap
->ap_Info
.fib_Size
;
561 STRPTR filenote
= ap
->ap_Info
.fib_Comment
;
562 ULONG diskKey
= ap
->ap_Info
.fib_DiskKey
;
566 UBYTE date
[LEN_DATSTRING
];
567 UBYTE time
[LEN_DATSTRING
];
572 #if defined(ACTION_GET_FILE_SIZE64)
573 if (ap
->ap_Info
.fib_Size
>= 0x7FFFFFFF)
576 flock
= Lock(filename
, ACCESS_READ
);
580 UQUAD
*size_ptr
= (UQUAD
*)DoPkt(((struct FileLock
*)flock
)->fl_Task
, ACTION_GET_FILE_SIZE64
, (IPTR
)flock
, 0, 0, 0, 0);
589 /* Do the file match the time interval we are looking for?
590 (ARG_SINCE and ARG_UPTO) -- any combination of these may be
592 if ((doSince
&& (CompareDates(sinceDate
, ds
) < 0)) ||
593 (doUpto
&& (CompareDates(uptoDate
, ds
) > 0)))
598 /* Does the filename match a certain pattern? (ARG_PAT) */
599 if (parsedPattern
!= NULL
&&
600 !MatchPatternNoCase(parsedPattern
, FilePart(filename
)))
605 /* Does a substring of the filename match a certain pattern? (ARG_SUB) */
606 if (subpatternStr
!= NULL
&&
607 !MatchPatternNoCase(subpatternStr
, FilePart(filename
)))
612 CopyMem(ds
, &dt
.dat_Stamp
, sizeof(struct DateStamp
));
613 dt
.dat_Format
= FORMAT_DOS
;
617 dt
.dat_Flags
= DTF_SUBST
;
618 dt
.dat_StrDay
= NULL
;
619 dt
.dat_StrDate
= date
;
620 dt
.dat_StrTime
= time
;
623 /* Convert the protection bits to a string */
625 flags
[0] = protection
& FIBF_SCRIPT
? 's' : '-';
626 flags
[1] = protection
& FIBF_PURE
? 'p' : '-';
627 flags
[2] = protection
& FIBF_ARCHIVE
? 'a' : '-';
629 // Active when unset!
630 flags
[3] = protection
& FIBF_READ
? '-' : 'r';
631 flags
[4] = protection
& FIBF_WRITE
? '-' : 'w';
632 flags
[5] = protection
& FIBF_EXECUTE
? '-' : 'e';
633 flags
[6] = protection
& FIBF_DELETE
? '-' : 'd';
641 ++*nBlocks
; /* dir entry uses 1 block on AROS, 2 on OS31) */
645 struct lfstruct lf
= { ap
, isDir
, date
, time
, flags
, filename
,
646 filenote
, size
, diskKey
};
648 printLformat(lFormat
, &lf
);
653 D(bug("Found file %s\n", filename
));
655 Printf("%-24s ", FilePart(filename
)); // Entry name field width
659 Printf("%7s %7s ", DIRTEXT
, flags
); // Size field width, flags field width
662 if (!noDates
&& (!quick
|| dates
))
664 Printf("%-11s %s", date
, time
); // Date field width
674 *nBlocks
+= roundUp(size
, BLOCKSIZE
);
678 struct lfstruct lf
= { ap
, isDir
, date
, time
, flags
, filename
,
679 filenote
, size
, diskKey
};
681 printLformat(lFormat
, &lf
);
686 Printf("%-24s ", FilePart(filename
)); // Entryname field width
694 __sprintf(key
, "%lu", (unsigned long)diskKey
);
696 Printf("[%5lu] ", diskKey
); // Key field width
702 UQUAD filesize
= block
? roundUp(size
, BLOCKSIZE
) : size
;
704 UBYTE buf
[ 256]; // Should be UQUADSTRSIZE +1, but this will suffice.
705 UBYTE
*quadstr
= UQUAD2string( filesize
, buf
, 256);
707 Printf("%7s ", quadstr
); // Size field width
711 Printf("%7s ", EMPTYTEXT
); // Size field width
715 Printf("%7s ", flags
); // Flags field width
718 if (!noDates
&& (!quick
|| dates
))
720 Printf("%-11s %s", date
, time
); // Date field width
723 if (!quick
&& (*filenote
!= 0))
725 Printf("\n: %s", filenote
);
736 /* Print directory summary information */
737 void printSummary(CONST_STRPTR dirname
, int files
, int dirs
, int nBlocks
,
738 BOOL noHead
, BOOL PrintEmpty
)
747 Printf("%ld files", files
);
751 if( files
&& (dirs
|| nBlocks
) ) PutStr(" - ");
754 Printf("%ld directories", dirs
);
756 PutStr("1 directory");
758 if( dirs
&& nBlocks
) PutStr(" - ");
761 Printf("%ld blocks used\n", nBlocks
);
762 else if (nBlocks
> 0)
763 PutStr("1 block used\n");
768 Printf("Directory \"%s\" is empty\n", dirname
);
772 int listFile(CONST_STRPTR filename
, BOOL showFiles
, BOOL showDirs
,
773 STRPTR parsedPattern
, BOOL noHead
, STRPTR lFormat
, BOOL quick
,
774 BOOL dates
, BOOL noDates
, BOOL block
, struct DateStamp
*sinceDate
,
775 struct DateStamp
*uptoDate
, BOOL doSince
, BOOL doUpto
,
776 STRPTR subpatternStr
, BOOL all
, BOOL keys
, Statistics
*stats
)
778 struct AnchorPath
*ap
;
779 struct List DirList
, FreeDirNodeList
;
780 struct DirNode
*dirnode
, *prev_dirnode
= NULL
;
788 NewList(&FreeDirNodeList
);
792 ap
= AllocVec(sizeof(struct AnchorPath
) + MAX_PATH_LEN
, MEMF_CLEAR
);
799 ap
->ap_Strlen
= MAX_PATH_LEN
;
801 error
= MatchFirst(filename
, ap
);
803 /* Explicitly named directory and not a pattern? --> enter dir */
807 if (!(ap
->ap_Flags
& APF_ITSWILD
))
809 if (ap
->ap_Info
.fib_DirEntryType
>= 0)
811 //error = printDirHeader(filename, noHead);
812 ap
->ap_Flags
|= APF_DODIR
;
816 error
= MatchNext(ap
);
826 ap
->ap_BreakBits
= SIGBREAKF_CTRL_C
;
827 if (FilePart(ap
->ap_Buf
) == ap
->ap_Buf
)
829 ap
->ap_Flags
&= ~APF_DirChanged
;
835 ** There's something to show.
837 if (!(ap
->ap_Flags
& APF_DIDDIR
))
839 if (ap
->ap_Flags
& APF_DirChanged
)
844 if (!first
) printSummary(filename
, files
, dirs
, nBlocks
, noHead
, TRUE
);
846 /* Update global statistics for (possible) ALL option */
847 stats
->nFiles
+= files
;
848 stats
->nDirs
+= dirs
;
849 stats
->nBlocks
+= nBlocks
;
855 p
= PathPart(ap
->ap_Buf
);
859 error
= printDirHeader(ap
->ap_Buf
, noHead
);
865 error
= printFileData(ap
,
884 if (all
&& (ap
->ap_Info
.fib_DirEntryType
>= 0))
886 if ((dirnode
= AllocMem(sizeof(struct DirNode
), MEMF_ANY
)))
888 if ((dirnode
->dirname
= StrDup(ap
->ap_Buf
)))
890 Insert(&DirList
, (struct Node
*)dirnode
,
891 (struct Node
*)prev_dirnode
);
893 prev_dirnode
= dirnode
;
897 FreeMem(dirnode
, sizeof(struct DirNode
));
903 error
= MatchNext(ap
);
907 } while (0 == error
);
914 if (error
== ERROR_BREAK
)
916 PrintFault(error
, NULL
);
919 if (error
== ERROR_NO_MORE_ENTRIES
)
924 if ((error
== 0) || (error
== ERROR_BREAK
))
926 BOOL printEmpty
= !(ap
->ap_Flags
& APF_ITSWILD
);
927 printSummary(filename
, files
, dirs
, nBlocks
, noHead
, printEmpty
);
930 /* Update global statistics for (possible) ALL option */
931 stats
->nFiles
+= files
;
932 stats
->nDirs
+= dirs
;
933 stats
->nBlocks
+= nBlocks
;
942 dirnode
= (struct DirNode
*)RemHead(&DirList
);
946 filename
= dirnode
->dirname
;
950 /* do not free() dirnode, as we reference dirnode->dirname! */
952 AddTail(&FreeDirNodeList
, (struct Node
*)dirnode
);
956 while ((dirnode
= (struct DirNode
*)RemHead(&FreeDirNodeList
)))
958 FreeVec(dirnode
->dirname
);
959 FreeMem(dirnode
, sizeof(struct DirNode
));
970 IPTR args
[NOOFARGS
] =
972 (IPTR
) NULL
, // ARG_DIR
973 (IPTR
) NULL
, // ARG_PAT
976 FALSE
, // ARG_NODATES
977 (IPTR
) NULL
, // ARG_TO
978 (IPTR
) NULL
, // ARG_SUB
979 (IPTR
) NULL
, // ARG_SINCE
980 (IPTR
) NULL
, // ARG_UPTO
986 FALSE
, // ARG_LFORMAT
989 static CONST_STRPTR default_directories
[] = {(CONST_STRPTR
)"", 0};
992 LONG result
= RETURN_OK
;
994 STRPTR parsedPattern
= NULL
;
995 STRPTR subpatternStr
= NULL
;
996 BPTR oldOutput
= BNULL
;
998 Statistics stats
= { 0, 0, 0 };
1000 rda
= ReadArgs(ARG_TEMPLATE
, args
, NULL
);
1004 CONST_STRPTR
*directories
= (CONST_STRPTR
*)args
[ARG_DIR
];
1005 STRPTR lFormat
= (STRPTR
)args
[ARG_LFORMAT
];
1006 STRPTR pattern
= (STRPTR
)args
[ARG_PAT
];
1007 STRPTR toFile
= (STRPTR
)args
[ARG_TO
];
1008 STRPTR subStr
= (STRPTR
)args
[ARG_SUB
];
1009 STRPTR since
= (STRPTR
)args
[ARG_SINCE
];
1010 STRPTR upto
= (STRPTR
)args
[ARG_UPTO
];
1011 BOOL files
= (BOOL
)args
[ARG_FILES
];
1012 BOOL dirs
= (BOOL
)args
[ARG_DIRS
];
1013 BOOL noDates
= (BOOL
)args
[ARG_NODATES
];
1014 BOOL dates
= (BOOL
)args
[ARG_DATES
];
1015 BOOL quick
= (BOOL
)args
[ARG_QUICK
];
1016 BOOL noHead
= (BOOL
)args
[ARG_NOHEAD
];
1017 BOOL block
= (BOOL
)args
[ARG_BLOCK
];
1018 BOOL all
= (BOOL
)args
[ARG_ALL
];
1019 BOOL keys
= (BOOL
)args
[ARG_KEYS
];
1021 struct DateTime sinceDatetime
;
1022 struct DateTime uptoDatetime
;
1024 ULONG i
; /* Loop variable */
1028 sinceDatetime
.dat_StrDate
= since
;
1029 sinceDatetime
.dat_StrTime
= NULL
;
1030 sinceDatetime
.dat_Format
= FORMAT_DEF
;
1031 sinceDatetime
.dat_Flags
= 0;
1032 if (StrToDate(&sinceDatetime
) == DOSFALSE
)
1035 Printf("*** Illegal 'SINCE' parameter\n");
1039 sinceDatetime
.dat_Stamp
.ds_Minute
= 0;
1040 sinceDatetime
.dat_Stamp
.ds_Tick
= 0;
1045 uptoDatetime
.dat_StrDate
= upto
;
1046 uptoDatetime
.dat_StrTime
= NULL
;
1047 uptoDatetime
.dat_Format
= FORMAT_DEF
;
1048 uptoDatetime
.dat_Flags
= 0;
1050 if (StrToDate(&uptoDatetime
) == DOSFALSE
)
1053 Printf("*** Illegal 'UPTO' parameter\n");
1057 uptoDatetime
.dat_Stamp
.ds_Minute
= 1439;
1058 uptoDatetime
.dat_Stamp
.ds_Tick
= 2999;
1063 STRPTR subStrWithPat
;
1064 ULONG length
= (strlen(subStr
) + sizeof("#?#?"))*2 + 2;
1066 subStrWithPat
= AllocVec(length
, MEMF_ANY
);
1068 if (subStrWithPat
== NULL
)
1072 PrintFault(error
, "List");
1077 strcpy(subStrWithPat
, "#?");
1078 strcat(subStrWithPat
, subStr
);
1079 strcat(subStrWithPat
, "#?");
1081 subpatternStr
= AllocVec(length
, MEMF_ANY
);
1083 if (subpatternStr
== NULL
||
1084 ParsePatternNoCase(subStrWithPat
, subpatternStr
, length
) == -1)
1087 FreeVec(subStrWithPat
);
1089 PrintFault(error
, "List");
1094 FreeVec(subStrWithPat
);
1098 if (pattern
!= NULL
)
1100 ULONG length
= strlen(pattern
)*2 + 2;
1102 parsedPattern
= AllocVec(length
, MEMF_ANY
);
1104 if (parsedPattern
== NULL
||
1105 ParsePatternNoCase(pattern
, parsedPattern
, length
) == -1)
1107 FreeVec(subpatternStr
);
1116 BPTR file
= Open(toFile
, MODE_NEWFILE
);
1121 FreeVec(subpatternStr
);
1122 FreeVec(parsedPattern
);
1124 PrintFault(error
, "List");
1128 oldOutput
= SelectOutput(file
);
1131 if (!files
&& !dirs
)
1137 /* if (!dates && !noDates)
1147 if ((directories
== NULL
) || (*directories
== NULL
))
1149 directories
= default_directories
;
1152 for (i
= 0; directories
[i
] != NULL
; i
++)
1154 error
= listFile(directories
[i
], files
, dirs
, parsedPattern
,
1155 noHead
, lFormat
, quick
, dates
, noDates
,
1156 block
, &sinceDatetime
.dat_Stamp
,
1157 &uptoDatetime
.dat_Stamp
, since
!= NULL
,
1158 upto
!= NULL
, subpatternStr
, all
, keys
,
1176 if ((BOOL
)args
[ARG_NOHEAD
] == FALSE
&&
1177 (BOOL
)args
[ARG_LFORMAT
] == FALSE
&&
1178 (BOOL
)args
[ARG_ALL
] &&
1179 (stats
.nFiles
|| stats
.nDirs
))
1181 Printf("\nTOTAL: %ld files - %ld directories - %ld blocks used\n",
1182 stats
.nFiles
, stats
.nDirs
, stats
.nBlocks
);
1188 if (error
== ERROR_BREAK
)
1190 result
= RETURN_WARN
;
1194 PrintFault(error
, "List");
1195 result
= RETURN_FAIL
;
1199 if (parsedPattern
!= NULL
)
1201 FreeVec(parsedPattern
);
1204 if (subpatternStr
!= NULL
)
1206 FreeVec(subpatternStr
);
1209 if (oldOutput
!= BNULL
)
1211 Close(SelectOutput(oldOutput
));