2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
9 #define MAX_PATH_LEN 512
11 #define USE_SOFTLINKCHECK 0
13 #include <exec/devices.h>
15 #include <exec/memory.h>
16 #include <exec/semaphores.h>
18 #include <dos/exall.h>
19 #include <dos/datetime.h>
20 #include <utility/tagitem.h>
21 #include <utility/utility.h>
23 #include <aros/asmcall.h>
24 #include <aros/debug.h>
26 #include <proto/exec.h>
27 #include <proto/dos.h>
28 #include <proto/utility.h>
36 /******************************************************************************
41 Dir [(dir | pattern)] [OPT A | I | D | F] [ALL] [DIRS] [FILES] [INTER]
46 DIR,OPT/K,ALL/S,DIRS/S,FILES/S,INTER/S
54 DIR displays the file or directory contained in the current or
55 specified directory. Directories get listed first, then in alphabetical
56 order, the files are listed in two columns. Pressing CTRL-C aborts the
62 ALL -- Display all subdirectories and their files recursively.
63 DIRS -- Display only directories.
64 FILES -- Display only files.
65 INTER -- Enter interactive mode.
67 Interactive listing mode stops after each name to display
68 a question mark at which you can enter commands. These
71 Return -- Goto the next file or directory.
72 E/ENTER -- Enters a directory.
73 DEL/DELETE -- Delete a file or an empty directory.
74 C/COM -- Let the file or directory be the input of
75 a DOS command (which specified after the C or
76 COM or specified separately later).
77 Q/QUIT -- Quit interactive mode.
78 B/BACK -- Go back one directory level.
94 XY.11.2000 SDuvan added pattern matching support and support for
95 FILES/S, DIRS/S and OPT/K and some support for
96 INTER/S. Complete interactive support is still missing.
98 ******************************************************************************/
100 #define VERSTAG "\0$VER: Dir 50.8 (27.11.2004)"
102 const TEXT version
[] = VERSTAG
;
114 struct ExecBase
*SysBase
;
115 struct DosLibrary
*DOSBase
;
116 struct Library
*UtilityBase
;
120 #define SysBase data->SysBase
121 #define DOSBase data->DOSBase
122 #define UtilityBase data->UtilityBase
123 #define g_indent data->g_indent
129 LONG
doPatternDir(STRPTR dirPat
, BOOL all
, BOOL doDirs
, BOOL doFiles
,
130 BOOL inter
, struct data
*data
);
132 LONG
doDir(STRPTR dir
, BOOL all
, BOOL dirs
, BOOL files
, BOOL inter
, struct data
*data
);
135 void showline(char *fmt
, IPTR
*args
, struct data
*data
);
137 void maybeShowline(char *format
, IPTR
*args
, BOOL doIt
, BOOL inter
, struct data
*data
);
139 void maybeShowlineCR(char *format
, IPTR
*args
, BOOL doIt
, BOOL inter
, struct data
*data
);
142 int CheckDir(BPTR lock
, struct ExAllData
*ead
, ULONG eadSize
,
143 struct ExAllControl
*eac
, struct table
*dirs
,
144 struct table
*files
, struct data
*data
);
147 #define INTERARG_TEMPLATE "E=ENTER/S,B=BACK/S,DEL=DELETE/S,Q=QUIT/S,C=COM/S,COMMAND"
160 #define ARG_TEMPLATE "DIR,OPT/K,ALL/S,DIRS/S,FILES/S,INTER/S"
172 AROS_UFH3(__startup
static int, Start
,
173 AROS_UFHA(char *, argstr
, A0
),
174 AROS_UFHA(ULONG
, argsize
, D0
),
175 AROS_UFHA(struct ExecBase
*, sBase
, A6
))
179 struct data _data
, *data
= &_data
;
181 IPTR args
[] = { (IPTR
)NULL
, (IPTR
)NULL
, (IPTR
)FALSE
, (IPTR
)FALSE
, (IPTR
)FALSE
, (IPTR
)FALSE
};
183 LONG error
= RETURN_FAIL
;
186 if ((DOSBase
=(struct DosLibrary
*)OpenLibrary("dos.library",37)))
188 if ((UtilityBase
=OpenLibrary("utility.library",37)))
190 error
= RETURN_ERROR
;
192 rda
= ReadArgs(ARG_TEMPLATE
, args
, NULL
);
196 STRPTR dir
= (STRPTR
)args
[ARG_DIR
];
197 STRPTR opt
= (STRPTR
)args
[ARG_OPT
];
198 BOOL all
= (BOOL
)args
[ARG_ALL
];
199 BOOL dirs
= (BOOL
)args
[ARG_DIRS
];
200 BOOL files
= (BOOL
)args
[ARG_FILES
];
201 BOOL inter
= (BOOL
)args
[ARG_INTER
];
207 /* Convert the OPT arguments (if any) into the regular switches */
212 switch (ToUpper(*opt
))
231 Printf("%lc option ignored\n", *opt
);
245 ULONG toklen
= strlen(dir
) * 2;
246 STRPTR pattok
= AllocMem(toklen
, MEMF_PUBLIC
| MEMF_ANY
);
247 iswild
= ParsePattern(dir
, pattok
, toklen
);
248 FreeMem(pattok
, toklen
);
260 error
= doPatternDir(dir
, all
, dirs
, files
, inter
, data
);
264 error
= doDir(dir
, all
, dirs
, files
, inter
, data
);
267 if (error
!= RETURN_OK
)
269 LONG ioerr
= IoErr();
272 case ERROR_NO_MORE_ENTRIES
:
275 case ERROR_OBJECT_WRONG_TYPE
:
276 Printf("%s is not a directory\n", (IPTR
)dir
);
277 ioerr
= ERROR_DIR_NOT_FOUND
;
280 Printf("Could not get information for %s\n", (IPTR
)dir
);
282 PrintFault(ioerr
, NULL
);
289 PrintFault(IoErr(), NULL
);
292 CloseLibrary((struct Library
*)UtilityBase
);
294 CloseLibrary((struct Library
*)DOSBase
);
303 int AddEntry(struct table
*table
, char *entry
, struct data
*data
)
308 if (table
->num
== table
->max
)
310 int new_max
= table
->max
+ 128;
313 new_entries
= AllocVec(sizeof(char *) * new_max
, MEMF_ANY
);
315 if (new_entries
== NULL
)
320 CopyMemQuick(table
->entries
, new_entries
,
321 sizeof(char *) * table
->num
);
322 FreeVec(table
->entries
);
325 table
->entries
= new_entries
;
326 table
->max
= new_max
;
329 len
= strlen(entry
) + 1;
330 if ((dup
= AllocVec(len
,MEMF_ANY
)))
338 table
->entries
[table
->num
++] = dup
;
345 int mystrcasecmp(const char *s1
, const char *s2
)
354 if (a
>= 'a' && a
<= 'z') a
-= 'a' - 'A';
355 if (b
>= 'a' && b
<= 'z') b
-= 'a' - 'A';
358 if (a
) return (int) a
;
366 int compare_strings(const void * s1
, const void * s2
)
368 return mystrcasecmp(*(char **)s1
, *(char **)s2
);
373 void maybeShowlineCR(char *format
, IPTR
*args
, BOOL doIt
, BOOL inter
, struct data
*data
)
375 maybeShowline(format
, args
, doIt
, inter
, data
);
386 void maybeShowline(char *format
, IPTR
*args
, BOOL doIt
, BOOL inter
, struct data
*data
)
390 showline(format
, args
, data
);
395 struct ReadArgs
*rda
;
397 IPTR interArgs
[NOOFINTERARGS
] = { (IPTR
)FALSE
,
404 rda
= ReadArgs(INTERARG_TEMPLATE
, interArgs
, NULL
);
408 if (interArgs
[ARG_ENTER
])
412 else if (interArgs
[ARG_BACK
])
416 else if (interArgs
[ARG_DELETE
])
420 else if (interArgs
[ARG_QUIT
])
424 else if (interArgs
[ARG_COM
])
428 else if (interArgs
[ARG_COMMAND
] != NULL
)
442 void showline(char *fmt
, IPTR
*args
, struct data
*data
)
446 for (t
= 0; t
< g_indent
; t
++)
452 // Returns TRUE if all lines shown, FALSE if broken by SIGBREAKF_CTRL_C
454 BOOL
showfiles(struct table
*files
, BOOL inter
, struct data
*data
)
459 qsort(files
->entries
, files
->num
, sizeof(char *),compare_strings
);
461 for (t
= 0; t
< files
->num
; t
+= 2)
463 argv
[0] = (IPTR
)(files
->entries
[t
]);
464 argv
[1] = (IPTR
)(t
+ 1 < files
->num
? files
->entries
[t
+1] : "");
466 if (SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
468 SetIoErr(ERROR_BREAK
);
472 maybeShowlineCR(" %-32.s %s", argv
, TRUE
, inter
, data
);
478 BOOL
showdir(char *dirName
, BOOL inter
, struct data
*data
)
480 IPTR argv
[1] = {(IPTR
)dirName
};
481 maybeShowlineCR("%s (dir)", argv
, TRUE
, inter
, data
);
486 LONG
doPatternDir(STRPTR dirPat
, BOOL all
, BOOL doDirs
, BOOL doFiles
, BOOL inter
, struct data
*data
)
489 struct AnchorPath
*ap
; /* Matching structure */
491 LONG match
; /* Loop variable */
492 LONG error
= RETURN_FAIL
;
496 files
.entries
= NULL
;
500 ap
= (struct AnchorPath
*)AllocVec(sizeof(struct AnchorPath
) + MAX_PATH_LEN
, MEMF_CLEAR
);
504 ap
->ap_Strlen
= MAX_PATH_LEN
;
505 ap
->ap_BreakBits
= SIGBREAKF_CTRL_C
;
507 if ((match
= MatchFirst(dirPat
, ap
)) == 0)
513 #if USE_SOFTLINKCHECK
514 if (SoftlinkDODIR(ap
, TRUE
, FALSE
, DOSBase
))
515 #else /* USE_SOFTLINKCHECK */
516 if (ap
->ap_Info
.fib_DirEntryType
> 0)
517 #endif /* USE_SOFTLINKCHECK */
521 BPTR l
= Lock(ap
->ap_Buf
, SHARED_LOCK
);
526 NameFromLock(l
, name
, 512);
528 showdir(name
, inter
, data
);
533 error
= doDir(ap
->ap_Buf
, all
, doDirs
, doFiles
, inter
, data
);
538 if (!AddEntry(&files
, ap
->ap_Info
.fib_FileName
, data
))
540 ioerr
= ERROR_NO_FREE_STORE
;
547 if (error
!= RETURN_OK
)
551 ap
->ap_Strlen
= MAX_PATH_LEN
;
552 match
= MatchNext(ap
);
557 if (error
== RETURN_OK
&& files
.num
!= 0)
559 if (!showfiles(&files
, inter
, data
))
584 LONG
doDir(STRPTR dir
, BOOL all
, BOOL doDirs
, BOOL doFiles
, BOOL inter
, struct data
*data
)
587 static UBYTE buffer
[4096];
588 struct ExAllControl
*eac
;
589 LONG error
= RETURN_OK
;
594 dirs
.entries
= files
.entries
= NULL
;
595 dirs
.max
= files
.max
= 0;
596 dirs
.num
= files
.num
= 0;
598 lock
= Lock(dir
, SHARED_LOCK
);
602 eac
= AllocDosObject(DOS_EXALLCONTROL
, NULL
);
608 eac
->eac_LastKey
= 0;
610 error
= CheckDir(lock
, (struct ExAllData
*)buffer
, sizeof(buffer
), eac
, &dirs
, &files
, data
);
611 FreeDosObject(DOS_EXALLCONTROL
, eac
);
613 if (SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
615 SetIoErr(ERROR_BREAK
);
619 if (error
== 0 && doDirs
)
625 //qsort(dirs.entries, dirs.num, sizeof(char *), compare_strings);
627 // Output the directories
628 for (t
= 0; t
< dirs
.num
; t
++)
630 STRPTR dirname
= dirs
.entries
[t
];
632 // Recurse into subdirectories if "ALL" was specified by the user
637 int pathlen
= strlen(dir
);
639 len
= pathlen
+ strlen(dirs
.entries
[t
]) + 2;
640 newpath
= AllocVec(len
, MEMF_ANY
);
644 CopyMem(dir
, newpath
, pathlen
+ 1);
645 if (AddPart(newpath
, dirs
.entries
[t
], len
))
648 showdir(dirname
, inter
, data
);
649 error
= doDir(newpath
, all
, doDirs
, doFiles
, inter
, data
);
653 SetIoErr(ERROR_LINE_TOO_LONG
);
654 error
= RETURN_ERROR
;
660 SetIoErr(ERROR_NO_FREE_STORE
);
663 if (error
!= RETURN_OK
)
668 showdir(dirname
, inter
, data
);
676 if (error
== RETURN_OK
&& (files
.num
!= 0 && doFiles
))
678 if (!showfiles(&files
, inter
, data
))
687 for (t
= 0; t
< dirs
.num
; t
++)
689 FreeVec(dirs
.entries
[t
]);
694 FreeVec(dirs
.entries
);
700 for (t
= 0; t
< files
.num
; t
++)
702 FreeVec(files
.entries
[t
]);
707 FreeVec(files
.entries
);
714 SetIoErr(ERROR_NO_FREE_STORE
);
722 #if USE_SOFTLINKCHECK
730 if (ioerr
== ERROR_OBJECT_NOT_FOUND
&&
731 (dvp
= GetDeviceProc(dir
, NULL
)))
733 if (ReadLink(dvp
->dvp_Port
, dvp
->dvp_Lock
, dir
, buffer
, sizeof(buffer
) - 1) > 0)
735 buffer
[sizeof(buffer
) - 1] = '\0';
737 Printf("Warning: Skipping dangling softlink %s -> %s\n",
738 (LONG
) dir
, (LONG
) buffer
);
748 #else /* USE_SOFTLINKCHECK */
752 #endif /* USE_SOFTLINKCHECK */
760 int CheckDir(BPTR lock
, struct ExAllData
*ead
, ULONG eadSize
,
761 struct ExAllControl
*eac
, struct table
*dirs
,
762 struct table
*files
, struct data
*data
)
764 int error
= RETURN_OK
;
766 struct ExAllData
*oldEad
= ead
;
771 loop
= ExAll(lock
, ead
, eadSize
, ED_COMMENT
, eac
);
773 if(!loop
&& IoErr() != ERROR_NO_MORE_ENTRIES
)
775 error
= RETURN_ERROR
;
779 if(eac
->eac_Entries
!= 0)
784 #if USE_SOFTLINKCHECK
785 if (ead
->ed_Type
== ST_SOFTLINK
)
789 dirlock
= CurrentDir(lock
);
790 l
= Lock(ead
->ed_Name
, ACCESS_READ
);
795 UBYTE _fib
[sizeof(struct FileInfoBlock
) + 3];
796 struct FileInfoBlock
*fib
= (APTR
) (((IPTR
) _fib
+ 3) & ~3);
800 ead
->ed_Type
= fib
->fib_DirEntryType
;
801 //ead->ed_Size = fib->fib_Size;
807 #endif /* USE_SOFTLINKCHECK */
809 if (!AddEntry(ead
->ed_Type
> 0 ? dirs
: files
,ead
->ed_Name
, data
))
813 SetIoErr(ERROR_NO_FREE_STORE
);
822 while((loop
) && (error
== RETURN_OK
));