mwm@mica.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/17/89)
Before I sit down & write it myself, does anyone have a piece of code that will give me a full name for the binary it's running in? Not just argv[0], but the name path & file name (not file, but c:file, or sys:system/file, or whatever). Thanx, <mike -- And then I saw her... Mike Meyer She was a bright red '64 GTO mwm@berkeley.edu With fins and gills like some giant piranha fish, ucbvax!mwm Some obscene phallic symbol on wheels. mwm@ucbjade.BITNET
rap@peck.ardent.com (Rob Peck) (07/18/89)
In article <26385@agate.BERKELEY.EDU> mwm@mica.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: >Before I sit down & write it myself, does anyone have a piece of code >that will give me a full name for the binary it's running in? Not just >argv[0], but the name path & file name (not file, but c:file, or >sys:system/file, or whatever). Listing 2.9 in the Programmer's Guide To The Amiga gives you the path to where the binary is located. You can use argv[0] for the binary's name. The program is called mybranch.c Rob Peck
mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/18/89)
<In article <26385@agate.BERKELEY.EDU> mwm@mica.berkeley.edu (Mike (I'll think of something yet) Meyer) writes:
<>Before I sit down & write it myself, does anyone have a piece of code
<>that will give me a full name for the binary it's running in? Not just
<>argv[0], but the name path & file name (not file, but c:file, or
<>sys:system/file, or whatever).
<
<Listing 2.9 in the Programmer's Guide To The Amiga gives you the
<path to where the binary is located. You can use argv[0] for the
<binary's name. The program is called mybranch.c
I must have not made myself clear - you're the second person to make
that mistake. The code in listing 2.9 prints the name of the current
directory. This is may not be the name of the directory that the
running file is from. Consider the following script, with "myname.c"
as the program I'm looking for:
1> path
Current directory
bin:Utilities
bin:System
bin:S
C:
1> cd
src:c
1> cc myname.c -o myname
1> myname
src:c/myname
1> copy myname ram:
1> ram:myname
ram:myname
1> rename ram:myname c: ; Note: no longer a copy in current directory
1> myname
c:myname ; Or bin:c/myname, or dh0:c/myname, or etc.
1> rename c:myname c:system
1> myname
bin:system/myname ; Or dh0:system/myname, or some such.
1>
You see the difference? The code is conceptually simple, but has some
non-trivial details (like dealing with "//x/y/myname") to make it
work right.
<mike
--
He was your reason for living Mike Meyer
So you once said mwm@berkeley.edu
Now your reason for living ucbvax!mwm
Has left you half dead mwm@ucbjade.BITNET
thad@cup.portal.com (Thad P Floryan) (07/18/89)
Mike is asking about a program that will return more than just argv[0] re the name of "what program am I?" A program named "which" was posted to Usenet back in November 1987 by Carolyn Scheppner (CATS); didn't see it in my Fish Index, so if you need it, lemme know. The sizes: CLI2> ls -l src:which ----ar-e- 87-11-25 12:45:04 13 6180 which ----ar--- 87-11-25 12:44:46 9 4401 which.c ----ar--- 87-12-07 05:16:01 2 832 which.doc Dirs:0 Files:3 Blocks:24 Bytes:11413 CLI2> It would be trivial to adapt "which" to match the first occurrence of */argv[0] in the PATH searched by "which". Thad Floryan [ thad@cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]
rap@peck.ardent.com (Rob Peck) (07/18/89)
In article <26406@agate.BERKELEY.EDU> mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: ><In article <26385@agate.BERKELEY.EDU> mwm@mica.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: ><>Before I sit down & write it myself, does anyone have a piece of code ><>that will give me a full name for the binary it's running in? Not just ><>argv[0], but the name path & file name (not file, but c:file, or ><>sys:system/file, or whatever). [examples deleted] I now understand your question exactly and I agree that the current directory path name listing is inadequate. Looks like you have some work on your hands. To know exactly where-from the binary that is running was drawn, you need to know both the PATH and the command that was issued, so you'd have to get to the command history of the originating CLI (if there was one). Frankly, without doing both of these, I cannot see how a binary can identify the directory in which it resides and from which it was called. AAARRRGGGHHH! Rob Peck
louie@trantor.umd.edu (Louis A. Mamakos) (07/19/89)
Just a thought, but doesn't the program that's running have an open I/O stream to the binary that it was loaded from? At least programs with overlays do, so that the overlay manager can load the appropriate segments. Now, given this struct FileHandle * or whatever, maybe you can get a lock. And from there do the normal sorts of things to get the full path name to the binary. Sounds ugly. Louis A. Mamakos WA3YMH Internet: louie@TRANTOR.UMD.EDU University of Maryland, Computer Science Center - Systems Programming
jwright@atanasoff.cs.iastate.edu (Jim Wright) (07/19/89)
In article <20565@cup.portal.com> thad@cup.portal.com (Thad P Floryan) writes: | | It would be trivial to adapt "which" to match the first occurrence | of */argv[0] in the PATH searched by "which". Wouldn't this fail if, for example, I had a script file in S: which then explicitly called the program and the program was not in a directory on the PATH. -- Jim Wright jwright@atanasoff.cs.iastate.edu
mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/19/89)
In article <1227@atanasoff.cs.iastate.edu> jwright@atanasoff.cs.iastate.edu.UUCP (Jim Wright) writes: <In article <20565@cup.portal.com> thad@cup.portal.com (Thad P Floryan) writes: <| <| It would be trivial to adapt "which" to match the first occurrence <| of */argv[0] in the PATH searched by "which". < <Wouldn't this fail if, for example, I had a script file in S: which <then explicitly called the program and the program was not in a directory <on the PATH. No, it won't. If the program is invoked explicitly, then argv[0] should contain a ':', so the path is never searched. That's why you have to adapt the code, instead of dropping it in as is. Which, of course, doesn't check argv[0], so it will find the script - which is what you want it to do. <mike -- Come all you rolling minstrels, Mike Meyer And together we will try, mwm@berkeley.edu To rouse the spirit of the air, ucbvax!mwm And move the rolling sky. mwm@ucbjade.BITNET
doug@xdos.UUCP (Doug Merritt) (07/19/89)
><In article <26385@agate.BERKELEY.EDU> mwm@mica.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: ><>Before I sit down & write it myself, does anyone have a piece of code ><>that will give me a full name for the binary it's running in? Not just Rob Peck said: ><Listing 2.9 in the Programmer's Guide To The Amiga gives you the In article <26406@agate.BERKELEY.EDU> mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: > The code in listing 2.9 prints the name of the current >directory. This is may not be the name of the directory that the >running file is from. Consider the following script, with "myname.c" Well, for a workbench program that's easy...WBenchMsg->sm_ArgList[0].wa_Lock is a lock on the file the executable came from, and the usual Examine()/ ParentDir() loop will turn that into a full path quite easily (SMOP). I couldn't find anything comparable for CLI-launched programs, although I wondered about (struct CommandLineInterface)->cli_CommandDir. If that doesn't do it than I guess the only solution is the previously posted answer of "which". Doug -- Doug Merritt {pyramid,apple}!xdos!doug Member, Crusaders for a Better Tomorrow Professional Wildeyed Visionary
doug@xdos.UUCP (Doug Merritt) (07/19/89)
In article <1227@atanasoff.cs.iastate.edu> jwright@atanasoff.cs.iastate.edu.UUCP (Jim Wright) writes: >In article <20565@cup.portal.com> thad@cup.portal.com (Thad P Floryan) writes: >| >| It would be trivial to adapt "which" to match the first occurrence >| of */argv[0] in the PATH searched by "which". > >Wouldn't this fail if, for example, I had a script file in S: which >then explicitly called the program and the program was not in a directory >on the PATH. But in this case the full path is in argv[0], making this the easiest of the solutions. if (!argc) look at WBenchMsg else if (any {':','/'} in argv[0]) use argv[0] else use PATH The only case I can see that would fail is when someone gets some code going using loadseg() explicitly, which (as far as I know, anyone want to correct me?) does not save the executable's name anywhere. Doug -- Doug Merritt {pyramid,apple}!xdos!doug Member, Crusaders for a Better Tomorrow Professional Wildeyed Visionary
daveh@cbmvax.UUCP (Dave Haynie) (07/19/89)
in article <7374@ardent.UUCP>, rap@peck.ardent.com (Rob Peck) says: > In article <26406@agate.BERKELEY.EDU> mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: >><In article <26385@agate.BERKELEY.EDU> mwm@mica.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: >><>Before I sit down & write it myself, does anyone have a piece of code >><>that will give me a full name for the binary it's running in? Not just >><>argv[0], but the name path & file name (not file, but c:file, or >><>sys:system/file, or whatever). > I now understand your question exactly and I agree that the current > directory path name listing is inadequate. Looks like you have some > work on your hands. AAARRRGGGHHH! > Rob Peck We had a big discussion on bix about this some time back, when I wanted to do pretty much the same kind of thing. The basis for it was this. I have a program which can get launched from Workbench or from the CLI. I have a number of parameters than can be fed to the program, and I'd like a way to set any number of these to user-defined defaults, instead of the defaults I picked when I wrote the code. Under Workbench, the ToolTypes array does this just dandy. So I think to myself, all I need to make this the standard place to put defaults is to have the program, when started under CLI, go hunt down it's icon, and we're set. But whoops; there's no easy parent lock or anything like that passed down to a CLI program. This is actually a case in which Workbench does a better job than CLI. The only obvious fix to this I could think of would require the shell a CLI program is launched from to pass down a lock to that image's parent as well as the name as it currently does. This is obviously known at the time the image is launched. In any case, sure would be nice to have this stuff more consistent. Maybe in 1.4? -- Dave Haynie Commodore-Amiga (Systems Engineering) "The Crew That Never Rests" {uunet|pyramid|rutgers}!cbmvax!daveh PLINK: D-DAVE H BIX: hazy Be careful what you wish for -- you just might get it
new@udel.EDU (Darren New) (07/20/89)
In article <1227@atanasoff.cs.iastate.edu> jwright@atanasoff.cs.iastate.edu.UUCP (Jim Wright) writes: >Wouldn't this fail if, for example, I had a script file in S: which >then explicitly called the program and the program was not in a directory >on the PATH. Wouldn't argv[0] then contain the full path-name of the program? You may need to use _main (before the parsing gets done). It must be doable, since the CLI does it and you have all the information in the process structure you need. I would think you could do it as follows: 1) attempt to obtain a lock on argv[0] (or the first string in the command line, if _main). If that succeeds, use that lock to generate the full path name. 2) walk down the path, attempting to lock argv[0] from each directory so found. If I remember, the path in some way hangs off of the current directory pointer in the process structure. When found, use that lock to find the full path name. 3) try to loc strcat("C:", argv[0]); 4) If all of these fail, then my algorithm is wrong :-). Note that you can CD to a file and not just a directory. Thus any print-current-directory function should be able to give you the full path of a lock. (Er, from DOS calls, not with the CD command.) -- Darren
trantow@csd4.milw.wisc.edu (Jerry J Trantow) (07/20/89)
>In article <26385@agate.BERKELEY.EDU> mwm@mica.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: >>Before I sit down & write it myself, does anyone have a piece of code >>that will give me a full name for the binary it's running in? Not just >>argv[0], but the name path & file name (not file, but c:file, or >>sys:system/file, or whatever). Try the ARP PathName() function. I believe it is defined char *PathName(lock)
jesup@cbmvax.UUCP (Randell Jesup) (07/20/89)
In article <7374@ardent.UUCP> rap@peck.ardent.com (Rob Peck) writes: >I now understand your question exactly and I agree that the current >directory path name listing is inadequate. Looks like you have some >work on your hands. To know exactly where-from the binary that is >running was drawn, you need to know both the PATH and the command >that was issued, so you'd have to get to the command history of >the originating CLI (if there was one). Frankly, without doing >both of these, I cannot see how a binary can identify the directory >in which it resides and from which it was called. AAARRRGGGHHH! Quite true, the current CLI/Shell doesn't preserve the needed information (some other shells do). The ability to get to the file the program was run from should be addressed in 1.4. -- Randell Jesup, Keeper of AmigaDos, Commodore Engineering. {uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.cbm.commodore.com BIX: rjesup Common phrase heard at Amiga Devcon '89: "It's in there!"
jesup@cbmvax.UUCP (Randell Jesup) (07/20/89)
In article <432@xdos.UUCP> doug@xdos.UUCP (Doug Merritt) writes: >But in this case the full path is in argv[0], making this the easiest >of the solutions. > if (!argc) > look at WBenchMsg > else if (any {':','/'} in argv[0]) > use argv[0] > else > use PATH That should work (though it is painful) under 1.2/1.3. I thought of that one 5 minutes after I posted my other response. Glad to see someone beat me to it. -- Randell Jesup, Keeper of AmigaDos, Commodore Engineering. {uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.cbm.commodore.com BIX: rjesup Common phrase heard at Amiga Devcon '89: "It's in there!"
doug@xdos.UUCP (Doug Merritt) (07/21/89)
In article <7372@cbmvax.UUCP> jesup@cbmvax.UUCP (Randell Jesup) writes: >In article <432@xdos.UUCP> doug@xdos.UUCP (Doug Merritt) writes: >>But in this case the full path is in argv[0], making this the easiest >>of the solutions. >> if (!argc) >> look at WBenchMsg >> else if (any {':','/'} in argv[0]) >> use argv[0] >> else >> use PATH > > That should work (though it is painful) under 1.2/1.3. I thought of >that one 5 minutes after I posted my other response. Glad to see someone >beat me to it. Yeah, and even aside from the complexity, it's painful to have to look things up in the PATH...inelegant, since it's sort of guessing. But Josh Rovero pointed out that cli_CommandName has what we need, which made things easier and more robust, so I put together a full solution based on that idea and some code I already had lying around (this made it possible for me to go from start to finish in 1 hour). Hope it's useful. Doug Doug Merritt {pyramid,apple}!xdos!doug Member, Crusaders for a Better Tomorrow Professional Wildeyed Visionary --------------------- CUT HERE ----- CUT HERE ------- CUT HERE ------------- /* * whence -- Example program: show full path of executable the current * process was launched from. Works under both CLI and Workbench. * * Thanks to Josh Rovero for pointing out that the info needed for * working under CLI was available in cli_CommandName. * * Written because Mike Meyer wanted it. Happy to oblige, Mike. */ /* * Copyright 1989 Doug Merritt. License to use hereby granted. * {pyramid,apple}!xdos!doug * (408) 370-7875 */ /* * Compiled under Manx Aztec C V3.6A * cc -Iinclude: whence.c * ln -o whence whence.o -lc * * Note use of BufRound() macro instead of allocated memory; this * is widely useful. * Also the Lock2Path() function is very handy. * * Bugs: when called from workbench, or relative to current directory, * the device name is shown, but when called via absolute path from CLI, * the ASSIGN'ed name is shown (e.g. "mydisk:" rather than "df0:"). * I have a function that'll fix that (i.e. convert assign names to * device names), if anyone wants it let me know. * * Please retain my copyright notice if/when you borrow this code. */ #include "libraries/dos.h" #include "libraries/dosextens.h" #include "workbench/startup.h" #include "stdio.h" /* * RoundUp0 -- ceiling (yields 0 if n % TO == 0) * BufRound -- given buffer address, rounds up to word boundary */ #define RoundUp0(N,TO) ( (TO - (((ULONG)N) & (TO-1)) ) & (TO-1)) #define BufRound(BUF) &BUF[ RoundUp0(BUF,4) ] char * bstr2str(d, bs) char *d; unsigned long bs; { char *s; int len; s = (char *) (bs << 2); len = *s++ & 0xff; while (len-- > 0) *d++ = *s++; *d = '\0'; } Lock2Path(curlock, pathbuf) struct FileLock *curlock; char *pathbuf; { #define LOCKSTACKSIZE 128 struct FileLock *locklist[LOCKSTACKSIZE]; UBYTE Ibuf [ sizeof(struct FileInfoBlock) + 4]; struct FileInfoBlock *Ifib; int i; char *s, *path; extern struct FileLock *ParentDir(); Ifib = (struct FileInfoBlock *) BufRound(Ibuf); if (!Examine(curlock, Ifib)) return(0); /* * find full path name; build LIFO stack of * pushed locks; when full use popped locks with * Examine() to get each name in path. */ for (i=0; i<LOCKSTACKSIZE; i++) { locklist[i] = curlock; if (!(curlock = ParentDir(curlock)) ) break; /* normal loop exit */ } path = &pathbuf[0]; if (i >= LOCKSTACKSIZE) { printf("Too many subdirectories\n"); *path++ = '?'; *path++ = '/'; --i; } /* * concatenate each component of path */ if (!Examine(locklist[i--], Ifib)) goto wierd; for (s=Ifib->fib_FileName; *s; ) *path++ = *s++; *path++ = ':'; while (i >= 0) { if (!Examine(locklist[i], Ifib)) goto wierd; for (s=Ifib->fib_FileName; *s; ) *path++ = *s++; if (i>0) *path++ = '/'; --i; } *path = '\0'; return(path - &pathbuf[0]); wierd: *path++ = '?'; *path++ = '/'; *path = '\0'; return(path - &pathbuf[0]); } /* Lock2Path() */ /* * get head of path by chopping off tail (delete anything after : or /) */ head(s) char *s; { char *start; if (!*s) return(0); start = s; while (*s) ++s; while (*s != ':' && *s != '/') { if (s == start) return(0); --s; } *++s = '\0'; return(1); } main(argc, argv) int argc; char **argv; { struct Process *proc; struct CommandLineInterface *cli; extern struct Process *FindTask(); extern struct WBStartup *WBenchMsg; extern struct FileLock *Lock(); char buf[256]; FILE *f; if (!argc) { if ((f = fopen("CON:0/0/640/200/whence", "w")) == NULL) exit(20); if (!Lock2Path(WBenchMsg->sm_ArgList[0].wa_Lock, buf)) { fprintf(f, "Error\n"); Delay(150L); exit(10); } fprintf(f, "%s\n", buf); Delay(150L); fclose(f); exit(0); } else { proc = (struct Process *) FindTask(0L); cli = (struct CommandLineInterface *) ( ((long) proc->pr_CLI) << 2); bstr2str(buf, cli->cli_CommandName); if (!head(buf)) { /* launched relative to current dir? */ struct FileLock *lock; lock = Lock("", ACCESS_READ); if (!Lock2Path( lock, buf)) { UnLock(lock); printf("No current dir?\n"); exit(10); } UnLock(lock); } printf("%s\n", buf); } } -- Doug Merritt {pyramid,apple}!xdos!doug Member, Crusaders for a Better Tomorrow Professional Wildeyed Visionary
mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/21/89)
I wish to thank everyone for the comments & help on this topic. I knew the basic algorithm implemented by Doug (thanx, Doug!) before I asked, having done this for Unix. Like I said, this is a nontrivial problem (doing it that way, anyway - I was hoping for a nicer way). To wit, Doug failed to consider a number of cases that cause problems. It's obvious the code won't deal with them, _if_ you know about them. But they aren't obvious cases. Script follows: 1> pwd src:c 1> whence ; correct case src:c 1> /c/whence ; mishandled example 1 /c/ 1> :c/whence ; mishandled example 2 :c/ 1> makedir c:x 1> copy whence c:x/whence 1> x/whence ; mishandled example 3 x/ 1> cd / 1> x/whence ; mishandled example 4 x/ 1> x//x/whence ; mishandled example 5 x//x/ All three are wrong, as the incorrectly give back a relative path. Example 2 is absolute on a device, but doesn't specify the device. For example 3, I'm running WShell; your milage may vary with other shells. Example 5 doesn't matter now - but once the other bugs are fixed, it will. This problem ranks with 'more' as being "one of the worlds hardest single-evening hacks", in that it _looks_ straightforward and simple; it's just that to do either one right, there are lots of non-obvious things you have to deal with. I would be surprised if anyone could sit down and write code that dealt correctly with all the cases in a single evening, unless you've done it before. Note that my examples are pulled from Unix, and there are other gotchas that can't happen on the Amiga. There's one on the list that can't happen on Unix (#2), and there are probably others. That's why I asked before trying to write it myself. <mike -- Il brilgue: les toves lubricilleux Mike Meyer Se gyrent en vrillant dans le guave, mwm@berkeley.edu Enmimes sont les gougebosqueux, ucbvax!mwm Et le momerade horsgrave. mwm@ucbjade.BITNET
mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/21/89)
Having seen everyone's examples, I finally sat down and wrote my own. For my uses, I needed a subroutine that handed back a "canonical" form - i.e., one that gave me the same name every time, no matter how invoked. Two things made this happen. One was taking the device part of any absolute names to a lock, then using getpath() from the Lattice library (this is basically just Lock2Path, as written by Doug) to turn it back into a path. Thus, all path names come out with assigns, etc. mapped out. The other step is to take any part of the file name not handed back by getpath, and deal with occurences of "//" in the name. There's one other Lattice library function here, findpath(). It walks the path of a cli, and returns a lock on the first directory that contains a file (subdirectory path) with the name of it's argument file (subdirectory path). This is pretty trivial to derive from which.c. Since I was using those routines, I went ahead and wrote my preferred function headers - ANSI prototype style. Those of you with Lattice 5. or later should be able to just compile this. -L -dTEST to get a binary that reports it's name in canonical form, sans those to get a .o file with a "which" routine that will pass back that name. Those of you with Manx will have to change it. <mike ---------------- cut here ---------------- /* * which - figure out where I was run from, and return the name * of that binary. */ #include <dos.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <libraries/dos.h> #include <proto/dos.h> static int myname(char *, char *) ; #ifdef TEST void main(argc, argv) char **argv; { char pathbuf[FMSIZE] ; if (!which(argv[0], pathbuf)) puts("Can't find path") ; else puts(pathbuf) ; } #endif which(char *myname, char *pathbuf) { char *ip ; BPTR lock ; int status ; if (*myname != ':' && (ip = strchr(myname, ':')) != NULL) { /* * Absolute path, so just canonicalize that. This means we * need to get a lock on the dev: file, and change myname * to point at the rest of it. */ ip = '\0' ; lock = Lock(myname, ACCESS_READ) ; myname = ip + 1 ; } else { /* * Get a lock on the directory we're from, if we're in * a directory on the path. * N.B.: findpath returns a lock on the current directory * if we feed it an absolute path name. Strange, but true. */ lock = findpath(myname) ; if (lock == -1) { /* * Not on the path, so see if we're in C: */ sprintf(pathbuf, "c:%s", myname) ; if (getfa(pathbuf) != -1) return 0 ; /* * It exists in C:. So get a lock on C:, so get a lock * on the c: directory for later use. */ lock = Lock("c:", ACCESS_READ) ; if (lock == -1) return 0 ; } } /* * At this point, lock is a lock on the directory that we were * run from (well, one hopes that, anyway). So we turn that * into a path name, then combine the two correctly. */ status = getpath(lock, pathbuf) ; UnLock(lock) ; if (status) return 0 ; /* * We now have a directory name known to be in canonical form, * and the name of a file that isn't canonical, but can be found * in that directory. So we canonicalize the catenation of the two. * * Step one: deal with ":". Note that getpath has the noxious habit * of returning "dev", instead of the more proper "dev:". This leaves * four cases: * * *myname : ? * * status * true add ':' to pathbuf add ':' to pathbuf * false ip = strchr(pathbuf, ':') add '/' to pathbuf * * both above need myname += 1 * * "add x to pathbuf" means ip = memchr(pathbuf, '\0', FMSIZE) * and *ip = x */ status = (ip = strchr(pathbuf, ':')) == NULL ; if (*myname == ':' && !status) myname += 1 ; else { ip = strchr(pathbuf, '\0') ; *ip = status ? ':' : '/' ; if (*myname == ':') myname += 1 ; } /* * Step two: Deal with "//" in the non-canonical path. Since * pathbuf now holds a valid "dev:" string plus some canonical * path from it, and myname a path from that directory down, that's * all we have to worry about. Actually, we ought to put in a check * for *myname == '/' && *ip == ':' (meaning we're trying to back up * over the device), but that should never happen. */ for (;*myname; myname += 1) if (*myname == '/' && *ip == '/') /* double '/', get rid of one of them! */ while (*--ip != '/' && *ip != ':') ; else *++ip = *myname ; return 1 ; } -- Il brilgue: les toves lubricilleux Mike Meyer Se gyrent en vrillant dans le guave, mwm@berkeley.edu Enmimes sont les gougebosqueux, ucbvax!mwm Et le momerade horsgrave. mwm@ucbjade.BITNET
toebes@sas.UUCP (John Toebes) (07/21/89)
One thing that seems to be forgotten in this discussion is that it is entirely possible that a commands has no 'inherant' path. Take for example a resident command (written in C and made residentable) that is on the resident list. When it is run, there is no path that it came from... The only way to work in the presence of the various shells (which may have hidden paths such as WShell) is to utilize the (admiditly ugly) method of creating an overlay program which WILL retain an open handle on the original file. This has the one problem of not being able to locate the directory as all you have is a file handle. Converting from a file handle to a lock is not a legal operation (currently)... However you do have the ability to store information as part of the file itself. Have you considered environment variables??? :-) :-) :-) -- |0|\ John A. Toebes, VIII usenet:..mcnc!rti!sas!toebes |.|/ Coordinator of The Software Distillery BBS: (919)-471-6436 === Bix: JTOEBES Plink: JTOEBES CI$:"sorry Charlie"
doug@xdos.UUCP (Doug Merritt) (07/21/89)
In article <26555@agate.BERKELEY.EDU> mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) writes: > >knew the basic algorithm implemented by Doug (thanx, Doug!) before I >asked, having done this for Unix. (You're welcome!) Me too, years ago (I did a pwd/getcwd() for V6 Unix). >To wit, Doug failed to consider a number of cases that cause problems. Ouch! Mea maxima culpa. Ok, I didn't test it thoroughly enough. But the fix (enclosed below) is much simpler than you imply. The bug in the code amounts to: if (buggy check for relative path) use Lock2Path The fix that makes it work for *all* of your counterexamples is: always get lock on path, use Lock2Path This does a little unnecessary work when we've already got the full path, but it saves some annoying code for correctly detecting relative versus absolute paths, *and* it has the virtue that it now is fully consistent, and always starts the path with the volume name, never an assigned name nor a device name. Also it is more obvious that it will work on all cases than it would be with a relative path check. >Like I said, this is a nontrivial >problem (doing it that way, anyway - I was hoping for a nicer way). Actually I'm not sure how to arrange for a much nicer way. Slightly nicer, yes, by making a lock on the executable available for cli just like for Workbench. But that's minor; the only major improvement would be if AmigaDOS left the absolute path lying around somewhere. Yet to do this, AmigaDOS would have to do the same kind of work itself. Better to skip the overhead that's usually not needed, and let the application do it in the few cases it's wanted. I *do* think that functions like my Lock2Path() should be in a standard link or shared library somewhere, to save trouble. >This problem ranks with 'more' as being "one of the worlds hardest >single-evening hacks", in that it _looks_ straightforward and simple; >it's just that to do either one right, there are lots of non-obvious >things you have to deal with. I would be surprised if anyone could sit >down and write code that dealt correctly with all the cases in a >single evening, unless you've done it before. I found out a couple of weeks ago that "more" is, as you say, much harder than it looks. Well, "less" is, anyway. If you rigidly enforce a restriction of only going forward/back by units of a page, it's not *too* bad. But as soon as you allow units of a line, and goto line number, etc, it starts getting wierd. I don't think they're in the same class. After all, this one only took me one hour yesterday, and ten minutes today to fix the bug I would've found if I'd had more time for testing (I was in a hurry to get to work by 10:00am yesterday). And aside from comments, it's relatively short. If Lock2Path() were available in a library, as it should be, it would be positively trivial (once we understand about both WBenchMsg *and* cli_CommandName). Doug P.S. Thanks for the gentle phrasing of your bug report. ------------------------ CUT HERE ---------- CUT HERE -------------------- /* * whence 2.0 -- Example program: show full path of executable from whence * the current process was launched from. Works under both CLI and * Workbench. This version works on all relative paths as well as absolute. * * Thanks to Josh Rovero for pointing out that the info needed for * working under CLI was available in cli_CommandName. * * Written because Mike Meyer wanted it. Happy to oblige, Mike. * * (Mike pointed out what looked like a major bug involving relative * paths in the first release yesterday. A minor logic change fixed that. * Mea Maxima Culpa. But hey, that's what I get for trying to release code * I wrote and tested before nine in the morning. Hmmm...it's 8:30am now :-) * DRM Fri Jul 21 08:36:11 PDT 1989 */ /* * Copyright 1989 Doug Merritt. License to use hereby granted. * {pyramid,apple}!xdos!doug * (408) 370-7875 */ /* * Compiled under Manx Aztec C V3.6A * cc -Iinclude: whence.c * ln -o whence whence.o -lc * * Note use of BufRound() macro instead of allocated memory; this * is widely useful. * Also the Lock2Path() function is very handy. * * Please retain my copyright notice if/when you borrow this code. */ #include "libraries/dos.h" #include "libraries/dosextens.h" #include "workbench/startup.h" #include "stdio.h" /* * RoundUp0 -- ceiling (yields 0 if n % TO == 0) * BufRound -- given buffer address, rounds up to word boundary */ #define RoundUp0(N,TO) ( (TO - (((ULONG)N) & (TO-1)) ) & (TO-1)) #define BufRound(BUF) &BUF[ RoundUp0(BUF,4) ] /* * convert BSTR to C string */ char * bstr2str(d, bs) char *d; unsigned long bs; { char *s; int len; s = (char *) (bs << 2); len = *s++ & 0xff; while (len-- > 0) *d++ = *s++; *d = '\0'; } /* * convert file lock to a full path */ Lock2Path(curlock, pathbuf) struct FileLock *curlock; char *pathbuf; { #define LOCKSTACKSIZE 128 struct FileLock *locklist[LOCKSTACKSIZE]; UBYTE Ibuf [ sizeof(struct FileInfoBlock) + 4]; struct FileInfoBlock *Ifib; int i; char *s, *path; extern struct FileLock *ParentDir(); Ifib = (struct FileInfoBlock *) BufRound(Ibuf); if (!Examine(curlock, Ifib)) return(0); /* * find full path name; build LIFO stack of * pushed locks; when full use popped locks with * Examine() to get each name in path. */ for (i=0; i<LOCKSTACKSIZE; i++) { locklist[i] = curlock; if (!(curlock = ParentDir(curlock)) ) break; /* normal loop exit */ } path = &pathbuf[0]; if (i >= LOCKSTACKSIZE) { printf("Too many subdirectories\n"); *path++ = '?'; *path++ = '/'; --i; } /* * concatenate each component of path */ if (!Examine(locklist[i--], Ifib)) goto wierd; for (s=Ifib->fib_FileName; *s; ) *path++ = *s++; *path++ = ':'; while (i >= 0) { if (!Examine(locklist[i], Ifib)) goto wierd; for (s=Ifib->fib_FileName; *s; ) *path++ = *s++; if (i>0) *path++ = '/'; --i; } *path = '\0'; return(path - &pathbuf[0]); wierd: *path++ = '?'; *path++ = '/'; *path = '\0'; return(path - &pathbuf[0]); } /* Lock2Path() */ /* * get head of path by chopping off tail (delete anything after : or /) */ head(s) char *s; { char *start; if (!*s) return(0); start = s; while (*s) ++s; while (*s != ':' && *s != '/') { if (s == start) return(0); --s; } *++s = '\0'; return(1); } main(argc, argv) int argc; char **argv; { struct Process *proc; struct CommandLineInterface *cli; extern struct Process *FindTask(); extern struct WBStartup *WBenchMsg; extern struct FileLock *Lock(); char buf[256]; FILE *f; if (!argc) { /* minimal workbench support; this is only an example! */ if ((f = fopen("CON:0/0/640/200/whence", "w")) == NULL) exit(20); if (!Lock2Path(WBenchMsg->sm_ArgList[0].wa_Lock, buf)) { fprintf(f, "Error\n"); Delay(150L); exit(10); } fprintf(f, "%s\n", buf); Delay(150L); /* delay 3 seconds to see example results */ fclose(f); exit(0); } else { /* cli support */ struct FileLock *lock; proc = (struct Process *) FindTask(0L); cli = (struct CommandLineInterface *) ( ((long) proc->pr_CLI) << 2); bstr2str(buf, cli->cli_CommandName); lock = Lock(buf, ACCESS_READ); if (!Lock2Path( lock, buf)) { printf("No current dir?\n"); exit(10); } UnLock(lock); head(buf); printf("%s\n", buf); } } -- Doug Merritt {pyramid,apple}!xdos!doug Member, Crusaders for a Better Tomorrow Professional Wildeyed Visionary
mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/22/89)
In article <1114@sas.UUCP> toebes@sas.UUCP (John Toebes) writes:
<One thing that seems to be forgotten in this discussion is that it is
<entirely possible that a commands has no 'inherant' path.
No, that's not forgotten. I've been assuming that if there isn't a
file in the file system from which the binary came, you have to give
up. Nothing else to do, and no way around it.
It's also pretty obvious that checking the search path for a file that
matches your name may not return the right name. But that
approximation is better than nothing. Especially when I want it to
replace similar code for Unix in a port :-).
<mike
--
[Our regularly scheduled .signature preempted.] Mike Meyer
The Amiga 1000: Let's build _the_ hackers machine. mwm@berkeley.edu
The Amiga 500: Let's build one as cheaply as possible! ucbvax!mwm
The Amiga 2000: Let's build one inside an IBM PC! mwm@ucbjade.BITNET
peter@sugar.hackercorp.com (Peter da Silva) (07/22/89)
In article <7359@cbmvax.UUCP>, daveh@cbmvax.UUCP (Dave Haynie) writes: > This is actually a case in which Workbench > does a better job than CLI. The Workbench startup message has LOTS of advantages over the CLI. For one thing, the WBArgs structure is a lot closer to an ARGV: there's no limit to thenumber of files, etc... More importantly, it works a lot more reliably in a lot more environments. CLI/Execute is hard to use and easy to break. I have one BIG wish for 1.4. It doesn't require any code changes. It just requires a documentation change: In the WBArgs structure, document it that the LOCK may be 0, and if it is the corresponding argument may not be a valid file name... i.e., an option or a filename with embedded wildcards. In the WBStartup structure, if sm_ToolWindow is NULL, then there's an extra two BPTRs at the end of the structure, that are intended to correspond to Input() and Output(). This will allow the Workbench to be expanded into a true shell. If you do this, I'll *write* a shell that uses WBStartup structures, and a C startup that will build a REAL argv/argc out of it... See 'launch' for further details. -- Peter "Have you hugged your wolf today" da Silva `-_-' ...texbell!sugar!peter, or peter@sugar.hackercorp.com 'U`
peter@sugar.hackercorp.com (Peter da Silva) (07/22/89)
In article <432@xdos.UUCP>, doug@xdos.UUCP (Doug Merritt) writes: > The only case I can see that would fail is when someone gets some code > going using loadseg() explicitly, which (as far as I know, anyone want > to correct me?) does not save the executable's name anywhere. Well, Browser and Launch use LoadSeg, but they then produce a WBStartup message, so everything's copacetic. (What does Copacetic mean, anyway?) -- Peter "Have you hugged your wolf today" da Silva `-_-' ...texbell!sugar!peter, or peter@sugar.hackercorp.com 'U`
aleks@well.UUCP (Brian J. Witt) (07/24/89)
Yes, you might have problems when using a script, but try this out and see how far you get. If your program was launched under CLI or Shell (true programs officially from CA), then: myproc->pr_CLI->cli_CommandName is a BSTR to the path used to invoke your program as typed in on the command line. If there are now path seperators here, then the program was in the current directory (a quick Lock() should answer that question). If the lock fails, then walk the path seglist in: myproc->pr_CLI->cli_CommandDir attempting locks on the path directories. You can try this right now by running one program using an explicit path. In another CLI type, status full . Check out those paths!!! Danger Will Robinson!!!!! The prophets have announced that AmigaDOS will receive some serious changes in the next few years. As such, the sturctures named here may wither and die. The best long-term solution may be to ask for a DOS function call to return the lock. For short term, allow this method to work while SysBase->version < 40... If program private resources are ever to become reality (ala Mac), then this function call must be available. Danger Will Robinson!!!!! If you program came into being from some one LoadSeg()ing-CreateProc()'ing, chances are there won't be a CLI structure. At that point, you're just an orphan... :-( --- When you re-zone vacate cemetry land for apartment buildings, do you have to notify the next of kind of those buried nearby? --- brian witt --- well!aleks@ucbvax.Berkeley.EDU
thad@cup.portal.com (Thad P Floryan) (07/24/89)
Re: Peter da Silva's question ... In my Funk & Wagnall's " co-pa-set-ic (pronunciation glyphs) See copesetic. co-pe-set-ic ( "" ) adj. Slang. tip-top; first-rate; excellent; fine: said of one's condition: also spelled copasetic. Also copesettic. [US coinage, circa 1930] " Thad Floryan [ thad@cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]