1 ;;; Parsing Guile's command-line
3 ;;; Copyright (C) 1994-1998, 2000-2015 Free Software Foundation, Inc.
5 ;;;; This library is free software; you can redistribute it and/or
6 ;;;; modify it under the terms of the GNU Lesser General Public
7 ;;;; License as published by the Free Software Foundation; either
8 ;;;; version 3 of the License, or (at your option) any later version.
10 ;;;; This library is distributed in the hope that it will be useful,
11 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ;;;; Lesser General Public License for more details.
15 ;;;; You should have received a copy of the GNU Lesser General Public
16 ;;;; License along with this library; if not, write to the Free Software
17 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 ;;; Please be careful not to load up other modules in this file, unless
23 ;;; they are explicitly requested. Loading modules currently imposes a
24 ;;; speed penalty of a few stats, an mmap, and some allocation, which
25 ;;; can range from 1 to 20ms, depending on the state of your disk cache.
26 ;;; Since `compile-shell-switches' is called even for the most transient
27 ;;; of command-line programs, we need to keep it lean.
29 ;;; Generally speaking, the goal is for Guile to boot and execute simple
30 ;;; expressions like "1" within 20ms or less, measured using system time
31 ;;; from the time of the `guile' invocation to exit.
34 (define-module (ice-9 command-line)
35 #:autoload (system vm vm) (set-default-vm-engine! set-vm-engine!)
36 #:export (compile-shell-switches
40 emit-bug-reporting-address))
42 ;; An initial stab at i18n.
46 (_ "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
47 This is free software: you are free to change and redistribute it.
48 There is NO WARRANTY, to the extent permitted by law."))
51 (_ "License LGPLv3+: GNU LGPL 3 or later <http://gnu.org/licenses/lgpl.html>.
52 This is free software: you are free to change and redistribute it.
53 There is NO WARRANTY, to the extent permitted by law."))
55 ;; Display the --version information in the
56 ;; standard way: command and package names, package version, followed
57 ;; by a short license notice and a list of up to 10 author names.
58 ;; If COMMAND_NAME is NULL, the PACKAGE is asumed to be the name of
59 ;; the program. The formats are therefore:
62 ;; COMMAND_NAME (PACKAGE) VERSION.
64 ;; Based on the version-etc gnulib module.
66 (define* (version-etc package version #:key
67 (port (current-output-port))
70 (copyright-holder "Free Software Foundation, Inc.")
71 (copyright (format #f "Copyright (C) ~a ~a"
72 copyright-year copyright-holder))
75 packager packager-version)
77 (format port "~a (~a) ~a\n" command-name package version)
78 (format port "~a ~a\n" package version))
82 (format port (_ "Packaged by ~a (~a)\n") packager packager-version)
83 (format port (_ "Packaged by ~a\n") packager)))
85 (display copyright port)
88 (display license port)
92 ;; Display the usual `Report bugs to' stanza.
94 (define* (emit-bug-reporting-address package bug-address #:key
95 (port (current-output-port))
97 "http://www.gnu.org/software/"
100 packager packager-bug-address)
101 (format port (_ "\nReport bugs to: ~a\n") bug-address)
102 (if (and packager packager-bug-address)
103 (format port (_ "Report ~a bugs to: ~a\n") packager packager-bug-address))
104 (format port (_ "~a home page: <~a>\n") package url)
106 (_ "General help using GNU software: <http://www.gnu.org/gethelp/>\n")))
109 (_ "Evaluate code with Guile, interactively or from a script.
111 [-s] FILE load source code from FILE, and exit
112 -c EXPR evalute expression EXPR, and exit
113 -- stop scanning arguments; run interactively
115 The above switches stop argument processing, and pass all
116 remaining arguments as the value of (command-line).
117 If FILE begins with `-' the -s switch is mandatory.
119 -L DIRECTORY add DIRECTORY to the front of the module load path
120 -C DIRECTORY like -L, but for compiled files
121 -x EXTENSION add EXTENSION to the front of the load extensions
122 -l FILE load source code from FILE
123 -e FUNCTION after reading script, apply FUNCTION to
124 command line arguments
125 --language=LANG change language; default: scheme
126 -ds do -s script at this point
127 --debug start with the \"debugging\" VM engine
128 --no-debug start with the normal VM engine (backtraces but
129 no breakpoints); default is --debug for interactive
130 use, but not for `-s' and `-c'.
131 --auto-compile compile source files automatically
132 --fresh-auto-compile invalidate auto-compilation cache
133 --no-auto-compile disable automatic source file compilation;
134 default is to enable auto-compilation of source
136 --listen[=P] listen on a local port or a path for REPL clients;
137 if P is not given, the default is local port 37146
138 -q inhibit loading of user init file
139 --use-srfi=LS load SRFI modules for the SRFIs in LS,
140 which is a list of numbers like \"2,13,14\"
141 -h, --help display this help and exit
142 -v, --version display version information and exit
143 \\ read arguments from following script lines"))
146 (define* (shell-usage name fatal? #:optional fmt . args)
147 (let ((port (if fatal?
149 (current-output-port))))
151 (apply format port fmt args)
154 (format port (_ "Usage: ~a [OPTION]... [FILE]...\n") name)
155 (display *usage* port)
158 (emit-bug-reporting-address
159 "GNU Guile" "bug-guile@gnu.org"
161 #:url "http://www.gnu.org/software/guile/"
162 #:packager (assq-ref %guile-build-info 'packager)
163 #:packager-bug-address
164 (assq-ref %guile-build-info 'packager-bug-address))
169 ;; Try to avoid loading (ice-9 eval-string) and (system base compile) if
171 (define (eval-string/lang str)
172 (case (current-language)
174 (call-with-input-string
178 (let ((exp (read port)))
179 (if (not (eof-object? exp))
181 (eval exp (current-module))
184 ((module-ref (resolve-module '(ice-9 eval-string)) 'eval-string) str))))
186 (define (load/lang f)
187 (case (current-language)
189 (load-in-vicinity (getcwd) f))
191 ((module-ref (resolve-module '(system base compile)) 'compile-file)
194 (define* (compile-shell-switches args #:optional (usage-name "guile"))
199 (user-load-compiled-path '())
200 (user-extensions '())
202 (inhibit-user-init? #f)
203 (turn-on-debugging? #f)
204 (turn-off-debugging? #f))
206 (define (error fmt . args)
207 (apply shell-usage usage-name #t
208 (string-append "error: " fmt "~%") args))
210 (define (parse args out)
215 (let ((arg (car args))
218 ((not (string-prefix? "-" arg)) ; foo
219 ;; If we specified the -ds option, script-cell is the cdr of
220 ;; an expression like (load #f). We replace the car (i.e.,
221 ;; the #f) with the script name.
223 (set! interactive? #f)
226 (set-car! script-cell arg0)
229 (cons `((@@ (ice-9 command-line) load/lang) ,arg0)
232 ((string=? arg "-s") ; foo
234 (error "missing argument to `-s' switch"))
235 (set! arg0 (car args))
236 (set! interactive? #f)
239 (set-car! script-cell arg0)
240 (finish (cdr args) out))
242 (cons `((@@ (ice-9 command-line) load/lang) ,arg0)
245 ((string=? arg "-c") ; evaluate expr
247 (error "missing argument to `-c' switch"))
248 (set! interactive? #f)
250 (cons `((@@ (ice-9 command-line) eval-string/lang)
254 ((string=? arg "--") ; end args go interactive
257 ((string=? arg "-l") ; load a file
259 (error "missing argument to `-l' switch"))
261 (cons `((@@ (ice-9 command-line) load/lang) ,(car args))
264 ((string=? arg "-L") ; add to %load-path
266 (error "missing argument to `-L' switch"))
267 (set! user-load-path (cons (car args) user-load-path))
271 ((string=? arg "-C") ; add to %load-compiled-path
273 (error "missing argument to `-C' switch"))
274 (set! user-load-compiled-path
275 (cons (car args) user-load-compiled-path))
279 ((string=? arg "-x") ; add to %load-extensions
281 (error "missing argument to `-x' switch"))
282 (set! user-extensions (cons (car args) user-extensions))
286 ((string=? arg "-e") ; entry point
288 (error "missing argument to `-e' switch"))
289 (let* ((port (open-input-string (car args)))
292 ;; Recognize syntax of certain versions of guile 1.4 and
293 ;; transform to (@ MODULE-NAME FUNC).
296 ((not (eof-object? arg2))
299 (not (memq (car arg1) '(@ @@)))
300 (and-map symbol? arg1))
307 ((string-prefix? "--language=" arg) ; language
309 (cons `(current-language
311 (substring arg (string-length "--language="))))
314 ((string=? "--language" arg) ; language
316 (error "missing argument to `--language' option"))
318 (cons `(current-language ',(string->symbol (car args)))
321 ((string=? arg "-ds") ; do script here
322 ;; We put a dummy "load" expression, and let the -s put the
325 (error "the -ds switch may only be specified once"))
326 (set! script-cell (list #f))
328 (acons '(@@ (ice-9 command-line) load/lang)
332 ((string=? arg "--debug")
333 (set! turn-on-debugging? #t)
334 (set! turn-off-debugging? #f)
337 ((string=? arg "--no-debug")
338 (set! turn-off-debugging? #t)
339 (set! turn-on-debugging? #f)
342 ;; Do auto-compile on/off now, because the form itself might
343 ;; need this decision.
344 ((string=? arg "--auto-compile")
345 (set! %load-should-auto-compile #t)
348 ((string=? arg "--fresh-auto-compile")
349 (set! %load-should-auto-compile #t)
350 (set! %fresh-auto-compile #t)
353 ((string=? arg "--no-auto-compile")
354 (set! %load-should-auto-compile #f)
357 ((string=? arg "-q") ; don't load user init
358 (set! inhibit-user-init? #t)
361 ((string-prefix? "--use-srfi=" arg)
362 (let ((srfis (map (lambda (x)
363 (let ((n (string->number x)))
364 (if (and n (exact? n) (integer? n) (>= n 0))
366 (error "invalid SRFI specification"))))
367 (string-split (substring arg 11) #\,))))
369 (error "invalid SRFI specification"))
371 (cons `(use-srfis ',srfis) out))))
373 ((string=? arg "--listen") ; start a repl server
375 (cons '((@@ (system repl server) spawn-server)) out)))
377 ((string-prefix? "--listen=" arg) ; start a repl server
381 (let ((where (substring arg 9)))
383 ((string->number where) ; --listen=PORT
385 (if (and (integer? port) (exact? port) (>= port 0))
386 `((@@ (system repl server) spawn-server)
387 ((@@ (system repl server) make-tcp-server-socket) #:port ,port))
388 (error "invalid port for --listen"))))
389 ((string-prefix? "/" where) ; --listen=/PATH/TO/SOCKET
390 `((@@ (system repl server) spawn-server)
391 ((@@ (system repl server) make-unix-domain-server-socket) #:path ,where)))
393 (error "unknown argument to --listen"))))
396 ((or (string=? arg "-h") (string=? arg "--help"))
397 (shell-usage usage-name #f)
400 ((or (string=? arg "-v") (string=? arg "--version"))
401 (version-etc "GNU Guile" (version)
403 #:command-name "guile"
404 #:packager (assq-ref %guile-build-info 'packager)
406 (assq-ref %guile-build-info 'packager-version))
410 (error "unrecognized switch ~a" arg)))))))
412 (define (finish args out)
413 ;; Check to make sure the -ds got a -s.
414 (when (and script-cell (not (car script-cell)))
415 (error "the `-ds' switch requires the use of `-s' as well"))
417 ;; Make any remaining arguments available to the
418 ;; script/command/whatever.
419 (set-program-arguments (cons arg0 args))
421 ;; If debugging was requested, or we are interactive and debugging
422 ;; was not explicitly turned off, use the debug engine.
423 (if (or turn-on-debugging?
424 (and interactive? (not turn-off-debugging?)))
426 (set-default-vm-engine! 'debug)
427 (set-vm-engine! 'debug)))
429 ;; Return this value.
430 `(;; It would be nice not to load up (ice-9 control), but the
431 ;; default-prompt-handler is nontrivial.
432 (@ (ice-9 control) %)
434 ;; If we didn't end with a -c or a -s and didn't supply a -q, load
435 ;; the user's customization file.
436 ,@(if (and interactive? (not inhibit-user-init?))
440 ;; Use-specified extensions.
442 `(set! %load-extensions (cons ,ext %load-extensions)))
445 ;; Add the user-specified load paths here, so they won't be in
446 ;; effect during the loading of the user's customization file.
447 ,@(map (lambda (path)
448 `(set! %load-path (cons ,path %load-path)))
450 ,@(map (lambda (path)
451 `(set! %load-compiled-path
452 (cons ,path %load-compiled-path)))
453 user-load-compiled-path)
455 ;; Put accumulated actions in their correct order.
458 ;; Handle the `-e' switch, if it was specified.
460 `((,entry-point (command-line)))
463 ;; If we didn't end with a -c or a -s, start the
465 '((@ (ice-9 top-repl) top-repl))
466 ;; Otherwise, after doing all the other actions
467 ;; prescribed by the command line, quit.
472 (set! arg0 (car args))
473 (let ((slash (string-rindex arg0 #\/)))
475 (if slash (substring arg0 (1+ slash)) arg0)))
476 (parse (cdr args) '()))