getting absolute pathname from pathname

For the Compleat Fan
Locked
cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

getting absolute pathname from pathname

Post by cormullion »

I'm trying to find out what the 'real' pathname of a file would be. For example, given :

././temp.txt

I'd like to convert it to:

/Users/me/Documents/Junk/temp.txt

Is there a way to do this in newLISP? I found a Unix command 'realpath', but no way to do it without calling out using exec.

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Hi Cormullion,

With the command (directory) it is impossible to find the name of the current directory you are in. You only will see the files and subdirectories in the current directory. If you go 1 directory higher, it is impossible to see the name of the directory you came from.

With (directory?) you can make a query, and compare the contents of the current directory with the contents of a subdirectory. Still you are never sure if the queried directory is the same directory as you are in.

In other words: to get an absolute reference for "../temp.txt" without using '!' or 'exec' is very hard :-), if not impossible...

Peter


PS Lutz: the codesnippet "Show Directory Tree" at the "Tips&Tricks" section does not work.

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Thanks, Peter. I'm hoping Lutz can find a way to do the impossible! ;-)

The show-tree example seems to work, if you call it with a directory:

(show-tree "/Users/me/Documents")

And, if you copy from the web page into a text editor like BBEdit, make sure you remove all the non-ASCII codes first!

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

Well actualy you must interact with the shell eventualy i guess.. because thats
what newlisp does too (underwater)

The same goes for ~/ which could be intepreted as $HOME but it depends on the shell below..

But on both newlisp does not return a name.. neighter on ../../ nor on ~/ so you have to fiddle with the shell i guess.

I there is another way..Im pleased to see that ;-)

A way to do that is:

(exec "pwd") that returns you current working directory
Then count the ammount of "/" you awant to go back "../../"
(including current dir) If that is true with 'pwd" string output
then chop off those from your string. I think its quick with a regex..

Norman.
-- (define? (Cornflakes))

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Perhaps I shouldn't worry about the shell calls as much - but I always thought that an 'exec' type call was going to be slower than a direct call. Perhaps there's too little speed difference to worry these days.

I don't think the (exec "pwd") will work. The working directory seems to stay the same for the whole script, even though a recursive function may be 20 levels down...

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Try importing the 'C' function getwd() instead and supply a buffer parameter:

Code: Select all

newLISP v.8.8.0 on BSD, execute 'newlisp -h' for more info.

> (import "libc.so" "getwd") ; on MacOS X use "libc.dylib"
getcwd <2814C114>
> (set 'dir (dup "\000" 256))

> (get-string (getwd dir))
"/usr/home/lutz"
Lutz

ps: this works on both: MacOSX with libc.dylib and FreeBSD with libc.so

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Nice trick! On Slackware I have to do this:

Code: Select all


(set 'dir ".")
(import "/lib/libc-2.3.5.so" "getcwd")
(println (get-string (getcwd dir 256)))

But it is not secure, as the manpage mentions:
The pathname shall contain no components that are symbolic links.
Also it prints the location where I am currently, not where the script is. So if I am at "/home/peter" and I execute the script like "some/dir/else/script.lsp" the command will show "/home/peter". Then it is difficult to find the absolute path of a file called "../../file.txt".

The directory stuff uses <sys/types.h> and <dirent.h>. There is no API for finding the current dir of the script. In C programming you can parse argv[0] to find the current dir of a binary. But still it would show a "./bla" or something like that; so a relative pathname.

So if you do not startup your newLISP program with a full path, also (main-args) does not help you.

Maybe the only way is put your newLisp program in a fixed directory and put the location of this directory hard-coded into your program and take that as starting point to get a fixed dir. (Probably no programming language can workaround this?)

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

... but shouldn't you reserve memory for the 'dir' buffer? From the getcwd() man page:

"The getcwd() function copies the absolute pathname of the current working directory into the memory referenced by buf"

At least on MacOS X and FreeBSD getcwd() and getwd() copy the directory name into the buffer variable. Initializing with (set 'dir ".") will only reseve one byte of memory.

Lutz

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Ah yes, you are right there, I forgot to do that, it's also needed in Linux.... Still the program doesn't crash if I don't, even when allowing 256 bytes. That's weird.

Peter

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Thanks! I think I can build the full pathname from the relative name I'm getting from the recursive scanning, and adding the working directory to the front of it. I think.

Looks good. Would make a nice addition to newLISP built-in library ... :-)

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Yes, we will have a built-in function for it. It needs very little code to implement, too many people again and again have asked for it It will be 'cwd' for (c)urrent (w)working (d)directory

Lutz

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

... or perhaps it should be 'current-dir' to be more consistent with the naming of other directory functions.

Lutz

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Lutz wrote:... or perhaps it should be 'current-dir' to be more consistent with the naming of other directory functions.
Excellent, thanks!

Can you access the 'realpath' command using the same 'import' method that you gave above? man page starts:
NAME
realpath -- returns the canonicalized absolute pathname

LIBRARY
Standard C Library (libc, -lc)

SYNOPSIS
#include <sys/param.h>
#include <stdlib.h>

char *
realpath(const char *pathname, char resolved_path[PATH_MAX]);

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

Actualy lutz... Perhaps you can bring that option under

or directory? or directory

That keeps then a little together..

I Like (directory? "cwd") more then (cwd)

Just a tip..



Uhum... perhpas not a good idea ;-)

> (directory? "cwd")
nil
> (make-dir "cwd")
true
> (directory? "cwd")
true
>
-- (define? (Cornflakes))

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Can you access the 'realpath' command using the same 'import' method that you gave above?
yes ...

Code: Select all

> (import "libc.dylib" "realpath")
realpath <90048E40>
> (set 'res (dup "\000"256))

> (get-string (realpath "./newlisp" res))
"/Users/lutz/newlisp/newlisp"
> (get-string (realpath "." res))
"/Users/lutz/newlisp"
> 
may be 'realpath' has more usage than 'current-dir' taking the additional argument. One could make (realpath) the default for (realpath ".")?

But checking the history of 'realpath' it seems it did not appear until FreeBSD 4.3, which is fairly recent.

Lutz

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Code: Select all

newLISP v.8.8.3 on OSX UTF-8, execute 'newlisp -h' for more info.

> (realpath)
"/Users/lutz/newlisp-8.8.3"
> (realpath "~/newlisp")
nil
> (realpath "./newlisp")
"/Users/lutz/newlisp-8.8.3/newlisp"
> (realpath "../newlisp")
"/Users/lutz/newlisp"
> (realpath "newlisp.c")
"/Users/lutz/newlisp-8.8.3/newlisp.c"
> (realpath ".")
"/Users/lutz/newlisp-8.8.3"
> (realpath "..")
"/Users/lutz"
> 
realpath history:

FreeBSD: 4.3
Linux: libc 4.5.4
The libc4 and libc5 implementation contains a buffer overflow (fixed in libc-5.4.13).
Solaris: at least since 1999

Lutz

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Yes! I think that's great. Even easier to use than getwd/current-dir, and very useful for me.

statik
Posts: 58
Joined: Thu Apr 14, 2005 1:12 am

Post by statik »

Any idea when (cwd) is gonna make into newlisp? Next release? Release after that? Eventually?

Also, PWD is an environtment variable, and you can clearly see that by doing the following at the command line:

Code: Select all

$ set
Is there a reason why (env) does not utilize ALL available environment variables?
-statik

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Doesn't real-path do this (cwd) for you?

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Yes, look into 'real-path in 8.8.3, its like a 'cwd' on steroids because it also translates relative paths (based on UNIX realpath). A 'cwd' would be (real-path) or (real-path "."), which is the same.
is there a reason why (env) does not utilize ALL available environment variables?
When Unix starts a process, i.e. newLISP, it supplies it only with a subset of environment variables. What you see using 'env' is all you have avaiable in your process space, but you could use the following method to get all environment variablers in the shell you are running:

Code: Select all

(map (fn (e) (parse e "=")) (exec "set"))
This gives you an association list:

Code: Select all

(
...
("BASH_VERSION" "'2.05b.0(1)-release'") 
("DIRSTACK" "()") 
("EUID" "501") 
("GROUPS" "()") 
("HOME" "/Users/lutz") 
...
)
and you could use 'lookup' on it to get a certain value:

Code: Select all

> (set 'my-env (map (fn (e) (parse e "=")) (exec "set")))

> (lookup "PPID" my-env)
"29039"
> 
Lutz

statik
Posts: 58
Joined: Thu Apr 14, 2005 1:12 am

Post by statik »

I didn't realize you had implemented realpath into the latest dev... I'll check it out. Thanks.
-statik

statik
Posts: 58
Joined: Thu Apr 14, 2005 1:12 am

Post by statik »

Does anyone know how I can get the cwd of the file being executed, or a way to get the cwd of any given process?

My problem is that realpath shows the working directory from where newlisp was started.

Example:

Code: Select all

$ pwd
/home/statik/
$ cat code/test.lsp
(println (real-path))
(exit)
$ newlisp code/test.lsp
/home/statik/
$
I'd like a way to find the current working directory of the script being executed. Any ideas?
-statik

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

The location of the script is always the second member in (main-args):

Code: Select all

~> pwd
/Users/lutz
~> cat /usr/bin/mytest
#!/usr/bin/newlisp

(println "real-path -> " (real-path))
(println "script caller -> " (main-args 0))
(println "script -> " (main-args 1))

(exit)

~> mytest

real-path -> /Users/lutz
script caller -> /usr/bin/newlisp
script -> /usr/bin/mytest
~> 
Lutz

statik
Posts: 58
Joined: Thu Apr 14, 2005 1:12 am

Post by statik »

That's fine and all, but how does one handle files that are loaded via (load)? How do those file determine where they are?
-statik

Locked