Prevent partitions from extending beyond end of container partition.
[AROS.git] / workbench / c / List.c
blob9b84c096c323fa79b78bbc9cbbde67ce102c9241
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 <utility/tagitem.h>
121 #include <stdio.h>
122 #include <string.h>
123 #include <ctype.h>
124 #include <stdlib.h>
125 #include <memory.h>
127 const TEXT version[] = "$VER: List 41.7 (18.08.2010)\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"
131 struct DirNode
133 struct MinNode node;
134 char *dirname;
138 typedef struct _Statistics
140 ULONG nFiles;
141 ULONG nDirs;
142 ULONG nBlocks;
143 } Statistics;
146 enum
148 ARG_DIR = 0,
149 ARG_PAT,
150 ARG_KEYS,
151 ARG_DATES,
152 ARG_NODATES,
153 ARG_TO,
154 ARG_SUB,
155 ARG_SINCE,
156 ARG_UPTO,
157 ARG_QUICK,
158 ARG_BLOCK,
159 ARG_NOHEAD,
160 ARG_FILES,
161 ARG_DIRS,
162 ARG_LFORMAT,
163 ARG_ALL,
164 NOOFARGS
167 #define MAX_PATH_LEN 1024
169 #define BLOCKSIZE 512
171 int printDirHeader(STRPTR dirname, BOOL noHead)
173 struct DateTime dt;
175 char datestr[LEN_DATSTRING];
176 char dow[LEN_DATSTRING];
178 if (!noHead)
180 DateStamp((struct DateStamp *)&dt);
181 dt.dat_Format = FORMAT_DEF;
182 dt.dat_Flags = 0;
183 dt.dat_StrDay = dow;
184 dt.dat_StrDate = datestr;
185 dt.dat_StrTime = NULL;
186 DateToStr(&dt);
188 Printf("Directory \"%s\" on %s %s:\n", dirname, dow, datestr);
191 return RETURN_OK;
195 /* Possible printf-type switches
197 %A -- file attributes
198 %B -- size of file in blocks rather than bytes
199 %C -- file comment
200 %D -- file date
201 %E -- file extension
202 %F -- volume name
203 %K -- file key block number
204 %L -- size of file in bytes
205 %M -- file name without extension
206 %N -- file name
207 %P -- file path
208 %S -- file name or file path
209 %T -- creation date
212 struct lfstruct
214 struct AnchorPath *ap;
215 BOOL isdir;
216 STRPTR date;
217 STRPTR time;
218 STRPTR flags;
219 STRPTR filename;
220 STRPTR comment;
221 ULONG size;
222 ULONG key;
226 #define roundUp(x, bSize) ((x + bSize - 1)/bSize)
228 int printLformat(STRPTR format, struct lfstruct *lf)
230 STRPTR filename = FilePart(lf->filename);
231 STRPTR temp = format;
232 LONG substitutePath = 0;
233 char c;
236 Whether the path or the filename is substituted for an occurrence
237 of %S depends on how many occurrences are in the LFORMAT line, and
238 their order, as follows:
240 Occurrences of %S 1st 2nd 3rd 4th
241 1 filename
242 2 path filename
243 3 path filename filename
244 4 path filename path filename
247 while ( ( substitutePath < 4 ) && ( '\0' != (c = *temp++) ) )
249 if ( '%' == c )
250 if ( 'S' == toupper(*temp++) )
251 substitutePath++;
253 if ( substitutePath == 3 )
254 substitutePath = 2;
256 while ('\0' != (c = *format++))
258 if ('%' == c)
260 switch (toupper(*format++))
262 /* File comment */
263 case 'C':
264 Printf(lf->comment);
265 break;
267 /* Creation date */
268 case 'D':
269 Printf(lf->date);
270 break;
272 /* Creation time */
273 case 'T':
274 Printf(lf->time);
275 break;
277 /* File size in blocks of BLOCKSIZE bytes */
278 case 'B':
279 if (lf->isdir)
281 Printf("Dir");
283 else
285 ULONG tmp = roundUp(lf->size, BLOCKSIZE);
287 /* File is 0 bytes? */
288 if (tmp == 0)
290 Printf("empty");
292 else
294 Printf("%lu", tmp);
298 break;
300 /* Path incl. volume name*/
301 case 'F':
303 UBYTE buf[256];
305 if (NameFromLock(lf->ap->ap_Current->an_Lock, buf, 256))
307 int len;
309 Printf(buf);
311 len = strlen(buf);
312 if ((len > 0) && (buf[len - 1] != ':') && (buf[len - 1] != '/'))
314 Printf("/");
319 break;
321 /* File attributes (flags) */
322 case 'A':
323 Printf(lf->flags);
324 break;
326 /* Disk block key */
327 case 'K':
328 Printf("[%ld]", lf->key);
329 break;
331 /* File size */
332 case 'L':
333 if (lf->isdir)
335 Printf("Dir");
337 else
339 if (lf->size == 0)
341 Printf("empty");
343 else
345 Printf("%lu", lf->size);
349 break;
351 /* File name without extension */
352 case 'M':
354 STRPTR lastPoint = strrchr(filename, '.');
356 if (lastPoint != NULL)
358 *lastPoint = 0;
361 Printf(filename);
363 /* Resurrect filename in case we should print it once
364 more */
365 if (lastPoint != NULL)
367 *lastPoint = '.';
371 break;
373 /* Filename or Path name */
374 case 'S':
375 D(bug("[List] substitutePath = %d\n", substitutePath));
376 if ( (--substitutePath == 3) || (substitutePath == 1) )
378 STRPTR end = FilePart(lf->filename);
379 UBYTE token = *end;
381 *end = '\0';
383 Printf(lf->filename);
385 /* Restore pathname */
386 *end = token;
388 break;
390 /* Fall through */
391 case 'N':
392 Printf(filename);
393 break;
395 /* File extension */
396 case 'E':
398 STRPTR extension = strrchr(filename, '.');
400 if (extension != NULL)
402 Printf(extension);
406 break;
408 /* Path name, but without volume */
409 case 'P':
411 STRPTR end = FilePart(lf->filename);
412 UBYTE token = *end;
414 *end = 0;
416 Printf(lf->filename);
418 /* Restore pathname */
419 *end = token;
422 break;
424 case 0:
425 return 0;
426 break;
428 default:
429 Printf("%%%lc", *format);
430 break;
433 else
435 Printf("%lc", c);
439 return 0;
443 int printFileData(struct AnchorPath *ap,
444 BOOL showFiles, BOOL showDirs, STRPTR parsedPattern,
445 ULONG *files, ULONG *dirs, ULONG *nBlocks, STRPTR lFormat,
446 BOOL quick, BOOL dates, BOOL noDates, BOOL block,
447 struct DateStamp *sinceDate, struct DateStamp *uptoDate,
448 BOOL doSince, BOOL doUpto, STRPTR subpatternStr,
449 BOOL keys)
451 STRPTR filename = ap->ap_Buf;
452 BOOL isDir = (ap->ap_Info.fib_DirEntryType >= 0);
453 struct DateStamp *ds = &ap->ap_Info.fib_Date;
454 ULONG protection = ap->ap_Info.fib_Protection;
455 ULONG size = ap->ap_Info.fib_Size;
456 STRPTR filenote = ap->ap_Info.fib_Comment;
457 LONG diskKey = ap->ap_Info.fib_DiskKey;
459 int error = 0;
461 UBYTE date[LEN_DATSTRING];
462 UBYTE time[LEN_DATSTRING];
463 UBYTE flags[8];
465 struct DateTime dt;
467 /* Do the file match the time interval we are looking for?
468 (ARG_SINCE and ARG_UPTO) -- any combination of these may be
469 specified */
470 if ((doSince && (CompareDates(sinceDate, ds) < 0)) ||
471 (doUpto && (CompareDates(uptoDate, ds) > 0)))
473 return 0;
476 /* Does the filename match a certain pattern? (ARG_PAT) */
477 if (parsedPattern != NULL &&
478 !MatchPatternNoCase(parsedPattern, FilePart(filename)))
480 return 0;
483 /* Does a substring of the filename match a certain pattern? (ARG_SUB) */
484 if (subpatternStr != NULL &&
485 !MatchPatternNoCase(subpatternStr, FilePart(filename)))
487 return 0;
490 CopyMem(ds, &dt.dat_Stamp, sizeof(struct DateStamp));
491 dt.dat_Format = FORMAT_DOS;
492 dt.dat_Flags = DTF_SUBST;
493 dt.dat_StrDay = NULL;
494 dt.dat_StrDate = date;
495 dt.dat_StrTime = time;
496 DateToStr(&dt); /* returns 0 if invalid */
498 /* Convert the protection bits to a string */
499 flags[0] = protection & FIBF_SCRIPT ? 's' : '-';
500 flags[1] = protection & FIBF_PURE ? 'p' : '-';
501 flags[2] = protection & FIBF_ARCHIVE ? 'a' : '-';
503 /* The following flags are high-active! */
504 flags[3] = protection & FIBF_READ ? '-' : 'r';
505 flags[4] = protection & FIBF_WRITE ? '-' : 'w';
506 flags[5] = protection & FIBF_EXECUTE ? '-' : 'e';
507 flags[6] = protection & FIBF_DELETE ? '-' : 'd';
508 flags[7] = 0x00;
510 if (isDir)
512 if (showDirs)
514 ++*dirs;
515 ++*nBlocks; /* dir entry uses 1 block on AROS, 2 on OS31) */
517 if (lFormat != NULL)
519 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
520 filenote, size, diskKey};
522 printLformat(lFormat, &lf);
523 Printf("\n");
525 else
527 D(bug("Found file %s\n", filename));
529 Printf("%-25s ", FilePart(filename));
531 if (!quick)
533 Printf(" <Dir> %7s ", flags);
536 if (!noDates && (!quick || dates))
538 Printf("%-11s %s", date, time);
541 Printf("\n");
545 else if (showFiles)
547 ++*files;
548 *nBlocks += roundUp(size, BLOCKSIZE);
550 if (lFormat != NULL)
552 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
553 filenote, size, diskKey };
555 printLformat(lFormat, &lf);
556 Printf("\n");
558 else
560 Printf("%-25s ", FilePart(filename));
562 if (!quick)
564 if(keys)
566 char key[16];
567 int fill;
568 int i; /* Loop variable */
570 sprintf(key, "%ld", (long)diskKey);
571 fill = 7 - strlen(key) - 2;
573 for (i = 0; i < fill; i++)
575 Printf(" ");
578 Printf("[%ld] ", diskKey);
580 else
582 if (0 != size)
584 Printf("%7ld ",
585 block ? roundUp(size, BLOCKSIZE) : size);
587 else
589 Printf(" empty ");
593 Printf("%7s ", flags);
596 if (!noDates && (!quick || dates))
598 Printf("%-11s %s", date, time);
601 if (!quick && (*filenote != 0))
603 Printf("\n: %s", filenote);
606 Printf("\n");
610 return error;
614 /* Print directory summary information */
615 void printSummary(CONST_STRPTR dirname, int files, int dirs, int nBlocks,
616 BOOL noHead, BOOL PrintEmpty)
618 if (noHead)
619 return;
621 if (files || dirs)
623 if (files > 1)
624 Printf("%ld files - ", files);
625 else if (files > 0)
626 PutStr("1 file - ");
628 if (dirs > 1)
629 Printf("%ld directories - ", dirs);
630 else if (dirs > 0)
631 PutStr("1 directory - ");
633 if (nBlocks > 1)
634 Printf("%ld blocks used\n", nBlocks);
635 else if (nBlocks > 0)
636 PutStr("1 block used\n");
638 else if (PrintEmpty)
639 Printf("Directory \"%s\" is empty\n", dirname);
643 int listFile(CONST_STRPTR filename, BOOL showFiles, BOOL showDirs,
644 STRPTR parsedPattern, BOOL noHead, STRPTR lFormat, BOOL quick,
645 BOOL dates, BOOL noDates, BOOL block, struct DateStamp *sinceDate,
646 struct DateStamp *uptoDate, BOOL doSince, BOOL doUpto,
647 STRPTR subpatternStr, BOOL all, BOOL keys, Statistics *stats)
649 struct AnchorPath *ap;
650 struct List DirList, FreeDirNodeList;
651 struct DirNode *dirnode, *prev_dirnode = NULL;
653 ULONG files = 0;
654 ULONG dirs = 0;
655 ULONG nBlocks = 0;
656 LONG error;
658 NewList(&DirList);
659 NewList(&FreeDirNodeList);
663 ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN, MEMF_CLEAR);
665 if (ap == NULL)
667 return 0;
670 ap->ap_Strlen = MAX_PATH_LEN;
672 error = MatchFirst(filename, ap);
674 /* Explicitly named directory and not a pattern? --> enter dir */
676 if (0 == error)
678 if (!(ap->ap_Flags & APF_ITSWILD))
680 if (ap->ap_Info.fib_DirEntryType >= 0)
682 //error = printDirHeader(filename, noHead);
683 ap->ap_Flags |= APF_DODIR;
685 if (0 == error)
687 error = MatchNext(ap);
693 if (0 == error)
695 BOOL first = TRUE;
697 ap->ap_BreakBits = SIGBREAKF_CTRL_C;
698 if (FilePart(ap->ap_Buf) == ap->ap_Buf)
700 ap->ap_Flags &= ~APF_DirChanged;
706 ** There's something to show.
708 if (!(ap->ap_Flags & APF_DIDDIR))
710 if (ap->ap_Flags & APF_DirChanged)
712 STRPTR p;
713 UBYTE c;
715 if (!first) printSummary(filename, files, dirs, nBlocks, noHead, TRUE);
717 /* Update global statistics for (possible) ALL option */
718 stats->nFiles += files;
719 stats->nDirs += dirs;
720 stats->nBlocks += nBlocks;
722 files = 0;
723 dirs = 0;
724 nBlocks = 0;
726 p = PathPart(ap->ap_Buf);
727 c = *p;
728 *p = 0;
730 error = printDirHeader(ap->ap_Buf, noHead);
732 *p = c;
736 error = printFileData(ap,
737 showFiles,
738 showDirs,
739 parsedPattern,
740 &files,
741 &dirs,
742 &nBlocks,
743 lFormat,
744 quick,
745 dates,
746 noDates,
747 block,
748 sinceDate,
749 uptoDate,
750 doSince,
751 doUpto,
752 subpatternStr,
753 keys);
755 if (all && (ap->ap_Info.fib_DirEntryType >= 0))
757 if ((dirnode = malloc(sizeof(struct DirNode))))
759 if ((dirnode->dirname = strdup(ap->ap_Buf)))
761 Insert(&DirList, (struct Node *)dirnode,
762 (struct Node *)prev_dirnode);
764 prev_dirnode = dirnode;
766 else
768 free(dirnode);
774 error = MatchNext(ap);
776 first = FALSE;
778 } while (0 == error);
781 MatchEnd(ap);
783 FreeVec(ap);
785 if (error == ERROR_BREAK)
787 PrintFault(error, NULL);
790 if (error == ERROR_NO_MORE_ENTRIES)
792 error = 0;
795 if ((error == 0) || (error == ERROR_BREAK))
797 BOOL printEmpty = !(ap->ap_Flags & APF_ITSWILD);
798 printSummary(filename, files, dirs, nBlocks, noHead, printEmpty);
801 /* Update global statistics for (possible) ALL option */
802 stats->nFiles += files;
803 stats->nDirs += dirs;
804 stats->nBlocks += nBlocks;
806 files = 0;
807 dirs = 0;
808 nBlocks = 0;
811 if (error) break;
813 dirnode = (struct DirNode *)RemHead(&DirList);
815 if (dirnode != NULL)
817 filename = dirnode->dirname;
819 prev_dirnode = NULL;
821 /* do not free() dirnode, as we reference dirnode->dirname! */
823 AddTail(&FreeDirNodeList, (struct Node *)dirnode);
825 } while (dirnode);
827 while ((dirnode = (struct DirNode *)RemHead(&FreeDirNodeList)))
829 free(dirnode->dirname);
830 free(dirnode);
833 return error;
837 int __nocommandline;
839 int main(void)
841 IPTR args[NOOFARGS] =
843 (IPTR) NULL, // ARG_DIR
844 (IPTR) NULL, // ARG_PAT
845 FALSE, // ARG_KEYS
846 FALSE, // ARG_DATES
847 FALSE, // ARG_NODATES
848 (IPTR) NULL, // ARG_TO
849 (IPTR) NULL, // ARG_SUB
850 (IPTR) NULL, // ARG_SINCE
851 (IPTR) NULL, // ARG_UPTO
852 FALSE, // ARG_QUICK
853 FALSE, // ARG_BLOCK
854 FALSE, // ARG_NOHEAD
855 FALSE, // ARG_FILES
856 FALSE, // ARG_DIRS
857 FALSE, // ARG_LFORMAT
858 FALSE // ARG_ALL
860 static CONST_STRPTR default_directories[] = {(CONST_STRPTR)"", 0};
861 struct RDArgs *rda;
863 LONG result = RETURN_OK;
864 LONG error = 0;
865 STRPTR parsedPattern = NULL;
866 STRPTR subpatternStr = NULL;
867 BPTR oldOutput = BNULL;
869 Statistics stats = { 0, 0, 0 };
871 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
873 if (rda != NULL)
875 CONST_STRPTR *directories = (CONST_STRPTR *)args[ARG_DIR];
876 STRPTR lFormat = (STRPTR)args[ARG_LFORMAT];
877 STRPTR pattern = (STRPTR)args[ARG_PAT];
878 STRPTR toFile = (STRPTR)args[ARG_TO];
879 STRPTR subStr = (STRPTR)args[ARG_SUB];
880 STRPTR since = (STRPTR)args[ARG_SINCE];
881 STRPTR upto = (STRPTR)args[ARG_UPTO];
882 BOOL files = (BOOL)args[ARG_FILES];
883 BOOL dirs = (BOOL)args[ARG_DIRS];
884 BOOL noDates = (BOOL)args[ARG_NODATES];
885 BOOL dates = (BOOL)args[ARG_DATES];
886 BOOL quick = (BOOL)args[ARG_QUICK];
887 BOOL noHead = (BOOL)args[ARG_NOHEAD];
888 BOOL block = (BOOL)args[ARG_BLOCK];
889 BOOL all = (BOOL)args[ARG_ALL];
890 BOOL keys = (BOOL)args[ARG_KEYS];
892 struct DateTime sinceDatetime;
893 struct DateTime uptoDatetime;
895 ULONG i; /* Loop variable */
897 if (since != NULL)
899 sinceDatetime.dat_StrDate = since;
900 sinceDatetime.dat_StrTime = NULL;
901 sinceDatetime.dat_Format = FORMAT_DEF;
902 sinceDatetime.dat_Flags = 0;
903 if (StrToDate(&sinceDatetime) == DOSFALSE)
905 FreeArgs(rda);
906 Printf("*** Illegal 'SINCE' parameter\n");
908 return RETURN_FAIL;
912 if (upto != NULL)
914 uptoDatetime.dat_StrDate = upto;
915 uptoDatetime.dat_StrTime = NULL;
916 uptoDatetime.dat_Format = FORMAT_DEF;
917 uptoDatetime.dat_Flags = 0;
919 if (StrToDate(&uptoDatetime) == DOSFALSE)
921 FreeArgs(rda);
922 Printf("*** Illegal 'UPTO' parameter\n");
924 return RETURN_FAIL;
928 if (subStr != NULL)
930 STRPTR subStrWithPat;
931 ULONG length = (strlen(subStr) + sizeof("#?#?"))*2 + 2;
933 subStrWithPat = AllocVec(length, MEMF_ANY);
935 if (subStrWithPat == NULL)
937 FreeArgs(rda);
938 PrintFault(IoErr(), "List");
940 return RETURN_FAIL;
943 strcpy(subStrWithPat, "#?");
944 strcat(subStrWithPat, subStr);
945 strcat(subStrWithPat, "#?");
947 subpatternStr = AllocVec(length, MEMF_ANY);
949 if (subpatternStr == NULL ||
950 ParsePatternNoCase(subStrWithPat, subpatternStr, length) == -1)
952 FreeVec(subStrWithPat);
953 FreeArgs(rda);
954 PrintFault(IoErr(), "List");
956 return RETURN_FAIL;
959 FreeVec(subStrWithPat);
963 if (pattern != NULL)
965 ULONG length = strlen(pattern)*2 + 2;
967 parsedPattern = AllocVec(length, MEMF_ANY);
969 if (parsedPattern == NULL ||
970 ParsePatternNoCase(pattern, parsedPattern, length) == -1)
972 FreeVec(subpatternStr);
973 FreeArgs(rda);
975 return RETURN_FAIL;
979 if (toFile != NULL)
981 BPTR file = Open(toFile, MODE_NEWFILE);
983 if (file == BNULL)
985 FreeVec(subpatternStr);
986 FreeVec(parsedPattern);
987 FreeArgs(rda);
988 PrintFault(IoErr(), "List");
990 return RETURN_FAIL;
992 oldOutput = SelectOutput(file);
995 if (!files && !dirs)
997 files = TRUE;
998 dirs = TRUE;
1001 /* if (!dates && !noDates)
1003 dates = TRUE;
1006 if (lFormat)
1008 noHead = TRUE;
1011 if ((directories == NULL) || (*directories == NULL))
1013 directories = default_directories;
1016 for (i = 0; directories[i] != NULL; i++)
1018 error = listFile(directories[i], files, dirs, parsedPattern,
1019 noHead, lFormat, quick, dates, noDates,
1020 block, &sinceDatetime.dat_Stamp,
1021 &uptoDatetime.dat_Stamp, since != NULL,
1022 upto != NULL, subpatternStr, all, keys,
1023 &stats);
1025 if (error != 0)
1027 break;
1030 // Printf("\n");
1033 FreeArgs(rda);
1035 else
1037 error = IoErr();
1040 if ((BOOL)args[ARG_NOHEAD] == FALSE &&
1041 (BOOL)args[ARG_LFORMAT] == FALSE &&
1042 (BOOL)args[ARG_ALL] &&
1043 (stats.nFiles || stats.nDirs))
1045 Printf("\nTOTAL: %ld files - %ld directories - %ld blocks used\n",
1046 stats.nFiles, stats.nDirs, stats.nBlocks);
1050 if (error != 0)
1052 if (error == ERROR_BREAK)
1054 result = RETURN_WARN;
1056 else
1058 PrintFault(error, "List");
1059 result = RETURN_FAIL;
1063 if (parsedPattern != NULL)
1065 FreeVec(parsedPattern);
1068 if (subpatternStr != NULL)
1070 FreeVec(subpatternStr);
1073 if (oldOutput != BNULL)
1075 Close(SelectOutput(oldOutput));
1078 return result;