POSIX command line argument processing

Started by TedWalther, July 22, 2011, 02:19:18 AM

Previous topic - Next topic

TedWalther

I have made a module called "getopts".  It doesn't use its own context.  I don't think it needs to.  If people can try it out, it does the following:



It parses command line options in the following forms:



-f filename
-ffilename (-f filename)
-avh (-a -v -h)
-avfboo (-a -v -f boo)
--long-option
--long-option with-argument
--long-option=with-argument (--long-option "with-argument")
-- (everything after -- is ignored)


Anything that is not an option, or an argument to an option, is just accumulated to a list.  At the end of the option processing, this accumulated list is returned for your own custom processing.



There is just one possible glitch.  I start the argument parsing at index position 2 of main-args.  For my scripts, this works well.



As a bonus, the way it is set up, the "usage" function, automatically lists all the options that you have specified.  Also, unlike in C, you don't call getopt repeatedly.  The getopts function does it all in one pass.  Here is an example of how to use it:



(module "getopts.lsp")

(short-opt "v" (++ verbosity) nil "Increase verbosity")
(short-opt "q" (setq verbosity 0) nil "Quiet")
(short-opt "?" (usage) nil "Print this usage message")
(short-opt "h" (usage) nil "Print this usage message")
(short-opt "o" (setq output-file arg) "file" "Output file")
(long-opt "help" (usage) nil "Print this usage message")
(long-opt "quiet" (setq verbosity 0) nil "Quiet")
(long-opt "verbose" (++ verbosity) nil)
(long-opt "output" (setq output-file arg) "file" "Output file")

(println (getopts)) ; this shows the command line datum that weren't options
(println "Verbosity: " verbosity)
(println "Output To: " output-file)
(exit)


Example usage:



$ ./test.lsp --output foo -obar -v --quiet -vv arg1 arg2
("arg1" "arg2")
Verbosity: 2
Output To: bar


There is just one issue.  If I pass an argument to newlisp, it changes the starting point for processing in main-args.  I see no way to detect this.



#!/usr/bin/newlisp

$ ./test.lsp foo bar
main-args: "/usr/bin/newlisp" "./test.lsp" "foo" "bar"

#!/usr/bin/newlisp -m 50 -s 1024

$ ./test.lsp foo bar
main-args: "/usr/bin/newlisp" "-m 50 -s 1024" "./test.lsp" "foo" "bar"


See how it differs?  Wouldn't it be better if there was an empty string there always, in index position 1, if there are no arguments passed to the newlisp interpreter?
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

Lutz

#1
Different UNIX behave differently on how they treat arguments in the #! line of a script file:



With this "args" program:

#!/usr/bin/newlisp -m 50 -s 1024

(println (main-args))

(exit)

you get different output on different platforms:



on Mac OSX:

~> ./args foo bar
("/usr/bin/newlisp" "-m" "50" "-s" "1024" "./args" "foo" "bar")

on FreeBSD, OpenBSD and Linux:

~> ./args foo bar
("/usr/bin/newlisp" "-m 50 -s 1024" "./args" "foo" "bar")

Only Mac OSX does it "correctly". newLISP just passes on whatever the argv[] array is offered by the standard libraries and C startup code, assuming that this is the excpected behavior on that platform.



But I don't think it really matters, because starting with the script name "./args" the structure of the list is the same.

TedWalther

#2
Thank you for that feedback.  I am modifying the getopts function so now you have to pass in the list of arguments.  That will allow it to work across all platforms.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

TedWalther

#3
I have updated the getopts module, and anyone can now download and test it here:



http://dpkg.reactor-core.org/modules/">http://dpkg.reactor-core.org/modules/



I hope that everyone finds it useful.  Especially if you want to distribute a newlisp script as a commandline utility, this module makes it easy to support the GNU coding standards, and pass information into your script through the command line.



Please look at it, test it, and comment.  I included sample code so you can cut and paste to get started.



Ted
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.