File: options.lisp

package info (click to toggle)
mcvs 1.0.13-8
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 668 kB
  • ctags: 648
  • sloc: lisp: 5,091; ansic: 223; sh: 190; makefile: 58
file content (170 lines) | stat: -rw-r--r-- 5,629 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
;;; This source file is part of the Meta-CVS program, 
;;; which is distributed under the GNU license.
;;; Copyright 2002 Kaz Kylheku

(require "system")
(require "chatter")
(require "find-bind")
(require "split")
(require "error")
(provide "options")

(defvar *print-usage* nil)
(defvar *nometa-option* nil)
(defvar *meta-option* nil)
(defvar *metaonly-option* nil)
(defvar *dry-run-option* nil)
(defvar *nesting-escape-option* 0)

(defun option-spec-expand (num-args string-list)
  (mapcar #'(lambda (string) (list string num-args))
	  string-list))

(defmacro option-spec (&rest option-specs)
  `(append ,@(mapcar #'(lambda (spec)
			 (destructuring-bind (number word &rest strings) spec
			   (when (not (string= (symbol-name word) "ARG"))
			     (error "OPTIONS: word \"ARG\" expected."))
			   `(option-spec-expand ,number ',strings)))
		     option-specs)))

(defmacro define-option-constant (var &rest option-specs)
  `(defconstant ,var (option-spec ,@option-specs)))

(defun parse-opt (arguments option-spec)
  (flet ((process-option (arg)
	   (let* ((split-opt (split-fields arg #(#\=)))
		  (opt-name (first split-opt))
		  (opt-arg (second split-opt))
		  (spec (find opt-name option-spec 
			      :test #'string= 
			      :key #'first)))
	     (when (null spec)
	       (error "unknown option ~a." opt-name))
	     (when opt-arg
	       (push opt-arg arguments))
	     (let ((num-req-params (second spec))
		   (opt-args ()))
	       (dotimes (i num-req-params)
		 (let ((opt-arg (pop arguments)))
		   (when (null opt-arg)
		     (error "option ~a requires ~a parameter~:p." 
			    opt-name num-req-params))
		   (push opt-arg opt-args)))
	       (cons opt-name (nreverse opt-args))))))
    (let ((parsed-options ()))
      (loop
	(if (null arguments)
	  (return))
	(let ((arg (pop arguments)))
	  (cond 
	    ((string= arg "--")
	       (return))
	    ((and (> (length arg) 2) (string= (subseq arg 0 2) "--"))
	       (push (process-option (subseq arg 2)) parsed-options))
	    ((and (> (length arg) 1) (char= (char arg 0) #\-))
	       (let ((num-chars (- (length arg) 1))
		     (last-iter (- (length arg) 2)))
		 (dotimes (i num-chars)
		   (let ((option (subseq arg (+ i 1) (+ i 2)))
			 (arg (subseq arg (+ i 2))))
		     (when (< i last-iter)
		       (push arg arguments))
		     (let ((result (process-option option)))
		       (push result parsed-options)
		       (when (and (second result)
				  (/= i (- (length arg) 2)))
			 (return))
		       (when (< i last-iter)
			 (pop arguments)))))))
	    (t (push arg arguments) 
	       (return)))))
      (values (nreverse parsed-options) arguments))))
		  
(defun format-opt (options)
"Convert list of options as produced by parse-opt back into a list
of strings."
  (mapcan #'(lambda (option-list)
	      (let ((option (first option-list)) 
		    (arg (rest option-list)))
		(if (> (length option) 1)
		  (cons (format nil "--~a" option) arg)
		  (if (= (length arg) 1)
		    (list (format nil "-~a~a" option (first arg)))
		    (cons (format nil "-~a" option) arg))))) 
	  options))

(defun filter-mcvs-options (opts)
"Processes and removes any Meta-CVS-specific options."
  (find-bind (:test #'string= :key #'first)
	     (remainder (meta "meta")
			(metaonly "metaonly")
			(nometa "nometa")
			(ec "error-continue") 
			(et "error-terminate")
			(nesting-escape "up")
		        (debug "debug"))
	     opts
    (when (and meta nometa)
      (error "cannot specify both --nometa and --meta"))
    (when (and metaonly nometa)
      (error "cannot specify both --nometa and --metaonly"))
    (setf *meta-option* meta)
    (setf *metaonly-option* metaonly)
    (setf *nometa-option* nometa)
    (when nesting-escape
      (unless (setf *nesting-escape-option* 
		    (parse-integer (second nesting-escape)
				   :junk-allowed t))
	(error "--up option takes integer argument"))
      (unless (>= *nesting-escape-option* 0)
	(error "--up argument must be nonnegative")))
    (when debug
      (setf *mcvs-chatter-level* *mcvs-debug*))
    (cond
      (ec (setf *mcvs-error-treatment* :continue))
      (et (setf *mcvs-error-treatment* :terminate)))
    remainder))

(defun process-cvs-options (opts)
"Take care of any CVS options that must also be interpreted by Meta-CVS."
  (find-bind (:test #'string= :key #'first) 
	     ((help-long "help") (help "H") (quiet "q")
	      (very-quiet "Q") (version "v") (version-long "version")
	      (editor "e") (interpret-file "i") (dry-run "n"))
	     opts
    (when (or help-long help)
      (setf *print-usage* t))
    (when (or version version-long)
      (let* ((vers (split-words "$Name: mcvs-1-0-13 $" "$:- "))
	     (major (third vers))
	     (minor (fourth vers))
	     (patch (fifth vers)))
	(if (and major minor patch)
	  (format t "Meta-CVS version ~a.~a.~a Copyright 2004 Kaz Kylheku~%"
		  major minor patch)
	  (format t "Meta-CVS unknown version Copyright 2004 Kaz Kylheku~%"))
	(throw 'mcvs-terminate nil)))
    (when editor
      (setf *mcvs-editor* (second editor)))
    (cond
      (very-quiet (setf *mcvs-chatter-level* *mcvs-silent*))
      (quiet (setf *mcvs-chatter-level* *mcvs-terse*)))
    (when dry-run
      (setf *dry-run-option* t))
    (when interpret-file
      (load (second interpret-file))
      (throw 'mcvs-terminate nil)))
  opts)

(defun filter-global-options (opts)
  (process-cvs-options (filter-mcvs-options opts)))

(defmacro honor-dry-run (vars &rest forms)
  `(cond
     (*dry-run-option*
       (chatter-debug 
	 "Because of -n option, not executing ~s with bindings ~s.~%"
	 ',forms
	 (list ,@(mapcar #'(lambda (var) `(list ',var ,var)) vars))))
     (t ,@forms)))