Detabbed.
[AROS.git] / workbench / c / Which.c
blob091e33b7c1b3cb6049f4fc058bca707eb7d48893
1 /*
2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Find the whereabouts of an executable file
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.
26 Resident programs are marked as RES 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 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
62 ******************************************************************************/
64 #include <aros/debug.h>
65 #include <proto/exec.h>
66 #include <proto/dos.h>
67 #include <exec/memory.h>
68 #include <dos/dosextens.h>
69 #include <utility/tagitem.h>
71 #define ARG_COUNT 4 /* Number of ReadArgs() arguments */
73 const TEXT version[] = "$VER: Which 41.2 (13.2.2016)";
75 /* NOTE: For now, compatibility to the Amiga Which command is kept, but
76 I think that the restriction to only executable files should be
77 removed, especially considering soft links and such. */
81 * Check the resident list for the command 'name'.
83 static BOOL FindResidentCommand(STRPTR name);
87 * Check the paths for the command 'name'.
89 static BOOL FindCommandinPath(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib);
93 * Check the C: multiassign for the command 'name'.
95 static BOOL FindCommandinC(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib);
99 * Look in the current directory for the command 'name'.
101 static BOOL CheckDirectory(STRPTR name, struct FileInfoBlock *fib);
105 * Get a string that specifies the full path to a file or NULL if there
106 * was not enough memory to allocate the string. This string should be
107 * freed using FreeVec().
109 static STRPTR GetFullPath(BPTR lock);
112 int __nocommandline;
114 int main(void)
116 /* Array filled by ReadArgs() call */
117 IPTR args[ARG_COUNT] = {0, 0, 0, 0};
119 struct RDArgs *rda; /* ReadArgs standard struct */
120 BOOL found = FALSE; /* Indicates whether we've found a file
121 or not -- used for ALL ReadArgs() tag. */
122 int error = RETURN_WARN; /* Error value to return */
124 struct FileInfoBlock *fib; /* Used in Examine(). Allocated at top level
125 to skip multiple calls to
126 AllocDosObject() / FreeDosObject */
128 if((rda = ReadArgs("FILE/A,NORES/S,RES/S,ALL/S", args, NULL)) != NULL)
130 BOOL noRes = (BOOL)args[1]; /* Don't check resident commands */
131 BOOL resOnly = (BOOL)args[2]; /* Check resident commands only */
132 BOOL checkAll = (BOOL)args[3]; /* Check for multiple occurances */
134 STRPTR commandName = (STRPTR)args[0]; /* Command to look for */
136 fib = AllocDosObject(DOS_FIB, NULL);
138 if(fib != NULL)
140 if(!noRes)
142 /* Check resident lists */
143 found |= FindResidentCommand(commandName);
144 D(bug("Resident list\n"));
147 if(!found && !resOnly)
149 /* Check all available paths */
150 found |= FindCommandinPath(commandName, checkAll, fib);
151 D(bug("Path\n"));
154 if(!found && !resOnly)
156 /* Check C: multiassign */
157 found |= FindCommandinC(commandName, checkAll, fib);
158 D(bug("C:\n"));
160 if (found)
162 error = RETURN_OK;
165 FreeDosObject(DOS_FIB, fib);
168 FreeArgs(rda);
170 else
172 PrintFault(IoErr(), "Which");
173 error = RETURN_FAIL;
176 return error;
180 /* NOTE: The filesystemtask stuff is only necessary for this to work
181 correctly on AmigaOS. AROS doesn't use this concept. */
182 static BOOL FindCommandinC(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib)
184 BOOL found = FALSE; /* Object found? */
185 struct DevProc *dp = NULL; /* For GetDeviceProc() call */
186 BPTR oldCurDir; /* Temporary holder of old current dir */
187 // struct MsgPort *oldFST; /* Temporary holder of old FileSysTask */
189 /* If FilePart(name) is not name itself, it can't be in the C: directory;
190 or rather, it isn't in the C: directory or we found it in
191 FindCommandinPath(). */
192 if(FilePart(name) != name)
193 return FALSE;
195 oldCurDir = CurrentDir(BNULL); /* Just to save the old current dir... */
196 // oldFST = GetFileSysTask(); /* ... and the filesystem task */
198 while(((dp = GetDeviceProc("C:", dp)) != NULL) && (!found || checkAll))
200 // SetFileSysTask(dp2->dvp_Port);
201 CurrentDir(dp->dvp_Lock);
202 found |= CheckDirectory(name, fib);
204 /* Is this a multi assign? */
205 if(!(dp->dvp_Flags & DVPF_ASSIGN))
206 break;
209 // SetFileSysTask(oldFST);
210 CurrentDir(oldCurDir);
211 FreeDeviceProc(dp);
213 return found;
217 static BOOL FindCommandinPath(STRPTR name, BOOL checkAll, struct FileInfoBlock *fib)
219 BOOL found; /* Have we found the 'file' yet? */
220 BPTR oldCurDir; /* Space to store the current dir */
221 BPTR *paths; /* Loop variable */
223 struct CommandLineInterface *cli = Cli();
224 D(bug("checkAll = %ld\n", checkAll));
225 /* Can this happen at all? */
226 if(cli == NULL)
227 return FALSE;
229 /* Check the current directory */
230 D(bug("Calling CheckDirectory()\n"));
231 found = CheckDirectory(name, fib);
233 oldCurDir = CurrentDir(BNULL);
235 /* Check all paths */
236 paths = (BPTR *)BADDR(cli->cli_CommandDir);
237 D(bug("paths = 0x%08lx\n", paths));
239 while((!found || checkAll) && (paths != NULL))
241 CurrentDir(paths[1]);
243 D(bug("Calling CheckDirectory()\n"));
244 found |= CheckDirectory(name, fib);
246 paths = (BPTR *)BADDR(paths[0]); /* Go on with the next path */
249 CurrentDir(oldCurDir);
251 return found;
255 static BOOL CheckDirectory(STRPTR name, struct FileInfoBlock *fib)
257 BPTR lock; /* Lock on 'name' */
258 BOOL found = FALSE; /* For return value purposes */
259 STRPTR pathName;
261 lock = Lock(name, SHARED_LOCK);
263 D(bug("Locked command %s\n", name));
265 if(lock != BNULL)
267 D(bug("Calling Examine()\n"));
269 if(Examine(lock, fib) == DOSTRUE)
271 D(bug("Calling GetFullPath()\n"));
273 pathName = GetFullPath(lock);
275 if(pathName != NULL)
277 /* File or directory? */
278 if(fib->fib_DirEntryType < 0)
280 /* FIBF_EXECUTE is active low! */
281 if(!(fib->fib_Protection & FIBF_EXECUTE))
283 Printf("%s\n", pathName);
284 found = TRUE;
288 FreeVec(pathName); /* Free memory holding the full path name */
292 UnLock(lock);
295 return found;
299 static STRPTR GetFullPath(BPTR lock)
301 UBYTE *buf; /* Pointer to the memory allocated for the string */
302 ULONG size; /* Holder of the (growing) size of the string */
304 for(size = 512; ; size += 512)
306 buf = AllocVec(size, MEMF_ANY);
308 if(buf == NULL)
309 break;
311 if(NameFromLock(lock, buf, size))
313 return (STRPTR)buf;
316 FreeVec(buf);
319 return NULL;
323 static BOOL FindResidentCommand(STRPTR name)
325 BOOL found = FALSE; /* For return value purposes */
326 struct Segment *seg; /* Holder of segment if 'name' is a
327 resident command */
329 /* Look in both system and normal list. Or rather, in the normal list
330 ONLY if it wasn't found in the system list. This is what the Amiga
331 Which does thus not giving the whole picture if you have 'cmd'
332 resident while 'cmd' is an internal command also. However, if this
333 is the case, you may never access it as the system list is searched
334 first by the Shell? */
335 if((seg = FindSegment(name, NULL, TRUE)) == NULL)
337 seg = FindSegment(name, NULL, FALSE);
340 if(seg != NULL)
342 found = TRUE;
344 if(seg->seg_UC == CMD_INTERNAL)
346 Printf("INTERNAL %s\n", name);
348 else if(seg->seg_UC == CMD_DISABLED)
350 Printf("INTERNAL %s ;(DISABLED)\n", name);
352 else
353 Printf("RES %s\n", name);
356 return found;