[PATCH] Support #!, to allow XEmacs to be called as a script interpreter.

Aidan Kehoe kehoea at parhasard.net
Sun Jan 20 14:00:09 EST 2008


GNU have this already. This implementation allows shebang lines of the form:

#!/usr/bin/env xemacs-script

(where #!/usr/bin/env xemacs --script doesn’t necessarily work, and where
xemacs-script is a link to the binary), which theirs doesn’t. It also,
unfortunately, fails because I don’t understand autoconf enough to have
@SHEBANG_PROGNAME@ actually expanded; when I do a make-install it creates a
literal /usr/local/bin/@SHEBANG_PROGNAME@ link to the XEmacs binary. Help
appreciated. 

Beyond that, issues remaining with this; the byte compiler needs to be
modified to be aware of the syntax when reading source files, and perhaps to
add the shebang line to the corresponding .elc files.

comparing with /Sources/xemacs-21.5-checked-out
searching for changes
changeset:   4409:fd8a9a4d81d9
tag:         tip
user:        Aidan Kehoe <kehoea at parhasard.net>
date:        Sun Jan 20 19:53:54 2008 +0100
summary:     Support #!, to allow XEmacs to be called as a script interpreter.

diff -r 8bbabcab2c42 -r fd8a9a4d81d9 ChangeLog
--- a/ChangeLog	Sun Jan 20 13:09:58 2008 +0100
+++ b/ChangeLog	Sun Jan 20 19:53:54 2008 +0100
@@ -1,3 +1,13 @@ 2008-01-17  Aidan Kehoe  <kehoea at parhasa
+2008-01-20  Aidan Kehoe  <kehoea at parhasard.net>
+
+	* Makefile.in.in (SHEBANG_PROGNAME): 
+	New variable; a symbol link to the XEmacs binary to tell it it
+	should read a script from stdin. 
+	* configure.ac (XE_EXPAND_VARIABLE): 
+	Set SHEBANG_PROGNAME. 
+	* configure: 
+	Regenerate.
+
 2008-01-17  Aidan Kehoe  <kehoea at parhasard.net>
 
 	* configure.ac:
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 Makefile.in.in
--- a/Makefile.in.in	Sun Jan 20 13:09:58 2008 +0100
+++ b/Makefile.in.in	Sun Jan 20 19:53:54 2008 +0100
@@ -92,6 +92,7 @@ configuration=@configuration@
 ## This will be the name of the generated binary and is set automatically
 ## by configure.
 PROGNAME=@PROGNAME@
+SHEBANG_PROGNAME=@SHEBANG_PROGNAME@
 
 ## ==================== Where To Install Things ====================
 
@@ -407,10 +408,12 @@ install-arch-dep: mkdir
 	${INSTALL_PROGRAM} src/${PROGNAME} ${bindir}/${PROGNAME}-${version}.exe
 	-chmod 0755 ${bindir}/${PROGNAME}-${version}.exe
 	cd ${bindir} && $(RM) ./${PROGNAME} && ${LN_S} ${PROGNAME}-${version}.exe ./${PROGNAME}
+	cd ${bindir} && $(RM) ./${SHEBANG_PROGNAME} && ${LN_S} ${PROGNAME}-${version}.exe ./${SHEBANG_PROGNAME}
 # else
 	${INSTALL_PROGRAM} src/${PROGNAME} ${bindir}/${PROGNAME}-${version}
 	-chmod 0755 ${bindir}/${PROGNAME}-${version}
 	cd ${bindir} && $(RM) ./${PROGNAME} && ${LN_S} ${PROGNAME}-${version} ./${PROGNAME}
+	cd ${bindir} && $(RM) ./${SHEBANG_PROGNAME} && ${LN_S} ${PROGNAME}-${version}.exe ./${SHEBANG_PROGNAME}
 # endif /* CYGWIN */
 #endif /* WIN32_NATIVE */
 	if test "${prefix}" != "${exec_prefix}"; then \
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 configure
--- a/configure	Sun Jan 20 13:09:58 2008 +0100
+++ b/configure	Sun Jan 20 19:53:54 2008 +0100
@@ -4851,13 +4851,20 @@ _ACEOF
 
   version=${infodock_major_version}.${infodock_minor_version}.${infodock_build_version}
   PROGNAME=infodock
+  SHEBANG_PROGNAME=infodock-script
   CPPFLAGS="$CPPFLAGS -DINFODOCK"
 else
   PROGNAME=xemacs
+  SHEBANG_PROGNAME=xemacs-script
 fi
 
 cat >>confdefs.h <<_ACEOF
 #define EMACS_PROGNAME "$PROGNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SHEBANG_PROGNAME "${PROGNAME}-script"
 _ACEOF
 
 
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 configure.ac
--- a/configure.ac	Sun Jan 20 13:09:58 2008 +0100
+++ b/configure.ac	Sun Jan 20 19:53:54 2008 +0100
@@ -1219,12 +1219,16 @@ if test "$with_infodock" = "yes"; then
   AC_DEFINE_UNQUOTED(INFODOCK_BUILD_VERSION, $infodock_build_version)
   version=${infodock_major_version}.${infodock_minor_version}.${infodock_build_version}
   PROGNAME=infodock
+  SHEBANG_PROGNAME=infodock-script
   CPPFLAGS="$CPPFLAGS -DINFODOCK"
 else
   PROGNAME=xemacs
+  SHEBANG_PROGNAME=xemacs-script
 fi
 
 AC_DEFINE_UNQUOTED(EMACS_PROGNAME, "$PROGNAME")
+
+AC_DEFINE_UNQUOTED(SHEBANG_PROGNAME, "${PROGNAME}-script")
 
 dnl ----------------------------------
 dnl Error checking and debugging flags
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 lisp/ChangeLog
--- a/lisp/ChangeLog	Sun Jan 20 13:09:58 2008 +0100
+++ b/lisp/ChangeLog	Sun Jan 20 19:53:54 2008 +0100
@@ -1,3 +1,10 @@ 2008-01-17  Mike Sperber  <mike at xemacs.o
+2008-01-20  Aidan Kehoe  <kehoea at parhasard.net>
+
+	* startup.el (command-line-do-script): New.
+	(command-switch-alist): Use command-line-do-script.
+	New argument, compatible with GNU; --script or -script says "treat
+	the following argument as a file to load in batch mode".
+
 2008-01-17  Mike Sperber  <mike at xemacs.org>
 
 	* files.el (insert-directory): Bind `coding-system-for-read' to
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 lisp/startup.el
--- a/lisp/startup.el	Sun Jan 20 13:09:58 2008 +0100
+++ b/lisp/startup.el	Sun Jan 20 19:53:54 2008 +0100
@@ -234,6 +234,8 @@ after, and will not be true at any time 
     ("-eval"	. command-line-do-eval)
     ("-load"	. command-line-do-load)
     ("-l"	. command-line-do-load)
+    ("--script"	. command-line-do-script)
+    ("-script"	. command-line-do-script)
     ("-insert"	. command-line-do-insert)
     ("-i"	. command-line-do-insert)
     ("-kill"	. command-line-do-kill)
@@ -436,6 +438,12 @@ Type ^H^H^H (Control-h Control-h Control
     (if (file-exists-p (expand-file-name file))
 	(setq file (expand-file-name file)))
     (load file nil t)))
+
+(defun command-line-do-script (arg)
+  "Load the named file of Lisp code into XEmacs.
+<file>"
+  (let ((file (pop command-line-args-left)))
+    (load file nil t t)))
 
 (defun command-line-do-insert (arg)
   "Insert file into the current buffer.
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 man/ChangeLog
--- a/man/ChangeLog	Sun Jan 20 13:09:58 2008 +0100
+++ b/man/ChangeLog	Sun Jan 20 19:53:54 2008 +0100
@@ -1,3 +1,8 @@ 2007-12-17  Aidan Kehoe  <kehoea at parhasa
+2008-01-20  Aidan Kehoe  <kehoea at parhasard.net>
+
+	* xemacs/cmdargs.texi (Command Switches): 
+	Describe --script, -script. 
+
 2007-12-17  Aidan Kehoe  <kehoea at parhasard.net>
 
 	* lispref/strings.texi (Formatting Strings):
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 man/xemacs/cmdargs.texi
--- a/man/xemacs/cmdargs.texi	Sun Jan 20 13:09:58 2008 +0100
+++ b/man/xemacs/cmdargs.texi	Sun Jan 20 19:53:54 2008 +0100
@@ -171,6 +171,27 @@ Do not process early packages.  (For mor
 Do not process early packages.  (For more information on startup issues
 concerning the package system, @xref{Startup Paths}.)
 
+ at item -script @var{file}
+ at item --script @var{file}
+Load @var{file} as a (compiled or interpreted) Lisp file; do not load
+any window-system or TTY code, do not load the user init file, the site
+file, or the early packages.  This is comparable to running
+ at samp{xemacs} @samp{-batch} @samp{-l} @var{file}.
+
+You can also specify this flag implicitly by calling the XEmacs binary
+with a value for @samp{argv[0]} of @samp{xemacs-script}, normally by
+means of a symbolic link.  On a POSIX system, this means that adding the
+line:
+
+ at example
+#!/usr/bin/env xemacs-script
+ at end example
+
+at the start of an XEmacs Lisp file, and changing that file's
+permissions to executable, creates a script that can be invoked by
+typing the path to the file.  XEmacs has logic to ignore the #! line at
+the start of the script, so that won't cause an error.
+
 @item -vanilla
 This is equivalent to @samp{-q -no-site-file -no-early-packages}.
 
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 src/ChangeLog
--- a/src/ChangeLog	Sun Jan 20 13:09:58 2008 +0100
+++ b/src/ChangeLog	Sun Jan 20 19:53:54 2008 +0100
@@ -1,3 +1,15 @@ 2007-12-26  Aidan Kehoe  <kehoea at parhasa
+2008-01-20  Aidan Kehoe  <kehoea at parhasard.net>
+
+	* config.h.in: Add SHEBANG_PROGNAME.
+	* emacs.c (main_1): 
+	If we've been called using SHEBANG_PROGNAME, rewrite our arguments
+	to add a --script argument. 
+	Also, handle the --script argument by setting noninteractive and
+	vanilla. 
+	* lread.c (Fload_internal): 
+	If the first two characters of a file are #!, replace them with ;!
+	before they get to the Lisp reader. 
+
 2007-12-26  Aidan Kehoe  <kehoea at parhasard.net>
 
 	* casetab.c:
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 src/config.h.in
--- a/src/config.h.in	Sun Jan 20 13:09:58 2008 +0100
+++ b/src/config.h.in	Sun Jan 20 19:53:54 2008 +0100
@@ -90,6 +90,9 @@ things are arranged in config.h.in.  In 
 
 /* Program name */
 #undef EMACS_PROGNAME
+
+/* Name of the link to the program to be used with #! scripts */
+#undef SHEBANG_PROGNAME
 
 /* Allow s&m files to differentiate OS versions without having
    multiple files to maintain. */
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 src/emacs.c
--- a/src/emacs.c	Sun Jan 20 13:09:58 2008 +0100
+++ b/src/emacs.c	Sun Jan 20 19:53:54 2008 +0100
@@ -955,6 +955,42 @@ main_1 (int argc, Wexttext **argv, Wextt
   init_free_hook ();
 #endif
 
+#define SHEBANG_PROGNAME_LENGTH                                         \
+  (int)((sizeof (WEXTSTRING (SHEBANG_PROGNAME)) - sizeof (WEXTSTRING (""))))
+#define SHEBANG_EXE_PROGNAME_LENGTH                                     \
+  (int)(sizeof (WEXTSTRING (SHEBANG_PROGNAME ".exe"))                   \
+        - sizeof (WEXTSTRING ("")))
+
+  {
+    int progname_len = wext_strlen (argv[0]);
+    if (progname_len >= SHEBANG_PROGNAME_LENGTH)
+      {
+	if (!wext_strcmp_ascii (argv[0] +
+				(progname_len - SHEBANG_PROGNAME_LENGTH),
+				SHEBANG_PROGNAME)
+	    /* Allow trailing .exe. Don't check it, it could also be
+	       .com.  */
+	    || (progname_len >= SHEBANG_EXE_PROGNAME_LENGTH && 
+		!wext_strncmp_ascii
+		(argv[0] + (progname_len - SHEBANG_EXE_PROGNAME_LENGTH),
+		 SHEBANG_PROGNAME,
+		 SHEBANG_PROGNAME_LENGTH)))
+	  {
+	    Wexttext **newarr = alloca_array (Wexttext *, argc + 2);
+	    int j;
+
+	    newarr[0] = argv[0];
+	    newarr[1] = WEXTSTRING ("--script");
+	    for (j = 1; j < argc; ++j)
+	      {
+		newarr[j + 1] = argv[j];
+	      }
+	    argv = newarr;
+	    argc++;
+	  }
+      }
+  }
+
   sort_args (argc, argv);
 
 #if 0 /* defined (_SCO_DS)
@@ -1048,6 +1084,20 @@ main_1 (int argc, Wexttext **argv, Wextt
       noninteractive = 1;
     }
 
+  {
+    int count_before = skip_args;
+    /* Handle the -script switch, which implies batch and vanilla. The -l
+       part of its functionality is implemented in Lisp. */
+    if (argmatch (argv, argc, "-script", "--script", 0, NULL,
+		  &skip_args))
+      {
+	noninteractive = 1;
+	vanilla_inhibiting = 1;
+      }
+
+    /* Don't actually discard this argument. */
+    skip_args = count_before;
+  }
 #ifdef WIN32_NATIVE
   {
     /* Since we aren't a console application, we can't easily be terminated
@@ -2690,6 +2740,7 @@ static const struct standard_args standa
   { "-sd", "--show-dump-id", 105, 0 },
   { "-nd", "--no-dump-file", 95, 0 },
   { "-batch", "--batch", 88, 0 },
+  { "-script", "--script", 89, 1 },
 #ifdef WIN32_NATIVE
   { "-mswindows-termination-handle", 0, 84, 1 },
   { "-nuni", "--no-unicode-lib-calls", 83, 0 },
diff -r 8bbabcab2c42 -r fd8a9a4d81d9 src/lread.c
--- a/src/lread.c	Sun Jan 20 13:09:58 2008 +0100
+++ b/src/lread.c	Sun Jan 20 19:53:54 2008 +0100
@@ -743,6 +743,25 @@ do {								\
     /* set it to nil; a call to #'domain will set it. */
     internal_bind_lisp_object (&Vfile_domain, Qnil);
 #endif
+
+    /* Is there a #!? If so, read it, and unread ;!.
+
+       GNU implement this by treating any #! anywhere in the source text as
+       commenting out the whole line. */
+    {
+      char shebangp[2];
+      int num_read;
+
+      num_read = Lstream_read (XLSTREAM (lispstream), shebangp,
+                               sizeof(shebangp));
+      if (sizeof(shebangp) == num_read
+	  && 0 == strncmp("#!", shebangp, sizeof(shebangp)))
+	{
+          shebangp[0] = ';';
+	}
+
+      Lstream_unread (XLSTREAM (lispstream), shebangp, num_read);
+    }
 
     /* Now determine what sort of ELC file we're reading in. */
     internal_bind_int (&load_byte_code_version, load_byte_code_version);

-- 
¿Dónde estará ahora mi sobrino Yoghurtu Nghé, que tuvo que huir
precipitadamente de la aldea por culpa de la escasez de rinocerontes?



More information about the XEmacs-Beta mailing list