2 Copyright © 1995-2014, 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 -- superceded 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 minumum -- 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 fuction to generates 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
693 int i
; /* Loop variable */
695 __sprintf(key
, "%lu", (unsigned long)diskKey
);
697 Printf("[%5lu] ", diskKey
); // Key field width
703 UQUAD filesize
= block
? roundUp(size
, BLOCKSIZE
) : size
;
705 UBYTE buf
[ 256]; // Should be UQUADSTRSIZE +1, but this will suffice.
706 UBYTE
*quadstr
= UQUAD2string( filesize
, buf
, 256);
708 Printf("%7s ", quadstr
); // Size field width
712 Printf("%7s ", EMPTYTEXT
); // Size field width
716 Printf("%7s ", flags
); // Flags field width
719 if (!noDates
&& (!quick
|| dates
))
721 Printf("%-11s %s", date
, time
); // Date field width
724 if (!quick
&& (*filenote
!= 0))
726 Printf("\n: %s", filenote
);
737 /* Print directory summary information */
738 void printSummary(CONST_STRPTR dirname
, int files
, int dirs
, int nBlocks
,
739 BOOL noHead
, BOOL PrintEmpty
)
748 Printf("%ld files", files
);
752 if( files
&& (dirs
|| nBlocks
) ) PutStr(" - ");
755 Printf("%ld directories", dirs
);
757 PutStr("1 directory");
759 if( dirs
&& nBlocks
) PutStr(" - ");
762 Printf("%ld blocks used\n", nBlocks
);
763 else if (nBlocks
> 0)
764 PutStr("1 block used\n");
769 Printf("Directory \"%s\" is empty\n", dirname
);
773 int listFile(CONST_STRPTR filename
, BOOL showFiles
, BOOL showDirs
,
774 STRPTR parsedPattern
, BOOL noHead
, STRPTR lFormat
, BOOL quick
,
775 BOOL dates
, BOOL noDates
, BOOL block
, struct DateStamp
*sinceDate
,
776 struct DateStamp
*uptoDate
, BOOL doSince
, BOOL doUpto
,
777 STRPTR subpatternStr
, BOOL all
, BOOL keys
, Statistics
*stats
)
779 struct AnchorPath
*ap
;
780 struct List DirList
, FreeDirNodeList
;
781 struct DirNode
*dirnode
, *prev_dirnode
= NULL
;
789 NewList(&FreeDirNodeList
);
793 ap
= AllocVec(sizeof(struct AnchorPath
) + MAX_PATH_LEN
, MEMF_CLEAR
);
800 ap
->ap_Strlen
= MAX_PATH_LEN
;
802 error
= MatchFirst(filename
, ap
);
804 /* Explicitly named directory and not a pattern? --> enter dir */
808 if (!(ap
->ap_Flags
& APF_ITSWILD
))
810 if (ap
->ap_Info
.fib_DirEntryType
>= 0)
812 //error = printDirHeader(filename, noHead);
813 ap
->ap_Flags
|= APF_DODIR
;
817 error
= MatchNext(ap
);
827 ap
->ap_BreakBits
= SIGBREAKF_CTRL_C
;
828 if (FilePart(ap
->ap_Buf
) == ap
->ap_Buf
)
830 ap
->ap_Flags
&= ~APF_DirChanged
;
836 ** There's something to show.
838 if (!(ap
->ap_Flags
& APF_DIDDIR
))
840 if (ap
->ap_Flags
& APF_DirChanged
)
845 if (!first
) printSummary(filename
, files
, dirs
, nBlocks
, noHead
, TRUE
);
847 /* Update global statistics for (possible) ALL option */
848 stats
->nFiles
+= files
;
849 stats
->nDirs
+= dirs
;
850 stats
->nBlocks
+= nBlocks
;
856 p
= PathPart(ap
->ap_Buf
);
860 error
= printDirHeader(ap
->ap_Buf
, noHead
);
866 error
= printFileData(ap
,
885 if (all
&& (ap
->ap_Info
.fib_DirEntryType
>= 0))
887 if ((dirnode
= AllocMem(sizeof(struct DirNode
), MEMF_ANY
)))
889 if ((dirnode
->dirname
= StrDup(ap
->ap_Buf
)))
891 Insert(&DirList
, (struct Node
*)dirnode
,
892 (struct Node
*)prev_dirnode
);
894 prev_dirnode
= dirnode
;
898 FreeMem(dirnode
, sizeof(struct DirNode
));
904 error
= MatchNext(ap
);
908 } while (0 == error
);
915 if (error
== ERROR_BREAK
)
917 PrintFault(error
, NULL
);
920 if (error
== ERROR_NO_MORE_ENTRIES
)
925 if ((error
== 0) || (error
== ERROR_BREAK
))
927 BOOL printEmpty
= !(ap
->ap_Flags
& APF_ITSWILD
);
928 printSummary(filename
, files
, dirs
, nBlocks
, noHead
, printEmpty
);
931 /* Update global statistics for (possible) ALL option */
932 stats
->nFiles
+= files
;
933 stats
->nDirs
+= dirs
;
934 stats
->nBlocks
+= nBlocks
;
943 dirnode
= (struct DirNode
*)RemHead(&DirList
);
947 filename
= dirnode
->dirname
;
951 /* do not free() dirnode, as we reference dirnode->dirname! */
953 AddTail(&FreeDirNodeList
, (struct Node
*)dirnode
);
957 while ((dirnode
= (struct DirNode
*)RemHead(&FreeDirNodeList
)))
959 FreeVec(dirnode
->dirname
);
960 FreeMem(dirnode
, sizeof(struct DirNode
));
971 IPTR args
[NOOFARGS
] =
973 (IPTR
) NULL
, // ARG_DIR
974 (IPTR
) NULL
, // ARG_PAT
977 FALSE
, // ARG_NODATES
978 (IPTR
) NULL
, // ARG_TO
979 (IPTR
) NULL
, // ARG_SUB
980 (IPTR
) NULL
, // ARG_SINCE
981 (IPTR
) NULL
, // ARG_UPTO
987 FALSE
, // ARG_LFORMAT
990 static CONST_STRPTR default_directories
[] = {(CONST_STRPTR
)"", 0};
993 LONG result
= RETURN_OK
;
995 STRPTR parsedPattern
= NULL
;
996 STRPTR subpatternStr
= NULL
;
997 BPTR oldOutput
= BNULL
;
999 Statistics stats
= { 0, 0, 0 };
1001 rda
= ReadArgs(ARG_TEMPLATE
, args
, NULL
);
1005 CONST_STRPTR
*directories
= (CONST_STRPTR
*)args
[ARG_DIR
];
1006 STRPTR lFormat
= (STRPTR
)args
[ARG_LFORMAT
];
1007 STRPTR pattern
= (STRPTR
)args
[ARG_PAT
];
1008 STRPTR toFile
= (STRPTR
)args
[ARG_TO
];
1009 STRPTR subStr
= (STRPTR
)args
[ARG_SUB
];
1010 STRPTR since
= (STRPTR
)args
[ARG_SINCE
];
1011 STRPTR upto
= (STRPTR
)args
[ARG_UPTO
];
1012 BOOL files
= (BOOL
)args
[ARG_FILES
];
1013 BOOL dirs
= (BOOL
)args
[ARG_DIRS
];
1014 BOOL noDates
= (BOOL
)args
[ARG_NODATES
];
1015 BOOL dates
= (BOOL
)args
[ARG_DATES
];
1016 BOOL quick
= (BOOL
)args
[ARG_QUICK
];
1017 BOOL noHead
= (BOOL
)args
[ARG_NOHEAD
];
1018 BOOL block
= (BOOL
)args
[ARG_BLOCK
];
1019 BOOL all
= (BOOL
)args
[ARG_ALL
];
1020 BOOL keys
= (BOOL
)args
[ARG_KEYS
];
1022 struct DateTime sinceDatetime
;
1023 struct DateTime uptoDatetime
;
1025 ULONG i
; /* Loop variable */
1029 sinceDatetime
.dat_StrDate
= since
;
1030 sinceDatetime
.dat_StrTime
= NULL
;
1031 sinceDatetime
.dat_Format
= FORMAT_DEF
;
1032 sinceDatetime
.dat_Flags
= 0;
1033 if (StrToDate(&sinceDatetime
) == DOSFALSE
)
1036 Printf("*** Illegal 'SINCE' parameter\n");
1040 sinceDatetime
.dat_Stamp
.ds_Minute
= 0;
1041 sinceDatetime
.dat_Stamp
.ds_Tick
= 0;
1046 uptoDatetime
.dat_StrDate
= upto
;
1047 uptoDatetime
.dat_StrTime
= NULL
;
1048 uptoDatetime
.dat_Format
= FORMAT_DEF
;
1049 uptoDatetime
.dat_Flags
= 0;
1051 if (StrToDate(&uptoDatetime
) == DOSFALSE
)
1054 Printf("*** Illegal 'UPTO' parameter\n");
1058 uptoDatetime
.dat_Stamp
.ds_Minute
= 1439;
1059 uptoDatetime
.dat_Stamp
.ds_Tick
= 2999;
1064 STRPTR subStrWithPat
;
1065 ULONG length
= (strlen(subStr
) + sizeof("#?#?"))*2 + 2;
1067 subStrWithPat
= AllocVec(length
, MEMF_ANY
);
1069 if (subStrWithPat
== NULL
)
1073 PrintFault(error
, "List");
1078 strcpy(subStrWithPat
, "#?");
1079 strcat(subStrWithPat
, subStr
);
1080 strcat(subStrWithPat
, "#?");
1082 subpatternStr
= AllocVec(length
, MEMF_ANY
);
1084 if (subpatternStr
== NULL
||
1085 ParsePatternNoCase(subStrWithPat
, subpatternStr
, length
) == -1)
1088 FreeVec(subStrWithPat
);
1090 PrintFault(error
, "List");
1095 FreeVec(subStrWithPat
);
1099 if (pattern
!= NULL
)
1101 ULONG length
= strlen(pattern
)*2 + 2;
1103 parsedPattern
= AllocVec(length
, MEMF_ANY
);
1105 if (parsedPattern
== NULL
||
1106 ParsePatternNoCase(pattern
, parsedPattern
, length
) == -1)
1108 FreeVec(subpatternStr
);
1117 BPTR file
= Open(toFile
, MODE_NEWFILE
);
1122 FreeVec(subpatternStr
);
1123 FreeVec(parsedPattern
);
1125 PrintFault(error
, "List");
1129 oldOutput
= SelectOutput(file
);
1132 if (!files
&& !dirs
)
1138 /* if (!dates && !noDates)
1148 if ((directories
== NULL
) || (*directories
== NULL
))
1150 directories
= default_directories
;
1153 for (i
= 0; directories
[i
] != NULL
; i
++)
1155 error
= listFile(directories
[i
], files
, dirs
, parsedPattern
,
1156 noHead
, lFormat
, quick
, dates
, noDates
,
1157 block
, &sinceDatetime
.dat_Stamp
,
1158 &uptoDatetime
.dat_Stamp
, since
!= NULL
,
1159 upto
!= NULL
, subpatternStr
, all
, keys
,
1177 if ((BOOL
)args
[ARG_NOHEAD
] == FALSE
&&
1178 (BOOL
)args
[ARG_LFORMAT
] == FALSE
&&
1179 (BOOL
)args
[ARG_ALL
] &&
1180 (stats
.nFiles
|| stats
.nDirs
))
1182 Printf("\nTOTAL: %ld files - %ld directories - %ld blocks used\n",
1183 stats
.nFiles
, stats
.nDirs
, stats
.nBlocks
);
1189 if (error
== ERROR_BREAK
)
1191 result
= RETURN_WARN
;
1195 PrintFault(error
, "List");
1196 result
= RETURN_FAIL
;
1200 if (parsedPattern
!= NULL
)
1202 FreeVec(parsedPattern
);
1205 if (subpatternStr
!= NULL
)
1207 FreeVec(subpatternStr
);
1210 if (oldOutput
!= BNULL
)
1212 Close(SelectOutput(oldOutput
));