(struct xftface_info): Delete the member xft_draw.
[bpt/emacs.git] / src / callproc.c
index 90e5b11..567fe3a 100644 (file)
@@ -6,7 +6,7 @@ This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -75,7 +75,7 @@ extern int errno;
 #include "lisp.h"
 #include "commands.h"
 #include "buffer.h"
-#include "charset.h"
+#include "character.h"
 #include "ccl.h"
 #include "coding.h"
 #include "composite.h"
@@ -84,6 +84,8 @@ extern int errno;
 #include "syssignal.h"
 #include "systty.h"
 #include "blockinput.h"
+#include "frame.h"
+#include "termhooks.h"
 
 #ifdef MSDOS
 #include "msdos.h"
@@ -111,13 +113,13 @@ Lisp_Object Vtemp_file_name_pattern;
 
 Lisp_Object Vshell_file_name;
 
-Lisp_Object Vprocess_environment;
+Lisp_Object Vprocess_environment, Vinitial_environment;
 
 #ifdef DOS_NT
 Lisp_Object Qbuffer_file_type;
 #endif /* DOS_NT */
 
-/* True iff we are about to fork off a synchronous process or if we
+/* True if we are about to fork off a synchronous process or if we
    are waiting for it.  */
 int synch_process_alive;
 
@@ -130,6 +132,7 @@ int synch_process_termsig;
 /* If synch_process_death is zero,
    this is exit code of synchronous subprocess.  */
 int synch_process_retcode;
+
 \f
 /* Clean up when exiting Fcall_process.
    On MSDOS, delete the temporary file on any kind of termination.
@@ -138,6 +141,8 @@ int synch_process_retcode;
 /* Nonzero if this is termination due to exit.  */
 static int call_process_exited;
 
+EXFUN (Fgetenv_internal, 2);
+
 #ifndef VMS  /* VMS version is in vmsproc.c.  */
 
 static Lisp_Object
@@ -273,6 +278,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     if (nargs >= 5)
       {
        int must_encode = 0;
+       Lisp_Object coding_attrs;
 
        for (i = 4; i < nargs; i++)
          CHECK_STRING (args[i]);
@@ -298,11 +304,15 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
            else
              val = Qnil;
          }
+       val = coding_inherit_eol_type (val, Qnil);
        setup_coding_system (Fcheck_coding_system (val), &argument_coding);
-       if (argument_coding.common_flags & CODING_ASCII_INCOMPATIBLE_MASK)
-         setup_coding_system (Qraw_text, &argument_coding);
-       if (argument_coding.eol_type == CODING_EOL_UNDECIDED)
-         argument_coding.eol_type = system_eol_type;
+       coding_attrs = CODING_ID_ATTRS (argument_coding.id);
+       if (NILP (CODING_ATTR_ASCII_COMPAT (coding_attrs)))
+         {
+           /* We should not use an ASCII incompatible coding system.  */
+           val = raw_text_coding_system (val);
+           setup_coding_system (val, &argument_coding);
+         }
       }
   }
 
@@ -425,12 +435,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
        {
          argument_coding.src_multibyte = STRING_MULTIBYTE (args[i]);
          if (CODING_REQUIRE_ENCODING (&argument_coding))
-           {
-             /* We must encode this argument.  */
-             args[i] = encode_coding_string (args[i], &argument_coding, 1);
-             if (argument_coding.type == coding_type_ccl)
-               setup_ccl_program (&(argument_coding.spec.ccl.encoder), Qnil);
-           }
+           /* We must encode this argument.  */
+           args[i] = encode_coding_string (&argument_coding, args[i], 1);
          new_argv[i - 3] = SDATA (args[i]);
        }
       UNGCPRO;
@@ -742,19 +748,15 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
          else
            val = Qnil;
        }
-      setup_coding_system (Fcheck_coding_system (val), &process_coding);
+      Fcheck_coding_system (val);
       /* In unibyte mode, character code conversion should not take
         place but EOL conversion should.  So, setup raw-text or one
         of the subsidiary according to the information just setup.  */
       if (NILP (current_buffer->enable_multibyte_characters)
          && !NILP (val))
-       setup_raw_text_coding_system (&process_coding);
+       val = raw_text_coding_system (val);
+      setup_coding_system (val, &process_coding);
     }
-  process_coding.src_multibyte = 0;
-  process_coding.dst_multibyte
-    = (BUFFERP (buffer)
-       ? ! NILP (XBUFFER (buffer)->enable_multibyte_characters)
-       : ! NILP (current_buffer->enable_multibyte_characters));
 
   immediate_quit = 1;
   QUIT;
@@ -766,12 +768,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     int carryover = 0;
     int display_on_the_fly = display_p;
     struct coding_system saved_coding;
-    int pt_orig = PT, pt_byte_orig = PT_BYTE;
-    int inserted;
 
     saved_coding = process_coding;
-    if (process_coding.composing != COMPOSITION_DISABLED)
-      coding_allocate_composition_data (&process_coding, PT);
     while (1)
       {
        /* Repeatedly read until we've filled as much as possible
@@ -804,133 +802,49 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
 
        if (!NILP (buffer))
          {
-           if (! CODING_MAY_REQUIRE_DECODING (&process_coding))
+           if (NILP (current_buffer->enable_multibyte_characters)
+               && ! CODING_MAY_REQUIRE_DECODING (&process_coding))
              insert_1_both (buf, nread, nread, 0, 1, 0);
            else
              {                 /* We have to decode the input.  */
-               int size;
-               char *decoding_buf;
-
-             repeat_decoding:
-               size = decoding_buffer_size (&process_coding, nread);
-               decoding_buf = (char *) xmalloc (size);
-
-               /* We can't use the macro CODING_REQUIRE_DETECTION
-                  because it always returns nonzero if the coding
-                  system requires EOL detection.  Here, we have to
-                  check only whether or not the coding system
-                  requires text-encoding detection.  */
-               if (process_coding.type == coding_type_undecided)
-                 {
-                   detect_coding (&process_coding, buf, nread);
-                   if (process_coding.composing != COMPOSITION_DISABLED)
-                     /* We have not yet allocated the composition
-                        data because the coding type was undecided.  */
-                     coding_allocate_composition_data (&process_coding, PT);
-                 }
-               if (process_coding.cmp_data)
-                 process_coding.cmp_data->char_offset = PT;
-
-               decode_coding (&process_coding, buf, decoding_buf,
-                              nread, size);
+               Lisp_Object curbuf;
 
+               XSETBUFFER (curbuf, current_buffer);
+               decode_coding_c_string (&process_coding, buf, nread,
+                                       curbuf);
                if (display_on_the_fly
-                   && saved_coding.type == coding_type_undecided
-                   && process_coding.type != coding_type_undecided)
+                   && CODING_REQUIRE_DETECTION (&saved_coding)
+                   && ! CODING_REQUIRE_DETECTION (&process_coding))
                  {
                    /* We have detected some coding system.  But,
                       there's a possibility that the detection was
-                      done by insufficient data.  So, we try the code
-                      detection again with more data.  */
-                   xfree (decoding_buf);
+                      done by insufficient data.  So, we give up
+                      displaying on the fly.  */
+                   if (process_coding.produced > 0)
+                     del_range_2 (process_coding.dst_pos,
+                                  process_coding.dst_pos_byte,
+                                  process_coding.dst_pos
+                                  + process_coding.produced_char,
+                                  process_coding.dst_pos_byte
+                                  + process_coding.produced, 0);
                    display_on_the_fly = 0;
                    process_coding = saved_coding;
                    carryover = nread;
                    /* This is to make the above condition always
                       fails in the future.  */
-                   saved_coding.type = coding_type_no_conversion;
+                   saved_coding.common_flags
+                     &= ~CODING_REQUIRE_DETECTION_MASK;
                    continue;
                  }
 
-               if (process_coding.produced > 0)
-                 insert_1_both (decoding_buf, process_coding.produced_char,
-                                process_coding.produced, 0, 1, 0);
-               xfree (decoding_buf);
-
-               if (process_coding.result == CODING_FINISH_INCONSISTENT_EOL)
-                 {
-                   Lisp_Object eol_type, coding;
-
-                   if (process_coding.eol_type == CODING_EOL_CR)
-                     {
-                       /* CRs have been replaced with LFs.  Undo
-                          that in the text inserted above.  */
-                       unsigned char *p;
-
-                       move_gap_both (PT, PT_BYTE);
-
-                       p = BYTE_POS_ADDR (pt_byte_orig);
-                       for (; p < GPT_ADDR; ++p)
-                         if (*p == '\n')
-                           *p = '\r';
-                     }
-                   else if (process_coding.eol_type == CODING_EOL_CRLF)
-                     {
-                       /* CR LFs have been replaced with LFs.  Undo
-                          that by inserting CRs in front of LFs in
-                          the text inserted above.  */
-                       EMACS_INT bytepos, old_pt, old_pt_byte, nCR;
-
-                       old_pt = PT;
-                       old_pt_byte = PT_BYTE;
-                       nCR = 0;
-
-                       for (bytepos = PT_BYTE - 1;
-                            bytepos >= pt_byte_orig;
-                            --bytepos)
-                         if (FETCH_BYTE (bytepos) == '\n')
-                           {
-                             EMACS_INT charpos = BYTE_TO_CHAR (bytepos);
-                             TEMP_SET_PT_BOTH (charpos, bytepos);
-                             insert_1_both ("\r", 1, 1, 0, 1, 0);
-                             ++nCR;
-                           }
-
-                       TEMP_SET_PT_BOTH (old_pt + nCR, old_pt_byte + nCR);
-                     }
-
-                   /* Set the coding system symbol to that for
-                      Unix-like EOL.  */
-                   eol_type = Fget (saved_coding.symbol, Qeol_type);
-                   if (VECTORP (eol_type)
-                       && ASIZE (eol_type) == 3
-                       && SYMBOLP (AREF (eol_type, CODING_EOL_LF)))
-                     coding = AREF (eol_type, CODING_EOL_LF);
-                   else
-                     coding = saved_coding.symbol;
-
-                   process_coding.symbol = coding;
-                   process_coding.eol_type = CODING_EOL_LF;
-                   process_coding.mode
-                     &= ~CODING_MODE_INHIBIT_INCONSISTENT_EOL;
-                 }
-
-               nread -= process_coding.consumed;
-               carryover = nread;
+               TEMP_SET_PT_BOTH (PT + process_coding.produced_char,
+                                 PT_BYTE + process_coding.produced);
+               carryover = process_coding.carryover_bytes;
                if (carryover > 0)
                  /* As CARRYOVER should not be that large, we had
                     better avoid overhead of bcopy.  */
-                 BCOPY_SHORT (buf + process_coding.consumed, buf,
-                              carryover);
-               if (process_coding.result == CODING_FINISH_INSUFFICIENT_CMP)
-                 {
-                   /* The decoding ended because of insufficient data
-                      area to record information about composition.
-                      We must try decoding with additional data area
-                      before reading more output for the process.  */
-                   coding_allocate_composition_data (&process_coding, PT);
-                   goto repeat_decoding;
-                 }
+                 BCOPY_SHORT (process_coding.carryover, buf,
+                              process_coding.carryover_bytes);
              }
          }
 
@@ -961,33 +875,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
       }
   give_up: ;
 
-    if (!NILP (buffer)
-       && process_coding.cmp_data)
-      {
-       coding_restore_composition (&process_coding, Fcurrent_buffer ());
-       coding_free_composition_data (&process_coding);
-      }
-
-    {
-      int post_read_count = SPECPDL_INDEX ();
-
-      record_unwind_protect (save_excursion_restore, save_excursion_save ());
-      inserted = PT - pt_orig;
-      TEMP_SET_PT_BOTH (pt_orig, pt_byte_orig);
-      if (SYMBOLP (process_coding.post_read_conversion)
-         && !NILP (Ffboundp (process_coding.post_read_conversion)))
-       call1 (process_coding.post_read_conversion, make_number (inserted));
-
-      Vlast_coding_system_used = process_coding.symbol;
-
-      /* If the caller required, let the buffer inherit the
-        coding-system used to decode the process output.  */
-      if (inherit_process_coding_system)
-       call1 (intern ("after-insert-file-set-buffer-file-coding-system"),
-              make_number (total_read));
-
-      unbind_to (post_read_count, Qnil);
-    }
+    Vlast_coding_system_used = CODING_ID_NAME (process_coding.id);
+    /* If the caller required, let the buffer inherit the
+       coding-system used to decode the process output.  */
+    if (inherit_process_coding_system)
+      call1 (intern ("after-insert-file-set-buffer-file-coding-system"),
+              make_number (total_read));
   }
 
   /* Wait for it to terminate, unless it already has.  */
@@ -1181,6 +1074,40 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
 
 static int relocate_fd ();
 
+static char **
+add_env (char **env, char **new_env, char *string)
+{
+  char **ep;
+  int ok = 1;
+  if (string == NULL)
+    return new_env;
+
+  /* See if this string duplicates any string already in the env.
+     If so, don't put it in.
+     When an env var has multiple definitions,
+     we keep the definition that comes first in process-environment.  */
+  for (ep = env; ok && ep != new_env; ep++)
+    {
+      char *p = *ep, *q = string;
+      while (ok)
+        {
+          if (*q != *p)
+            break;
+          if (*q == 0)
+            /* The string is a lone variable name; keep it for now, we
+               will remove it later.  It is a placeholder for a
+               variable that is not to be included in the environment.  */
+            break;
+          if (*q == '=')
+            ok = 0;
+          p++, q++;
+        }
+    }
+  if (ok)
+    *new_env++ = string;
+  return new_env;
+}
+
 /* This is the last thing run in a newly forked inferior
    either synchronous or asynchronous.
    Copy descriptors IN, OUT and ERR as descriptors 0, 1 and 2.
@@ -1236,9 +1163,10 @@ child_setup (in, out, err, new_argv, set_pgrp, current_dir)
 
   /* Note that use of alloca is always safe here.  It's obvious for systems
      that do not have true vfork or that have true (stack) alloca.
-     If using vfork and C_ALLOCA it is safe because that changes
-     the superior's static variables as if the superior had done alloca
-     and will be cleaned up in the usual way.  */
+     If using vfork and C_ALLOCA (when Emacs used to include
+     src/alloca.c) it is safe because that changes the superior's
+     static variables as if the superior had done alloca and will be
+     cleaned up in the usual way. */
   {
     register char *temp;
     register int i;
@@ -1282,57 +1210,80 @@ child_setup (in, out, err, new_argv, set_pgrp, current_dir)
       temp[--i] = 0;
   }
 
-  /* Set `env' to a vector of the strings in Vprocess_environment.  */
+  /* Set `env' to a vector of the strings in the environment.  */
   {
     register Lisp_Object tem;
     register char **new_env;
+    char **p, **q;
     register int new_length;
-
+    Lisp_Object display = Qnil;
+    
     new_length = 0;
+
     for (tem = Vprocess_environment;
-        CONSP (tem) && STRINGP (XCAR (tem));
-        tem = XCDR (tem))
-      new_length++;
+         CONSP (tem) && STRINGP (XCAR (tem));
+         tem = XCDR (tem))
+      {
+       if (strncmp (SDATA (XCAR (tem)), "DISPLAY", 7) == 0
+           && (SDATA (XCAR (tem)) [7] == '\0'
+               || SDATA (XCAR (tem)) [7] == '='))
+         /* DISPLAY is specified in process-environment.  */
+         display = Qt;
+       new_length++;
+      }
+
+    /* If not provided yet, use the frame's DISPLAY.  */
+    if (NILP (display))
+      {
+       Lisp_Object tmp = Fframe_parameter (selected_frame, Qdisplay);
+       if (!STRINGP (tmp) && CONSP (Vinitial_environment))
+         /* If still not found, Look for DISPLAY in Vinitial_environment.  */
+         tmp = Fgetenv_internal (build_string ("DISPLAY"),
+                                 Vinitial_environment);
+       if (STRINGP (tmp))
+         {
+           display = tmp;
+           new_length++;
+         }
+      }
 
     /* new_length + 2 to include PWD and terminating 0.  */
     env = new_env = (char **) alloca ((new_length + 2) * sizeof (char *));
-
     /* If we have a PWD envvar, pass one down,
        but with corrected value.  */
-    if (getenv ("PWD"))
+    if (egetenv ("PWD"))
       *new_env++ = pwd_var;
+    if (STRINGP (display))
+      {
+       int vlen = strlen ("DISPLAY=") + strlen (SDATA (display)) + 1;
+       char *vdata = (char *) alloca (vlen);
+       strcpy (vdata, "DISPLAY=");
+       strcat (vdata, SDATA (display));
+       new_env = add_env (env, new_env, vdata);
+      }
 
-    /* Copy the Vprocess_environment strings into new_env.  */
+    /* Overrides.  */
     for (tem = Vprocess_environment;
         CONSP (tem) && STRINGP (XCAR (tem));
         tem = XCDR (tem))
+      new_env = add_env (env, new_env, SDATA (XCAR (tem)));
+
+    *new_env = 0;
+
+    /* Remove variable names without values.  */
+    p = q = env;
+    while (*p != 0)
       {
-       char **ep = env;
-       char *string = (char *) SDATA (XCAR (tem));
-       /* See if this string duplicates any string already in the env.
-          If so, don't put it in.
-          When an env var has multiple definitions,
-          we keep the definition that comes first in process-environment.  */
-       for (; ep != new_env; ep++)
-         {
-           char *p = *ep, *q = string;
-           while (1)
-             {
-               if (*q == 0)
-                 /* The string is malformed; might as well drop it.  */
-                 goto duplicate;
-               if (*q != *p)
-                 break;
-               if (*q == '=')
-                 goto duplicate;
-               p++, q++;
-             }
-         }
-       *new_env++ = string;
-      duplicate: ;
+        while (*q != 0 && strchr (*q, '=') == NULL)
+          q++;
+        *p = *q++;
+        if (*p != 0)
+          p++;
       }
-    *new_env = 0;
   }
+
+  
 #ifdef WINDOWSNT
   prepare_standard_handles (in, out, err, handles);
   set_process_dir (SDATA (current_dir));
@@ -1446,22 +1397,18 @@ relocate_fd (fd, minfd)
 }
 
 static int
-getenv_internal (var, varlen, value, valuelen)
+getenv_internal_1 (var, varlen, value, valuelen, env)
      char *var;
      int varlen;
      char **value;
      int *valuelen;
+     Lisp_Object env;
 {
-  Lisp_Object scan;
-
-  for (scan = Vprocess_environment; CONSP (scan); scan = XCDR (scan))
+  for (; CONSP (env); env = XCDR (env))
     {
-      Lisp_Object entry;
-
-      entry = XCAR (scan);
+      Lisp_Object entry = XCAR (env);
       if (STRINGP (entry)
-         && SBYTES (entry) > varlen
-         && SREF (entry, varlen) == '='
+         && SBYTES (entry) >= varlen
 #ifdef WINDOWSNT
          /* NT environment variables are case insensitive.  */
          && ! strnicmp (SDATA (entry), var, varlen)
@@ -1470,35 +1417,95 @@ getenv_internal (var, varlen, value, valuelen)
 #endif /* not WINDOWSNT */
          )
        {
-         *value    = (char *) SDATA (entry) + (varlen + 1);
-         *valuelen = SBYTES (entry) - (varlen + 1);
+         if (SBYTES (entry) > varlen && SREF (entry, varlen) == '=')
+           {
+             *value = (char *) SDATA (entry) + (varlen + 1);
+             *valuelen = SBYTES (entry) - (varlen + 1);
+             return 1;
+           }
+         else if (SBYTES (entry) == varlen)
+           {
+             /* Lone variable names in Vprocess_environment mean that
+                variable should be removed from the environment. */
+             *value = NULL;
+             return 1;
+           }
+       }
+    }
+  return 0;
+}
+
+static int
+getenv_internal (var, varlen, value, valuelen, frame)
+     char *var;
+     int varlen;
+     char **value;
+     int *valuelen;
+     Lisp_Object frame;
+{
+  /* Try to find VAR in Vprocess_environment first.  */
+  if (getenv_internal_1 (var, varlen, value, valuelen,
+                        Vprocess_environment))
+    return *value ? 1 : 0;
+
+  /* For DISPLAY try to get the values from the frame or the initial env.  */
+  if (strcmp (var, "DISPLAY") == 0)
+    {
+      Lisp_Object display
+       = Fframe_parameter (NILP (frame) ? selected_frame : frame, Qdisplay);
+      if (STRINGP (display))
+       {
+         *value    = (char *) SDATA (display);
+         *valuelen = SBYTES (display);
          return 1;
        }
+      /* If still not found, Look for DISPLAY in Vinitial_environment.  */
+      if (getenv_internal_1 (var, varlen, value, valuelen,
+                            Vinitial_environment))
+       return *value ? 1 : 0;
     }
 
   return 0;
 }
 
-DEFUN ("getenv-internal", Fgetenv_internal, Sgetenv_internal, 1, 1, 0,
-       doc: /* Return the value of environment variable VAR, as a string.
-VAR should be a string.  Value is nil if VAR is undefined in the environment.
-This function consults the variable `process-environment' for its value.  */)
-     (var)
-     Lisp_Object var;
+DEFUN ("getenv-internal", Fgetenv_internal, Sgetenv_internal, 1, 2, 0,
+       doc: /* Get the value of environment variable VARIABLE.
+VARIABLE should be a string.  Value is nil if VARIABLE is undefined in
+the environment.  Otherwise, value is a string.
+
+This function searches `process-environment' for VARIABLE.  If it is
+not found there, then it continues the search in the environment list
+of the selected frame.
+
+If optional parameter ENV is a list, then search this list instead of
+`process-environment', and return t when encountering a negative entry.
+
+If it is a frame, then this function will ignore `process-environment' and
+will simply look up the variable in that frame's environment.  */)
+     (variable, env)
+     Lisp_Object variable, env;
 {
   char *value;
   int valuelen;
 
-  CHECK_STRING (var);
-  if (getenv_internal (SDATA (var), SBYTES (var),
-                      &value, &valuelen))
+  CHECK_STRING (variable);
+  if (CONSP (env))
+    {
+      if (getenv_internal_1 (SDATA (variable), SBYTES (variable),
+                            &value, &valuelen, env))
+       return value ? make_string (value, valuelen) : Qt;
+      else
+       return Qnil;
+    }
+  else if (getenv_internal (SDATA (variable), SBYTES (variable),
+                           &value, &valuelen, env))
     return make_string (value, valuelen);
   else
     return Qnil;
 }
 
-/* A version of getenv that consults process_environment, easily
-   callable from C.  */
+/* A version of getenv that consults the Lisp environment lists,
+   easily callable from C.  */
 char *
 egetenv (var)
      char *var;
@@ -1506,7 +1513,7 @@ egetenv (var)
   char *value;
   int valuelen;
 
-  if (getenv_internal (var, strlen (var), &value, &valuelen))
+  if (getenv_internal (var, strlen (var), &value, &valuelen, Qnil))
     return value;
   else
     return 0;
@@ -1629,8 +1636,8 @@ init_callproc ()
     {
       char *dir = getenv ("TMPDIR");
       Vtemp_file_name_pattern
-       = Fexpand_file_name (build_string ("emacsXXXXXX"),
-                            build_string (dir));
+       = Fexpand_file_name (build_string ("emacsXXXXXX"),
+                            build_string (dir));
     }
   else
     Vtemp_file_name_pattern = build_string ("/tmp/emacsXXXXXX");
@@ -1646,17 +1653,20 @@ init_callproc ()
 }
 
 void
-set_process_environment ()
+set_initial_environment ()
 {
   register char **envp;
-
-  Vprocess_environment = Qnil;
 #ifndef CANNOT_DUMP
   if (initialized)
 #endif
-    for (envp = environ; *envp; envp++)
-      Vprocess_environment = Fcons (build_string (*envp),
-                                   Vprocess_environment);
+    {
+      for (envp = environ; *envp; envp++)
+       Vprocess_environment = Fcons (build_string (*envp),
+                                     Vprocess_environment);
+      /* Ideally, the `copy' shouldn't be necessary, but it seems it's frequent
+        to use `delete' and friends on process-environment.  */
+      Vinitial_environment = Fcopy_sequence (Vprocess_environment);
+    }
 }
 
 void
@@ -1715,16 +1725,34 @@ If this variable is nil, then Emacs is unable to use a shared directory.  */);
 This is used by `call-process-region'.  */);
   /* This variable is initialized in init_callproc.  */
 
+  DEFVAR_LISP ("initial-environment", &Vinitial_environment,
+              doc: /* List of environment variables inherited from the parent process.
+Each element should be a string of the form ENVVARNAME=VALUE.
+The elements must normally be decoded (using `locale-coding-system') for use.  */);
+  Vinitial_environment = Qnil;
+
   DEFVAR_LISP ("process-environment", &Vprocess_environment,
-              doc: /* List of environment variables for subprocesses to inherit.
+              doc: /* List of overridden environment variables for subprocesses to inherit.
 Each element should be a string of the form ENVVARNAME=VALUE.
+
+Entries in this list take precedence to those in the frame-local
+environments.  Therefore, let-binding `process-environment' is an easy
+way to temporarily change the value of an environment variable,
+irrespective of where it comes from.  To use `process-environment' to
+remove an environment variable, include only its name in the list,
+without "=VALUE".
+
+This variable is set to nil when Emacs starts.
+
 If multiple entries define the same variable, the first one always
 takes precedence.
-The environment which Emacs inherits is placed in this variable
-when Emacs starts.
+
 Non-ASCII characters are encoded according to the initial value of
-`locale-coding-system', i.e. the elements must normally be decoded for use.
+`locale-coding-system', i.e. the elements must normally be decoded for
+use.
+
 See `setenv' and `getenv'.  */);
+  Vprocess_environment = Qnil;
 
 #ifndef VMS
   defsubr (&Scall_process);