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 B/BACK -- Go back one directory level.
76 DEL/DELETE -- Delete a file or an empty directory.
77 T/TYPE -- Display content of a file.
78 C/COM -- Let the file or directory be the input of
79 a DOS command (which specified after the C or
80 COM or specified separately later).
81 Q/QUIT -- Quit interactive mode.
91 Interactive mode isn't fully working. It only walks stepwise
92 through the directory.
98 ******************************************************************************/
107 /* Global variables */
109 struct UtilityBase
*UtilityBase
;
114 LONG
doPatternDir(CONST_STRPTR dirPat
, BOOL all
, BOOL doDirs
, BOOL doFiles
,
117 LONG
doDir(CONST_STRPTR dir
, BOOL all
, BOOL dirs
, BOOL files
, BOOL inter
);
120 void showline(char *fmt
, RAWARG args
);
122 void maybeShowline(char *format
, RAWARG args
, BOOL doIt
, BOOL inter
);
124 void maybeShowlineCR(char *format
, RAWARG args
, BOOL doIt
, BOOL inter
);
127 int CheckDir(BPTR lock
, struct ExAllData
*ead
, ULONG eadSize
,
128 struct ExAllControl
*eac
, struct table
*dirs
,
129 struct table
*files
);
132 TEXT
* getLine(CONST_STRPTR prompt
, TEXT
*buffer
, LONG buflen
);
134 #define INTERARG_TEMPLATE "E=ENTER/S,B=BACK/S,T=TYPE/S,DEL=DELETE/S,Q=QUIT/S,C=COM/S,COMMAND"
149 AROS_SHA(CONST_STRPTR
, ,DIR , , NULL
),
150 AROS_SHA(CONST_STRPTR
, ,OPT
, /K
, NULL
),
151 AROS_SHA(BOOL
, ,ALL
, /S
, FALSE
),
152 AROS_SHA(BOOL
, ,DIRS
, /S
, FALSE
),
153 AROS_SHA(BOOL
, ,FILES
, /S
, FALSE
),
154 AROS_SHA(BOOL
, ,INTER
, /S
, FALSE
)
159 LONG error
= RETURN_FAIL
;
160 CONST_STRPTR dir
= SHArg(DIR);
161 CONST_STRPTR opt
= SHArg(OPT
);
162 BOOL all
= SHArg(ALL
);
163 BOOL dirs
= SHArg(DIRS
);
164 BOOL files
= SHArg(FILES
);
165 BOOL inter
= SHArg(INTER
);
171 UtilityBase
= (struct UtilityBase
*)OpenLibrary("utility.library", 37);
175 /* Convert the OPT arguments (if any) into the regular switches */
180 switch (ToUpper(*opt
))
199 Printf("%lc option ignored\n", *opt
);
213 ULONG toklen
= strlen(dir
) * 2;
214 STRPTR pattok
= AllocMem(toklen
, MEMF_PUBLIC
| MEMF_ANY
);
215 iswild
= ParsePattern(dir
, pattok
, toklen
);
216 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
);
260 int AddEntry(struct table
*table
, char *entry
)
265 if (table
->num
== table
->max
)
267 int new_max
= table
->max
+ 128;
270 new_entries
= AllocVec(sizeof(char *) * new_max
, MEMF_ANY
);
272 if (new_entries
== NULL
)
277 CopyMemQuick(table
->entries
, new_entries
,
278 sizeof(char *) * table
->num
);
279 FreeVec(table
->entries
);
282 table
->entries
= new_entries
;
283 table
->max
= new_max
;
286 len
= strlen(entry
) + 1;
287 if ((dup
= AllocVec(len
,MEMF_ANY
)))
295 table
->entries
[table
->num
++] = dup
;
302 int mystrcasecmp(const char *s1
, const char *s2
)
311 if (a
>= 'a' && a
<= 'z') a
-= 'a' - 'A';
312 if (b
>= 'a' && b
<= 'z') b
-= 'a' - 'A';
315 if (a
) return (int) a
;
323 int compare_strings(const void * s1
, const void * s2
)
325 return mystrcasecmp(*(char **)s1
, *(char **)s2
);
330 void maybeShowlineCR(char *format
, RAWARG args
, BOOL doIt
, BOOL inter
)
332 maybeShowline(format
, args
, doIt
, inter
);
342 void maybeShowline(char *format
, RAWARG args
, BOOL doIt
, BOOL inter
)
346 showline(format
, args
);
350 struct RDArgs
*inter_rdargs
= AllocDosObject(DOS_RDARGS
, NULL
);
353 IPTR interArgs
[NOOFINTERARGS
] = { (IPTR
)FALSE
,
361 memset(inter_rdargs
, 0, sizeof *inter_rdargs
);
363 if (getLine(" ? ", buffer
, sizeof buffer
))
365 inter_rdargs
->RDA_Source
.CS_Buffer
= buffer
;
366 inter_rdargs
->RDA_Source
.CS_Length
= sizeof buffer
;
368 if (ReadArgs(INTERARG_TEMPLATE
, interArgs
, inter_rdargs
))
371 if (interArgs
[ARG_ENTER
])
375 else if (interArgs
[ARG_BACK
])
379 else if (interArgs
[ARG_DELETE
])
383 else if (interArgs
[ARG_QUIT
])
387 else if (interArgs
[ARG_COM
])
391 else if (interArgs
[ARG_COMMAND
] != NULL
)
397 FreeArgs(inter_rdargs
);
400 FreeDosObject(DOS_RDARGS
, inter_rdargs
);
408 void showline(char *fmt
, RAWARG args
)
412 for (t
= 0; t
< g_indent
; t
++)
419 // Returns TRUE if all lines shown, FALSE if broken by SIGBREAKF_CTRL_C
421 BOOL
showfiles(struct table
*files
, BOOL inter
)
423 CONST_STRPTR argv
[2];
426 qsort(files
->entries
, files
->num
, sizeof(char *),compare_strings
);
430 for (t
= 0; t
< files
->num
; t
++)
432 argv
[0] = files
->entries
[t
];
434 if (SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
436 SetIoErr(ERROR_BREAK
);
440 maybeShowlineCR(" %s", (RAWARG
)argv
, TRUE
, inter
);
445 for (t
= 0; t
< files
->num
; t
+= 2)
447 argv
[0] = files
->entries
[t
];
448 argv
[1] = t
+ 1 < files
->num
? files
->entries
[t
+1] : "";
450 if (SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
452 SetIoErr(ERROR_BREAK
);
456 maybeShowlineCR(" %-32.s %s", (RAWARG
)argv
, TRUE
, inter
);
464 BOOL
showdir(char *dirName
, BOOL inter
)
466 maybeShowlineCR("%s (dir)", (RAWARG
)&dirName
, TRUE
, inter
);
472 LONG
doPatternDir(CONST_STRPTR dirPat
, BOOL all
, BOOL doDirs
, BOOL doFiles
, BOOL inter
)
475 struct AnchorPath
*ap
; /* Matching structure */
477 LONG match
; /* Loop variable */
478 LONG error
= RETURN_FAIL
;
482 files
.entries
= NULL
;
486 ap
= (struct AnchorPath
*)AllocVec(sizeof(struct AnchorPath
) + MAX_PATH_LEN
, MEMF_CLEAR
);
490 ap
->ap_Strlen
= MAX_PATH_LEN
;
491 ap
->ap_BreakBits
= SIGBREAKF_CTRL_C
;
493 if ((match
= MatchFirst(dirPat
, ap
)) == 0)
499 #if USE_SOFTLINKCHECK
500 if (SoftlinkDODIR(ap
, TRUE
, FALSE
, DOSBase
))
501 #else /* USE_SOFTLINKCHECK */
502 if (ap
->ap_Info
.fib_DirEntryType
> 0)
503 #endif /* USE_SOFTLINKCHECK */
507 BPTR l
= Lock(ap
->ap_Buf
, SHARED_LOCK
);
512 NameFromLock(l
, name
, 512);
514 showdir(name
, inter
);
519 error
= doDir(ap
->ap_Buf
, all
, doDirs
, doFiles
, inter
);
524 if (!AddEntry(&files
, ap
->ap_Info
.fib_FileName
))
526 ioerr
= ERROR_NO_FREE_STORE
;
533 if (error
!= RETURN_OK
)
537 ap
->ap_Strlen
= MAX_PATH_LEN
;
538 match
= MatchNext(ap
);
543 if (error
== RETURN_OK
&& files
.num
!= 0)
545 if (!showfiles(&files
, inter
))
568 LONG
doDir(CONST_STRPTR dir
, BOOL all
, BOOL doDirs
, BOOL doFiles
, BOOL inter
)
571 static UBYTE buffer
[4096];
572 struct ExAllControl
*eac
;
573 LONG error
= RETURN_OK
;
578 dirs
.entries
= files
.entries
= NULL
;
579 dirs
.max
= files
.max
= 0;
580 dirs
.num
= files
.num
= 0;
582 lock
= Lock(dir
, SHARED_LOCK
);
586 eac
= AllocDosObject(DOS_EXALLCONTROL
, NULL
);
592 eac
->eac_LastKey
= 0;
594 error
= CheckDir(lock
, (struct ExAllData
*)buffer
, sizeof(buffer
), eac
, &dirs
, &files
);
595 FreeDosObject(DOS_EXALLCONTROL
, eac
);
597 if (SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
599 SetIoErr(ERROR_BREAK
);
603 if (error
== 0 && doDirs
)
609 //qsort(dirs.entries, dirs.num, sizeof(char *), compare_strings);
611 // Output the directories
612 for (t
= 0; t
< dirs
.num
; t
++)
614 STRPTR dirname
= dirs
.entries
[t
];
616 // Recurse into subdirectories if "ALL" was specified by the user
621 int pathlen
= strlen(dir
);
623 len
= pathlen
+ strlen(dirs
.entries
[t
]) + 2;
624 newpath
= AllocVec(len
, MEMF_ANY
);
628 CopyMem(dir
, newpath
, pathlen
+ 1);
629 if (AddPart(newpath
, dirs
.entries
[t
], len
))
632 showdir(dirname
, inter
);
633 error
= doDir(newpath
, all
, doDirs
, doFiles
, inter
);
637 SetIoErr(ERROR_LINE_TOO_LONG
);
638 error
= RETURN_ERROR
;
644 SetIoErr(ERROR_NO_FREE_STORE
);
647 if (error
!= RETURN_OK
)
652 showdir(dirname
, inter
);
660 if (error
== RETURN_OK
&& (files
.num
!= 0 && doFiles
))
662 if (!showfiles(&files
, inter
))
671 for (t
= 0; t
< dirs
.num
; t
++)
673 FreeVec(dirs
.entries
[t
]);
678 FreeVec(dirs
.entries
);
684 for (t
= 0; t
< files
.num
; t
++)
686 FreeVec(files
.entries
[t
]);
691 FreeVec(files
.entries
);
698 SetIoErr(ERROR_NO_FREE_STORE
);
706 #if USE_SOFTLINKCHECK
714 if (ioerr
== ERROR_OBJECT_NOT_FOUND
&&
715 (dvp
= GetDeviceProc(dir
, NULL
)))
717 if (ReadLink(dvp
->dvp_Port
, dvp
->dvp_Lock
, dir
, buffer
, sizeof(buffer
) - 1) > 0)
719 buffer
[sizeof(buffer
) - 1] = '\0';
721 Printf("Warning: Skipping dangling softlink %s -> %s\n",
722 (LONG
) dir
, (LONG
) buffer
);
732 #else /* USE_SOFTLINKCHECK */
736 #endif /* USE_SOFTLINKCHECK */
744 int CheckDir(BPTR lock
, struct ExAllData
*ead
, ULONG eadSize
,
745 struct ExAllControl
*eac
, struct table
*dirs
,
748 int error
= RETURN_OK
;
750 struct ExAllData
*oldEad
= ead
;
755 loop
= ExAll(lock
, ead
, eadSize
, ED_COMMENT
, eac
);
757 if(!loop
&& IoErr() != ERROR_NO_MORE_ENTRIES
)
759 error
= RETURN_ERROR
;
763 if(eac
->eac_Entries
!= 0)
768 #if USE_SOFTLINKCHECK
769 if (ead
->ed_Type
== ST_SOFTLINK
)
773 dirlock
= CurrentDir(lock
);
774 l
= Lock(ead
->ed_Name
, ACCESS_READ
);
779 UBYTE _fib
[sizeof(struct FileInfoBlock
) + 3];
780 struct FileInfoBlock
*fib
= (APTR
) (((IPTR
) _fib
+ 3) & ~3);
784 ead
->ed_Type
= fib
->fib_DirEntryType
;
785 //ead->ed_Size = fib->fib_Size;
791 #endif /* USE_SOFTLINKCHECK */
793 if (!AddEntry(ead
->ed_Type
> 0 ? dirs
: files
,ead
->ed_Name
))
797 SetIoErr(ERROR_NO_FREE_STORE
);
806 while((loop
) && (error
== RETURN_OK
));
813 TEXT
* getLine(CONST_STRPTR prompt
, TEXT
*buffer
, LONG buflen
)
820 return FGets(Input(), buffer
, buflen
);