
Raymond Toy pushed to branch master at cmucl / cmucl Commits: 67cb15e6 by Raymond Toy at 2025-02-15T15:34:50+00:00 Fix #379: Support GNU-style command line option names - - - - - 38da65c4 by Raymond Toy at 2025-02-15T15:34:50+00:00 Merge branch 'issue-379-gnu-style-options' into 'master' Fix #379: Support GNU-style command line option names Closes #379 See merge request cmucl/cmucl!266 - - - - - 4 changed files: - src/code/commandline.lisp - src/general-info/release-21f.md - src/i18n/locale/cmucl.pot - src/lisp/lisp.c Changes: ===================================== src/code/commandline.lisp ===================================== @@ -109,7 +109,13 @@ (return (setf *command-line-switches* (nreverse *command-line-switches*)))) (let* ((position (position #\= (the simple-string str) :test #'char=)) - (switch (subseq (the simple-string str) 1 position)) + ;; Extract the name of the switch. The actual arg can be + ;; "-switch" or "--switch". + (switch (subseq (the simple-string str) + (position-if-not #'(lambda (c) + (char= c #\-)) + str) + position)) (value (if position (subseq (the simple-string str) (1+ position) (length (the simple-string str)))))) @@ -143,7 +149,14 @@ the switch. If no value was specified, then any following words are returned. If there are no following words, then t is returned. If the switch was not specified, then nil is returned." - (let* ((name (if (char= (schar sname 0) #\-) (subseq sname 1) sname)) + (let* ((posn (position-if-not #'(lambda (ch) + (char= ch #\-)) + sname)) + ;; Strip up to 2 leading "-" to get the switch name. + ;; Otherwise, return the entire switch name. + (name (if (and posn (<= posn 2)) + (subseq sname posn) + sname)) (switch (find name *command-line-switches* :test #'string-equal :key #'cmd-switch-name))) @@ -230,12 +243,12 @@ (lisp::finish-standard-output-streams) (setf start next))))) -;; Docstrings should have lines longer than 72 characters so that we -;; can print out the docstrings nicely on one line for help. -;; | <-- char 72 +;; Docstrings MUST consist of simple text and punctuation and +;; newlines; no special markup is allowed. When help is printed, the +;; help string is automatically filled and wrapped to 80 columns. (defswitch "eval" #'eval-switch-demon "Evaluate the specified Lisp expression during the start up - sequence. the value of the form will not be printed unless it is + sequence. The value of the form will not be printed unless it is wrapped in a form that does output." "expression") @@ -325,7 +338,7 @@ (defswitch "quiet" nil "Causes Lisp to start up silently, disabling printing of the herald - and causing most unnecessary noise, like GC messages,load messages, + and causing most unnecessary noise, like GC messages, load messages, etc. to be suppressed.") (defswitch "debug-lisp-search" nil @@ -338,7 +351,8 @@ (defun help-switch-demon (switch) (declare (ignore switch)) - (format t (intl:gettext "~&Usage: ~A <options>~2%") *command-line-utility-name*) + (format t (intl:gettext "~&Usage: ~A <options> [-- [app-args]*]~2%") + *command-line-utility-name*) (flet ((get-words (s) (declare (string s)) @@ -366,7 +380,12 @@ :key #'car)) (destructuring-bind (name doc arg) s - (format t " -~A ~@[~A~]~%" name (if arg (intl:gettext arg))) + ;; Print both -switch and --switch, and the optional arg + ;; value. + (format t " -~A|--~A ~@[~A~]~%" + name name + (if arg (intl:gettext arg))) + ;; Poor man's formatting of the help string (let ((*print-right-margin* 80)) ;; Extract all the words from the string and print them out @@ -392,9 +411,6 @@ (defswitch "help" #'help-switch-demon "Print out the command line options and exit") -(defswitch "-help" #'help-switch-demon - "Same as -help.") - (defun version-switch-demon (switch) (declare (ignore switch)) (format t "~A~%" (lisp-implementation-version)) @@ -406,8 +422,3 @@ ;; it out so the user knows about it. (defswitch "version" #'version-switch-demon "Prints the cmucl version and exits, without loading the lisp core.") - -;; Make --version work for the benefit of those who are accustomed to -;; GNU software. -(defswitch "-version" #'version-switch-demon - "Prints the cmucl version and exits; same as -version") ===================================== src/general-info/release-21f.md ===================================== @@ -119,6 +119,7 @@ public domain. * ~~#364~~ Add interface to `mkdtemp` and `mkstemp` * ~~#367~~ Add stream:string-count-octets to count octets in a string * ~~#369~~ Improve docstring for `unix::unix-setlocale` + * ~~#379~~ Support GNU-style command-line option names * Other changes: * Improvements to the PCL implementation of CLOS: * Changes to building procedure: ===================================== src/i18n/locale/cmucl.pot ===================================== @@ -6060,7 +6060,7 @@ msgstr "" #: src/code/commandline.lisp msgid "" "Evaluate the specified Lisp expression during the start up\n" -" sequence. the value of the form will not be printed unless it is\n" +" sequence. The value of the form will not be printed unless it is\n" " wrapped in a form that does output." msgstr "" @@ -6182,7 +6182,7 @@ msgstr "" #: src/code/commandline.lisp msgid "" "Causes Lisp to start up silently, disabling printing of the herald\n" -" and causing most unnecessary noise, like GC messages,load messages,\n" +" and causing most unnecessary noise, like GC messages, load messages,\n" " etc. to be suppressed." msgstr "" @@ -6197,25 +6197,17 @@ msgid "Specify the unidata.bin file to be used." msgstr "" #: src/code/commandline.lisp -msgid "~&Usage: ~A <options>~2%" +msgid "~&Usage: ~A <options> [-- [app-args]*]~2%" msgstr "" #: src/code/commandline.lisp msgid "Print out the command line options and exit" msgstr "" -#: src/code/commandline.lisp -msgid "Same as -help." -msgstr "" - #: src/code/commandline.lisp msgid "Prints the cmucl version and exits, without loading the lisp core." msgstr "" -#: src/code/commandline.lisp -msgid "Prints the cmucl version and exits; same as -version" -msgstr "" - #: src/code/env-access.lisp msgid "" "Returns information about the symbol VAR in the lexical environment ENV.\n" ===================================== src/lisp/lisp.c ===================================== @@ -460,6 +460,41 @@ core_failure(const char* core, const char* argv[]) exit(1); } +/* + * Match the actual command line option "arg" with the arg name in + * "argname". The option matches if it is exacty the arg name + * prefixed by either one or two "-" characters. + * + * Returns non-zero if it matches. + */ +int match_option(const char* arg, const char* argname) +{ + if ((strlen(arg) < 2) || strlen(argname) < 1) { + /* + * The actual arg must be at least 2 characters. The argname + * must have at least 1. + */ + return 0; + } + + /* Must start with a "-" */ + if (arg[0] != '-') { + return 0; + } + + if (strcmp(arg + 1, argname) == 0) { + /* We have "-" followed by the argname. That's a match. */ + return 1; + } + + if ((arg[1] == '-') && (strcmp(arg + 2, argname) == 0)) { + /* We have "--" followed by the argname. That's a match. */ + return 1; + } + + return 0; +} + int main(int argc, const char *argv[], const char *envp[]) { @@ -529,7 +564,7 @@ main(int argc, const char *argv[], const char *envp[]) argptr = argv; while ((arg = *++argptr) != NULL) { - if (strcmp(arg, "-core") == 0) { + if (match_option(arg, "core")) { if (builtin_image_flag) { fprintf(stderr, "Warning: specifying a core file with an executable image is unusual,\nbut should work.\n"); @@ -543,87 +578,98 @@ main(int argc, const char *argv[], const char *envp[]) core = *++argptr; if (core == NULL) { fprintf(stderr, - "-core must be followed by the name of the core file to use.\n"); + "%s must be followed by the name of the core file to use.\n", + arg); exit(1); } - } else if (strcmp(arg, "-lib") == 0) { + } else if (match_option(arg, "lib")) { lib = *++argptr; if (lib == NULL) { fprintf(stderr, - "-lib must be followed by a string denoting the CMUCL library path.\n"); + "%s must be followed by a string denoting the CMUCL library path.\n", + arg); exit(1); } - } else if (strcmp(arg, "-read-only-space-size") == 0) { + } else if (match_option(arg, "read-only-space-size")) { const char *str = *++argptr; if (str == NULL) { fprintf(stderr, - "-read-only-space-size must be followed by the size in MBytes.\n"); + "%s must be followed by the size in MBytes.\n", + arg); exit(1); } read_only_space_size = atoi(str) * 1024 * 1024; if (read_only_space_size > READ_ONLY_SPACE_SIZE) { fprintf(stderr, - "-read-only-space-size must be no greater than %lu MBytes.\n", + "%s must be no greater than %lu MBytes.\n", + arg, READ_ONLY_SPACE_SIZE / (1024 * 1024UL)); fprintf(stderr, " Continuing with default size.\n"); read_only_space_size = READ_ONLY_SPACE_SIZE; } - } else if (strcmp(arg, "-static-space-size") == 0) { + } else if (match_option(arg, "static-space-size")) { const char *str = *++argptr; if (str == NULL) { fprintf(stderr, - "-static-space-size must be followed by the size in MBytes.\n"); + "%s must be followed by the size in MBytes.\n", + arg); exit(1); } static_space_size = atoi(str) * 1024 * 1024; if (static_space_size > STATIC_SPACE_SIZE) { fprintf(stderr, - "-static-space-size must be no greater than %lu MBytes.\n", + "%s must be no greater than %lu MBytes.\n", + arg, STATIC_SPACE_SIZE / (1024 * 1024UL)); fprintf(stderr, " Continuing with default size.\n"); static_space_size = STATIC_SPACE_SIZE; } - } else if (strcmp(arg, "-binding-stack-size") == 0) { + } else if (match_option(arg, "binding-stack-size")) { const char *str = *++argptr; if (str == NULL) { fprintf(stderr, - "-binding-stack-size must be followed by the size in MBytes.\n"); + "%s must be followed by the size in MBytes.\n", + arg); exit(1); } binding_stack_size = atoi(str) * 1024 * 1024; if (binding_stack_size > BINDING_STACK_SIZE) { fprintf(stderr, - "-binding-stack-size must be no greater than %lu MBytes.\n", + "%s must be no greater than %lu MBytes.\n", + arg, BINDING_STACK_SIZE / (1024 * 1024UL)); fprintf(stderr, " Continuing with default size.\n"); binding_stack_size = BINDING_STACK_SIZE; } - } else if (strcmp(arg, "-control-stack-size") == 0) { + } else if (match_option(arg, "control-stack-size")) { const char *str = *++argptr; if (str == NULL) { fprintf(stderr, - "-control-stack-size must be followed by the size in MBytes.\n"); + "%s must be followed by the size in MBytes.\n", + arg); exit(1); } control_stack_size = atoi(str) * 1024 * 1024; if (control_stack_size > CONTROL_STACK_SIZE) { fprintf(stderr, - "-control-stack-size must be no greater than %lu MBytes.\n", + "%s must be no greater than %lu MBytes.\n", + arg, CONTROL_STACK_SIZE / (1024 * 1024UL)); fprintf(stderr, " Continuing with default size.\n"); control_stack_size = CONTROL_STACK_SIZE; } - } else if (strcmp(arg, "-dynamic-space-size") == 0) { + } else if (match_option(arg, "dynamic-space-size")) { const char *str; str = *++argptr; if (str == NULL) { fprintf(stderr, - "-dynamic-space-size must be followed by the size to use in MBytes.\n"); + "%s must be followed by the size to use in MBytes.\n", + arg); exit(1); } #ifndef sparc @@ -669,15 +715,16 @@ main(int argc, const char *argv[], const char *envp[]) #endif if (dynamic_space_size > DYNAMIC_SPACE_SIZE) { fprintf(stderr, - "-dynamic-space-size must be no greater than %lu MBytes.\n", + "%s must be no greater than %lu MBytes.\n", + arg, DYNAMIC_SPACE_SIZE / (1024 * 1024UL)); exit(1); } - } else if (strcmp(arg, "-monitor") == 0) { + } else if (match_option(arg, "monitor")) { monitor = TRUE; - } else if (strcmp(arg, "-debug-lisp-search") == 0) { + } else if (match_option(arg, "debug-lisp-search")) { debug_lisp_search = TRUE; - } else if (strcmp(arg, "-unidata") == 0) { + } else if (match_option(arg, "unidata")) { unidata = *++argptr; } else if ((strcmp(arg, "-version") == 0) || (strcmp(arg, "--version") == 0)) { @@ -904,7 +951,7 @@ main(int argc, const char *argv[], const char *envp[]) argptr = argv; while ((arg = *++argptr) != NULL) { - if (strcmp(arg, "-batch") == 0) + if (match_option(arg, "batch")) SetSymbolValue(BATCH_MODE, T); } View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/5269a666ef5ffd4e32a7d12... -- View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/5269a666ef5ffd4e32a7d12... You're receiving this email because of your account on gitlab.common-lisp.net.