getting the path to the executing program

oleg at pobox.com oleg at pobox.com
Fri Jan 9 19:26:33 EST 2004


Hal Daume wrote:
> is there a function, related to getProgName, which returns the (absolute)
> path to the current program?

> basically, i want to be able to read a file which i know will be in the
> same directory as the current program, but not necessarily in the same
> directory that we're running it from.

Actually, if you want to read a file located in the same directory
as the executable itself, you don't need the absolute path of the
executable. You merely need any path to the executable that is valid with
respect to the working directory at the start-up time.

Some four years ago I wrote a similar code that seems to work reliably
across HP/UX, Solaris, Linux, FreeBSD and various versions of Winxx
(from Windows98 onwards). The application has been deployed in more
than thousand copies and nobody has complained regarding the path.
The application reliably finds the name of a file from the
application's own directory no matter how the application was invoked:
from its own directory by name, from its own directory as "./appname",
from its own directory by the absolute or relative (../dir/appname)
name, or from some other directory by the absolute or relative name,
or by a symbolic link.

The only assumption is that neither forward nor backward slash can
appear in a file path. The latter assumption seems to always hold on
Winxx, which takes the forward slash as a path delimiter too. On
Unixen, the backward slash in file names seems to appear only on
hacked systems. So, the failure of the approach in that case should be
considered a feature.

The algorithm is simple: remove the last path-component from argv[0]
and append the local file name to the result (which may be an empty
string). A path component is a sequence of characters that does not
contain a path delimiter. Note that argv[0] may not end in a path
delimiter.

The algorithm requires argv[0] as it is given by the OS. Alas, neither
GHC nor Hugs seem to give us that. Therefore, I'm inclosing the Scheme
code that implements the algorithm. I do not have the guts to post the
original code (which was in Perl).

If I may suggest, a Haskell implementation may want to give a
programmer a way to obtain the unmangled argv0.


; last-delimiter STR -> POS
; where POS is the location of the last path-delimiter in STR
; or #f

(define delimiters '(#\\ #\/))

(define (last-delimiter str)
  (let loop ((i (- (string-length str) 1)))
    (cond
      ((negative? i) #f)
      ((memv (string-ref str i) delimiters) i)
      (else (loop (- i 1))))))

(define local-file-name "that-is-it")

; Like with-input-from file, but the file
; is assumed to be in the same directory as the executable
; itself
(define (with-input-from-local-file local-file-name thunk)
  (let* ((argv0 (car (command-line)))
	 (last-delim (last-delimiter argv0)))
    (with-input-from-file
      (if last-delim
	(if (< (+ 1 last-delim) (string-length argv0))
	  (string-append (substring argv0 0 (+ 1 last-delim))
	    local-file-name)
	  (error 'with-input-from-local-file
	    "path-delim at the end of argv0: " argv0))
	local-file-name)
      thunk)))

(display (with-input-from-local-file local-file-name read))
(newline)



More information about the Haskell mailing list