Build various tools as native versions
[AROS.git] / workbench / c / List.c
blob042f658a636dccfb4970893de66dc18a27c9baf1
1 /*
2 Copyright © 1995-2014, 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 -- 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
62 The following attributes of the LFORMAT strings are available
64 %A -- file attributes
65 %B -- size of file in blocks rather than bytes
66 %C -- file comment
67 %D -- modification date
68 %E -- file extension
69 %F -- volume name
70 %K -- file key block number
71 %L -- size of file in bytes
72 %M -- file name without extension
73 %N -- file name
74 %P -- file path
75 %S -- superceded by %N and %P; obsolete
76 %T -- modification time
78 RESULT
80 Standard DOS return codes.
82 EXAMPLE
84 1> List C:
85 Directory "C:" on Wednesday 12-Dec-99
86 AddBuffers 444 --p-rwed 02-Sep-99 11:51:31
87 Assign 3220 --p-rwed 02-Sep-99 11:51:31
88 Avail 728 --p-rwed 02-Sep-99 11:51:31
89 Copy 3652 --p-rwed 02-Sep-99 11:51:31
90 Delete 1972 --p-rwed 02-Sep-99 11:51:31
91 Execute 4432 --p-rwed 02-Sep-99 11:51:31
92 List 5108 --p-rwed 02-Sep-99 11:51:31
93 Installer 109956 ----rwed 02-Sep-99 11:51:31
94 Which 1068 --p-rwed 02-Sep-99 11:51:31
95 9 files - 274 blocks used
97 BUGS
99 SEE ALSO
103 INTERNALS
105 ******************************************************************************/
107 #define DEBUG 0
108 #include <aros/debug.h>
110 #include <clib/macros.h>
111 #include <exec/memory.h>
112 #include <proto/exec.h>
113 #include <dos/datetime.h>
114 #include <dos/dos.h>
115 #include <dos/exall.h>
116 #include <dos/dosasl.h>
117 #include <dos/datetime.h>
118 #include <proto/dos.h>
119 #include <proto/alib.h>
120 #include <proto/utility.h>
121 #include <utility/tagitem.h>
123 const TEXT version[] = "$VER: List 41.12 (3.4.2014)\n";
125 #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"
127 struct DirNode
129 struct MinNode node;
130 char *dirname;
134 typedef struct _Statistics
136 ULONG nFiles;
137 ULONG nDirs;
138 UQUAD nBlocks;
139 } Statistics;
142 enum
144 ARG_DIR = 0,
145 ARG_PAT,
146 ARG_KEYS,
147 ARG_DATES,
148 ARG_NODATES,
149 ARG_TO,
150 ARG_SUB,
151 ARG_SINCE,
152 ARG_UPTO,
153 ARG_QUICK,
154 ARG_BLOCK,
155 ARG_NOHEAD,
156 ARG_FILES,
157 ARG_DIRS,
158 ARG_LFORMAT,
159 ARG_ALL,
160 NOOFARGS
163 #define MAX_PATH_LEN 1024
165 #define BLOCKSIZE 512
167 int printDirHeader(STRPTR dirname, BOOL noHead)
169 struct DateTime dt;
171 char datestr[LEN_DATSTRING];
172 char dow[LEN_DATSTRING];
174 if (!noHead)
176 DateStamp((struct DateStamp *)&dt);
177 dt.dat_Format = FORMAT_DEF;
178 dt.dat_Flags = 0;
179 dt.dat_StrDay = dow;
180 dt.dat_StrDate = datestr;
181 dt.dat_StrTime = NULL;
182 DateToStr(&dt);
184 Printf("Directory \"%s\" on %s %s:\n", dirname, dow, datestr);
187 return RETURN_OK;
191 /* Possible printf-type switches
193 %A -- file attributes
194 %B -- size of file in blocks rather than bytes
195 %C -- file comment
196 %D -- file date
197 %E -- file extension
198 %F -- volume name
199 %K -- file key block number
200 %L -- size of file in bytes
201 %M -- file name without extension
202 %N -- file name
203 %P -- file path
204 %S -- file name or file path
205 %T -- file time
208 struct lfstruct
210 struct AnchorPath *ap;
211 BOOL isdir;
212 STRPTR date;
213 STRPTR time;
214 STRPTR flags;
215 STRPTR filename;
216 STRPTR comment;
217 UQUAD size;
218 ULONG key;
222 #define roundUp(x, bSize) ((x + bSize - 1)/bSize)
224 int printLformat(STRPTR format, struct lfstruct *lf)
226 STRPTR filename = FilePart(lf->filename);
227 STRPTR temp = format;
228 LONG substitutePath = 0;
229 char c;
232 Whether the path or the filename is substituted for an occurrence
233 of %S depends on how many occurrences are in the LFORMAT line, and
234 their order, as follows:
236 Occurrences of %S 1st 2nd 3rd 4th
237 1 filename
238 2 path filename
239 3 path filename filename
240 4 path filename path filename
243 while ( ( substitutePath < 4 ) && ( '\0' != (c = *temp++) ) )
245 if ( '%' == c )
246 if ( 'S' == ToUpper(*temp++) )
247 substitutePath++;
249 if ( substitutePath == 3 )
250 substitutePath = 2;
252 while ('\0' != (c = *format++))
254 if ('%' == c)
256 switch (ToUpper(*format++))
258 /* File comment */
259 case 'C':
260 Printf(lf->comment);
261 break;
263 /* Modification date */
264 case 'D':
265 Printf(lf->date);
266 break;
268 /* Modification time */
269 case 'T':
270 Printf(lf->time);
271 break;
273 /* File size in blocks of BLOCKSIZE bytes */
274 case 'B':
275 if (lf->isdir)
277 Printf("Dir");
279 else
281 ULONG tmp = roundUp(lf->size, BLOCKSIZE);
283 /* File is 0 bytes? */
284 if (tmp == 0)
286 Printf("empty");
288 else
290 Printf("%lu", tmp);
294 break;
296 /* Path incl. volume name*/
297 case 'F':
299 UBYTE buf[256];
301 if (NameFromLock(lf->ap->ap_Current->an_Lock, buf, 256))
303 int len;
305 Printf(buf);
307 len = strlen(buf);
308 if ((len > 0) && (buf[len - 1] != ':') && (buf[len - 1] != '/'))
310 Printf("/");
315 break;
317 /* File attributes (flags) */
318 case 'A':
319 Printf(lf->flags);
320 break;
322 /* Disk block key */
323 case 'K':
324 Printf("[%lu]", lf->key);
325 break;
327 /* File size */
328 case 'L':
329 if (lf->isdir)
331 Printf("Dir");
333 else
335 if (lf->size == 0)
337 Printf("empty");
339 else
341 UQUAD filesize = lf->size;
343 char buf[256];
344 buf[255] = '\0';
345 int fill, i;
347 char *bufpos = &buf[254];
351 bufpos[0] = '0' + (filesize % 10);
352 filesize /= 10;
353 bufpos--;
354 } while (filesize);
356 fill = 13 - (&buf[254] - bufpos);
357 for (i = 0; i < fill; i++)
359 Printf(" ");
361 Printf("%s ", &bufpos[1]);
365 break;
367 /* File name without extension */
368 case 'M':
370 STRPTR lastPoint = strrchr(filename, '.');
372 if (lastPoint != NULL)
374 *lastPoint = 0;
377 Printf(filename);
379 /* Resurrect filename in case we should print it once
380 more */
381 if (lastPoint != NULL)
383 *lastPoint = '.';
387 break;
389 /* Filename or Path name */
390 case 'S':
391 D(bug("[List] substitutePath = %d\n", substitutePath));
392 if ( (--substitutePath == 3) || (substitutePath == 1) )
394 STRPTR end = FilePart(lf->filename);
395 UBYTE token = *end;
397 *end = '\0';
399 Printf(lf->filename);
401 /* Restore pathname */
402 *end = token;
404 break;
406 /* Fall through */
407 case 'N':
408 Printf(filename);
409 break;
411 /* File extension */
412 case 'E':
414 STRPTR extension = strrchr(filename, '.');
416 if (extension != NULL)
418 Printf(extension);
422 break;
424 /* Path name, but without volume */
425 case 'P':
427 STRPTR end = FilePart(lf->filename);
428 UBYTE token = *end;
430 *end = 0;
432 Printf(lf->filename);
434 /* Restore pathname */
435 *end = token;
438 break;
440 case 0:
441 return 0;
442 break;
444 default:
445 Printf("%%%lc", *format);
446 break;
449 else
451 Printf("%lc", c);
455 return 0;
459 int printFileData(struct AnchorPath *ap,
460 BOOL showFiles, BOOL showDirs, STRPTR parsedPattern,
461 ULONG *files, ULONG *dirs, ULONG *nBlocks, STRPTR lFormat,
462 BOOL quick, BOOL dates, BOOL noDates, BOOL block,
463 struct DateStamp *sinceDate, struct DateStamp *uptoDate,
464 BOOL doSince, BOOL doUpto, STRPTR subpatternStr,
465 BOOL keys)
467 STRPTR filename = ap->ap_Buf;
468 BOOL isDir = (ap->ap_Info.fib_DirEntryType >= 0);
469 struct DateStamp *ds = &ap->ap_Info.fib_Date;
470 ULONG protection = ap->ap_Info.fib_Protection;
471 UQUAD size = ap->ap_Info.fib_Size;
472 STRPTR filenote = ap->ap_Info.fib_Comment;
473 ULONG diskKey = ap->ap_Info.fib_DiskKey;
475 int error = 0;
477 UBYTE date[LEN_DATSTRING];
478 UBYTE time[LEN_DATSTRING];
479 UBYTE flags[8];
481 struct DateTime dt;
483 #if defined(ACTION_GET_FILE_SIZE64)
484 if (ap->ap_Info.fib_Size >= 0x7FFFFFFF)
486 BPTR flock = BNULL;
487 flock = Lock(filename, ACCESS_READ);
489 if (flock)
491 UQUAD *size_ptr = (UQUAD *)DoPkt(((struct FileLock *)flock)->fl_Task, ACTION_GET_FILE_SIZE64, (IPTR)flock, 0, 0, 0, 0);
492 if (size_ptr)
494 size = *size_ptr;
496 UnLock(flock);
499 #endif
500 /* Do the file match the time interval we are looking for?
501 (ARG_SINCE and ARG_UPTO) -- any combination of these may be
502 specified */
503 if ((doSince && (CompareDates(sinceDate, ds) < 0)) ||
504 (doUpto && (CompareDates(uptoDate, ds) > 0)))
506 return 0;
509 /* Does the filename match a certain pattern? (ARG_PAT) */
510 if (parsedPattern != NULL &&
511 !MatchPatternNoCase(parsedPattern, FilePart(filename)))
513 return 0;
516 /* Does a substring of the filename match a certain pattern? (ARG_SUB) */
517 if (subpatternStr != NULL &&
518 !MatchPatternNoCase(subpatternStr, FilePart(filename)))
520 return 0;
523 CopyMem(ds, &dt.dat_Stamp, sizeof(struct DateStamp));
524 dt.dat_Format = FORMAT_DOS;
525 if (dates)
526 dt.dat_Flags = 0;
527 else
528 dt.dat_Flags = DTF_SUBST;
529 dt.dat_StrDay = NULL;
530 dt.dat_StrDate = date;
531 dt.dat_StrTime = time;
532 DateToStr(&dt);
534 /* Convert the protection bits to a string */
535 flags[0] = protection & FIBF_SCRIPT ? 's' : '-';
536 flags[1] = protection & FIBF_PURE ? 'p' : '-';
537 flags[2] = protection & FIBF_ARCHIVE ? 'a' : '-';
539 /* The following flags are high-active! */
540 flags[3] = protection & FIBF_READ ? '-' : 'r';
541 flags[4] = protection & FIBF_WRITE ? '-' : 'w';
542 flags[5] = protection & FIBF_EXECUTE ? '-' : 'e';
543 flags[6] = protection & FIBF_DELETE ? '-' : 'd';
544 flags[7] = 0x00;
546 if (isDir)
548 if (showDirs)
550 ++*dirs;
551 ++*nBlocks; /* dir entry uses 1 block on AROS, 2 on OS31) */
553 if (lFormat != NULL)
555 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
556 filenote, size, diskKey};
558 printLformat(lFormat, &lf);
559 Printf("\n");
561 else
563 D(bug("Found file %s\n", filename));
565 Printf("%-25s ", FilePart(filename));
567 if (!quick)
569 Printf(" <Dir> %7s ", flags);
572 if (!noDates && (!quick || dates))
574 Printf("%-11s %s", date, time);
577 Printf("\n");
581 else if (showFiles)
583 ++*files;
584 *nBlocks += roundUp(size, BLOCKSIZE);
586 if (lFormat != NULL)
588 struct lfstruct lf = { ap, isDir, date, time, flags, filename,
589 filenote, size, diskKey };
591 printLformat(lFormat, &lf);
592 Printf("\n");
594 else
596 Printf("%-25s ", FilePart(filename));
598 if (!quick)
600 if(keys)
602 char key[16];
603 int fill;
604 int i; /* Loop variable */
606 __sprintf(key, "%lu", (unsigned long)diskKey);
607 fill = 7 - strlen(key) - 2;
609 for (i = 0; i < fill; i++)
611 Printf(" ");
614 Printf("[%lu] ", diskKey);
616 else
618 if (0 != size)
620 UQUAD filesize = block ? roundUp(size, BLOCKSIZE) : size;
622 char buf[256];
623 buf[255] = '\0';
624 int fill, i;
626 char *bufpos = &buf[254];
630 bufpos[0] = '0' + (filesize % 10);
631 filesize /= 10;
632 bufpos--;
633 } while (filesize);
635 fill = 13 - (&buf[254] - bufpos);
636 for (i = 0; i < fill; i++)
638 Printf(" ");
640 Printf("%s ", &bufpos[1]);
642 else
644 Printf(" empty ");
648 Printf("%7s ", flags);
651 if (!noDates && (!quick || dates))
653 Printf("%-11s %s", date, time);
656 if (!quick && (*filenote != 0))
658 Printf("\n: %s", filenote);
661 Printf("\n");
665 return error;
669 /* Print directory summary information */
670 void printSummary(CONST_STRPTR dirname, int files, int dirs, int nBlocks,
671 BOOL noHead, BOOL PrintEmpty)
674 if (noHead) return;
676 if (files || dirs)
679 if (files > 1)
680 Printf("%ld files", files);
681 else if (files > 0)
682 PutStr("1 file");
684 if( files && (dirs || nBlocks) ) PutStr(" - ");
686 if (dirs > 1)
687 Printf("%ld directories", dirs);
688 else if (dirs > 0)
689 PutStr("1 directory");
691 if( dirs && nBlocks ) PutStr(" - ");
693 if (nBlocks > 1)
694 Printf("%ld blocks used\n", nBlocks);
695 else if (nBlocks > 0)
696 PutStr("1 block used\n");
697 else PutStr("\n");
700 else if (PrintEmpty)
701 Printf("Directory \"%s\" is empty\n", dirname);
705 int listFile(CONST_STRPTR filename, BOOL showFiles, BOOL showDirs,
706 STRPTR parsedPattern, BOOL noHead, STRPTR lFormat, BOOL quick,
707 BOOL dates, BOOL noDates, BOOL block, struct DateStamp *sinceDate,
708 struct DateStamp *uptoDate, BOOL doSince, BOOL doUpto,
709 STRPTR subpatternStr, BOOL all, BOOL keys, Statistics *stats)
711 struct AnchorPath *ap;
712 struct List DirList, FreeDirNodeList;
713 struct DirNode *dirnode, *prev_dirnode = NULL;
715 ULONG files = 0;
716 ULONG dirs = 0;
717 ULONG nBlocks = 0;
718 LONG error;
720 NewList(&DirList);
721 NewList(&FreeDirNodeList);
725 ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN, MEMF_CLEAR);
727 if (ap == NULL)
729 return 0;
732 ap->ap_Strlen = MAX_PATH_LEN;
734 error = MatchFirst(filename, ap);
736 /* Explicitly named directory and not a pattern? --> enter dir */
738 if (0 == error)
740 if (!(ap->ap_Flags & APF_ITSWILD))
742 if (ap->ap_Info.fib_DirEntryType >= 0)
744 //error = printDirHeader(filename, noHead);
745 ap->ap_Flags |= APF_DODIR;
747 if (0 == error)
749 error = MatchNext(ap);
755 if (0 == error)
757 BOOL first = TRUE;
759 ap->ap_BreakBits = SIGBREAKF_CTRL_C;
760 if (FilePart(ap->ap_Buf) == ap->ap_Buf)
762 ap->ap_Flags &= ~APF_DirChanged;
768 ** There's something to show.
770 if (!(ap->ap_Flags & APF_DIDDIR))
772 if (ap->ap_Flags & APF_DirChanged)
774 STRPTR p;
775 UBYTE c;
777 if (!first) printSummary(filename, files, dirs, nBlocks, noHead, TRUE);
779 /* Update global statistics for (possible) ALL option */
780 stats->nFiles += files;
781 stats->nDirs += dirs;
782 stats->nBlocks += nBlocks;
784 files = 0;
785 dirs = 0;
786 nBlocks = 0;
788 p = PathPart(ap->ap_Buf);
789 c = *p;
790 *p = 0;
792 error = printDirHeader(ap->ap_Buf, noHead);
794 *p = c;
798 error = printFileData(ap,
799 showFiles,
800 showDirs,
801 parsedPattern,
802 &files,
803 &dirs,
804 &nBlocks,
805 lFormat,
806 quick,
807 dates,
808 noDates,
809 block,
810 sinceDate,
811 uptoDate,
812 doSince,
813 doUpto,
814 subpatternStr,
815 keys);
817 if (all && (ap->ap_Info.fib_DirEntryType >= 0))
819 if ((dirnode = AllocMem(sizeof(struct DirNode), MEMF_ANY)))
821 if ((dirnode->dirname = StrDup(ap->ap_Buf)))
823 Insert(&DirList, (struct Node *)dirnode,
824 (struct Node *)prev_dirnode);
826 prev_dirnode = dirnode;
828 else
830 FreeMem(dirnode, sizeof(struct DirNode));
836 error = MatchNext(ap);
838 first = FALSE;
840 } while (0 == error);
843 MatchEnd(ap);
845 FreeVec(ap);
847 if (error == ERROR_BREAK)
849 PrintFault(error, NULL);
852 if (error == ERROR_NO_MORE_ENTRIES)
854 error = 0;
857 if ((error == 0) || (error == ERROR_BREAK))
859 BOOL printEmpty = !(ap->ap_Flags & APF_ITSWILD);
860 printSummary(filename, files, dirs, nBlocks, noHead, printEmpty);
863 /* Update global statistics for (possible) ALL option */
864 stats->nFiles += files;
865 stats->nDirs += dirs;
866 stats->nBlocks += nBlocks;
868 files = 0;
869 dirs = 0;
870 nBlocks = 0;
873 if (error) break;
875 dirnode = (struct DirNode *)RemHead(&DirList);
877 if (dirnode != NULL)
879 filename = dirnode->dirname;
881 prev_dirnode = NULL;
883 /* do not free() dirnode, as we reference dirnode->dirname! */
885 AddTail(&FreeDirNodeList, (struct Node *)dirnode);
887 } while (dirnode);
889 while ((dirnode = (struct DirNode *)RemHead(&FreeDirNodeList)))
891 FreeVec(dirnode->dirname);
892 FreeMem(dirnode, sizeof(struct DirNode));
895 return error;
899 int __nocommandline;
901 int main(void)
903 IPTR args[NOOFARGS] =
905 (IPTR) NULL, // ARG_DIR
906 (IPTR) NULL, // ARG_PAT
907 FALSE, // ARG_KEYS
908 FALSE, // ARG_DATES
909 FALSE, // ARG_NODATES
910 (IPTR) NULL, // ARG_TO
911 (IPTR) NULL, // ARG_SUB
912 (IPTR) NULL, // ARG_SINCE
913 (IPTR) NULL, // ARG_UPTO
914 FALSE, // ARG_QUICK
915 FALSE, // ARG_BLOCK
916 FALSE, // ARG_NOHEAD
917 FALSE, // ARG_FILES
918 FALSE, // ARG_DIRS
919 FALSE, // ARG_LFORMAT
920 FALSE // ARG_ALL
922 static CONST_STRPTR default_directories[] = {(CONST_STRPTR)"", 0};
923 struct RDArgs *rda;
925 LONG result = RETURN_OK;
926 LONG error = 0;
927 STRPTR parsedPattern = NULL;
928 STRPTR subpatternStr = NULL;
929 BPTR oldOutput = BNULL;
931 Statistics stats = { 0, 0, 0 };
933 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
935 if (rda != NULL)
937 CONST_STRPTR *directories = (CONST_STRPTR *)args[ARG_DIR];
938 STRPTR lFormat = (STRPTR)args[ARG_LFORMAT];
939 STRPTR pattern = (STRPTR)args[ARG_PAT];
940 STRPTR toFile = (STRPTR)args[ARG_TO];
941 STRPTR subStr = (STRPTR)args[ARG_SUB];
942 STRPTR since = (STRPTR)args[ARG_SINCE];
943 STRPTR upto = (STRPTR)args[ARG_UPTO];
944 BOOL files = (BOOL)args[ARG_FILES];
945 BOOL dirs = (BOOL)args[ARG_DIRS];
946 BOOL noDates = (BOOL)args[ARG_NODATES];
947 BOOL dates = (BOOL)args[ARG_DATES];
948 BOOL quick = (BOOL)args[ARG_QUICK];
949 BOOL noHead = (BOOL)args[ARG_NOHEAD];
950 BOOL block = (BOOL)args[ARG_BLOCK];
951 BOOL all = (BOOL)args[ARG_ALL];
952 BOOL keys = (BOOL)args[ARG_KEYS];
954 struct DateTime sinceDatetime;
955 struct DateTime uptoDatetime;
957 ULONG i; /* Loop variable */
959 if (since != NULL)
961 sinceDatetime.dat_StrDate = since;
962 sinceDatetime.dat_StrTime = NULL;
963 sinceDatetime.dat_Format = FORMAT_DEF;
964 sinceDatetime.dat_Flags = 0;
965 if (StrToDate(&sinceDatetime) == DOSFALSE)
967 FreeArgs(rda);
968 Printf("*** Illegal 'SINCE' parameter\n");
970 return RETURN_FAIL;
972 sinceDatetime.dat_Stamp.ds_Minute = 0;
973 sinceDatetime.dat_Stamp.ds_Tick = 0;
976 if (upto != NULL)
978 uptoDatetime.dat_StrDate = upto;
979 uptoDatetime.dat_StrTime = NULL;
980 uptoDatetime.dat_Format = FORMAT_DEF;
981 uptoDatetime.dat_Flags = 0;
983 if (StrToDate(&uptoDatetime) == DOSFALSE)
985 FreeArgs(rda);
986 Printf("*** Illegal 'UPTO' parameter\n");
988 return RETURN_FAIL;
990 uptoDatetime.dat_Stamp.ds_Minute = 1439;
991 uptoDatetime.dat_Stamp.ds_Tick = 2999;
994 if (subStr != NULL)
996 STRPTR subStrWithPat;
997 ULONG length = (strlen(subStr) + sizeof("#?#?"))*2 + 2;
999 subStrWithPat = AllocVec(length, MEMF_ANY);
1001 if (subStrWithPat == NULL)
1003 error = IoErr();
1004 FreeArgs(rda);
1005 PrintFault(error, "List");
1007 return RETURN_FAIL;
1010 strcpy(subStrWithPat, "#?");
1011 strcat(subStrWithPat, subStr);
1012 strcat(subStrWithPat, "#?");
1014 subpatternStr = AllocVec(length, MEMF_ANY);
1016 if (subpatternStr == NULL ||
1017 ParsePatternNoCase(subStrWithPat, subpatternStr, length) == -1)
1019 error = IoErr();
1020 FreeVec(subStrWithPat);
1021 FreeArgs(rda);
1022 PrintFault(error, "List");
1024 return RETURN_FAIL;
1027 FreeVec(subStrWithPat);
1031 if (pattern != NULL)
1033 ULONG length = strlen(pattern)*2 + 2;
1035 parsedPattern = AllocVec(length, MEMF_ANY);
1037 if (parsedPattern == NULL ||
1038 ParsePatternNoCase(pattern, parsedPattern, length) == -1)
1040 FreeVec(subpatternStr);
1041 FreeArgs(rda);
1043 return RETURN_FAIL;
1047 if (toFile != NULL)
1049 BPTR file = Open(toFile, MODE_NEWFILE);
1051 if (file == BNULL)
1053 error = IoErr();
1054 FreeVec(subpatternStr);
1055 FreeVec(parsedPattern);
1056 FreeArgs(rda);
1057 PrintFault(error, "List");
1059 return RETURN_FAIL;
1061 oldOutput = SelectOutput(file);
1064 if (!files && !dirs)
1066 files = TRUE;
1067 dirs = TRUE;
1070 /* if (!dates && !noDates)
1072 dates = TRUE;
1075 if (lFormat)
1077 noHead = TRUE;
1080 if ((directories == NULL) || (*directories == NULL))
1082 directories = default_directories;
1085 for (i = 0; directories[i] != NULL; i++)
1087 error = listFile(directories[i], files, dirs, parsedPattern,
1088 noHead, lFormat, quick, dates, noDates,
1089 block, &sinceDatetime.dat_Stamp,
1090 &uptoDatetime.dat_Stamp, since != NULL,
1091 upto != NULL, subpatternStr, all, keys,
1092 &stats);
1094 if (error != 0)
1096 break;
1099 // Printf("\n");
1102 FreeArgs(rda);
1104 else
1106 error = IoErr();
1109 if ((BOOL)args[ARG_NOHEAD] == FALSE &&
1110 (BOOL)args[ARG_LFORMAT] == FALSE &&
1111 (BOOL)args[ARG_ALL] &&
1112 (stats.nFiles || stats.nDirs))
1114 Printf("\nTOTAL: %ld files - %ld directories - %ld blocks used\n",
1115 stats.nFiles, stats.nDirs, stats.nBlocks);
1119 if (error != 0)
1121 if (error == ERROR_BREAK)
1123 result = RETURN_WARN;
1125 else
1127 PrintFault(error, "List");
1128 result = RETURN_FAIL;
1132 if (parsedPattern != NULL)
1134 FreeVec(parsedPattern);
1137 if (subpatternStr != NULL)
1139 FreeVec(subpatternStr);
1142 if (oldOutput != BNULL)
1144 Close(SelectOutput(oldOutput));
1147 return result;