command-line.scm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. ;;; Parsing Guile's command-line
  2. ;;; Copyright (C) 1994-1998, 2000-2011, 2012, 2013 Free Software Foundation, Inc.
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;; Code:
  17. ;;;
  18. ;;; Please be careful not to load up other modules in this file, unless
  19. ;;; they are explicitly requested. Loading modules currently imposes a
  20. ;;; speed penalty of a few stats, an mmap, and some allocation, which
  21. ;;; can range from 1 to 20ms, depending on the state of your disk cache.
  22. ;;; Since `compile-shell-switches' is called even for the most transient
  23. ;;; of command-line programs, we need to keep it lean.
  24. ;;;
  25. ;;; Generally speaking, the goal is for Guile to boot and execute simple
  26. ;;; expressions like "1" within 20ms or less, measured using system time
  27. ;;; from the time of the `guile' invocation to exit.
  28. ;;;
  29. (define-module (ice-9 command-line)
  30. #:autoload (system vm vm) (set-default-vm-engine! set-vm-engine! the-vm)
  31. #:export (compile-shell-switches
  32. version-etc
  33. *GPLv3+*
  34. *LGPLv3+*
  35. emit-bug-reporting-address))
  36. ;; An initial stab at i18n.
  37. (define _ gettext)
  38. (define *GPLv3+*
  39. (_ "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
  40. This is free software: you are free to change and redistribute it.
  41. There is NO WARRANTY, to the extent permitted by law."))
  42. (define *LGPLv3+*
  43. (_ "License LGPLv3+: GNU LGPL 3 or later <http://gnu.org/licenses/lgpl.html>.
  44. This is free software: you are free to change and redistribute it.
  45. There is NO WARRANTY, to the extent permitted by law."))
  46. ;; Display the --version information in the
  47. ;; standard way: command and package names, package version, followed
  48. ;; by a short license notice and a list of up to 10 author names.
  49. ;; If COMMAND_NAME is NULL, the PACKAGE is asumed to be the name of
  50. ;; the program. The formats are therefore:
  51. ;; PACKAGE VERSION
  52. ;; or
  53. ;; COMMAND_NAME (PACKAGE) VERSION.
  54. ;;
  55. ;; Based on the version-etc gnulib module.
  56. ;;
  57. (define* (version-etc package version #:key
  58. (port (current-output-port))
  59. ;; FIXME: authors
  60. (copyright-year 2013)
  61. (copyright-holder "Free Software Foundation, Inc.")
  62. (copyright (format #f "Copyright (C) ~a ~a"
  63. copyright-year copyright-holder))
  64. (license *GPLv3+*)
  65. command-name
  66. packager packager-version)
  67. (if command-name
  68. (format port "~a (~a) ~a\n" command-name package version)
  69. (format port "~a ~a\n" package version))
  70. (if packager
  71. (if packager-version
  72. (format port (_ "Packaged by ~a (~a)\n") packager packager-version)
  73. (format port (_ "Packaged by ~a\n") packager)))
  74. (display copyright port)
  75. (newline port)
  76. (newline port)
  77. (display license port)
  78. (newline port))
  79. ;; Display the usual `Report bugs to' stanza.
  80. ;;
  81. (define* (emit-bug-reporting-address package bug-address #:key
  82. (port (current-output-port))
  83. (url (string-append
  84. "http://www.gnu.org/software/"
  85. package
  86. "/"))
  87. packager packager-bug-address)
  88. (format port (_ "\nReport bugs to: ~a\n") bug-address)
  89. (if (and packager packager-bug-address)
  90. (format port (_ "Report ~a bugs to: ~a\n") packager packager-bug-address))
  91. (format port (_ "~a home page: <~a>\n") package url)
  92. (format port
  93. (_ "General help using GNU software: <http://www.gnu.org/gethelp/>\n")))
  94. (define *usage*
  95. (_ "Evaluate code with Guile, interactively or from a script.
  96. [-s] FILE load source code from FILE, and exit
  97. -c EXPR evalute expression EXPR, and exit
  98. -- stop scanning arguments; run interactively
  99. The above switches stop argument processing, and pass all
  100. remaining arguments as the value of (command-line).
  101. If FILE begins with `-' the -s switch is mandatory.
  102. -L DIRECTORY add DIRECTORY to the front of the module load path
  103. -C DIRECTORY like -L, but for compiled files
  104. -x EXTENSION add EXTENSION to the front of the load extensions
  105. -l FILE load source code from FILE
  106. -e FUNCTION after reading script, apply FUNCTION to
  107. command line arguments
  108. --language=LANG change language; default: scheme
  109. -ds do -s script at this point
  110. --debug start with the \"debugging\" VM engine
  111. --no-debug start with the normal VM engine (backtraces but
  112. no breakpoints); default is --debug for interactive
  113. use, but not for `-s' and `-c'.
  114. --auto-compile compile source files automatically
  115. --fresh-auto-compile invalidate auto-compilation cache
  116. --no-auto-compile disable automatic source file compilation;
  117. default is to enable auto-compilation of source
  118. files.
  119. --listen[=P] listen on a local port or a path for REPL clients;
  120. if P is not given, the default is local port 37146
  121. -q inhibit loading of user init file
  122. --use-srfi=LS load SRFI modules for the SRFIs in LS,
  123. which is a list of numbers like \"2,13,14\"
  124. -h, --help display this help and exit
  125. -v, --version display version information and exit
  126. \\ read arguments from following script lines"))
  127. (define* (shell-usage name fatal? #:optional fmt . args)
  128. (let ((port (if fatal?
  129. (current-error-port)
  130. (current-output-port))))
  131. (if fmt
  132. (apply format port fmt args))
  133. (format port (_ "Usage: ~a [OPTION]... [FILE]...\n") name)
  134. (display *usage* port)
  135. (newline port)
  136. (emit-bug-reporting-address
  137. "GNU Guile" "bug-guile@gnu.org"
  138. #:port port
  139. #:url "http://www.gnu.org/software/guile/"
  140. #:packager (assq-ref %guile-build-info 'packager)
  141. #:packager-bug-address
  142. (assq-ref %guile-build-info 'packager-bug-address))
  143. (if fatal?
  144. (exit 1))))
  145. ;; Try to avoid loading (ice-9 eval-string) and (system base compile) if
  146. ;; possible.
  147. (define (eval-string/lang str)
  148. (case (current-language)
  149. ((scheme)
  150. (call-with-input-string
  151. str
  152. (lambda (port)
  153. (let lp ()
  154. (let ((exp (read port)))
  155. (if (not (eof-object? exp))
  156. (begin
  157. (eval exp (current-module))
  158. (lp))))))))
  159. (else
  160. ((module-ref (resolve-module '(ice-9 eval-string)) 'eval-string) str))))
  161. (define (load/lang f)
  162. (case (current-language)
  163. ((scheme)
  164. (load-in-vicinity (getcwd) f))
  165. (else
  166. ((module-ref (resolve-module '(system base compile)) 'compile-file)
  167. f #:to 'value))))
  168. (define* (compile-shell-switches args #:optional (usage-name "guile"))
  169. (let ((arg0 "guile")
  170. (script-cell #f)
  171. (entry-point #f)
  172. (user-load-path '())
  173. (user-load-compiled-path '())
  174. (user-extensions '())
  175. (interactive? #t)
  176. (inhibit-user-init? #f)
  177. (turn-on-debugging? #f)
  178. (turn-off-debugging? #f))
  179. (define (error fmt . args)
  180. (apply shell-usage usage-name #t fmt args))
  181. (define (parse args out)
  182. (cond
  183. ((null? args)
  184. (finish args out))
  185. (else
  186. (let ((arg (car args))
  187. (args (cdr args)))
  188. (cond
  189. ((not (string-prefix? "-" arg)) ; foo
  190. ;; If we specified the -ds option, script-cell is the cdr of
  191. ;; an expression like (load #f). We replace the car (i.e.,
  192. ;; the #f) with the script name.
  193. (set! arg0 arg)
  194. (set! interactive? #f)
  195. (if script-cell
  196. (begin
  197. (set-car! script-cell arg0)
  198. (finish args out))
  199. (finish args
  200. (cons `((@@ (ice-9 command-line) load/lang) ,arg0)
  201. out))))
  202. ((string=? arg "-s") ; foo
  203. (if (null? args)
  204. (error "missing argument to `-s' switch"))
  205. (set! arg0 (car args))
  206. (set! interactive? #f)
  207. (if script-cell
  208. (begin
  209. (set-car! script-cell arg0)
  210. (finish (cdr args) out))
  211. (finish (cdr args)
  212. (cons `((@@ (ice-9 command-line) load/lang) ,arg0)
  213. out))))
  214. ((string=? arg "-c") ; evaluate expr
  215. (if (null? args)
  216. (error "missing argument to `-c' switch"))
  217. (set! interactive? #f)
  218. (finish (cdr args)
  219. (cons `((@@ (ice-9 command-line) eval-string/lang)
  220. ,(car args))
  221. out)))
  222. ((string=? arg "--") ; end args go interactive
  223. (finish args out))
  224. ((string=? arg "-l") ; load a file
  225. (if (null? args)
  226. (error "missing argument to `-l' switch"))
  227. (parse (cdr args)
  228. (cons `((@@ (ice-9 command-line) load/lang) ,(car args))
  229. out)))
  230. ((string=? arg "-L") ; add to %load-path
  231. (if (null? args)
  232. (error "missing argument to `-L' switch"))
  233. (set! user-load-path (cons (car args) user-load-path))
  234. (parse (cdr args)
  235. out))
  236. ((string=? arg "-C") ; add to %load-compiled-path
  237. (if (null? args)
  238. (error "missing argument to `-C' switch"))
  239. (set! user-load-compiled-path
  240. (cons (car args) user-load-compiled-path))
  241. (parse (cdr args)
  242. out))
  243. ((string=? arg "-x") ; add to %load-extensions
  244. (if (null? args)
  245. (error "missing argument to `-x' switch"))
  246. (set! user-extensions (cons (car args) user-extensions))
  247. (parse (cdr args)
  248. out))
  249. ((string=? arg "-e") ; entry point
  250. (if (null? args)
  251. (error "missing argument to `-e' switch"))
  252. (let* ((port (open-input-string (car args)))
  253. (arg1 (read port))
  254. (arg2 (read port)))
  255. ;; Recognize syntax of certain versions of guile 1.4 and
  256. ;; transform to (@ MODULE-NAME FUNC).
  257. (set! entry-point
  258. (cond
  259. ((not (eof-object? arg2))
  260. `(@ ,arg1 ,arg2))
  261. ((and (pair? arg1)
  262. (not (memq (car arg1) '(@ @@)))
  263. (and-map symbol? arg1))
  264. `(@ ,arg1 main))
  265. (else
  266. arg1))))
  267. (parse (cdr args)
  268. out))
  269. ((string-prefix? "--language=" arg) ; language
  270. (parse args
  271. (cons `(current-language
  272. ',(string->symbol
  273. (substring arg (string-length "--language="))))
  274. out)))
  275. ((string=? "--language" arg) ; language
  276. (when (null? args)
  277. (error "missing argument to `--language' option"))
  278. (parse (cdr args)
  279. (cons `(current-language ',(string->symbol (car args)))
  280. out)))
  281. ((string=? arg "-ds") ; do script here
  282. ;; We put a dummy "load" expression, and let the -s put the
  283. ;; filename in.
  284. (when script-cell
  285. (error "the -ds switch may only be specified once"))
  286. (set! script-cell (list #f))
  287. (parse args
  288. (acons '(@@ (ice-9 command-line) load/lang)
  289. script-cell
  290. out)))
  291. ((string=? arg "--debug")
  292. (set! turn-on-debugging? #t)
  293. (set! turn-off-debugging? #f)
  294. (parse args out))
  295. ((string=? arg "--no-debug")
  296. (set! turn-off-debugging? #t)
  297. (set! turn-on-debugging? #f)
  298. (parse args out))
  299. ;; Do auto-compile on/off now, because the form itself might
  300. ;; need this decision.
  301. ((string=? arg "--auto-compile")
  302. (set! %load-should-auto-compile #t)
  303. (parse args out))
  304. ((string=? arg "--fresh-auto-compile")
  305. (set! %load-should-auto-compile #t)
  306. (set! %fresh-auto-compile #t)
  307. (parse args out))
  308. ((string=? arg "--no-auto-compile")
  309. (set! %load-should-auto-compile #f)
  310. (parse args out))
  311. ((string=? arg "-q") ; don't load user init
  312. (set! inhibit-user-init? #t)
  313. (parse args out))
  314. ((string-prefix? "--use-srfi=" arg)
  315. (let ((srfis (map (lambda (x)
  316. (let ((n (string->number x)))
  317. (if (and n (exact? n) (integer? n) (>= n 0))
  318. n
  319. (error "invalid SRFI specification"))))
  320. (string-split (substring arg 11) #\,))))
  321. (if (null? srfis)
  322. (error "invalid SRFI specification"))
  323. (parse args
  324. (cons `(use-srfis ',srfis) out))))
  325. ((string=? arg "--listen") ; start a repl server
  326. (parse args
  327. (cons '((@@ (system repl server) spawn-server)) out)))
  328. ((string-prefix? "--listen=" arg) ; start a repl server
  329. (parse
  330. args
  331. (cons
  332. (let ((where (substring arg 9)))
  333. (cond
  334. ((string->number where) ; --listen=PORT
  335. => (lambda (port)
  336. (if (and (integer? port) (exact? port) (>= port 0))
  337. `((@@ (system repl server) spawn-server)
  338. ((@@ (system repl server) make-tcp-server-socket) #:port ,port))
  339. (error "invalid port for --listen"))))
  340. ((string-prefix? "/" where) ; --listen=/PATH/TO/SOCKET
  341. `((@@ (system repl server) spawn-server)
  342. ((@@ (system repl server) make-unix-domain-server-socket) #:path ,where)))
  343. (else
  344. (error "unknown argument to --listen"))))
  345. out)))
  346. ((or (string=? arg "-h") (string=? arg "--help"))
  347. (shell-usage usage-name #f)
  348. (exit 0))
  349. ((or (string=? arg "-v") (string=? arg "--version"))
  350. (version-etc "GNU Guile" (version)
  351. #:license *LGPLv3+*
  352. #:command-name "guile"
  353. #:packager (assq-ref %guile-build-info 'packager)
  354. #:packager-version
  355. (assq-ref %guile-build-info 'packager-version))
  356. (exit 0))
  357. (else
  358. (error "Unrecognized switch ~a" arg)))))))
  359. (define (finish args out)
  360. ;; Check to make sure the -ds got a -s.
  361. (when (and script-cell (not (car script-cell)))
  362. (error "the `-ds' switch requires the use of `-s' as well"))
  363. ;; Make any remaining arguments available to the
  364. ;; script/command/whatever.
  365. (set-program-arguments (cons arg0 args))
  366. ;; If debugging was requested, or we are interactive and debugging
  367. ;; was not explicitly turned off, use the debug engine.
  368. (if (or turn-on-debugging?
  369. (and interactive? (not turn-off-debugging?)))
  370. (begin
  371. (set-default-vm-engine! 'debug)
  372. (set-vm-engine! (the-vm) 'debug)))
  373. ;; Return this value.
  374. `(;; It would be nice not to load up (ice-9 control), but the
  375. ;; default-prompt-handler is nontrivial.
  376. (@ (ice-9 control) %)
  377. (begin
  378. ;; If we didn't end with a -c or a -s and didn't supply a -q, load
  379. ;; the user's customization file.
  380. ,@(if (and interactive? (not inhibit-user-init?))
  381. '((load-user-init))
  382. '())
  383. ;; Use-specified extensions.
  384. ,@(map (lambda (ext)
  385. `(set! %load-extensions (cons ,ext %load-extensions)))
  386. user-extensions)
  387. ;; Add the user-specified load paths here, so they won't be in
  388. ;; effect during the loading of the user's customization file.
  389. ,@(map (lambda (path)
  390. `(set! %load-path (cons ,path %load-path)))
  391. user-load-path)
  392. ,@(map (lambda (path)
  393. `(set! %load-compiled-path
  394. (cons ,path %load-compiled-path)))
  395. user-load-compiled-path)
  396. ;; Put accumulated actions in their correct order.
  397. ,@(reverse! out)
  398. ;; Handle the `-e' switch, if it was specified.
  399. ,@(if entry-point
  400. `((,entry-point (command-line)))
  401. '())
  402. ,(if interactive?
  403. ;; If we didn't end with a -c or a -s, start the
  404. ;; repl.
  405. '((@ (ice-9 top-repl) top-repl))
  406. ;; Otherwise, after doing all the other actions
  407. ;; prescribed by the command line, quit.
  408. '(quit)))))
  409. (if (pair? args)
  410. (begin
  411. (set! arg0 (car args))
  412. (let ((slash (string-rindex arg0 #\/)))
  413. (set! usage-name
  414. (if slash (substring arg0 (1+ slash)) arg0)))
  415. (parse (cdr args) '()))
  416. (parse args '()))))