2 Copyright © 1995-2012, 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>
30 #define SH_GLOBAL_SYSBASE 1
31 #define SH_GLOBAL_DOSBASE 1
33 #include <aros/shcommands.h>
38 /******************************************************************************
43 Dir [(dir | pattern)] [OPT A | I | D | F] [ALL] [DIRS] [FILES] [INTER]
48 DIR,OPT/K,ALL/S,DIRS/S,FILES/S,INTER/S
56 DIR displays the file or directory contained in the current or
57 specified directory. Directories get listed first, then in alphabetical
58 order, the files are listed in two columns. Pressing CTRL-C aborts the
64 ALL -- Display all subdirectories and their files recursively.
65 DIRS -- Display only directories.
66 FILES -- Display only files.
67 INTER -- Enter interactive mode.
69 Interactive listing mode stops after each name to display
70 a question mark at which you can enter commands. These
73 Return -- Goto the next file or directory.
74 E/ENTER -- Enters a directory.
75 DEL/DELETE -- Delete a file or an empty directory.
76 C/COM -- Let the file or directory be the input of
77 a DOS command (which specified after the C or
78 COM or specified separately later).
79 Q/QUIT -- Quit interactive mode.
80 B/BACK -- Go back one directory level.
96 XY.11.2000 SDuvan added pattern matching support and support for
97 FILES/S, DIRS/S and OPT/K and some support for
98 INTER/S. Complete interactive support is still missing.
100 ******************************************************************************/
109 /* Global variables */
111 struct UtilityBase
*UtilityBase
;
116 LONG
doPatternDir(CONST_STRPTR dirPat
, BOOL all
, BOOL doDirs
, BOOL doFiles
,
119 LONG
doDir(CONST_STRPTR dir
, BOOL all
, BOOL dirs
, BOOL files
, BOOL inter
);
122 void showline(char *fmt
, IPTR
*args
);
124 void maybeShowline(char *format
, IPTR
*args
, BOOL doIt
, BOOL inter
);
126 void maybeShowlineCR(char *format
, IPTR
*args
, BOOL doIt
, BOOL inter
);
129 int CheckDir(BPTR lock
, struct ExAllData
*ead
, ULONG eadSize
,
130 struct ExAllControl
*eac
, struct table
*dirs
,
131 struct table
*files
);
134 #define INTERARG_TEMPLATE "E=ENTER/S,B=BACK/S,DEL=DELETE/S,Q=QUIT/S,C=COM/S,COMMAND"
148 AROS_SHA(CONST_STRPTR
, ,DIR , , NULL
),
149 AROS_SHA(CONST_STRPTR
, ,OPT
, /K
, NULL
),
150 AROS_SHA(BOOL
, ,ALL
, /S
, FALSE
),
151 AROS_SHA(BOOL
, ,DIRS
, /S
, FALSE
),
152 AROS_SHA(BOOL
, ,FILES
, /S
, FALSE
),
153 AROS_SHA(BOOL
, ,INTER
, /S
, FALSE
)
158 LONG error
= RETURN_FAIL
;
159 CONST_STRPTR dir
= SHArg(DIR);
160 CONST_STRPTR opt
= SHArg(OPT
);
161 BOOL all
= SHArg(ALL
);
162 BOOL dirs
= SHArg(DIRS
);
163 BOOL files
= SHArg(FILES
);
164 BOOL inter
= SHArg(INTER
);
170 UtilityBase
= (struct UtilityBase
*)OpenLibrary("utility.library", 37);
174 /* Convert the OPT arguments (if any) into the regular switches */
179 switch (ToUpper(*opt
))
198 Printf("%lc option ignored\n", *opt
);
212 ULONG toklen
= strlen(dir
) * 2;
213 STRPTR pattok
= AllocMem(toklen
, MEMF_PUBLIC
| MEMF_ANY
);
214 iswild
= ParsePattern(dir
, pattok
, toklen
);
215 FreeMem(pattok
, toklen
);
227 error
= doPatternDir(dir
, all
, dirs
, files
, inter
);
231 error
= doDir(dir
, all
, dirs
, files
, inter
);
234 if (error
!= RETURN_OK
)
236 LONG ioerr
= IoErr();
239 case ERROR_NO_MORE_ENTRIES
:
242 case ERROR_OBJECT_WRONG_TYPE
:
243 Printf("%s is not a directory\n", (IPTR
)dir
);
244 ioerr
= ERROR_DIR_NOT_FOUND
;
247 Printf("Could not get information for %s\n", (IPTR
)dir
);
249 PrintFault(ioerr
, NULL
);
252 CloseLibrary((struct Library
*)UtilityBase
);
259 int AddEntry(struct table
*table
, char *entry
)
264 if (table
->num
== table
->max
)
266 int new_max
= table
->max
+ 128;
269 new_entries
= AllocVec(sizeof(char *) * new_max
, MEMF_ANY
);
271 if (new_entries
== NULL
)
276 CopyMemQuick(table
->entries
, new_entries
,
277 sizeof(char *) * table
->num
);
278 FreeVec(table
->entries
);
281 table
->entries
= new_entries
;
282 table
->max
= new_max
;
285 len
= strlen(entry
) + 1;
286 if ((dup
= AllocVec(len
,MEMF_ANY
)))
294 table
->entries
[table
->num
++] = dup
;
301 int mystrcasecmp(const char *s1
, const char *s2
)
310 if (a
>= 'a' && a
<= 'z') a
-= 'a' - 'A';
311 if (b
>= 'a' && b
<= 'z') b
-= 'a' - 'A';
314 if (a
) return (int) a
;
322 int compare_strings(const void * s1
, const void * s2
)
324 return mystrcasecmp(*(char **)s1
, *(char **)s2
);
329 void maybeShowlineCR(char *format
, IPTR
*args
, BOOL doIt
, BOOL inter
)
331 maybeShowline(format
, args
, doIt
, inter
);
342 void maybeShowline(char *format
, IPTR
*args
, BOOL doIt
, BOOL inter
)
346 showline(format
, args
);
351 struct ReadArgs
*rda
;
353 IPTR interArgs
[NOOFINTERARGS
] = { (IPTR
)FALSE
,
360 rda
= ReadArgs(INTERARG_TEMPLATE
, interArgs
, NULL
);
364 if (interArgs
[ARG_ENTER
])
368 else if (interArgs
[ARG_BACK
])
372 else if (interArgs
[ARG_DELETE
])
376 else if (interArgs
[ARG_QUIT
])
380 else if (interArgs
[ARG_COM
])
384 else if (interArgs
[ARG_COMMAND
] != NULL
)
398 void showline(char *fmt
, IPTR
*args
)
402 for (t
= 0; t
< g_indent
; t
++)
408 // Returns TRUE if all lines shown, FALSE if broken by SIGBREAKF_CTRL_C
410 BOOL
showfiles(struct table
*files
, BOOL inter
)
415 qsort(files
->entries
, files
->num
, sizeof(char *),compare_strings
);
417 for (t
= 0; t
< files
->num
; t
+= 2)
419 argv
[0] = (IPTR
)(files
->entries
[t
]);
420 argv
[1] = (IPTR
)(t
+ 1 < files
->num
? files
->entries
[t
+1] : "");
422 if (SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
424 SetIoErr(ERROR_BREAK
);
428 maybeShowlineCR(" %-32.s %s", argv
, TRUE
, inter
);
434 BOOL
showdir(char *dirName
, BOOL inter
)
436 IPTR argv
[1] = {(IPTR
)dirName
};
437 maybeShowlineCR("%s (dir)", argv
, TRUE
, inter
);
442 LONG
doPatternDir(CONST_STRPTR dirPat
, BOOL all
, BOOL doDirs
, BOOL doFiles
, BOOL inter
)
445 struct AnchorPath
*ap
; /* Matching structure */
447 LONG match
; /* Loop variable */
448 LONG error
= RETURN_FAIL
;
452 files
.entries
= NULL
;
456 ap
= (struct AnchorPath
*)AllocVec(sizeof(struct AnchorPath
) + MAX_PATH_LEN
, MEMF_CLEAR
);
460 ap
->ap_Strlen
= MAX_PATH_LEN
;
461 ap
->ap_BreakBits
= SIGBREAKF_CTRL_C
;
463 if ((match
= MatchFirst(dirPat
, ap
)) == 0)
469 #if USE_SOFTLINKCHECK
470 if (SoftlinkDODIR(ap
, TRUE
, FALSE
, DOSBase
))
471 #else /* USE_SOFTLINKCHECK */
472 if (ap
->ap_Info
.fib_DirEntryType
> 0)
473 #endif /* USE_SOFTLINKCHECK */
477 BPTR l
= Lock(ap
->ap_Buf
, SHARED_LOCK
);
482 NameFromLock(l
, name
, 512);
484 showdir(name
, inter
);
489 error
= doDir(ap
->ap_Buf
, all
, doDirs
, doFiles
, inter
);
494 if (!AddEntry(&files
, ap
->ap_Info
.fib_FileName
))
496 ioerr
= ERROR_NO_FREE_STORE
;
503 if (error
!= RETURN_OK
)
507 ap
->ap_Strlen
= MAX_PATH_LEN
;
508 match
= MatchNext(ap
);
513 if (error
== RETURN_OK
&& files
.num
!= 0)
515 if (!showfiles(&files
, inter
))
540 LONG
doDir(CONST_STRPTR dir
, BOOL all
, BOOL doDirs
, BOOL doFiles
, BOOL inter
)
543 static UBYTE buffer
[4096];
544 struct ExAllControl
*eac
;
545 LONG error
= RETURN_OK
;
550 dirs
.entries
= files
.entries
= NULL
;
551 dirs
.max
= files
.max
= 0;
552 dirs
.num
= files
.num
= 0;
554 lock
= Lock(dir
, SHARED_LOCK
);
558 eac
= AllocDosObject(DOS_EXALLCONTROL
, NULL
);
564 eac
->eac_LastKey
= 0;
566 error
= CheckDir(lock
, (struct ExAllData
*)buffer
, sizeof(buffer
), eac
, &dirs
, &files
);
567 FreeDosObject(DOS_EXALLCONTROL
, eac
);
569 if (SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
571 SetIoErr(ERROR_BREAK
);
575 if (error
== 0 && doDirs
)
581 //qsort(dirs.entries, dirs.num, sizeof(char *), compare_strings);
583 // Output the directories
584 for (t
= 0; t
< dirs
.num
; t
++)
586 STRPTR dirname
= dirs
.entries
[t
];
588 // Recurse into subdirectories if "ALL" was specified by the user
593 int pathlen
= strlen(dir
);
595 len
= pathlen
+ strlen(dirs
.entries
[t
]) + 2;
596 newpath
= AllocVec(len
, MEMF_ANY
);
600 CopyMem(dir
, newpath
, pathlen
+ 1);
601 if (AddPart(newpath
, dirs
.entries
[t
], len
))
604 showdir(dirname
, inter
);
605 error
= doDir(newpath
, all
, doDirs
, doFiles
, inter
);
609 SetIoErr(ERROR_LINE_TOO_LONG
);
610 error
= RETURN_ERROR
;
616 SetIoErr(ERROR_NO_FREE_STORE
);
619 if (error
!= RETURN_OK
)
624 showdir(dirname
, inter
);
632 if (error
== RETURN_OK
&& (files
.num
!= 0 && doFiles
))
634 if (!showfiles(&files
, inter
))
643 for (t
= 0; t
< dirs
.num
; t
++)
645 FreeVec(dirs
.entries
[t
]);
650 FreeVec(dirs
.entries
);
656 for (t
= 0; t
< files
.num
; t
++)
658 FreeVec(files
.entries
[t
]);
663 FreeVec(files
.entries
);
670 SetIoErr(ERROR_NO_FREE_STORE
);
678 #if USE_SOFTLINKCHECK
686 if (ioerr
== ERROR_OBJECT_NOT_FOUND
&&
687 (dvp
= GetDeviceProc(dir
, NULL
)))
689 if (ReadLink(dvp
->dvp_Port
, dvp
->dvp_Lock
, dir
, buffer
, sizeof(buffer
) - 1) > 0)
691 buffer
[sizeof(buffer
) - 1] = '\0';
693 Printf("Warning: Skipping dangling softlink %s -> %s\n",
694 (LONG
) dir
, (LONG
) buffer
);
704 #else /* USE_SOFTLINKCHECK */
708 #endif /* USE_SOFTLINKCHECK */
716 int CheckDir(BPTR lock
, struct ExAllData
*ead
, ULONG eadSize
,
717 struct ExAllControl
*eac
, struct table
*dirs
,
720 int error
= RETURN_OK
;
722 struct ExAllData
*oldEad
= ead
;
727 loop
= ExAll(lock
, ead
, eadSize
, ED_COMMENT
, eac
);
729 if(!loop
&& IoErr() != ERROR_NO_MORE_ENTRIES
)
731 error
= RETURN_ERROR
;
735 if(eac
->eac_Entries
!= 0)
740 #if USE_SOFTLINKCHECK
741 if (ead
->ed_Type
== ST_SOFTLINK
)
745 dirlock
= CurrentDir(lock
);
746 l
= Lock(ead
->ed_Name
, ACCESS_READ
);
751 UBYTE _fib
[sizeof(struct FileInfoBlock
) + 3];
752 struct FileInfoBlock
*fib
= (APTR
) (((IPTR
) _fib
+ 3) & ~3);
756 ead
->ed_Type
= fib
->fib_DirEntryType
;
757 //ead->ed_Size = fib->fib_Size;
763 #endif /* USE_SOFTLINKCHECK */
765 if (!AddEntry(ead
->ed_Type
> 0 ? dirs
: files
,ead
->ed_Name
))
769 SetIoErr(ERROR_NO_FREE_STORE
);
778 while((loop
) && (error
== RETURN_OK
));