Fixed out-by-one error in previous commit.
[AROS.git] / workbench / c / Which.c
blob88a4526a083adbcbf3071070df7006027b860d67
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Find the whereabouts of an executable file or directory
6 Lang: English
7 */
9 /******************************************************************************
11 NAME
13 Which
15 SYNOPSIS
17 FILE/A, NORES/S, RES/S, ALL/S
19 LOCATION
23 FUNCTION
25 Find and print the location of a specific program or directory.
26 Resident programs are marked as RESIDENT if they are not
27 internal resident in which case they are marked as INTERNAL.
29 Which searches the resident list, the current directory,
30 the command paths and the C: assign. If the item was not
31 found the condition flag is set to WARN but no error is
32 printed.
34 INPUTS
36 FILE -- the command/directory to search for
37 NORES -- don't include resident programs in the search
38 RES -- consider resident programs only
39 ALL -- find all locations of the FILE. This may cause the
40 printing of the same location several times, for
41 instance if the current directory is C: and the
42 FILE was found in C:
44 RESULT
46 NOTES
48 EXAMPLE
50 BUGS
52 SEE ALSO
54 INTERNALS
56 Executable files in AROS currently haven't got the e-flag set,
57 which makes Which unusable for now in emulated mode.
59 HISTORY
61 09.02.1998 SDuvan -- implemented
62 11.11.2000 SDuvan -- rewrote most of the code and added
63 correct path support
65 ******************************************************************************/
67 #include <aros/debug.h>
68 #include <proto/exec.h>
69 #include <proto/dos.h>
70 #include <exec/memory.h>
71 #include <dos/dosextens.h>
72 #include <utility/tagitem.h>
74 #define ARG_COUNT 4 /* Number of ReadArgs() arguments */
76 /* NOTE: For now, compatibility to the Amiga Which command is kept, but
77 I think that the restriction to only executable files should be
78 removed, especially considering soft links and such. */
82 * Check the resident list for the command 'name'.
84 BOOL FindResidentCommand(STRPTR name);
88 * Check the paths for the command 'name'.
90 BOOL FindCommandinPath(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib);
94 * Check the C: multiassign for the command 'name'.
96 BOOL FindCommandinC(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib);
100 * Look in the current directory for the command 'name'.
102 BOOL CheckDirectory(STRPTR name, struct FileInfoBlock *fib);
106 * Get a string that specifies the full path to a file or NULL if there
107 * was not enough memory to allocate the string. This string should be
108 * freed using FreeVec().
110 STRPTR GetFullPath(BPTR lock);
113 int __nocommandline;
115 int main(void)
117 /* Array filled by ReadArgs() call */
118 IPTR args[ARG_COUNT] = {0, 0, 0, 0};
120 struct RDArgs *rda; /* ReadArgs standard struct */
121 BOOL found = FALSE; /* Indicates whether we've found a file
122 or not -- used for ALL ReadArgs() tag. */
123 int error = RETURN_WARN; /* Error value to return */
125 struct FileInfoBlock *fib; /* Used in Examine(). Allocated at top level
126 to skip multiple calls to
127 AllocDosObject() / FreeDosObject */
129 if((rda = ReadArgs("FILE/A,NORES/S,RES/S,ALL/S", args, NULL)) != NULL)
131 BOOL noRes = (BOOL)args[1]; /* Don't check resident commands */
132 BOOL resOnly = (BOOL)args[2]; /* Check resident commands only */
133 BOOL checkAll = (BOOL)args[3]; /* Check for multiple occurances */
135 STRPTR commandName = (STRPTR)args[0]; /* Command to look for */
137 fib = AllocDosObject(DOS_FIB, NULL);
139 if(fib != NULL)
141 if(!noRes)
143 /* Check resident lists */
144 found |= FindResidentCommand(commandName);
145 // Printf("Resident list\n");
148 if(!found && !resOnly)
150 /* Check all available paths */
151 found |= FindCommandinPath(commandName, checkAll, fib);
152 // Printf("Path\n");
155 if(!found && !resOnly)
157 /* Check C: multiassign */
158 found |= FindCommandinC(commandName, checkAll, fib);
159 // Printf("C:\n");
161 if (found)
163 error = RETURN_OK;
166 FreeDosObject(DOS_FIB, fib);
169 FreeArgs(rda);
171 else
173 PrintFault(IoErr(), "Which");
174 error = RETURN_FAIL;
177 return error;
181 /* NOTE: The filesystemtask stuff is only necessary for this to work
182 correctly on AmigaOS. AROS doesn't use this concept. */
183 BOOL FindCommandinC(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib)
185 BOOL found = FALSE; /* Object found? */
186 struct DevProc *dp = NULL; /* For GetDeviceProc() call */
187 BPTR oldCurDir; /* Temporary holder of old current dir */
188 // struct MsgPort *oldFST; /* Temporary holder of old FileSysTask */
190 /* If FilePart(name) is not name itself, it can't be in the C: directory;
191 or rather, it isn't in the C: directory or we found it in
192 FindCommandinPath(). */
193 if(FilePart(name) != name)
194 return FALSE;
196 oldCurDir = CurrentDir(BNULL); /* Just to save the old current dir... */
197 // oldFST = GetFileSysTask(); /* ... and the filesystem task */
199 while(((dp = GetDeviceProc("C:", dp)) != NULL) && (!found || checkAll))
201 // SetFileSysTask(dp2->dvp_Port);
202 CurrentDir(dp->dvp_Lock);
203 found |= CheckDirectory(name, fib);
205 /* Is this a multi assign? */
206 if(!(dp->dvp_Flags & DVPF_ASSIGN))
207 break;
210 // SetFileSysTask(oldFST);
211 CurrentDir(oldCurDir);
212 FreeDeviceProc(dp);
214 return found;
218 BOOL FindCommandinPath(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib)
220 BOOL found; /* Have we found the 'file' yet? */
221 BPTR oldCurDir; /* Space to store the current dir */
222 BPTR *paths; /* Loop variable */
224 struct CommandLineInterface *cli = Cli();
225 // Printf("checkAll = %ld\n", checkAll);
226 /* Can this happen at all? */
227 if(cli == NULL)
228 return FALSE;
230 /* Check the current directory */
231 // Printf("Calling CheckDirectory()\n");
232 found = CheckDirectory(name, fib);
234 oldCurDir = CurrentDir(BNULL);
236 /* Check all paths */
237 paths = (BPTR *)BADDR(cli->cli_CommandDir);
238 // Printf("paths = 0x%08lx\n", paths);
240 while((!found || checkAll) && (paths != NULL))
242 CurrentDir(paths[1]);
244 // Printf("Calling CheckDirectory()\n");
245 found |= CheckDirectory(name, fib);
247 paths = (BPTR *)BADDR(paths[0]); /* Go on with the next path */
250 CurrentDir(oldCurDir);
252 return found;
256 BOOL CheckDirectory(STRPTR name, struct FileInfoBlock *fib)
258 BPTR lock; /* Lock on 'name' */
259 BOOL found = FALSE; /* For return value purposes */
260 STRPTR pathName;
262 lock = Lock(name, SHARED_LOCK);
264 // Printf("Locked command %s\n", name);
266 if(lock != BNULL)
268 // Printf("Calling Examine()\n");
270 if(Examine(lock, fib) == DOSTRUE)
272 // Printf("Calling GetFullPath()\n");
274 pathName = GetFullPath(lock);
276 if(pathName != NULL)
278 /* File or directory? */
279 if(fib->fib_DirEntryType < 0)
281 /* FIBF_EXECUTE is active low! */
282 if(!(fib->fib_Protection & FIBF_EXECUTE))
284 Printf("%s\n", pathName);
285 found = TRUE;
288 else
290 /* Directories are always printed */
291 Printf("%s\n", pathName);
292 found = TRUE;
295 FreeVec(pathName); /* Free memory holding the full path name */
299 UnLock(lock);
302 return found;
306 STRPTR GetFullPath(BPTR lock)
308 UBYTE *buf; /* Pointer to the memory allocated for the string */
309 ULONG size; /* Holder of the (growing) size of the string */
311 for(size = 512; ; size += 512)
313 buf = AllocVec(size, MEMF_ANY);
315 if(buf == NULL)
316 break;
318 if(NameFromLock(lock, buf, size))
320 return (STRPTR)buf;
323 FreeVec(buf);
326 return NULL;
330 BOOL FindResidentCommand(STRPTR name)
332 BOOL found = FALSE; /* For return value purposes */
333 struct Segment *seg; /* Holder of segment if 'name' is a
334 resident command */
336 /* Look in both system and normal list. Or rather, in the normal list
337 ONLY if it wasn't found in the system list. This is what the Amiga
338 Which does thus not giving the whole picture if you have 'cmd'
339 resident while 'cmd' is an internal command also. However, if this
340 is the case, you may never access it as the system list is searched
341 first by the Shell? */
342 if((seg = FindSegment(name, NULL, TRUE)) == NULL)
344 seg = FindSegment(name, NULL, FALSE);
347 if(seg != NULL)
349 found = TRUE;
351 if(seg->seg_UC == CMD_INTERNAL)
353 Printf("INTERNAL %s\n", name);
355 else if(seg->seg_UC == CMD_DISABLED)
357 Printf("INTERNAL %s ;(DISABLED)\n", name);
359 else
360 Printf("RES %s\n", name);
363 return found;