r9263@lvps87-230-33-50: verhaegs | 2008-10-04 23:31:42 +0200
[AROS.git] / workbench / c / List.c
blob67811a2dfc708f2a203f4ec6cd9847d73ee17bae
1 /*
2 Copyright © 1995-2007, 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,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
25 Sys:C
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.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"
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 -- the same as %N
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 char c;
233 while ('\0' != (c = *format++))
235 if ('%' == c)
237 switch (toupper(*format++))
239 /* File comment */
240 case 'C':
241 Printf(lf->comment);
242 break;
244 /* Creation date */
245 case 'D':
246 Printf(lf->date);
247 break;
249 /* Creation time */
250 case 'T':
251 Printf(lf->time);
252 break;
254 /* File size in blocks of BLOCKSIZE bytes */
255 case 'B':
256 if (lf->isdir)
258 Printf("Dir");
260 else
262 ULONG tmp = roundUp(lf->size, BLOCKSIZE);
264 /* File is 0 bytes? */
265 if (tmp == 0)
267 Printf("empty");
269 else
271 Printf("%lu", tmp);
275 break;
277 /* Path incl. volume name*/
278 case 'F':
280 UBYTE buf[256];
282 if (NameFromLock(lf->ap->ap_Current->an_Lock, buf, 256))
284 int len;
286 Printf(buf);
288 len = strlen(buf);
289 if ((len > 0) && (buf[len - 1] != ':') && (buf[len - 1] != '/'))
291 Printf("/");
296 break;
298 /* File attributes (flags) */
299 case 'A':
300 Printf(lf->flags);
301 break;
303 /* Disk block key */
304 case 'K':
305 Printf("[%ld]", lf->key);
306 break;
308 /* File size */
309 case 'L':
310 if (lf->isdir)
312 Printf("Dir");
314 else
316 if (lf->size == 0)
318 Printf("empty");
320 else
322 Printf("%lu", lf->size);
326 break;
328 /* File name without extension */
329 case 'M':
331 STRPTR lastPoint = strrchr(filename, '.');
333 if (lastPoint != NULL)
335 *lastPoint = 0;
338 Printf(filename);
340 /* Resurrect filename in case we should print it once
341 more */
342 if (lastPoint != NULL)
344 *lastPoint = '.';
348 break;
350 /* Filename */
351 case 'S':
352 /* Fall through */
353 case 'N':
354 Printf(filename);
355 break;
357 /* File extension */
358 case 'E':
360 STRPTR extension = strrchr(filename, '.');
362 if (extension != NULL)
364 Printf(extension);
368 break;
370 /* Path name, but without volume */
371 case 'P':
373 STRPTR end = FilePart(lf->filename);
374 UBYTE token = *end;
376 *end = 0;
378 Printf(lf->filename);
380 /* Restore pathname */
381 *end = token;
384 break;
386 case 0:
387 return 0;
388 break;
390 default:
391 Printf("%%%lc", *format);
392 break;
395 else
397 Printf("%lc", c);
401 return 0;
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,
411 BOOL keys)
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];
425 UBYTE flags[8];
427 struct DateTime dt;
429 /* Do the file match the time interval we are looking for?
430 (ARG_SINCE and ARG_UPTO) -- any combination of these may be
431 specified */
432 if ((doSince && (CompareDates(sinceDate, ds) < 0)) ||
433 (doUpto && (CompareDates(uptoDate, ds) > 0)))
435 return 0;
438 /* Does the filename match a certain pattern? (ARG_PAT) */
439 if (parsedPattern != NULL &&
440 !MatchPatternNoCase(parsedPattern, FilePart(filename)))
442 return 0;
445 /* Does a substring of the filename match a certain pattern? (ARG_SUB) */
446 if (subpatternStr != NULL &&
447 !MatchPatternNoCase(subpatternStr, FilePart(filename)))
449 return 0;
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';
470 flags[7] = 0x00;
472 if (isDir)
474 if (showDirs)
476 if (lFormat != NULL)
478 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
479 filenote, size, diskKey};
481 printLformat(lFormat, &lf);
482 Printf("\n");
484 *dirs += 1;
486 else
488 D(bug("Found file %s\n", filename));
490 Printf("%-25s ", FilePart(filename));
492 if (!quick)
494 Printf(" <Dir> %7s ", flags);
497 if (!noDates && (!quick || dates))
499 Printf("%-11s %s", date, time);
502 Printf("\n");
504 *dirs += 1;
508 else if (showFiles)
510 if (lFormat != NULL)
512 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
513 filenote, size, diskKey };
515 printLformat(lFormat, &lf);
516 Printf("\n");
518 *files += 1;
519 *nBlocks += roundUp(size, BLOCKSIZE);
521 else
523 Printf("%-25s ", FilePart(filename));
525 if (!quick)
527 if(keys)
529 char key[16];
530 int fill;
531 int i; /* Loop variable */
533 sprintf(key, "%ld", diskKey);
534 fill = 7 - strlen(key) - 2;
536 for (i = 0; i < fill; i++)
538 Printf(" ");
541 Printf("[%ld] ", diskKey);
543 else
545 if (0 != size)
547 Printf("%7ld ",
548 block ? roundUp(size, BLOCKSIZE) : size);
550 else
552 Printf(" empty ");
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);
569 Printf("\n");
570 *files += 1;
571 *nBlocks += roundUp(size, BLOCKSIZE);
575 return error;
579 /* Print directory summary information */
580 void printSummary(int files, int dirs, int nBlocks, BOOL noHead, BOOL PrintEmpty)
582 if (noHead)
584 return;
587 if ((files == 0) && (dirs == 0) && PrintEmpty)
589 Printf("Directory is empty\n");
591 if (files || dirs)
593 if (files != 0)
595 Printf("%ld files - ", files);
598 if (dirs != 0)
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;
618 ULONG files = 0;
619 ULONG dirs = 0;
620 ULONG nBlocks = 0;
621 ULONG error;
623 NewList(&DirList);
624 NewList(&FreeDirNodeList);
628 ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN, MEMF_CLEAR);
630 if (ap == NULL)
632 return RETURN_ERROR;
635 ap->ap_Strlen = MAX_PATH_LEN;
637 error = MatchFirst(filename, ap);
639 /* Explicitely named directory and not a pattern? --> enter dir */
641 if (0 == error)
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;
650 if (0 == error)
652 error = MatchNext(ap);
658 if (0 == error)
660 BOOL first = TRUE;
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)
677 STRPTR p;
678 UBYTE c;
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;
687 files = 0;
688 dirs = 0;
689 nBlocks = 0;
691 p = PathPart(ap->ap_Buf);
692 c = *p;
693 *p = 0;
695 error = printDirHeader(ap->ap_Buf, noHead);
697 *p = c;
701 error = printFileData(ap,
702 showFiles,
703 showDirs,
704 parsedPattern,
705 &files,
706 &dirs,
707 &nBlocks,
708 lFormat,
709 quick,
710 dates,
711 noDates,
712 block,
713 sinceDate,
714 uptoDate,
715 doSince,
716 doUpto,
717 subpatternStr,
718 keys);
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;
731 else
733 free(dirnode);
739 error = MatchNext(ap);
741 first = FALSE;
743 } while (0 == error);
746 MatchEnd(ap);
748 FreeVec(ap);
750 if (error == ERROR_BREAK)
752 PrintFault(error, NULL);
755 if (error == ERROR_NO_MORE_ENTRIES)
757 error = 0;
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;
770 files = 0;
771 dirs = 0;
772 nBlocks = 0;
775 if (error) break;
777 dirnode = (struct DirNode *)RemHead(&DirList);
779 if (dirnode != NULL)
781 filename = dirnode->dirname;
782 puts("");
784 prev_dirnode = NULL;
786 /* do not free() dirnode, as we reference dirnode->dirname! */
788 AddTail(&FreeDirNodeList, (struct Node *)dirnode);
790 } while (dirnode);
792 while ((dirnode = (struct DirNode *)RemHead(&FreeDirNodeList)))
794 free(dirnode->dirname);
795 free(dirnode);
798 return error;
802 int __nocommandline;
804 int main(void)
806 IPTR args[NOOFARGS] =
808 (IPTR) NULL, // ARG_DIR
809 (IPTR) NULL, // ARG_PAT
810 FALSE, // ARG_KEYS
811 FALSE, // ARG_DATES
812 FALSE, // ARG_NODATES
813 (IPTR) NULL, // ARG_TO
814 (IPTR) NULL, // ARG_SUB
815 (IPTR) NULL, // ARG_SINCE
816 (IPTR) NULL, // ARG_UPTO
817 FALSE, // ARG_QUICK
818 FALSE, // ARG_BLOCK
819 FALSE, // ARG_NOHEAD
820 FALSE, // ARG_FILES
821 FALSE, // ARG_DIRS
822 FALSE, // ARG_LFORMAT
823 FALSE // ARG_ALL
825 static const STRPTR *default_directories[] = {"", 0};
826 struct RDArgs *rda;
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);
837 if (rda != 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 */
861 if (since != NULL)
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)
869 FreeArgs(rda);
870 Printf("*** Illegal 'SINCE' parameter\n");
872 return RETURN_FAIL;
876 if (upto != NULL)
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)
885 FreeArgs(rda);
886 Printf("*** Illegal 'UPTO' parameter\n");
888 return RETURN_FAIL;
892 if (subStr != NULL)
894 STRPTR subStrWithPat;
895 ULONG length = (strlen(subStr) + sizeof("#?#?"))*2 + 2;
897 subStrWithPat = AllocVec(length, MEMF_ANY);
899 if (subStrWithPat == NULL)
901 FreeArgs(rda);
902 PrintFault(IoErr(), "List");
904 return RETURN_FAIL;
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);
917 FreeArgs(rda);
918 PrintFault(IoErr(), "List");
920 return RETURN_FAIL;
923 FreeVec(subStrWithPat);
927 if (pattern != NULL)
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);
937 FreeArgs(rda);
939 return RETURN_FAIL;
943 if (toFile != NULL)
945 BPTR file = Open(toFile, MODE_NEWFILE);
947 if (file == NULL)
949 FreeVec(subpatternStr);
950 FreeVec(parsedPattern);
951 FreeArgs(rda);
952 PrintFault(IoErr(), "List");
954 return RETURN_FAIL;
956 oldOutput = SelectOutput(file);
959 if (!files && !dirs)
961 files = TRUE;
962 dirs = TRUE;
965 /* if (!dates && !noDates)
967 dates = TRUE;
970 if (lFormat)
972 noHead = TRUE;
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,
987 &stats);
989 if (error != RETURN_OK)
991 break;
994 // Printf("\n");
997 FreeArgs(rda);
999 else
1001 error = IoErr();;
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;
1017 else
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));
1039 return error;