dirname wanted

Started by scratchy, August 16, 2004, 06:43:38 AM

Previous topic - Next topic

scratchy

Ok, here is a question:



If I am writing several scripts, and I want to put reusable definitions into a separate file, for instance:



  /home/scratchy/bin/a.lsp <-- one script

  /home/scratchy/bin/b.lsp <-- another script

  /home/scratchy/lib/common.lsp <-- reusable stuff



Obviously, in a.lsp and b.lsp I need to locate common.lsp, soft of:



  (load (sting (dirname (nth 1 (main-args))) "../lib/common.lsp"))



[correct me if I'm wrong]. However, I wasn't able to find any built-in "dirname" function. If it's not built-in => I would have to implement it myself => I can't put it into common.lsp because I need it before any file is loaded. Duplicating dirname in the beginning of each script is plain ugly. So is there an elegant solution to this problem?

Lutz

#1
newLISP looks for init.lsp in /usr/share/newlisp/init.lsp on Linux/UNIX or in the newLISP startup directory on Win32. The stuff you find in init.lsp from the distribution is not really required and you can throw it out and replace it with your own stuff.



You could put (load "common.lsp") into your init.lsp file or put those common functions directly into it. This would be one of many ways to get dirname:



(define (dirname path) (if (regex "(.*/).*" path) $1 "./"))



(dirname "/usr/etc/bashrc") => "/usr/etc/")



by default regex is 'greedy' so it will always get as much as it can toward the end of the path. To pick out the filename you could use:



(define (basename path) (last (parse path "/")))



(basename "/usr/etc/bashrc") => "bashrc")



Lutz



Ps: here is another one



(define (dirname path) (join (chop (parse path "/")) "/"))

Lutz

#2
... and of course you always can do:



(first (exec (append "direname " pathFile))) => "/home/scratchy"



(exec ...) can run any program/tool chains and returns stdout in a list of strings



Lutz

scratchy

#3
So it would take something like this:



    (define (dirname path)

        (if (= (& (nth 7 (sys-info)) 0x0F) 6)

            (if (regex "(.*\\).*" path) $1 ".\")

            (if (regex "(.*/).*" path) $1 "./")))



    (define *script-dir* (dirname (nth 1 (main-args))))



in the beginning of each script to be able to include an external script:



    (load (string *script-dir* "../lib/common.lsp"))



I haven't tested this implementation of dirname enough to guarantee that it works everywhere, but having to duplicate the code it is not cool. What else can I do to convince you that dirname should be a built-in?

Lutz

#4
Actually you don't need to use backslash on Win32. Even with drive specifiers it is ok as in "c:/somedir/somefile" . Although the Win32 command shell does not allow forward slash for directory specs it is perfectly legal to do it from programs.



Lutz

scratchy

#5
Quote from: "Lutz"Actually you don't need to use backslash on Win32...

Lutz


??? This information does not help. How about the dirname built-in?

Lutz

#6
I think it is just not used frequently enough. You far more compose path-filenames from their parts, than the other way around. Most popular scripting languages only offer it in a module. In Perl you have to use the File:Basename module, in Python you would have to use the OS.path module.  Just put it in your init.lsp.



Lutz

HPW

#7
>but having to duplicate the code it is not cool.



What's wrong with Lutz advice? When you put your own tools in the initialisation lsp, then you can use it from every of your own scripts.

No duplicate code neccesary. I use this technic to load a compatibility layer to another lisp-dialect.





"Lisp is a programmable programming language."

- John Foderaro, CACM, September 1991



from http://www.paulgraham.com/quotes.html">http://www.paulgraham.com/quotes.html
Hans-Peter

scratchy

#8
What's wrong with Lutz advice is that I don't want to write scripts that will work only with my init.lsp.[/quote]

nigelbrown

#9
I would put the define at the front of the script in that case.



Nigel

scratchy

#10
Thank you. That brings us back to my point #2 above.

nigelbrown

#11
Hi Scratchy

I guess I'm not clear on why you want dirname.

(load "./lib/common.lsp")  will load from the current directory's lib subdirectory.

Where do you want common.lsp to be? (Apologies for being a bit dense here

I've not thought through your above code completely)



Regards

Nigel

Lutz

#12
This one works for both  and / as path separator and on Win32 and Linux/UNIX OS:



(define (dirname path)

  (join (chop (parse path "/|\\" 0)) "/"))



Just put it in whatever file you need it. 'dirname' is just not used and asked for enough to include in newLISP.



Lutz

scratchy

#13
Quote(load "./lib/common.lsp")  will load from the current directory's lib subdirectory.


Current directory is variable. But the script should be able to figure out where it is located in the filesystem, and without 'dirname', it's impossible to do.


QuoteWhere do you want common.lsp to be?


Anywhere, at a fixed relative path (e.g. "../lib") to a.lsp and b.lsp. Equivalent functionality in sh can be achieved via:



   #!/bin/sh

   source `dirname $0`/../lib/common.sh



The philosophy of sh is to use external programs as much as possible, that is why dirname is not a built-in function in sh.

scratchy

#14
By the way, clisp has a built-in 'directory-namestring', which is essentially 'dirname', I was asking for in newLISP:



    (defconstant *script-dir* (directory-namestring *LOAD-PATHNAME*))



    (load (concatenate 'string *script-dir* "../lib/common.lsp"))



There you go.