Fix IO memory access .. SB128 driver makes noises in VMWare - CMI is untested (Curren...
[AROS.git] / workbench / c / List.c
blob531c55faa95ee8e63b79481f5ddd793beee68ef1
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 List the contents of a directory.
6 */
7 /*****************************************************************************
9 NAME
11 List
13 FORMAT
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]
19 TEMPLATE
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
23 LOCATION
27 FUNCTION
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:
35 name
36 size (in bytes)
37 protection bits
38 date and time
40 INPUTS
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
63 %A -- file attributes
64 %B -- size of file in blocks rather than bytes
65 %C -- file comment
66 %D -- creation date
67 %E -- file extension
68 %F -- volume name
69 %K -- file key block number
70 %L -- size of file in bytes
71 %M -- file name without extension
72 %N -- file name
73 %P -- file path
74 %S -- superceded by %N and %P; obsolete
75 %T -- creation time
77 RESULT
79 Standard DOS return codes.
81 EXAMPLE
83 1> List C:
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
96 BUGS
98 SEE ALSO
102 INTERNALS
104 ******************************************************************************/
106 #define DEBUG 0
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>
113 #include <dos/dos.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 <proto/utility.h>
120 #include <utility/tagitem.h>
122 const TEXT version[] = "$VER: List 41.7 (18.08.2010)\n";
124 #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"
126 struct DirNode
128 struct MinNode node;
129 char *dirname;
133 typedef struct _Statistics
135 ULONG nFiles;
136 ULONG nDirs;
137 ULONG nBlocks;
138 } Statistics;
141 enum
143 ARG_DIR = 0,
144 ARG_PAT,
145 ARG_KEYS,
146 ARG_DATES,
147 ARG_NODATES,
148 ARG_TO,
149 ARG_SUB,
150 ARG_SINCE,
151 ARG_UPTO,
152 ARG_QUICK,
153 ARG_BLOCK,
154 ARG_NOHEAD,
155 ARG_FILES,
156 ARG_DIRS,
157 ARG_LFORMAT,
158 ARG_ALL,
159 NOOFARGS
162 #define MAX_PATH_LEN 1024
164 #define BLOCKSIZE 512
166 int printDirHeader(STRPTR dirname, BOOL noHead)
168 struct DateTime dt;
170 char datestr[LEN_DATSTRING];
171 char dow[LEN_DATSTRING];
173 if (!noHead)
175 DateStamp((struct DateStamp *)&dt);
176 dt.dat_Format = FORMAT_DEF;
177 dt.dat_Flags = 0;
178 dt.dat_StrDay = dow;
179 dt.dat_StrDate = datestr;
180 dt.dat_StrTime = NULL;
181 DateToStr(&dt);
183 Printf("Directory \"%s\" on %s %s:\n", dirname, dow, datestr);
186 return RETURN_OK;
190 /* Possible printf-type switches
192 %A -- file attributes
193 %B -- size of file in blocks rather than bytes
194 %C -- file comment
195 %D -- file date
196 %E -- file extension
197 %F -- volume name
198 %K -- file key block number
199 %L -- size of file in bytes
200 %M -- file name without extension
201 %N -- file name
202 %P -- file path
203 %S -- file name or file path
204 %T -- creation date
207 struct lfstruct
209 struct AnchorPath *ap;
210 BOOL isdir;
211 STRPTR date;
212 STRPTR time;
213 STRPTR flags;
214 STRPTR filename;
215 STRPTR comment;
216 ULONG size;
217 ULONG key;
221 #define roundUp(x, bSize) ((x + bSize - 1)/bSize)
223 int printLformat(STRPTR format, struct lfstruct *lf)
225 STRPTR filename = FilePart(lf->filename);
226 STRPTR temp = format;
227 LONG substitutePath = 0;
228 char c;
231 Whether the path or the filename is substituted for an occurrence
232 of %S depends on how many occurrences are in the LFORMAT line, and
233 their order, as follows:
235 Occurrences of %S 1st 2nd 3rd 4th
236 1 filename
237 2 path filename
238 3 path filename filename
239 4 path filename path filename
242 while ( ( substitutePath < 4 ) && ( '\0' != (c = *temp++) ) )
244 if ( '%' == c )
245 if ( 'S' == ToUpper(*temp++) )
246 substitutePath++;
248 if ( substitutePath == 3 )
249 substitutePath = 2;
251 while ('\0' != (c = *format++))
253 if ('%' == c)
255 switch (ToUpper(*format++))
257 /* File comment */
258 case 'C':
259 Printf(lf->comment);
260 break;
262 /* Creation date */
263 case 'D':
264 Printf(lf->date);
265 break;
267 /* Creation time */
268 case 'T':
269 Printf(lf->time);
270 break;
272 /* File size in blocks of BLOCKSIZE bytes */
273 case 'B':
274 if (lf->isdir)
276 Printf("Dir");
278 else
280 ULONG tmp = roundUp(lf->size, BLOCKSIZE);
282 /* File is 0 bytes? */
283 if (tmp == 0)
285 Printf("empty");
287 else
289 Printf("%lu", tmp);
293 break;
295 /* Path incl. volume name*/
296 case 'F':
298 UBYTE buf[256];
300 if (NameFromLock(lf->ap->ap_Current->an_Lock, buf, 256))
302 int len;
304 Printf(buf);
306 len = strlen(buf);
307 if ((len > 0) && (buf[len - 1] != ':') && (buf[len - 1] != '/'))
309 Printf("/");
314 break;
316 /* File attributes (flags) */
317 case 'A':
318 Printf(lf->flags);
319 break;
321 /* Disk block key */
322 case 'K':
323 Printf("[%ld]", lf->key);
324 break;
326 /* File size */
327 case 'L':
328 if (lf->isdir)
330 Printf("Dir");
332 else
334 if (lf->size == 0)
336 Printf("empty");
338 else
340 Printf("%lu", lf->size);
344 break;
346 /* File name without extension */
347 case 'M':
349 STRPTR lastPoint = strrchr(filename, '.');
351 if (lastPoint != NULL)
353 *lastPoint = 0;
356 Printf(filename);
358 /* Resurrect filename in case we should print it once
359 more */
360 if (lastPoint != NULL)
362 *lastPoint = '.';
366 break;
368 /* Filename or Path name */
369 case 'S':
370 D(bug("[List] substitutePath = %d\n", substitutePath));
371 if ( (--substitutePath == 3) || (substitutePath == 1) )
373 STRPTR end = FilePart(lf->filename);
374 UBYTE token = *end;
376 *end = '\0';
378 Printf(lf->filename);
380 /* Restore pathname */
381 *end = token;
383 break;
385 /* Fall through */
386 case 'N':
387 Printf(filename);
388 break;
390 /* File extension */
391 case 'E':
393 STRPTR extension = strrchr(filename, '.');
395 if (extension != NULL)
397 Printf(extension);
401 break;
403 /* Path name, but without volume */
404 case 'P':
406 STRPTR end = FilePart(lf->filename);
407 UBYTE token = *end;
409 *end = 0;
411 Printf(lf->filename);
413 /* Restore pathname */
414 *end = token;
417 break;
419 case 0:
420 return 0;
421 break;
423 default:
424 Printf("%%%lc", *format);
425 break;
428 else
430 Printf("%lc", c);
434 return 0;
438 int printFileData(struct AnchorPath *ap,
439 BOOL showFiles, BOOL showDirs, STRPTR parsedPattern,
440 ULONG *files, ULONG *dirs, ULONG *nBlocks, STRPTR lFormat,
441 BOOL quick, BOOL dates, BOOL noDates, BOOL block,
442 struct DateStamp *sinceDate, struct DateStamp *uptoDate,
443 BOOL doSince, BOOL doUpto, STRPTR subpatternStr,
444 BOOL keys)
446 STRPTR filename = ap->ap_Buf;
447 BOOL isDir = (ap->ap_Info.fib_DirEntryType >= 0);
448 struct DateStamp *ds = &ap->ap_Info.fib_Date;
449 ULONG protection = ap->ap_Info.fib_Protection;
450 ULONG size = ap->ap_Info.fib_Size;
451 STRPTR filenote = ap->ap_Info.fib_Comment;
452 LONG diskKey = ap->ap_Info.fib_DiskKey;
454 int error = 0;
456 UBYTE date[LEN_DATSTRING];
457 UBYTE time[LEN_DATSTRING];
458 UBYTE flags[8];
460 struct DateTime dt;
462 /* Do the file match the time interval we are looking for?
463 (ARG_SINCE and ARG_UPTO) -- any combination of these may be
464 specified */
465 if ((doSince && (CompareDates(sinceDate, ds) < 0)) ||
466 (doUpto && (CompareDates(uptoDate, ds) > 0)))
468 return 0;
471 /* Does the filename match a certain pattern? (ARG_PAT) */
472 if (parsedPattern != NULL &&
473 !MatchPatternNoCase(parsedPattern, FilePart(filename)))
475 return 0;
478 /* Does a substring of the filename match a certain pattern? (ARG_SUB) */
479 if (subpatternStr != NULL &&
480 !MatchPatternNoCase(subpatternStr, FilePart(filename)))
482 return 0;
485 CopyMem(ds, &dt.dat_Stamp, sizeof(struct DateStamp));
486 dt.dat_Format = FORMAT_DOS;
487 dt.dat_Flags = DTF_SUBST;
488 dt.dat_StrDay = NULL;
489 dt.dat_StrDate = date;
490 dt.dat_StrTime = time;
491 DateToStr(&dt); /* returns 0 if invalid */
493 /* Convert the protection bits to a string */
494 flags[0] = protection & FIBF_SCRIPT ? 's' : '-';
495 flags[1] = protection & FIBF_PURE ? 'p' : '-';
496 flags[2] = protection & FIBF_ARCHIVE ? 'a' : '-';
498 /* The following flags are high-active! */
499 flags[3] = protection & FIBF_READ ? '-' : 'r';
500 flags[4] = protection & FIBF_WRITE ? '-' : 'w';
501 flags[5] = protection & FIBF_EXECUTE ? '-' : 'e';
502 flags[6] = protection & FIBF_DELETE ? '-' : 'd';
503 flags[7] = 0x00;
505 if (isDir)
507 if (showDirs)
509 ++*dirs;
510 ++*nBlocks; /* dir entry uses 1 block on AROS, 2 on OS31) */
512 if (lFormat != NULL)
514 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
515 filenote, size, diskKey};
517 printLformat(lFormat, &lf);
518 Printf("\n");
520 else
522 D(bug("Found file %s\n", filename));
524 Printf("%-25s ", FilePart(filename));
526 if (!quick)
528 Printf(" <Dir> %7s ", flags);
531 if (!noDates && (!quick || dates))
533 Printf("%-11s %s", date, time);
536 Printf("\n");
540 else if (showFiles)
542 ++*files;
543 *nBlocks += roundUp(size, BLOCKSIZE);
545 if (lFormat != NULL)
547 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
548 filenote, size, diskKey };
550 printLformat(lFormat, &lf);
551 Printf("\n");
553 else
555 Printf("%-25s ", FilePart(filename));
557 if (!quick)
559 if(keys)
561 char key[16];
562 int fill;
563 int i; /* Loop variable */
565 __sprintf(key, "%ld", (long)diskKey);
566 fill = 7 - strlen(key) - 2;
568 for (i = 0; i < fill; i++)
570 Printf(" ");
573 Printf("[%ld] ", diskKey);
575 else
577 if (0 != size)
579 Printf("%7ld ",
580 block ? roundUp(size, BLOCKSIZE) : size);
582 else
584 Printf(" empty ");
588 Printf("%7s ", flags);
591 if (!noDates && (!quick || dates))
593 Printf("%-11s %s", date, time);
596 if (!quick && (*filenote != 0))
598 Printf("\n: %s", filenote);
601 Printf("\n");
605 return error;
609 /* Print directory summary information */
610 void printSummary(CONST_STRPTR dirname, int files, int dirs, int nBlocks,
611 BOOL noHead, BOOL PrintEmpty)
613 if (noHead)
614 return;
616 if (files || dirs)
618 if (files > 1)
619 Printf("%ld files - ", files);
620 else if (files > 0)
621 PutStr("1 file - ");
623 if (dirs > 1)
624 Printf("%ld directories - ", dirs);
625 else if (dirs > 0)
626 PutStr("1 directory - ");
628 if (nBlocks > 1)
629 Printf("%ld blocks used\n", nBlocks);
630 else if (nBlocks > 0)
631 PutStr("1 block used\n");
633 else if (PrintEmpty)
634 Printf("Directory \"%s\" is empty\n", dirname);
638 int listFile(CONST_STRPTR filename, BOOL showFiles, BOOL showDirs,
639 STRPTR parsedPattern, BOOL noHead, STRPTR lFormat, BOOL quick,
640 BOOL dates, BOOL noDates, BOOL block, struct DateStamp *sinceDate,
641 struct DateStamp *uptoDate, BOOL doSince, BOOL doUpto,
642 STRPTR subpatternStr, BOOL all, BOOL keys, Statistics *stats)
644 struct AnchorPath *ap;
645 struct List DirList, FreeDirNodeList;
646 struct DirNode *dirnode, *prev_dirnode = NULL;
648 ULONG files = 0;
649 ULONG dirs = 0;
650 ULONG nBlocks = 0;
651 LONG error;
653 NewList(&DirList);
654 NewList(&FreeDirNodeList);
658 ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN, MEMF_CLEAR);
660 if (ap == NULL)
662 return 0;
665 ap->ap_Strlen = MAX_PATH_LEN;
667 error = MatchFirst(filename, ap);
669 /* Explicitly named directory and not a pattern? --> enter dir */
671 if (0 == error)
673 if (!(ap->ap_Flags & APF_ITSWILD))
675 if (ap->ap_Info.fib_DirEntryType >= 0)
677 //error = printDirHeader(filename, noHead);
678 ap->ap_Flags |= APF_DODIR;
680 if (0 == error)
682 error = MatchNext(ap);
688 if (0 == error)
690 BOOL first = TRUE;
692 ap->ap_BreakBits = SIGBREAKF_CTRL_C;
693 if (FilePart(ap->ap_Buf) == ap->ap_Buf)
695 ap->ap_Flags &= ~APF_DirChanged;
701 ** There's something to show.
703 if (!(ap->ap_Flags & APF_DIDDIR))
705 if (ap->ap_Flags & APF_DirChanged)
707 STRPTR p;
708 UBYTE c;
710 if (!first) printSummary(filename, files, dirs, nBlocks, noHead, TRUE);
712 /* Update global statistics for (possible) ALL option */
713 stats->nFiles += files;
714 stats->nDirs += dirs;
715 stats->nBlocks += nBlocks;
717 files = 0;
718 dirs = 0;
719 nBlocks = 0;
721 p = PathPart(ap->ap_Buf);
722 c = *p;
723 *p = 0;
725 error = printDirHeader(ap->ap_Buf, noHead);
727 *p = c;
731 error = printFileData(ap,
732 showFiles,
733 showDirs,
734 parsedPattern,
735 &files,
736 &dirs,
737 &nBlocks,
738 lFormat,
739 quick,
740 dates,
741 noDates,
742 block,
743 sinceDate,
744 uptoDate,
745 doSince,
746 doUpto,
747 subpatternStr,
748 keys);
750 if (all && (ap->ap_Info.fib_DirEntryType >= 0))
752 if ((dirnode = AllocMem(sizeof(struct DirNode), MEMF_ANY)))
754 if ((dirnode->dirname = StrDup(ap->ap_Buf)))
756 Insert(&DirList, (struct Node *)dirnode,
757 (struct Node *)prev_dirnode);
759 prev_dirnode = dirnode;
761 else
763 FreeMem(dirnode, sizeof(struct DirNode));
769 error = MatchNext(ap);
771 first = FALSE;
773 } while (0 == error);
776 MatchEnd(ap);
778 FreeVec(ap);
780 if (error == ERROR_BREAK)
782 PrintFault(error, NULL);
785 if (error == ERROR_NO_MORE_ENTRIES)
787 error = 0;
790 if ((error == 0) || (error == ERROR_BREAK))
792 BOOL printEmpty = !(ap->ap_Flags & APF_ITSWILD);
793 printSummary(filename, files, dirs, nBlocks, noHead, printEmpty);
796 /* Update global statistics for (possible) ALL option */
797 stats->nFiles += files;
798 stats->nDirs += dirs;
799 stats->nBlocks += nBlocks;
801 files = 0;
802 dirs = 0;
803 nBlocks = 0;
806 if (error) break;
808 dirnode = (struct DirNode *)RemHead(&DirList);
810 if (dirnode != NULL)
812 filename = dirnode->dirname;
814 prev_dirnode = NULL;
816 /* do not free() dirnode, as we reference dirnode->dirname! */
818 AddTail(&FreeDirNodeList, (struct Node *)dirnode);
820 } while (dirnode);
822 while ((dirnode = (struct DirNode *)RemHead(&FreeDirNodeList)))
824 FreeVec(dirnode->dirname);
825 FreeMem(dirnode, sizeof(struct DirNode));
828 return error;
832 int __nocommandline;
834 int main(void)
836 IPTR args[NOOFARGS] =
838 (IPTR) NULL, // ARG_DIR
839 (IPTR) NULL, // ARG_PAT
840 FALSE, // ARG_KEYS
841 FALSE, // ARG_DATES
842 FALSE, // ARG_NODATES
843 (IPTR) NULL, // ARG_TO
844 (IPTR) NULL, // ARG_SUB
845 (IPTR) NULL, // ARG_SINCE
846 (IPTR) NULL, // ARG_UPTO
847 FALSE, // ARG_QUICK
848 FALSE, // ARG_BLOCK
849 FALSE, // ARG_NOHEAD
850 FALSE, // ARG_FILES
851 FALSE, // ARG_DIRS
852 FALSE, // ARG_LFORMAT
853 FALSE // ARG_ALL
855 static CONST_STRPTR default_directories[] = {(CONST_STRPTR)"", 0};
856 struct RDArgs *rda;
858 LONG result = RETURN_OK;
859 LONG error = 0;
860 STRPTR parsedPattern = NULL;
861 STRPTR subpatternStr = NULL;
862 BPTR oldOutput = BNULL;
864 Statistics stats = { 0, 0, 0 };
866 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
868 if (rda != NULL)
870 CONST_STRPTR *directories = (CONST_STRPTR *)args[ARG_DIR];
871 STRPTR lFormat = (STRPTR)args[ARG_LFORMAT];
872 STRPTR pattern = (STRPTR)args[ARG_PAT];
873 STRPTR toFile = (STRPTR)args[ARG_TO];
874 STRPTR subStr = (STRPTR)args[ARG_SUB];
875 STRPTR since = (STRPTR)args[ARG_SINCE];
876 STRPTR upto = (STRPTR)args[ARG_UPTO];
877 BOOL files = (BOOL)args[ARG_FILES];
878 BOOL dirs = (BOOL)args[ARG_DIRS];
879 BOOL noDates = (BOOL)args[ARG_NODATES];
880 BOOL dates = (BOOL)args[ARG_DATES];
881 BOOL quick = (BOOL)args[ARG_QUICK];
882 BOOL noHead = (BOOL)args[ARG_NOHEAD];
883 BOOL block = (BOOL)args[ARG_BLOCK];
884 BOOL all = (BOOL)args[ARG_ALL];
885 BOOL keys = (BOOL)args[ARG_KEYS];
887 struct DateTime sinceDatetime;
888 struct DateTime uptoDatetime;
890 ULONG i; /* Loop variable */
892 if (since != NULL)
894 sinceDatetime.dat_StrDate = since;
895 sinceDatetime.dat_StrTime = NULL;
896 sinceDatetime.dat_Format = FORMAT_DEF;
897 sinceDatetime.dat_Flags = 0;
898 if (StrToDate(&sinceDatetime) == DOSFALSE)
900 FreeArgs(rda);
901 Printf("*** Illegal 'SINCE' parameter\n");
903 return RETURN_FAIL;
907 if (upto != NULL)
909 uptoDatetime.dat_StrDate = upto;
910 uptoDatetime.dat_StrTime = NULL;
911 uptoDatetime.dat_Format = FORMAT_DEF;
912 uptoDatetime.dat_Flags = 0;
914 if (StrToDate(&uptoDatetime) == DOSFALSE)
916 FreeArgs(rda);
917 Printf("*** Illegal 'UPTO' parameter\n");
919 return RETURN_FAIL;
923 if (subStr != NULL)
925 STRPTR subStrWithPat;
926 ULONG length = (strlen(subStr) + sizeof("#?#?"))*2 + 2;
928 subStrWithPat = AllocVec(length, MEMF_ANY);
930 if (subStrWithPat == NULL)
932 FreeArgs(rda);
933 PrintFault(IoErr(), "List");
935 return RETURN_FAIL;
938 strcpy(subStrWithPat, "#?");
939 strcat(subStrWithPat, subStr);
940 strcat(subStrWithPat, "#?");
942 subpatternStr = AllocVec(length, MEMF_ANY);
944 if (subpatternStr == NULL ||
945 ParsePatternNoCase(subStrWithPat, subpatternStr, length) == -1)
947 FreeVec(subStrWithPat);
948 FreeArgs(rda);
949 PrintFault(IoErr(), "List");
951 return RETURN_FAIL;
954 FreeVec(subStrWithPat);
958 if (pattern != NULL)
960 ULONG length = strlen(pattern)*2 + 2;
962 parsedPattern = AllocVec(length, MEMF_ANY);
964 if (parsedPattern == NULL ||
965 ParsePatternNoCase(pattern, parsedPattern, length) == -1)
967 FreeVec(subpatternStr);
968 FreeArgs(rda);
970 return RETURN_FAIL;
974 if (toFile != NULL)
976 BPTR file = Open(toFile, MODE_NEWFILE);
978 if (file == BNULL)
980 FreeVec(subpatternStr);
981 FreeVec(parsedPattern);
982 FreeArgs(rda);
983 PrintFault(IoErr(), "List");
985 return RETURN_FAIL;
987 oldOutput = SelectOutput(file);
990 if (!files && !dirs)
992 files = TRUE;
993 dirs = TRUE;
996 /* if (!dates && !noDates)
998 dates = TRUE;
1001 if (lFormat)
1003 noHead = TRUE;
1006 if ((directories == NULL) || (*directories == NULL))
1008 directories = default_directories;
1011 for (i = 0; directories[i] != NULL; i++)
1013 error = listFile(directories[i], files, dirs, parsedPattern,
1014 noHead, lFormat, quick, dates, noDates,
1015 block, &sinceDatetime.dat_Stamp,
1016 &uptoDatetime.dat_Stamp, since != NULL,
1017 upto != NULL, subpatternStr, all, keys,
1018 &stats);
1020 if (error != 0)
1022 break;
1025 // Printf("\n");
1028 FreeArgs(rda);
1030 else
1032 error = IoErr();
1035 if ((BOOL)args[ARG_NOHEAD] == FALSE &&
1036 (BOOL)args[ARG_LFORMAT] == FALSE &&
1037 (BOOL)args[ARG_ALL] &&
1038 (stats.nFiles || stats.nDirs))
1040 Printf("\nTOTAL: %ld files - %ld directories - %ld blocks used\n",
1041 stats.nFiles, stats.nDirs, stats.nBlocks);
1045 if (error != 0)
1047 if (error == ERROR_BREAK)
1049 result = RETURN_WARN;
1051 else
1053 PrintFault(error, "List");
1054 result = RETURN_FAIL;
1058 if (parsedPattern != NULL)
1060 FreeVec(parsedPattern);
1063 if (subpatternStr != NULL)
1065 FreeVec(subpatternStr);
1068 if (oldOutput != BNULL)
1070 Close(SelectOutput(oldOutput));
1073 return result;