August 07, 2013
On Wed, 07 Aug 2013 09:13:03 +0200
"Tommi" <tommitissari@hotmail.com> wrote:

> On Wednesday, 7 August 2013 at 05:31:24 UTC, Alan wrote:
> > Hello!  This may seem like a simple question, maybe an embarassing question but how would I fetch the absolute path to the directory where my executable is located?  My wording is known to be confusing so I will give an example:
> >
> > cd ~/projects/program
> > dmd Program.d -ofProgram
> >
> > That executable would be located in /home/alan/projects/program for example.  SO my question is how would I fetch the absolute path to that directory?
> >
> > Thanks for any help!
> 
> This should work on at least couple of systems, but I haven't tested this on other than Mac. Also, it's not completely robust, because paths could be longer than 4096 chars.
> 
> version(Windows) {
>      import std.c.windows.windows;
> }
> else version(OSX) {
>      private extern(C) int _NSGetExecutablePath(char* buf, uint*
> bufsize);
> }
> else version(linux) {
>      import std.c.linux.linux;
> }
> else {
>      static assert(0);
> }
> import std.conv;
> 
> // Returns the full path to the currently running executable
> string executablePath()
> {
>      static string cachedExecutablePath;
> 
>      if (!cachedExecutablePath) {
>          char[4096] buf;
>          uint filePathLength;
> 
>          version(Windows) {
>              filePathLength = GetModuleFileNameA(null, buf.ptr,
> buf.length - 1);
>              assert(filePathLength != 0);
>          }
>          else version(OSX) {
>              filePathLength = cast(uint) (buf.length - 1);
>              int res = _NSGetExecutablePath(buf.ptr,
> &filePathLength);
>              assert(res == 0);
>          }
>          else version(linux) {
>              filePathLength = readlink(toStringz(selfExeLink),
> buf.ptr, buf.length - 1);
>          }
>          else {
>              static assert(0);
>          }
>          cachedExecutablePath = to!string(buf[0 ..
> filePathLength]);
>      }
>      return cachedExecutablePath;
> }
> 
> // Returns the file name of the currently running executable
> string executableName()
> {
>      return executablePath().baseName();
> }
> 
> // Returns the path to the directory of the currently running
> executable
> string executableDirPath()
> {
>      return executablePath().dirName();
> }

Yes, this is the way to do it. Never use args[0]: it's useless as it
doesn't follow symlinks (might not even follow aliases, though I'm
not certain), and strictly-speaking can't even be guaranteed to be
correct at all anyway. If it were up to me, args[0] would be eliminated
outright.

August 10, 2013
On Wed, Aug 07, 2013 at 12:55:10PM -0400, Nick Sabalausky wrote:
> On Wed, 07 Aug 2013 09:13:03 +0200
> "Tommi" <tommitissari@hotmail.com> wrote:
> 
> > On Wednesday, 7 August 2013 at 05:31:24 UTC, Alan wrote:
> > > Hello!  This may seem like a simple question, maybe an embarassing question but how would I fetch the absolute path to the directory where my executable is located?  My wording is known to be confusing so I will give an example:
> > >
> > > cd ~/projects/program
> > > dmd Program.d -ofProgram
> > >
> > > That executable would be located in /home/alan/projects/program for example.  SO my question is how would I fetch the absolute path to that directory?
> > >
> > > Thanks for any help!
> > 
> > This should work on at least couple of systems, but I haven't tested this on other than Mac. Also, it's not completely robust, because paths could be longer than 4096 chars.
> > 
> > version(Windows) {
> >      import std.c.windows.windows;
> > }
> > else version(OSX) {
> >      private extern(C) int _NSGetExecutablePath(char* buf, uint*
> > bufsize);
> > }
> > else version(linux) {
> >      import std.c.linux.linux;
> > }
> > else {
> >      static assert(0);
> > }
> > import std.conv;
> > 
> > // Returns the full path to the currently running executable
> > string executablePath()
> > {
> >      static string cachedExecutablePath;
> > 
> >      if (!cachedExecutablePath) {
> >          char[4096] buf;
> >          uint filePathLength;
> > 
> >          version(Windows) {
> >              filePathLength = GetModuleFileNameA(null, buf.ptr,
> > buf.length - 1);
> >              assert(filePathLength != 0);
> >          }
> >          else version(OSX) {
> >              filePathLength = cast(uint) (buf.length - 1);
> >              int res = _NSGetExecutablePath(buf.ptr,
> > &filePathLength);
> >              assert(res == 0);
> >          }
> >          else version(linux) {
> >              filePathLength = readlink(toStringz(selfExeLink),
> > buf.ptr, buf.length - 1);
> >          }
> >          else {
> >              static assert(0);
> >          }
> >          cachedExecutablePath = to!string(buf[0 ..
> > filePathLength]);
> >      }
> >      return cachedExecutablePath;
> > }
> > 
> > // Returns the file name of the currently running executable
> > string executableName()
> > {
> >      return executablePath().baseName();
> > }
> > 
> > // Returns the path to the directory of the currently running
> > executable
> > string executableDirPath()
> > {
> >      return executablePath().dirName();
> > }
> 
> Yes, this is the way to do it. Never use args[0]: it's useless as it doesn't follow symlinks (might not even follow aliases, though I'm not certain), and strictly-speaking can't even be guaranteed to be correct at all anyway.

+1. If you invoke your program from the shell, it will generally be correct (though unhelpful if the program was found through $PATH, because the shell only passes the bare program name in argv[0], not the full path, leaving you having to search through $PATH all over again -- and even then, there's no guarantee the shell wasn't configured NOT to pass $PATH along: some security models recommend not doing so).

But if your program was invoked from another program, there's no guarantee at all what args[0] contains. For all you know, it could be "/path/to/rootkit/maliciousProgram.exe".


> If it were up to me, args[0] would be eliminated outright.

Naw, there are some valid use cases for it. Take a look at busybox, for example. :)


T

-- 
Не дорог подарок, дорога любовь.
August 11, 2013
On Wed, 7 Aug 2013 10:06:19 -0700
"H. S. Teoh" <hsteoh@quickfur.ath.cx> wrote:

> On Wed, Aug 07, 2013 at 12:55:10PM -0400, Nick Sabalausky wrote:
> 
> > If it were up to me, args[0] would be eliminated outright.
> 
> Naw, there are some valid use cases for it. Take a look at busybox, for example. :)
> 

Hmm, interesting tool. And you're right, I can't think of a better way than args[0] to do what it does.

In any case, Phobos needs to have this "get current executable's path" function if it doesn't already.

August 11, 2013
On Sun, 11 Aug 2013 00:45:43 -0400
Nick Sabalausky <SeeWebsiteToContactMe@semitwist.com> wrote:

> On Wed, 7 Aug 2013 10:06:19 -0700
> "H. S. Teoh" <hsteoh@quickfur.ath.cx> wrote:
> 
> > On Wed, Aug 07, 2013 at 12:55:10PM -0400, Nick Sabalausky wrote:
> > 
> > > If it were up to me, args[0] would be eliminated outright.
> > 
> > Naw, there are some valid use cases for it. Take a look at busybox, for example. :)
> > 
> 
> Hmm, interesting tool. And you're right, I can't think of a better way than args[0] to do what it does.
> 
> In any case, Phobos needs to have this "get current executable's path" function if it doesn't already.
> 

Pull request: https://github.com/D-Programming-Language/phobos/pull/1463

It's updated from an older version that I had in here: https://bitbucket.org/Abscissa/semitwistdtools/src/c7f89f7cd2c086591b544d5bffc536827ae6f763/src/semitwist/util/io.d?at=master#cl-190

1 2 3
Next ›   Last »