- Print out an error when the stack for a command can't be allocated
[AROS.git] / workbench / c / Which.c
blobce240e083a41b5086fbd0b8a959f44e2687f81e1
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 const TEXT version[] = "$VER: Which 41.1 (7.9.1999)";
78 /* NOTE: For now, compatibility to the Amiga Which command is kept, but
79 I think that the restriction to only executable files should be
80 removed, especially considering soft links and such. */
84 * Check the resident list for the command 'name'.
86 BOOL FindResidentCommand(STRPTR name);
90 * Check the paths for the command 'name'.
92 BOOL FindCommandinPath(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib);
96 * Check the C: multiassign for the command 'name'.
98 BOOL FindCommandinC(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib);
102 * Look in the current directory for the command 'name'.
104 BOOL CheckDirectory(STRPTR name, struct FileInfoBlock *fib);
108 * Get a string that specifies the full path to a file or NULL if there
109 * was not enough memory to allocate the string. This string should be
110 * freed using FreeVec().
112 STRPTR GetFullPath(BPTR lock);
115 int __nocommandline;
117 int main(void)
119 /* Array filled by ReadArgs() call */
120 IPTR args[ARG_COUNT] = {0, 0, 0, 0};
122 struct RDArgs *rda; /* ReadArgs standard struct */
123 BOOL found = FALSE; /* Indicates whether we've found a file
124 or not -- used for ALL ReadArgs() tag. */
125 int error = RETURN_WARN; /* Error value to return */
127 struct FileInfoBlock *fib; /* Used in Examine(). Allocated at top level
128 to skip multiple calls to
129 AllocDosObject() / FreeDosObject */
131 if((rda = ReadArgs("FILE/A,NORES/S,RES/S,ALL/S", args, NULL)) != NULL)
133 BOOL noRes = (BOOL)args[1]; /* Don't check resident commands */
134 BOOL resOnly = (BOOL)args[2]; /* Check resident commands only */
135 BOOL checkAll = (BOOL)args[3]; /* Check for multiple occurances */
137 STRPTR commandName = (STRPTR)args[0]; /* Command to look for */
139 fib = AllocDosObject(DOS_FIB, NULL);
141 if(fib != NULL)
143 if(!noRes)
145 /* Check resident lists */
146 found |= FindResidentCommand(commandName);
147 // Printf("Resident list\n");
150 if(!found && !resOnly)
152 /* Check all available paths */
153 found |= FindCommandinPath(commandName, checkAll, fib);
154 // Printf("Path\n");
157 if(!found && !resOnly)
159 /* Check C: multiassign */
160 found |= FindCommandinC(commandName, checkAll, fib);
161 // Printf("C:\n");
163 if (found)
165 error = RETURN_OK;
168 FreeDosObject(DOS_FIB, fib);
171 FreeArgs(rda);
173 else
175 PrintFault(IoErr(), "Which");
176 error = RETURN_FAIL;
179 return error;
183 /* NOTE: The filesystemtask stuff is only necessary for this to work
184 correctly on AmigaOS. AROS doesn't use this concept. */
185 BOOL FindCommandinC(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib)
187 BOOL found = FALSE; /* Object found? */
188 struct DevProc *dp = NULL; /* For GetDeviceProc() call */
189 BPTR oldCurDir; /* Temporary holder of old current dir */
190 // struct MsgPort *oldFST; /* Temporary holder of old FileSysTask */
192 /* If FilePart(name) is not name itself, it can't be in the C: directory;
193 or rather, it isn't in the C: directory or we found it in
194 FindCommandinPath(). */
195 if(FilePart(name) != name)
196 return FALSE;
198 oldCurDir = CurrentDir(BNULL); /* Just to save the old current dir... */
199 // oldFST = GetFileSysTask(); /* ... and the filesystem task */
201 while(((dp = GetDeviceProc("C:", dp)) != NULL) && (!found || checkAll))
203 // SetFileSysTask(dp2->dvp_Port);
204 CurrentDir(dp->dvp_Lock);
205 found |= CheckDirectory(name, fib);
207 /* Is this a multi assign? */
208 if(!(dp->dvp_Flags & DVPF_ASSIGN))
209 break;
212 // SetFileSysTask(oldFST);
213 CurrentDir(oldCurDir);
214 FreeDeviceProc(dp);
216 return found;
220 BOOL FindCommandinPath(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib)
222 BOOL found; /* Have we found the 'file' yet? */
223 BPTR oldCurDir; /* Space to store the current dir */
224 BPTR *paths; /* Loop variable */
226 struct CommandLineInterface *cli = Cli();
227 // Printf("checkAll = %ld\n", checkAll);
228 /* Can this happen at all? */
229 if(cli == NULL)
230 return FALSE;
232 /* Check the current directory */
233 // Printf("Calling CheckDirectory()\n");
234 found = CheckDirectory(name, fib);
236 oldCurDir = CurrentDir(BNULL);
238 /* Check all paths */
239 paths = (BPTR *)BADDR(cli->cli_CommandDir);
240 // Printf("paths = 0x%08lx\n", paths);
242 while((!found || checkAll) && (paths != NULL))
244 CurrentDir(paths[1]);
246 // Printf("Calling CheckDirectory()\n");
247 found |= CheckDirectory(name, fib);
249 paths = (BPTR *)BADDR(paths[0]); /* Go on with the next path */
252 CurrentDir(oldCurDir);
254 return found;
258 BOOL CheckDirectory(STRPTR name, struct FileInfoBlock *fib)
260 BPTR lock; /* Lock on 'name' */
261 BOOL found = FALSE; /* For return value purposes */
262 STRPTR pathName;
264 lock = Lock(name, SHARED_LOCK);
266 // Printf("Locked command %s\n", name);
268 if(lock != BNULL)
270 // Printf("Calling Examine()\n");
272 if(Examine(lock, fib) == DOSTRUE)
274 // Printf("Calling GetFullPath()\n");
276 pathName = GetFullPath(lock);
278 if(pathName != NULL)
280 /* File or directory? */
281 if(fib->fib_DirEntryType < 0)
283 /* FIBF_EXECUTE is active low! */
284 if(!(fib->fib_Protection & FIBF_EXECUTE))
286 Printf("%s\n", pathName);
287 found = TRUE;
290 else
292 /* Directories are always printed */
293 Printf("%s\n", pathName);
294 found = TRUE;
297 FreeVec(pathName); /* Free memory holding the full path name */
301 UnLock(lock);
304 return found;
308 STRPTR GetFullPath(BPTR lock)
310 UBYTE *buf; /* Pointer to the memory allocated for the string */
311 ULONG size; /* Holder of the (growing) size of the string */
313 for(size = 512; ; size += 512)
315 buf = AllocVec(size, MEMF_ANY);
317 if(buf == NULL)
318 break;
320 if(NameFromLock(lock, buf, size))
322 return (STRPTR)buf;
325 FreeVec(buf);
328 return NULL;
332 BOOL FindResidentCommand(STRPTR name)
334 BOOL found = FALSE; /* For return value purposes */
335 struct Segment *seg; /* Holder of segment if 'name' is a
336 resident command */
338 /* Look in both system and normal list. Or rather, in the normal list
339 ONLY if it wasn't found in the system list. This is what the Amiga
340 Which does thus not giving the whole picture if you have 'cmd'
341 resident while 'cmd' is an internal command also. However, if this
342 is the case, you may never access it as the system list is searched
343 first by the Shell? */
344 if((seg = FindSegment(name, NULL, TRUE)) == NULL)
346 seg = FindSegment(name, NULL, FALSE);
349 if(seg != NULL)
351 found = TRUE;
353 if(seg->seg_UC == CMD_INTERNAL)
355 Printf("INTERNAL %s\n", name);
357 else if(seg->seg_UC == CMD_DISABLED)
359 Printf("INTERNAL %s ;(DISABLED)\n", name);
361 else
362 Printf("RES %s\n", name);
365 return found;