getting absolute pathname from pathname

Started by cormullion, March 21, 2006, 04:33:17 AM

Previous topic - Next topic

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

#1
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

#2
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

#3
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

#4
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

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



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 "00" 256))

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


Lutz



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

pjot

#6
Nice trick! On Slackware I have to do this:




(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:


Quote
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

#7
... 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

#8
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

#9
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

#10
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

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



Lutz

cormullion

#12
Quote from: "Lutz"... 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:


QuoteNAME

     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

#13
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

#14
Quote
Can you access the 'realpath' command using the same 'import' method that you gave above?


yes ...



> (import "libc.dylib" "realpath")
realpath <90048E40>
> (set 'res (dup "00"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