[comp.emacs] Loading compressed .el's

meissner@osf.org (03/21/91)

| I'm using Gnu Emacs 18.55 on a machine with VERY little spare
| disk space. I've managed to persuade info to read compressed 
| info files, but am at a loss as to how to get emacs to read 
| /load compressed *.el or *.elc files. Has anyone managed to do
| this?

Sure, you have to modify Fload, and then add a new function to create
a filter on a file descriptor:

First replace the Fload function in lread.c with the following:

DEFUN ("load", Fload, Sload, 1, 4, 0,
  "Execute a file of Lisp code named FILE.\n\
First tries FILE with .elc appended, then tries with .elc.Z,\n\
 then tries with .el, then tries with .el.Z,\n\
 then tries FILE unmodified.  Searches directories in  load-path.\n\
 If a .elc.Z or .el.Z file is found, it is uncompressed.\n\
If optional second arg MISSING-OK is non-nil,\n\
 report no error if FILE doesn't exist.\n\
Print messages at start and end of loading unless\n\
 optional third arg NOMESSAGE is non-nil.\n\
If optional fourth arg NOSUFFIX is non-nil, don't try adding\n\
 suffixes .elc, .elc.Z, .el or .el.Z to the specified name FILE.\n\
Return t if file exists.")
  (str, missing_ok, nomessage, nosuffix)
     Lisp_Object str, missing_ok, nomessage, nosuffix;
{
  register FILE *stream;
  register int fd = -1;
  register Lisp_Object lispstream;
  register FILE **ptr;
  int count = specpdl_ptr - specpdl;
  struct gcpro gcpro1, gcpro2;
  Lisp_Object name = Qnil;
  register int len;
  register char *msg = "Loading %s...";

  CHECK_STRING (str, 0);
  str = Fsubstitute_in_file_name (str);

  /* Avoid weird lossage with null string as arg,
     since it would try to load a directory as a Lisp file */
  if (XSTRING (str)->size > 0)
    {
      fd = openp (Vload_path, str, !NULL (nosuffix) ? "" : ".elc:.elc.Z:.el:.el.Z:", &name, 0);
    }

  if (fd < 0)
    if (NULL (missing_ok))
      while (1)
	Fsignal (Qfile_error, Fcons (build_string ("Cannot open load file"),
				     Fcons (str, Qnil)));
    else return Qnil;

#ifndef standalone
  if (XTYPE (name) == Lisp_String
      && (len = XSTRING (name)->size) > 2
      && strcmp ((char *)&XSTRING (name)->data[len-2], ".Z") == 0)
    {
      char *new_argv[3];

      msg = "Decompressing and loading %s...";
      new_argv[0] = "zcat";
      new_argv[1] = (char *)XSTRING (name)->data;
      new_argv[2] = (char *)0;

      fd = create_filter (fd, new_argv);
    }
#endif	/* standalone */

  stream = fdopen (fd, "r");
  if (stream == 0)
    {
      close (fd);
      error ("Failure to create stdio stream for %s", XSTRING (str)->data);
    }

  if (NULL (nomessage))
    message (msg, XSTRING (name)->data);

  GCPRO2 (str, name);
  ptr = (FILE **) xmalloc (sizeof (FILE *));
  *ptr = stream;
  XSET (lispstream, Lisp_Internal_Stream, (int) ptr);
  record_unwind_protect (load_unwind, lispstream);
  load_in_progress++;
  readevalloop (Qget_file_char, stream, Feval, 0);
  unbind_to (count);
  UNGCPRO;

  if (!noninteractive && NULL (nomessage))
    message ("Loading %s...done", XSTRING (name)->data);
  return Qt;
}

And then add the following function somewhere in process.c:

/* Internal function to create a filter process, that given an
   input file descriptor and an argument list, invokes the
   process with the output directed to a pipe, and return the
   file descriptor of the read end of the pipe.  */

int
create_filter (infd, new_argv)
     int infd;			/* input file descriptor */
     char *new_argv[];		/* argument list */
{
  int pipe_fd[2];
  int pid;
  char **env;
  /* child_setup must clobber environ on systems with true vfork.
       Protect it from permanent change.  */
  extern char **environ;
  char **save_environ = environ;

#ifdef MAINTAIN_ENVIRONMENT
    env = (char **) alloca (size_of_current_environ ());
    get_current_environ (env);
#else
    env = environ;
#endif /* MAINTAIN_ENVIRONMENT */

  if (pipe (pipe_fd) < 0)
    {
      error ("Failure to create pipe for %s command", new_argv[0]);
      return -1;
    }

  /* Delay interrupts until we have a chance to store
     the new fork's pid in its process structure */
#ifdef SIGCHLD
#ifdef BSD4_1
  sighold (SIGCHLD);
#else /* not BSD4_1 */
#ifdef HPUX
  sigsetmask (1 << (SIGCHLD - 1));
#endif /* HPUX */
#if defined (BSD) || defined (UNIPLUS)
  sigsetmask (1 << (SIGCHLD - 1));
#else /* ordinary USG */
  sigchld = (int (*)()) signal (SIGCHLD, SIG_DFL);
#endif /* ordinary USG */
#endif /* not BSD4_1 */
#endif /* SIGCHLD */

  pid = vfork ();
  if (pid == 0)
    /* don't do controlling terminal stuff, since we are using pipes. */
    child_setup (infd, pipe_fd[1], pipe_fd[1], new_argv, env);

  environ = save_environ;

  close (pipe_fd[1]);
  close (infd);
  if (pid < 0)
    {
      close (pipe_fd[0]);
      pipe_fd[0] = -1;
      report_file_error ("Doing vfork", Qnil);
    }

#ifdef SIGCHLD
#ifdef BSD4_1
  sigrelse (SIGCHLD);
#else /* not BSD4_1 */
#ifdef HPUX
  sigsetmask (0);
#endif /* HPUX */
#if defined (BSD) || defined (UNIPLUS)
  sigsetmask (0);
#else /* ordinary USG */
  signal (SIGCHLD, sigchld);
#endif /* ordinary USG */
#endif /* not BSD4_1 */
#endif /* SIGCHLD */

  return pipe_fd[0];
}

--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142

Considering the flames and intolerance, shouldn't USENET be spelled ABUSENET?

rms@GNU.AI.MIT.EDU (Richard Stallman) (03/21/91)

It's not a good idea for people to introduce further use of compress,
because it's patented, and Unisys wants us to pay for the privilege.

True, they won't come after an individual to demand money.  They won't
even know about you.  However, the more we get in the habit of using
compress, the harder it will be for larger organizations to drop it
when forced otherwise to pay.

We are working on alternative data-compression programs, and so are
other people, but there's no telling when one will be available and
suitable.

mjh@kernel.co.uk (Mark J Hewitt) (03/21/91)

I'd be interested to know just how much time penalty vs. space saving
this trend for loading compressed .el[c]'s is.  After all, by not using
the byte compiled versions, or by off-line storing the .el sources and
loading only .elc's, there will be a considerable saving.  Using .el's
rather than .elc's must imply a load-time time penalty - which is what
compression must do in any case.

So the best saving is to off-line the .el's and compress the .elc's.

What are the time and space tradeoffs for all these options?

Mark J. Hewitt

bangpath: ...!ukc!kernel!mjh		JANET:	mjh@uk.co.kernel
voice:	  (+44) 532 444566		other:	mjh@kernel.co.uk
fax:	  (+44) 532 425456	    old style:  mjh%uk.co.kernel@uk.ac.ukc
paper:	Kernel Technology Ltd, Development Centre, 46 The Calls, Leeds,
	LS2 7EY, West Yorkshire, UK