Fixed out-by-one error in previous commit.
[AROS.git] / workbench / c / List.c
blob92ef3de21feac70abe42cce44389e528c3e06997
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.9 (04.06.2012)\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 UQUAD 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 UQUAD 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("[%lu]", 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 UQUAD filesize = lf->size;
342 char buf[256];
343 buf[255] = '\0';
344 int fill, i;
346 char *bufpos = &buf[254];
350 bufpos[0] = '0' + (filesize % 10);
351 filesize /= 10;
352 bufpos--;
353 } while (filesize);
355 fill = 13 - (&buf[254] - bufpos);
356 for (i = 0; i < fill; i++)
358 Printf(" ");
360 Printf("%s ", &bufpos[1]);
364 break;
366 /* File name without extension */
367 case 'M':
369 STRPTR lastPoint = strrchr(filename, '.');
371 if (lastPoint != NULL)
373 *lastPoint = 0;
376 Printf(filename);
378 /* Resurrect filename in case we should print it once
379 more */
380 if (lastPoint != NULL)
382 *lastPoint = '.';
386 break;
388 /* Filename or Path name */
389 case 'S':
390 D(bug("[List] substitutePath = %d\n", substitutePath));
391 if ( (--substitutePath == 3) || (substitutePath == 1) )
393 STRPTR end = FilePart(lf->filename);
394 UBYTE token = *end;
396 *end = '\0';
398 Printf(lf->filename);
400 /* Restore pathname */
401 *end = token;
403 break;
405 /* Fall through */
406 case 'N':
407 Printf(filename);
408 break;
410 /* File extension */
411 case 'E':
413 STRPTR extension = strrchr(filename, '.');
415 if (extension != NULL)
417 Printf(extension);
421 break;
423 /* Path name, but without volume */
424 case 'P':
426 STRPTR end = FilePart(lf->filename);
427 UBYTE token = *end;
429 *end = 0;
431 Printf(lf->filename);
433 /* Restore pathname */
434 *end = token;
437 break;
439 case 0:
440 return 0;
441 break;
443 default:
444 Printf("%%%lc", *format);
445 break;
448 else
450 Printf("%lc", c);
454 return 0;
458 int printFileData(struct AnchorPath *ap,
459 BOOL showFiles, BOOL showDirs, STRPTR parsedPattern,
460 ULONG *files, ULONG *dirs, ULONG *nBlocks, STRPTR lFormat,
461 BOOL quick, BOOL dates, BOOL noDates, BOOL block,
462 struct DateStamp *sinceDate, struct DateStamp *uptoDate,
463 BOOL doSince, BOOL doUpto, STRPTR subpatternStr,
464 BOOL keys)
466 STRPTR filename = ap->ap_Buf;
467 BOOL isDir = (ap->ap_Info.fib_DirEntryType >= 0);
468 struct DateStamp *ds = &ap->ap_Info.fib_Date;
469 ULONG protection = ap->ap_Info.fib_Protection;
470 UQUAD size = ap->ap_Info.fib_Size;
471 STRPTR filenote = ap->ap_Info.fib_Comment;
472 ULONG diskKey = ap->ap_Info.fib_DiskKey;
474 int error = 0;
476 UBYTE date[LEN_DATSTRING];
477 UBYTE time[LEN_DATSTRING];
478 UBYTE flags[8];
480 struct DateTime dt;
482 #if defined(ACTION_GET_FILE_SIZE64)
483 if (ap->ap_Info.fib_Size >= 0x7FFFFFFF)
485 BPTR flock = BNULL;
486 flock = Lock(filename, ACCESS_READ);
488 if (flock)
490 UQUAD *size_ptr = (UQUAD *)DoPkt(((struct FileLock *)flock)->fl_Task, ACTION_GET_FILE_SIZE64, (IPTR)flock, 0, 0, 0, 0);
491 if (size_ptr)
493 size = *size_ptr;
495 UnLock(flock);
498 #endif
499 /* Do the file match the time interval we are looking for?
500 (ARG_SINCE and ARG_UPTO) -- any combination of these may be
501 specified */
502 if ((doSince && (CompareDates(sinceDate, ds) < 0)) ||
503 (doUpto && (CompareDates(uptoDate, ds) > 0)))
505 return 0;
508 /* Does the filename match a certain pattern? (ARG_PAT) */
509 if (parsedPattern != NULL &&
510 !MatchPatternNoCase(parsedPattern, FilePart(filename)))
512 return 0;
515 /* Does a substring of the filename match a certain pattern? (ARG_SUB) */
516 if (subpatternStr != NULL &&
517 !MatchPatternNoCase(subpatternStr, FilePart(filename)))
519 return 0;
522 CopyMem(ds, &dt.dat_Stamp, sizeof(struct DateStamp));
523 dt.dat_Format = FORMAT_DOS;
524 dt.dat_Flags = DTF_SUBST;
525 dt.dat_StrDay = NULL;
526 dt.dat_StrDate = date;
527 dt.dat_StrTime = time;
528 DateToStr(&dt); /* returns 0 if invalid */
530 /* Convert the protection bits to a string */
531 flags[0] = protection & FIBF_SCRIPT ? 's' : '-';
532 flags[1] = protection & FIBF_PURE ? 'p' : '-';
533 flags[2] = protection & FIBF_ARCHIVE ? 'a' : '-';
535 /* The following flags are high-active! */
536 flags[3] = protection & FIBF_READ ? '-' : 'r';
537 flags[4] = protection & FIBF_WRITE ? '-' : 'w';
538 flags[5] = protection & FIBF_EXECUTE ? '-' : 'e';
539 flags[6] = protection & FIBF_DELETE ? '-' : 'd';
540 flags[7] = 0x00;
542 if (isDir)
544 if (showDirs)
546 ++*dirs;
547 ++*nBlocks; /* dir entry uses 1 block on AROS, 2 on OS31) */
549 if (lFormat != NULL)
551 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
552 filenote, size, diskKey};
554 printLformat(lFormat, &lf);
555 Printf("\n");
557 else
559 D(bug("Found file %s\n", filename));
561 Printf("%-25s ", FilePart(filename));
563 if (!quick)
565 Printf(" <Dir> %7s ", flags);
568 if (!noDates && (!quick || dates))
570 Printf("%-11s %s", date, time);
573 Printf("\n");
577 else if (showFiles)
579 ++*files;
580 *nBlocks += roundUp(size, BLOCKSIZE);
582 if (lFormat != NULL)
584 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
585 filenote, size, diskKey };
587 printLformat(lFormat, &lf);
588 Printf("\n");
590 else
592 Printf("%-25s ", FilePart(filename));
594 if (!quick)
596 if(keys)
598 char key[16];
599 int fill;
600 int i; /* Loop variable */
602 __sprintf(key, "%lu", (unsigned long)diskKey);
603 fill = 7 - strlen(key) - 2;
605 for (i = 0; i < fill; i++)
607 Printf(" ");
610 Printf("[%lu] ", diskKey);
612 else
614 if (0 != size)
616 UQUAD filesize = block ? roundUp(size, BLOCKSIZE) : size;
618 char buf[256];
619 buf[255] = '\0';
620 int fill, i;
622 char *bufpos = &buf[254];
626 bufpos[0] = '0' + (filesize % 10);
627 filesize /= 10;
628 bufpos--;
629 } while (filesize);
631 fill = 13 - (&buf[254] - bufpos);
632 for (i = 0; i < fill; i++)
634 Printf(" ");
636 Printf("%s ", &bufpos[1]);
638 else
640 Printf(" empty ");
644 Printf("%7s ", flags);
647 if (!noDates && (!quick || dates))
649 Printf("%-11s %s", date, time);
652 if (!quick && (*filenote != 0))
654 Printf("\n: %s", filenote);
657 Printf("\n");
661 return error;
665 /* Print directory summary information */
666 void printSummary(CONST_STRPTR dirname, int files, int dirs, int nBlocks,
667 BOOL noHead, BOOL PrintEmpty)
670 if (noHead) return;
672 if (files || dirs)
675 if (files > 1)
676 Printf("%ld files", files);
677 else if (files > 0)
678 PutStr("1 file");
680 if( files && (dirs || nBlocks) ) PutStr(" - ");
682 if (dirs > 1)
683 Printf("%ld directories", dirs);
684 else if (dirs > 0)
685 PutStr("1 directory");
687 if( dirs && nBlocks ) PutStr(" - ");
689 if (nBlocks > 1)
690 Printf("%ld blocks used\n", nBlocks);
691 else if (nBlocks > 0)
692 PutStr("1 block used\n");
693 else PutStr("\n");
696 else if (PrintEmpty)
697 Printf("Directory \"%s\" is empty\n", dirname);
701 int listFile(CONST_STRPTR filename, BOOL showFiles, BOOL showDirs,
702 STRPTR parsedPattern, BOOL noHead, STRPTR lFormat, BOOL quick,
703 BOOL dates, BOOL noDates, BOOL block, struct DateStamp *sinceDate,
704 struct DateStamp *uptoDate, BOOL doSince, BOOL doUpto,
705 STRPTR subpatternStr, BOOL all, BOOL keys, Statistics *stats)
707 struct AnchorPath *ap;
708 struct List DirList, FreeDirNodeList;
709 struct DirNode *dirnode, *prev_dirnode = NULL;
711 ULONG files = 0;
712 ULONG dirs = 0;
713 ULONG nBlocks = 0;
714 LONG error;
716 NewList(&DirList);
717 NewList(&FreeDirNodeList);
721 ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN, MEMF_CLEAR);
723 if (ap == NULL)
725 return 0;
728 ap->ap_Strlen = MAX_PATH_LEN;
730 error = MatchFirst(filename, ap);
732 /* Explicitly named directory and not a pattern? --> enter dir */
734 if (0 == error)
736 if (!(ap->ap_Flags & APF_ITSWILD))
738 if (ap->ap_Info.fib_DirEntryType >= 0)
740 //error = printDirHeader(filename, noHead);
741 ap->ap_Flags |= APF_DODIR;
743 if (0 == error)
745 error = MatchNext(ap);
751 if (0 == error)
753 BOOL first = TRUE;
755 ap->ap_BreakBits = SIGBREAKF_CTRL_C;
756 if (FilePart(ap->ap_Buf) == ap->ap_Buf)
758 ap->ap_Flags &= ~APF_DirChanged;
764 ** There's something to show.
766 if (!(ap->ap_Flags & APF_DIDDIR))
768 if (ap->ap_Flags & APF_DirChanged)
770 STRPTR p;
771 UBYTE c;
773 if (!first) printSummary(filename, files, dirs, nBlocks, noHead, TRUE);
775 /* Update global statistics for (possible) ALL option */
776 stats->nFiles += files;
777 stats->nDirs += dirs;
778 stats->nBlocks += nBlocks;
780 files = 0;
781 dirs = 0;
782 nBlocks = 0;
784 p = PathPart(ap->ap_Buf);
785 c = *p;
786 *p = 0;
788 error = printDirHeader(ap->ap_Buf, noHead);
790 *p = c;
794 error = printFileData(ap,
795 showFiles,
796 showDirs,
797 parsedPattern,
798 &files,
799 &dirs,
800 &nBlocks,
801 lFormat,
802 quick,
803 dates,
804 noDates,
805 block,
806 sinceDate,
807 uptoDate,
808 doSince,
809 doUpto,
810 subpatternStr,
811 keys);
813 if (all && (ap->ap_Info.fib_DirEntryType >= 0))
815 if ((dirnode = AllocMem(sizeof(struct DirNode), MEMF_ANY)))
817 if ((dirnode->dirname = StrDup(ap->ap_Buf)))
819 Insert(&DirList, (struct Node *)dirnode,
820 (struct Node *)prev_dirnode);
822 prev_dirnode = dirnode;
824 else
826 FreeMem(dirnode, sizeof(struct DirNode));
832 error = MatchNext(ap);
834 first = FALSE;
836 } while (0 == error);
839 MatchEnd(ap);
841 FreeVec(ap);
843 if (error == ERROR_BREAK)
845 PrintFault(error, NULL);
848 if (error == ERROR_NO_MORE_ENTRIES)
850 error = 0;
853 if ((error == 0) || (error == ERROR_BREAK))
855 BOOL printEmpty = !(ap->ap_Flags & APF_ITSWILD);
856 printSummary(filename, files, dirs, nBlocks, noHead, printEmpty);
859 /* Update global statistics for (possible) ALL option */
860 stats->nFiles += files;
861 stats->nDirs += dirs;
862 stats->nBlocks += nBlocks;
864 files = 0;
865 dirs = 0;
866 nBlocks = 0;
869 if (error) break;
871 dirnode = (struct DirNode *)RemHead(&DirList);
873 if (dirnode != NULL)
875 filename = dirnode->dirname;
877 prev_dirnode = NULL;
879 /* do not free() dirnode, as we reference dirnode->dirname! */
881 AddTail(&FreeDirNodeList, (struct Node *)dirnode);
883 } while (dirnode);
885 while ((dirnode = (struct DirNode *)RemHead(&FreeDirNodeList)))
887 FreeVec(dirnode->dirname);
888 FreeMem(dirnode, sizeof(struct DirNode));
891 return error;
895 int __nocommandline;
897 int main(void)
899 IPTR args[NOOFARGS] =
901 (IPTR) NULL, // ARG_DIR
902 (IPTR) NULL, // ARG_PAT
903 FALSE, // ARG_KEYS
904 FALSE, // ARG_DATES
905 FALSE, // ARG_NODATES
906 (IPTR) NULL, // ARG_TO
907 (IPTR) NULL, // ARG_SUB
908 (IPTR) NULL, // ARG_SINCE
909 (IPTR) NULL, // ARG_UPTO
910 FALSE, // ARG_QUICK
911 FALSE, // ARG_BLOCK
912 FALSE, // ARG_NOHEAD
913 FALSE, // ARG_FILES
914 FALSE, // ARG_DIRS
915 FALSE, // ARG_LFORMAT
916 FALSE // ARG_ALL
918 static CONST_STRPTR default_directories[] = {(CONST_STRPTR)"", 0};
919 struct RDArgs *rda;
921 LONG result = RETURN_OK;
922 LONG error = 0;
923 STRPTR parsedPattern = NULL;
924 STRPTR subpatternStr = NULL;
925 BPTR oldOutput = BNULL;
927 Statistics stats = { 0, 0, 0 };
929 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
931 if (rda != NULL)
933 CONST_STRPTR *directories = (CONST_STRPTR *)args[ARG_DIR];
934 STRPTR lFormat = (STRPTR)args[ARG_LFORMAT];
935 STRPTR pattern = (STRPTR)args[ARG_PAT];
936 STRPTR toFile = (STRPTR)args[ARG_TO];
937 STRPTR subStr = (STRPTR)args[ARG_SUB];
938 STRPTR since = (STRPTR)args[ARG_SINCE];
939 STRPTR upto = (STRPTR)args[ARG_UPTO];
940 BOOL files = (BOOL)args[ARG_FILES];
941 BOOL dirs = (BOOL)args[ARG_DIRS];
942 BOOL noDates = (BOOL)args[ARG_NODATES];
943 BOOL dates = (BOOL)args[ARG_DATES];
944 BOOL quick = (BOOL)args[ARG_QUICK];
945 BOOL noHead = (BOOL)args[ARG_NOHEAD];
946 BOOL block = (BOOL)args[ARG_BLOCK];
947 BOOL all = (BOOL)args[ARG_ALL];
948 BOOL keys = (BOOL)args[ARG_KEYS];
950 struct DateTime sinceDatetime;
951 struct DateTime uptoDatetime;
953 ULONG i; /* Loop variable */
955 if (since != NULL)
957 sinceDatetime.dat_StrDate = since;
958 sinceDatetime.dat_StrTime = NULL;
959 sinceDatetime.dat_Format = FORMAT_DEF;
960 sinceDatetime.dat_Flags = 0;
961 if (StrToDate(&sinceDatetime) == DOSFALSE)
963 FreeArgs(rda);
964 Printf("*** Illegal 'SINCE' parameter\n");
966 return RETURN_FAIL;
970 if (upto != NULL)
972 uptoDatetime.dat_StrDate = upto;
973 uptoDatetime.dat_StrTime = NULL;
974 uptoDatetime.dat_Format = FORMAT_DEF;
975 uptoDatetime.dat_Flags = 0;
977 if (StrToDate(&uptoDatetime) == DOSFALSE)
979 FreeArgs(rda);
980 Printf("*** Illegal 'UPTO' parameter\n");
982 return RETURN_FAIL;
986 if (subStr != NULL)
988 STRPTR subStrWithPat;
989 ULONG length = (strlen(subStr) + sizeof("#?#?"))*2 + 2;
991 subStrWithPat = AllocVec(length, MEMF_ANY);
993 if (subStrWithPat == NULL)
995 FreeArgs(rda);
996 PrintFault(IoErr(), "List");
998 return RETURN_FAIL;
1001 strcpy(subStrWithPat, "#?");
1002 strcat(subStrWithPat, subStr);
1003 strcat(subStrWithPat, "#?");
1005 subpatternStr = AllocVec(length, MEMF_ANY);
1007 if (subpatternStr == NULL ||
1008 ParsePatternNoCase(subStrWithPat, subpatternStr, length) == -1)
1010 FreeVec(subStrWithPat);
1011 FreeArgs(rda);
1012 PrintFault(IoErr(), "List");
1014 return RETURN_FAIL;
1017 FreeVec(subStrWithPat);
1021 if (pattern != NULL)
1023 ULONG length = strlen(pattern)*2 + 2;
1025 parsedPattern = AllocVec(length, MEMF_ANY);
1027 if (parsedPattern == NULL ||
1028 ParsePatternNoCase(pattern, parsedPattern, length) == -1)
1030 FreeVec(subpatternStr);
1031 FreeArgs(rda);
1033 return RETURN_FAIL;
1037 if (toFile != NULL)
1039 BPTR file = Open(toFile, MODE_NEWFILE);
1041 if (file == BNULL)
1043 FreeVec(subpatternStr);
1044 FreeVec(parsedPattern);
1045 FreeArgs(rda);
1046 PrintFault(IoErr(), "List");
1048 return RETURN_FAIL;
1050 oldOutput = SelectOutput(file);
1053 if (!files && !dirs)
1055 files = TRUE;
1056 dirs = TRUE;
1059 /* if (!dates && !noDates)
1061 dates = TRUE;
1064 if (lFormat)
1066 noHead = TRUE;
1069 if ((directories == NULL) || (*directories == NULL))
1071 directories = default_directories;
1074 for (i = 0; directories[i] != NULL; i++)
1076 error = listFile(directories[i], files, dirs, parsedPattern,
1077 noHead, lFormat, quick, dates, noDates,
1078 block, &sinceDatetime.dat_Stamp,
1079 &uptoDatetime.dat_Stamp, since != NULL,
1080 upto != NULL, subpatternStr, all, keys,
1081 &stats);
1083 if (error != 0)
1085 break;
1088 // Printf("\n");
1091 FreeArgs(rda);
1093 else
1095 error = IoErr();
1098 if ((BOOL)args[ARG_NOHEAD] == FALSE &&
1099 (BOOL)args[ARG_LFORMAT] == FALSE &&
1100 (BOOL)args[ARG_ALL] &&
1101 (stats.nFiles || stats.nDirs))
1103 Printf("\nTOTAL: %ld files - %ld directories - %ld blocks used\n",
1104 stats.nFiles, stats.nDirs, stats.nBlocks);
1108 if (error != 0)
1110 if (error == ERROR_BREAK)
1112 result = RETURN_WARN;
1114 else
1116 PrintFault(error, "List");
1117 result = RETURN_FAIL;
1121 if (parsedPattern != NULL)
1123 FreeVec(parsedPattern);
1126 if (subpatternStr != NULL)
1128 FreeVec(subpatternStr);
1131 if (oldOutput != BNULL)
1133 Close(SelectOutput(oldOutput));
1136 return result;