Rename files, add handle-command-line to simplify XCVB.
authorFrancois-Rene Rideau <fare@tunes.org>
Tue, 10 Nov 2009 13:21:06 +0000 (08:21 -0500)
committerFrancois-Rene Rideau <fare@tunes.org>
Tue, 10 Nov 2009 13:21:06 +0000 (08:21 -0500)
argv.lisp [new file with mode: 0644]
build.xcvb
command-line-arguments.asd
get-command-line-arguments.lisp [deleted file]
help.lisp [new file with mode: 0644]
parse.lisp [moved from parse-command-line-arguments.lisp with 79% similarity]
pkgdcl.lisp
test.lisp [new file with mode: 0644]

diff --git a/argv.lisp b/argv.lisp
new file mode 100644 (file)
index 0000000..96e571b
--- /dev/null
+++ b/argv.lisp
@@ -0,0 +1,61 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;                                                                  ;;;
+;;; Free Software available under an MIT-style license. See LICENSE  ;;;
+;;;                                                                  ;;;
+;;; Copyright (c) 2009 ITA Software, Inc.  All rights reserved.      ;;;
+;;;                                                                  ;;;
+;;; Original author: Francois-Rene Rideau                            ;;;
+;;;                                                                  ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#+xcvb (module (:depends-on ("pkgdcl")))
+;; let's not DEPEND on (:build "/cl-launch") since
+;; that opens a can of worm for people using ASDF.
+
+(in-package :command-line-arguments)
+
+(defun get-command-line-arguments ()
+  (if (find-package :cl-launch)
+    (symbol-value (find-symbol (string :*arguments*) :cl-launch))
+    (progn
+      #+sbcl (cdr sb-ext:*posix-argv*)
+      #+clozure (cdr (ccl::command-line-arguments))
+      #+gcl (cdr si:*command-args*)
+      #+ecl (loop for i from 1 below (si:argc) collect (si:argv i))
+      #+cmu (cdr extensions:*command-line-strings*)
+      #+allegro (cdr (sys:command-line-arguments))
+      #+lispworks (cdr sys:*line-arguments-list*)
+      #+clisp ext:*args*
+      #-(or sbcl clozure gcl ecl cmu allegro lispworks clisp)
+      (error "get-command-line-arguments not supported for your implementation"))))
+
+(defun compute-and-process-command-line-options (specification)
+  (process-command-line-options specification (get-command-line-arguments)))
+
+(defun invoke-command-line-handler (function options arguments &key
+                                    (positional-arity 0) (rest-arity nil) name)
+  (let ((l (length arguments)))
+    (unless (>= l positional-arity)
+      (error "~@[~A: ~] Too few arguments. Expected~@[ at least~] ~A, got ~A ~S"
+             name rest-arity positional-arity l arguments))
+    (when (and (> l positional-arity) (not rest-arity))
+      (error "~@[~A: ~] Too many arguments. Expected only ~A, got ~A ~S"
+             name positional-arity l arguments))
+    (let ((positional-arguments (subseq arguments 0 positional-arity))
+          (rest-arguments (when rest-arity (subseq arguments positional-arity))))
+      (apply function (append positional-arguments
+                              (etypecase rest-arity
+                                (null nil)
+                                ((eql t) (list rest-arguments))
+                                (keyword (list rest-arity rest-arguments)))
+                              options)))))
+
+(defun handle-command-line (specification function
+                            &key (positional-arity 0) (rest-arity nil) name
+                            (command-line (get-command-line-arguments)))
+  (multiple-value-bind (options arguments)
+      (process-command-line-options specification command-line)
+    (invoke-command-line-handler function options arguments
+                                 :name name
+                                 :positional-arity positional-arity
+                                 :rest-arity rest-arity)))
index 86e78f1..7af364b 100644 (file)
@@ -19,5 +19,5 @@
   :licence "MIT"
   :description "small library to deal with command-line arguments"
   :long-description "A library to abstract away the parsing of Unix-style command-line arguments"
-  :depends-on ("parse-command-line-arguments" "get-command-line-arguments")
+  :depends-on ("parse" "argv" "help")
   :build-image nil))
index b950fa6..1b054da 100644 (file)
@@ -18,5 +18,6 @@
   ;;:depends-on (:cl-launch) ; cl-launch affects the build too much for unsuspecting ASDF users.
   :components
   ((:file "pkgdcl")
-   (:file "get-command-line-arguments" :depends-on ("pkgdcl"))
-   (:file "parse-command-line-arguments" :depends-on ("get-command-line-arguments"))))
+   (:file "argv" :depends-on ("pkgdcl"))
+   (:file "parse" :depends-on ("pkgdcl"))
+   (:file "help" :depends-on ("pkgdcl"))))
diff --git a/get-command-line-arguments.lisp b/get-command-line-arguments.lisp
deleted file mode 100644 (file)
index 02af126..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;                                                                  ;;;
-;;; Free Software available under an MIT-style license. See LICENSE  ;;;
-;;;                                                                  ;;;
-;;; Copyright (c) 2009 ITA Software, Inc.  All rights reserved.      ;;;
-;;;                                                                  ;;;
-;;; Original author: Francois-Rene Rideau                            ;;;
-;;;                                                                  ;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-#+xcvb (module (:depends-on ("pkgdcl")))
-;; let's not DEPEND on (:build "/cl-launch") since
-;; that opens a can of worm for people using ASDF.
-
-(in-package :command-line-arguments)
-
-(defun get-command-line-arguments ()
-  (if (find-package :cl-launch)
-    (symbol-value (find-symbol (string :*arguments*) :cl-launch))
-    (progn
-      #+sbcl (cdr sb-ext:*posix-argv*)
-      #+clozure (cdr (ccl::command-line-arguments))
-      #+gcl (cdr si:*command-args*)
-      #+ecl (loop for i from 1 below (si:argc) collect (si:argv i))
-      #+cmu (cdr extensions:*command-line-strings*)
-      #+allegro (cdr (sys:command-line-arguments))
-      #+lispworks (cdr sys:*line-arguments-list*)
-      #+clisp ext:*args*
-      #-(or sbcl clozure gcl ecl cmu allegro lispworks clisp)
-      (error "get-command-line-arguments not supported for your implementation"))))
diff --git a/help.lisp b/help.lisp
new file mode 100644 (file)
index 0000000..3026e3c
--- /dev/null
+++ b/help.lisp
@@ -0,0 +1,43 @@
+#+xcvb (module (:depends-on ("pkgdcl")))
+
+(in-package :command-line-arguments)
+
+(defun split-sequence (sequence delimiter)
+  (loop
+     :with index = 0
+     :for match = (position delimiter sequence :start index)
+     :when (and match
+                (not (= index match)))
+     :collect (subseq sequence index match)
+     :when match
+     :do (setf index (1+ match))
+     :unless (or match
+                 (= index (length sequence)))
+     :collect (subseq sequence index)
+     :while match))
+
+(defun show-option-help (specification &key (stream *standard-output*) sort-names)
+  ;; TODO: be clever when trying to align stuff horizontally
+  (loop :with *print-right-margin* = (max (or *print-right-margin* 0) 100)
+        :for spec :in specification :do
+        (destructuring-bind (names &key negation documentation negation-documentation
+                                   type optional list (initial-value nil initial-value-p) &allow-other-keys) spec
+          (declare (ignorable negation documentation negation-documentation type optional list))
+          (unless (consp names)
+            (setf names (list names)))
+          (flet ((option-names (names)
+                   (let ((n (mapcar 'option-name names)))
+                     (if sort-names
+                       (stable-sort n #'< :key #'length)
+                       n))))
+            (when documentation
+              (format stream "~& ~32A ~8A ~@<~@;~{~A ~}~@:>"
+                      (format nil "~{ ~A~}" (option-names names))
+                      (string-downcase type)
+                      (split-sequence documentation #\Space))
+              (format stream "~:[~*~; (default: ~S)~]~%" initial-value-p initial-value))
+            (when negation-documentation
+              (format stream " ~32A ~8A ~@<~@;~{~A ~}~@:>~%"
+                      (format nil "~{ ~A~}" (option-names (make-negated-names names negation)))
+                      (string-downcase type)
+                      (split-sequence negation-documentation #\Space)))))))
similarity index 79%
rename from parse-command-line-arguments.lisp
rename to parse.lisp
index 3a59c3a..df748d6 100644 (file)
@@ -8,12 +8,10 @@
 ;;;                                                                  ;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-#+xcvb (module (:depends-on ("get-command-line-arguments")))
+#+xcvb (module (:depends-on ("pkgdcl")))
 
 (in-package :command-line-arguments)
 
-;;(declaim (optimize (speed 1) (safety 3) (debug 3)))
-
 (defvar *command-line-arguments* nil
   "a list of strings, the arguments passed to the program on its command-line,
 or what's currently left of them as they are processed")
@@ -358,79 +356,3 @@ or what's currently left of them as they are processed")
     (do-process-command-line-options)
     (values *command-line-options* *command-line-arguments*)))
 
-(defun compute-and-process-command-line-options (specification)
-  (process-command-line-options specification (get-command-line-arguments)))
-
-(defun split-sequence (sequence delimiter)
-  (loop
-     :with index = 0
-     :for match = (position delimiter sequence :start index)
-     :when (and match
-                (not (= index match)))
-     :collect (subseq sequence index match)
-     :when match
-     :do (setf index (1+ match))
-     :unless (or match
-                 (= index (length sequence)))
-     :collect (subseq sequence index)
-     :while match))
-
-(defun show-option-help (specification &key (stream *standard-output*) sort-names)
-  ;; TODO: be clever when trying to align stuff horizontally
-  (loop :with *print-right-margin* = (max (or *print-right-margin* 0) 100)
-        :for spec :in specification :do
-        (destructuring-bind (names &key negation documentation negation-documentation
-                                   type optional list (initial-value nil initial-value-p) &allow-other-keys) spec
-          (declare (ignorable negation documentation negation-documentation type optional list))
-          (unless (consp names)
-            (setf names (list names)))
-          (flet ((option-names (names)
-                   (let ((n (mapcar 'option-name names)))
-                     (if sort-names
-                       (stable-sort n #'< :key #'length)
-                       n))))
-            (when documentation
-              (format stream "~& ~32A ~8A ~@<~@;~{~A ~}~@:>"
-                      (format nil "~{ ~A~}" (option-names names))
-                      (string-downcase type)
-                      (split-sequence documentation #\Space))
-              (format stream "~:[~*~; (default: ~S)~]~%" initial-value-p initial-value))
-            (when negation-documentation
-              (format stream " ~32A ~8A ~@<~@;~{~A ~}~@:>~%"
-                      (format nil "~{ ~A~}" (option-names (make-negated-names names negation)))
-                      (string-downcase type)
-                      (split-sequence negation-documentation #\Space)))))))
-
-#| Testing:
-
-(defparameter *opt-spec*
- '((("all" #\a) :type boolean :documentation "do it all")
-   ("blah" :type string :initial-value "blob" :documentation "This is a very long multi line documentation. The function SHOW-OPTION-HELP should display this properly indented, that is all lines should start at the same column.")
-   (("verbose" #\v) :type boolean :documentation "include debugging output")
-   (("file" #\f) :type string :documentation "read from file instead of standard input")
-   (("xml-port" #\x) :type integer :optional t :documentation "specify port for an XML listener")
-   (("http-port" #\h) :type integer :initial-value 80 :documentation "specify port for an HTTP listener")
-   ("enable-cache" :type boolean :documentation "enable cache for queries")
-   ("path" :type string :list t :optional t :documentation "add given directory to the path")
-   ("port" :type integer :list (:initial-contents (1 2)) :optional t :documentation "add a normal listen on given port")))
-
-(defun foo (args &key all verbose file xml-port enable-cache port path http-port blah)
-  (list args :all all :verbose verbose :file file :xml-port xml-port :http-port http-port :blah blah
-        :enable-cache enable-cache :port port :path path))
-
-(multiple-value-bind (options arguments)
-    (process-command-line-options
-     *opt-spec*
-     '("--all" "--no-verbose" "--file" "foo" "-f" "-v" "-v"
-       "-x" "--disable-cache" "-h" "8080"
-       "--no-port" "--port" "3" "--port=4"
-       "--path" "/foo" "--path" "/bar"
-       "--" "--foo" "bar" "baz"))
-  (write arguments :pretty nil) (terpri)
-  (write options :pretty nil) (terpri)
-  (write (apply 'foo arguments options) :pretty nil)
-  (terpri))
-
-(show-option-help *opt-spec*)
-
-|#
index c791a49..9b50b1c 100644 (file)
@@ -9,5 +9,6 @@
    #:process-command-line-options
    #:compute-and-process-command-line-options
    #:get-command-line-arguments
+   #:handle-command-line
    #:show-option-help
    ))
diff --git a/test.lisp b/test.lisp
new file mode 100644 (file)
index 0000000..3b631a9
--- /dev/null
+++ b/test.lisp
@@ -0,0 +1,31 @@
+(in-package :command-line-arguments)
+
+(defparameter *opt-spec*
+ '((("all" #\a) :type boolean :documentation "do it all")
+   ("blah" :type string :initial-value "blob" :documentation "This is a very long multi line documentation. The function SHOW-OPTION-HELP should display this properly indented, that is all lines should start at the same column.")
+   (("verbose" #\v) :type boolean :documentation "include debugging output")
+   (("file" #\f) :type string :documentation "read from file instead of standard input")
+   (("xml-port" #\x) :type integer :optional t :documentation "specify port for an XML listener")
+   (("http-port" #\h) :type integer :initial-value 80 :documentation "specify port for an HTTP listener")
+   ("enable-cache" :type boolean :documentation "enable cache for queries")
+   ("path" :type string :list t :optional t :documentation "add given directory to the path")
+   ("port" :type integer :list (:initial-contents (1 2)) :optional t :documentation "add a normal listen on given port")))
+
+(defun foo (args &key all verbose file xml-port enable-cache port path http-port blah)
+  (list args :all all :verbose verbose :file file :xml-port xml-port :http-port http-port :blah blah
+        :enable-cache enable-cache :port port :path path))
+
+(multiple-value-bind (options arguments)
+    (process-command-line-options
+     *opt-spec*
+     '("--all" "--no-verbose" "--file" "foo" "-f" "-v" "-v"
+       "-x" "--disable-cache" "-h" "8080"
+       "--no-port" "--port" "3" "--port=4"
+       "--path" "/foo" "--path" "/bar"
+       "--" "--foo" "bar" "baz"))
+  (write arguments :pretty nil) (terpri)
+  (write options :pretty nil) (terpri)
+  (write (apply 'foo arguments options) :pretty nil)
+  (terpri))
+
+(show-option-help *opt-spec*)