Replace bcopy, bzero, bcmp by memcpy, memmove, memset, memcmp
[bpt/emacs.git] / src / sysdep.c
index 96ab399..cfa0efa 100644 (file)
@@ -1,6 +1,6 @@
 /* Interfaces to system-dependent kernel and library entries.
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1999, 2000, 2001,
-                 2002, 2003, 2004, 2005, 2006, 2007, 2008
+                 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -22,12 +22,21 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <config.h>
 #endif
 
+#include <ctype.h>
 #include <signal.h>
 #include <stdio.h>
 #include <setjmp.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#include <grp.h>
+#endif /* HAVE_PWD_H */
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif /* HAVE_LIMITS_H */
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+
 #include "lisp.h"
 /* Including stdlib.h isn't necessarily enough to get srandom
    declared, e.g. without __USE_XOPEN_EXTENDED with glibc 2.  */
@@ -49,19 +58,12 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 #endif /* not WINDOWSNT */
 
-/* Does anyone other than VMS need this? */
-#ifndef fwrite
-#define sys_fwrite fwrite
-#else
-#undef fwrite
-#endif
-
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
 
 #ifdef HAVE_SETPGID
-#if !defined (USG) || defined (BSD_PGRPS)
+#if !defined (USG)
 #undef setpgrp
 #define setpgrp setpgid
 #endif
@@ -78,17 +80,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "msdos.h"
 #include <sys/param.h>
 
-#if __DJGPP__ > 1
 extern int etext;
 extern unsigned start __asm__ ("start");
 #endif
-#endif
-
-#ifndef USE_CRT_DLL
-#ifndef errno
-extern int errno;
-#endif
-#endif
 
 #include <sys/file.h>
 
@@ -156,7 +150,7 @@ struct utimbuf {
 #define LPASS8 0
 #endif
 
-static int baud_convert[] =
+static const int baud_convert[] =
   {
     0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
     1800, 2400, 4800, 9600, 19200, 38400
@@ -175,7 +169,7 @@ static int baud_convert[] =
 
 int emacs_ospeed;
 
-void croak P_ ((char *)) NO_RETURN;
+void croak (char *) NO_RETURN;
 
 /* Temporary used by `sigblock' when defined in terms of signprocmask.  */
 
@@ -188,7 +182,7 @@ SIGMASKTYPE sigprocmask_set;
    Any other returned value must be freed with free. This is used
    only when get_current_dir_name is not defined on the system.  */
 char*
-get_current_dir_name ()
+get_current_dir_name (void)
 {
   char *buf;
   char *pwd;
@@ -260,7 +254,7 @@ get_current_dir_name ()
 /* Discard pending input on all input descriptors.  */
 
 void
-discard_tty_input ()
+discard_tty_input (void)
 {
 #ifndef WINDOWSNT
   struct emacs_tty buf;
@@ -359,8 +353,7 @@ init_baud_rate (int fd)
 \f
 /*ARGSUSED*/
 void
-set_exclusive_use (fd)
-     int fd;
+set_exclusive_use (int fd)
 {
 #ifdef FIOCLEX
   ioctl (fd, FIOCLEX, 0);
@@ -370,13 +363,10 @@ set_exclusive_use (fd)
 \f
 #ifndef subprocesses
 
-wait_without_blocking ()
+void
+wait_without_blocking (void)
 {
-#ifdef BSD_SYSTEM
-  wait3 (0, WNOHANG | WUNTRACED, 0);
-#else
   croak ("wait_without_blocking");
-#endif
   synch_process_alive = 0;
 }
 
@@ -386,15 +376,14 @@ int wait_debugging;   /* Set nonzero to make following function work under dbx
                         (at least for bsd).  */
 
 SIGTYPE
-wait_for_termination_signal ()
+wait_for_termination_signal (void)
 {}
 
 /* Wait for subprocess with process id `pid' to terminate and
    make sure it will get eliminated (not remain forever as a zombie) */
 
 void
-wait_for_termination (pid)
-     int pid;
+wait_for_termination (int pid)
 {
   while (1)
     {
@@ -419,7 +408,10 @@ wait_for_termination (pid)
       else
        sigpause (SIGEMPTYMASK);
 #else /* not BSD_SYSTEM, and not HPUX version >= 6 */
-#ifdef POSIX_SIGNALS    /* would this work for GNU/Linux as well? */
+#ifdef WINDOWSNT
+      wait (0);
+      break;
+#else /* not WINDOWSNT */
       sigblock (sigmask (SIGCHLD));
       errno = 0;
       if (kill (pid, 0) == -1 && errno == ESRCH)
@@ -429,38 +421,10 @@ wait_for_termination (pid)
        }
 
       sigsuspend (&empty_mask);
-#else /* not POSIX_SIGNALS */
-#ifdef HAVE_SYSV_SIGPAUSE
-      sighold (SIGCHLD);
-      if (0 > kill (pid, 0))
-       {
-         sigrelse (SIGCHLD);
-         break;
-       }
-      sigpause (SIGCHLD);
-#else /* not HAVE_SYSV_SIGPAUSE */
-#ifdef WINDOWSNT
-      wait (0);
-      break;
-#else /* not WINDOWSNT */
-      if (0 > kill (pid, 0))
-       break;
-      /* Using sleep instead of pause avoids timing error.
-        If the inferior dies just before the sleep,
-        we lose just one second.  */
-      sleep (1);
 #endif /* not WINDOWSNT */
-#endif /* not HAVE_SYSV_SIGPAUSE */
-#endif /* not POSIX_SIGNALS */
 #endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
 #else /* not subprocesses */
-#if __DJGPP__ > 1
       break;
-#else /* not __DJGPP__ > 1 */
-      if (kill (pid, 0) < 0)
-       break;
-      wait (0);
-#endif /* not __DJGPP__ > 1*/
 #endif /* not subprocesses */
     }
 }
@@ -473,8 +437,7 @@ wait_for_termination (pid)
  */
 
 void
-flush_pending_output (channel)
-     int channel;
+flush_pending_output (int channel)
 {
 #ifdef HAVE_TERMIOS
   /* If we try this, we get hit with SIGTTIN, because
@@ -500,8 +463,7 @@ flush_pending_output (channel)
     in Emacs.  No padding needed for insertion into an Emacs buffer.  */
 
 void
-child_setup_tty (out)
-     int out;
+child_setup_tty (int out)
 {
 #ifndef DOS_NT
   struct emacs_tty s;
@@ -535,8 +497,6 @@ child_setup_tty (out)
 #endif
   s.main.c_oflag &= ~TAB3;     /* Disable tab expansion */
   s.main.c_cflag = (s.main.c_cflag & ~CSIZE) | CS8; /* Don't strip 8th bit */
-  s.main.c_lflag |= ICANON;    /* Enable erase/kill and eof processing */
-  s.main.c_cc[VEOF] = 04;      /* insure that EOF is Control-D */
   s.main.c_cc[VERASE] = CDISABLE;      /* disable erase processing */
   s.main.c_cc[VKILL] = CDISABLE;       /* disable kill processing */
 
@@ -554,11 +514,6 @@ child_setup_tty (out)
 #endif /* not SIGNALS_VIA_CHARACTERS */
 
 #ifdef AIX
-/* AIX enhanced edit loses NULs, so disable it */
-#ifndef IBMR2AIX
-  s.main.c_line = 0;
-  s.main.c_iflag &= ~ASCEDIT;
-#endif
   /* Also, PTY overloads NUL and BREAK.
      don't ignore break, but don't signal either, so it looks like NUL.  */
   s.main.c_iflag &= ~IGNBRK;
@@ -566,16 +521,21 @@ child_setup_tty (out)
   /* rms: Formerly it set s.main.c_cc[VINTR] to 0377 here
      unconditionally.  Then a SIGNALS_VIA_CHARACTERS conditional
      would force it to 0377.  That looks like duplicated code.  */
-#ifndef SIGNALS_VIA_CHARACTERS
-  /* QUIT and INTR work better as signals, so disable character forms */
-  s.main.c_cc[VQUIT] = CDISABLE;
-  s.main.c_cc[VINTR] = CDISABLE;
-  s.main.c_lflag &= ~ISIG;
-#endif /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
-  s.main.c_cc[VEOL] = CDISABLE;
   s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
 #endif /* AIX */
 
+  /* We used to enable ICANON (and set VEOF to 04), but this leads to
+     problems where process.c wants to send EOFs every once in a while
+     to force the output, which leads to weird effects when the
+     subprocess has disabled ICANON and ends up seeing those spurious
+     extra EOFs.  So we don't send EOFs any more in
+     process.c:send_process, and instead we disable ICANON by default,
+     so if a subsprocess sets up ICANON, it's his problem (or the Elisp
+     package that talks to it) to deal with lines that are too long.  */
+  s.main.c_lflag &= ~ICANON;   /* Disable line editing and eof processing */
+  s.main.c_cc[VMIN] = 1;
+  s.main.c_cc[VTIME] = 0;
+
 #else /* not HAVE_TERMIO */
 
   s.main.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE
@@ -598,16 +558,16 @@ child_setup_tty (out)
 struct save_signal
 {
   int code;
-  SIGTYPE (*handler) P_ ((int));
+  SIGTYPE (*handler) (int);
 };
 
-static void save_signal_handlers P_ ((struct save_signal *));
-static void restore_signal_handlers P_ ((struct save_signal *));
+static void save_signal_handlers (struct save_signal *);
+static void restore_signal_handlers (struct save_signal *);
 
 /* Suspend the Emacs process; give terminal to its superior.  */
 
 void
-sys_suspend ()
+sys_suspend (void)
 {
 #if defined (SIGTSTP) && !defined (MSDOS)
 
@@ -617,25 +577,18 @@ sys_suspend ()
   }
 
 #else /* No SIGTSTP */
-#ifdef USG_JOBCTRL /* If you don't know what this is don't mess with it */
-  ptrace (0, 0, 0, 0);         /* set for ptrace - caught by csh */
-  kill (getpid (), SIGQUIT);
-
-#else /* No SIGTSTP or USG_JOBCTRL */
-
 /* On a system where suspending is not implemented,
    instead fork a subshell and let it talk directly to the terminal
    while we wait.  */
   sys_subshell ();
 
-#endif /* no USG_JOBCTRL */
 #endif /* no SIGTSTP */
 }
 
 /* Fork a subshell.  */
 
 void
-sys_subshell ()
+sys_subshell (void)
 {
 #ifdef DOS_NT  /* Demacs 1.1.2 91/10/20 Manabu Higashida */
   int st;
@@ -670,17 +623,15 @@ sys_subshell ()
   dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
   str = (unsigned char *) alloca (SCHARS (dir) + 2);
   len = SCHARS (dir);
-  bcopy (SDATA (dir), str, len);
+  memcpy (str, SDATA (dir), len);
   if (str[len - 1] != '/') str[len++] = '/';
   str[len] = 0;
  xyzzy:
 
 #ifdef DOS_NT
   pid = 0;
-#if __DJGPP__ > 1
   save_signal_handlers (saved_handlers);
   synch_process_alive = 1;
-#endif /* __DJGPP__ > 1 */
 #else
   pid = vfork ();
   if (pid == -1)
@@ -752,7 +703,7 @@ sys_subshell ()
     }
 
   /* Do this now if we did not do it before.  */
-#if !defined (MSDOS) || __DJGPP__ == 1
+#ifndef MSDOS
   save_signal_handlers (saved_handlers);
   synch_process_alive = 1;
 #endif
@@ -765,20 +716,18 @@ sys_subshell ()
 }
 
 static void
-save_signal_handlers (saved_handlers)
-     struct save_signal *saved_handlers;
+save_signal_handlers (struct save_signal *saved_handlers)
 {
   while (saved_handlers->code)
     {
       saved_handlers->handler
-       = (SIGTYPE (*) P_ ((int))) signal (saved_handlers->code, SIG_IGN);
+        = (SIGTYPE (*) (int)) signal (saved_handlers->code, SIG_IGN);
       saved_handlers++;
     }
 }
 
 static void
-restore_signal_handlers (saved_handlers)
-     struct save_signal *saved_handlers;
+restore_signal_handlers (struct save_signal *saved_handlers)
 {
   while (saved_handlers->code)
     {
@@ -815,8 +764,7 @@ unrequest_sigio (void)
 int old_fcntl_flags[MAXDESC];
 
 void
-init_sigio (fd)
-     int fd;
+init_sigio (int fd)
 {
 #ifdef FASYNC
   old_fcntl_flags[fd] = fcntl (fd, F_GETFL, 0) & ~FASYNC;
@@ -826,8 +774,7 @@ init_sigio (fd)
 }
 
 void
-reset_sigio (fd)
-     int fd;
+reset_sigio (int fd)
 {
 #ifdef FASYNC
   fcntl (fd, F_SETFL, old_fcntl_flags[fd]);
@@ -839,7 +786,7 @@ reset_sigio (fd)
 /* XXX Yeah, but you need it for SIGIO, don't you? */
 
 void
-request_sigio ()
+request_sigio (void)
 {
   if (noninteractive)
     return;
@@ -854,7 +801,7 @@ request_sigio ()
 
 void
 unrequest_sigio (void)
-{ 
+{
   if (noninteractive)
     return;
 
@@ -874,7 +821,7 @@ unrequest_sigio (void)
 #ifndef MSDOS
 
 void
-request_sigio ()
+request_sigio (void)
 {
   if (noninteractive || read_socket_hook)
     return;
@@ -883,7 +830,7 @@ request_sigio ()
 }
 
 void
-unrequest_sigio ()
+unrequest_sigio (void)
 {
   if (noninteractive || read_socket_hook)
     return;
@@ -895,65 +842,7 @@ unrequest_sigio ()
 #endif /* FASYNC */
 #endif /* F_SETFL */
 #endif /* SIGIO */
-\f
-/* Saving and restoring the process group of Emacs's terminal.  */
-
-#ifdef BSD_PGRPS
-
-/* The process group of which Emacs was a member when it initially
-   started.
-
-   If Emacs was in its own process group (i.e. inherited_pgroup ==
-   getpid ()), then we know we're running under a shell with job
-   control (Emacs would never be run as part of a pipeline).
-   Everything is fine.
-
-   If Emacs was not in its own process group, then we know we're
-   running under a shell (or a caller) that doesn't know how to
-   separate itself from Emacs (like sh).  Emacs must be in its own
-   process group in order to receive SIGIO correctly.  In this
-   situation, we put ourselves in our own pgroup, forcibly set the
-   tty's pgroup to our pgroup, and make sure to restore and reinstate
-   the tty's pgroup just like any other terminal setting.  If
-   inherited_group was not the tty's pgroup, then we'll get a
-   SIGTTmumble when we try to change the tty's pgroup, and a CONT if
-   it goes foreground in the future, which is what should happen.
-
-   This variable is initialized in emacs.c.  */
-int inherited_pgroup;
-
-/* Split off the foreground process group to Emacs alone.  When we are
-   in the foreground, but not started in our own process group,
-   redirect the tty device handle FD to point to our own process
-   group.  We need to be in our own process group to receive SIGIO
-   properly.  */
-static void
-narrow_foreground_group (int fd)
-{
-  int me = getpid ();
 
-  setpgrp (0, inherited_pgroup);
-#if 0
-  /* XXX inherited_pgroup should not be zero here, but GTK seems to
-     mess this up. */
-  if (! inherited_pgroup)
-    abort ();                   /* Should not happen. */
-#endif
-  if (inherited_pgroup != me)
-      EMACS_SET_TTY_PGRP (fd, &me); /* XXX This only works on the controlling tty. */
-  setpgrp (0, me);
-}
-
-/* Set the tty to our original foreground group.  */
-static void
-widen_foreground_group (int fd)
-{
-  if (inherited_pgroup != getpid ())
-    EMACS_SET_TTY_PGRP (fd, &inherited_pgroup);
-  setpgrp (0, inherited_pgroup);
-}
-
-#endif /* BSD_PGRPS */
 \f
 /* Getting and setting emacs_tty structures.  */
 
@@ -961,14 +850,12 @@ widen_foreground_group (int fd)
    Return zero if all's well, or -1 if we ran into an error we
    couldn't deal with.  */
 int
-emacs_get_tty (fd, settings)
-     int fd;
-     struct emacs_tty *settings;
+emacs_get_tty (int fd, struct emacs_tty *settings)
 {
   /* Retrieve the primary parameters - baud rate, character size, etcetera.  */
 #ifdef HAVE_TCATTR
   /* We have those nifty POSIX tcmumbleattr functions.  */
-  bzero (&settings->main, sizeof (settings->main));
+  memset (&settings->main, 0, sizeof (settings->main));
   if (tcgetattr (fd, &settings->main) < 0)
     return -1;
 
@@ -1010,10 +897,7 @@ emacs_get_tty (fd, settings)
    Return 0 if all went well, and -1 if anything failed.  */
 
 int
-emacs_set_tty (fd, settings, flushp)
-     int fd;
-     struct emacs_tty *settings;
-     int flushp;
+emacs_set_tty (int fd, struct emacs_tty *settings, int flushp)
 {
   /* Set the primary parameters - baud rate, character size, etcetera.  */
 #ifdef HAVE_TCATTR
@@ -1038,7 +922,7 @@ emacs_set_tty (fd, settings, flushp)
       {
        struct termios new;
 
-       bzero (&new, sizeof (new));
+       memset (&new, 0, sizeof (new));
        /* Get the current settings, and see if they're what we asked for.  */
        tcgetattr (fd, &new);
        /* We cannot use memcmp on the whole structure here because under
@@ -1125,8 +1009,7 @@ init_all_sys_modes (void)
 /* Initialize the terminal mode on the given tty device. */
 
 void
-init_sys_modes (tty_out)
-     struct tty_display_info *tty_out;
+init_sys_modes (struct tty_display_info *tty_out)
 {
   struct emacs_tty tty;
 
@@ -1137,19 +1020,10 @@ init_sys_modes (tty_out)
 
   if (!tty_out->output)
     return;                     /* The tty is suspended. */
-  
-#ifdef BSD_PGRPS
-#if 0
-  /* read_socket_hook is not global anymore.  I think doing this
-     unconditionally will not cause any problems. */
-  if (! read_socket_hook && EQ (Vinitial_window_system, Qnil))
-#endif
-    narrow_foreground_group (fileno (tty_out->input));
-#endif
 
   if (! tty_out->old_tty)
     tty_out->old_tty = (struct emacs_tty *) xmalloc (sizeof (struct emacs_tty));
-      
+
   EMACS_GET_TTY (fileno (tty_out->input), tty_out->old_tty);
 
   tty = *tty_out->old_tty;
@@ -1207,7 +1081,7 @@ init_sys_modes (tty_out)
          means that the interrupt and quit feature must be
          disabled on secondary ttys, or we would not even see the
          keypress.
-         
+
          Note that even though emacsclient could have special code
          to pass SIGINT to Emacs, we should _not_ enable
          interrupt/quit keys for emacsclient frames.  This means
@@ -1225,7 +1099,7 @@ init_sys_modes (tty_out)
   tty.main.c_cc[VSWTCH] = CDISABLE;    /* Turn off shell layering use
                                           of C-z */
 #endif /* VSWTCH */
-  
+
 #if defined (__mips__) || defined (HAVE_TCATTR)
 #ifdef VSUSP
   tty.main.c_cc[VSUSP] = CDISABLE;     /* Turn off mips handling of C-z.  */
@@ -1270,16 +1144,10 @@ init_sys_modes (tty_out)
 #endif /* mips or HAVE_TCATTR */
 
 #ifdef AIX
-#ifndef IBMR2AIX
-  /* AIX enhanced edit loses NULs, so disable it.  */
-  tty.main.c_line = 0;
-  tty.main.c_iflag &= ~ASCEDIT;
-#else
   tty.main.c_cc[VSTRT] = CDISABLE;
   tty.main.c_cc[VSTOP] = CDISABLE;
   tty.main.c_cc[VSUSP] = CDISABLE;
   tty.main.c_cc[VDSUSP] = CDISABLE;
-#endif /* IBMR2AIX */
   if (tty_out->flow_control)
     {
 #ifdef VSTART
@@ -1322,9 +1190,9 @@ init_sys_modes (tty_out)
       tty.tchars.t_startc = '\021';
       tty.tchars.t_stopc = '\023';
     }
-  
+
   tty.lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | tty_out->old_tty.lmode;
-  
+
 #endif /* HAVE_TCHARS */
 #endif /* not HAVE_TERMIO */
 
@@ -1402,9 +1270,8 @@ init_sys_modes (tty_out)
 
   if (tty_out->term_initted && no_redraw_on_reenter)
     {
-      /* XXX This seems wrong on multi-tty. */
-      if (display_completed)
-       direct_output_forward_char (0);
+      /* We used to call "direct_output_forward_char(0)" here,
+        but it's not clear why, since it may not do anything anyway.  */
     }
   else
     {
@@ -1485,8 +1352,7 @@ get_tty_size (int fd, int *widthp, int *heightp)
    to HEIGHT and WIDTH.  This is used mainly with ptys.  */
 
 int
-set_window_size (fd, height, width)
-     int fd, height, width;
+set_window_size (int fd, int height, int width)
 {
 #ifdef TIOCSWINSZ
 
@@ -1534,8 +1400,7 @@ reset_all_sys_modes (void)
    bottom of the frame, turn off interrupt-driven I/O, etc.  */
 
 void
-reset_sys_modes (tty_out)
-     struct tty_display_info *tty_out;
+reset_sys_modes (struct tty_display_info *tty_out)
 {
   if (noninteractive)
     {
@@ -1547,11 +1412,11 @@ reset_sys_modes (tty_out)
 
   if (!tty_out->output)
     return;                     /* The tty is suspended. */
-  
+
   /* Go to and clear the last line of the terminal. */
 
   cmgoto (tty_out, FrameRows (tty_out) - 1, 0);
-  
+
   /* Code adapted from tty_clear_end_of_line. */
   if (tty_out->TS_clr_line)
     {
@@ -1561,16 +1426,16 @@ reset_sys_modes (tty_out)
     {                  /* have to do it the hard way */
       int i;
       tty_turn_off_insert (tty_out);
-      
+
       for (i = curX (tty_out); i < FrameCols (tty_out) - 1; i++)
         {
           fputc (' ', tty_out->output);
         }
     }
-  
+
   cmgoto (tty_out, FrameRows (tty_out) - 1, 0);
   fflush (tty_out->output);
-  
+
   if (tty_out->terminal->reset_terminal_modes_hook)
     tty_out->terminal->reset_terminal_modes_hook (tty_out->terminal);
 
@@ -1603,9 +1468,6 @@ reset_sys_modes (tty_out)
   dos_ttcooked ();
 #endif
 
-#ifdef BSD_PGRPS
-  widen_foreground_group (fileno (tty_out->input));
-#endif
 }
 \f
 #ifdef HAVE_PTYS
@@ -1613,8 +1475,7 @@ reset_sys_modes (tty_out)
 /* Set up the proper status flags for use of a pty.  */
 
 void
-setup_pty (fd)
-     int fd;
+setup_pty (int fd)
 {
   /* I'm told that TOICREMOTE does not mean control chars
      "can't be sent" but rather that they don't have
@@ -1663,7 +1524,7 @@ setup_pty (fd)
 #if !(defined (__NetBSD__) && defined (__ELF__))
 #ifndef HAVE_TEXT_START
 char *
-start_of_text ()
+start_of_text (void)
 {
 #ifdef TEXT_START
   return ((char *) TEXT_START);
@@ -1703,7 +1564,7 @@ start_of_text ()
 
 #ifndef start_of_data
 char *
-start_of_data ()
+start_of_data (void)
 {
 #ifdef DATA_START
   return ((char *) DATA_START);
@@ -1744,7 +1605,7 @@ extern int h_errno;
 #endif /* TRY_AGAIN */
 
 void
-init_system_name ()
+init_system_name (void)
 {
 #ifndef HAVE_GETHOSTNAME
   struct utsname uts;
@@ -1785,7 +1646,7 @@ init_system_name ()
         struct addrinfo hints;
         int ret;
 
-        memset (&hints, 0, sizeof(hints));
+        memset (&hints, 0, sizeof (hints));
         hints.ai_socktype = SOCK_STREAM;
         hints.ai_flags = AI_CANONNAME;
 
@@ -1897,8 +1758,8 @@ jmp_buf read_alarm_throw;
 
 int read_alarm_should_throw;
 
-SIGTYPE
-select_alarm ()
+void
+select_alarm (int ignore)
 {
   select_alarmed = 1;
   signal (SIGALRM, SIG_IGN);
@@ -1910,13 +1771,12 @@ select_alarm ()
 #ifndef WINDOWSNT
 /* Only rfds are checked.  */
 int
-sys_select (nfds, rfds, wfds, efds, timeout)
-     int nfds;
-     SELECT_TYPE *rfds, *wfds, *efds;
-     EMACS_TIME *timeout;
+sys_select (int nfds,
+           SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
+           EMACS_TIME *timeout)
 {
   /* XXX This needs to be updated for multi-tty support.  Is there
-     anybody who needs to emulate select these days?  */ 
+     anybody who needs to emulate select these days?  */
  int ravail = 0;
   SELECT_TYPE orfds;
   int timeoutval;
@@ -2047,7 +1907,7 @@ sys_select (nfds, rfds, wfds, efds, timeout)
    waiting for at least one character.  */
 
 void
-read_input_waiting ()
+read_input_waiting (void)
 {
   /* XXX This needs to be updated for multi-tty support.  Is there
      anybody who needs to emulate select these days?  */
@@ -2114,10 +1974,10 @@ read_input_waiting ()
 /* POSIX signals support - DJB */
 /* Anyone with POSIX signals should have ANSI C declarations */
 
-#ifdef POSIX_SIGNALS
-
 sigset_t empty_mask, full_mask;
 
+#ifndef WINDOWSNT
+
 signal_handler_t
 sys_signal (int signal_number, signal_handler_t action)
 {
@@ -2135,6 +1995,8 @@ sys_signal (int signal_number, signal_handler_t action)
      When SYNC_INPUT is set, we don't want SA_RESTART because we need to poll
      for pending input so we need long-running syscalls to be interrupted
      after a signal that sets the interrupt_input_pending flag.  */
+  /* Non-interactive keyboard input goes through stdio, where we always
+     want restartable system calls.  */
 # if defined (BROKEN_SA_RESTART) || defined(SYNC_INPUT)
   if (noninteractive)
 # endif
@@ -2144,6 +2006,8 @@ sys_signal (int signal_number, signal_handler_t action)
   return (old_action.sa_handler);
 }
 
+#endif /* WINDOWSNT */
+
 #ifndef __GNUC__
 /* If we're compiling with GCC, we don't need this function, since it
    can be written as a macro.  */
@@ -2186,7 +2050,6 @@ sys_sigsetmask (sigset_t new_mask)
   return (old_mask);
 }
 
-#endif /* POSIX_SIGNALS */
 \f
 #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
 static char *my_sys_siglist[NSIG];
@@ -2197,12 +2060,10 @@ static char *my_sys_siglist[NSIG];
 #endif
 
 void
-init_signals ()
+init_signals (void)
 {
-#ifdef POSIX_SIGNALS
   sigemptyset (&empty_mask);
   sigfillset (&full_mask);
-#endif
 
 #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
   if (! initialized)
@@ -2405,8 +2266,7 @@ init_signals ()
 #endif /* !RAND_BITS */
 
 void
-seed_random (arg)
-     long arg;
+seed_random (long int arg)
 {
 #ifdef HAVE_RANDOM
   srandom ((unsigned int)arg);
@@ -2424,7 +2284,7 @@ seed_random (arg)
  * This suffices even for a 64-bit architecture with a 15-bit rand.
  */
 long
-get_random ()
+get_random (void)
 {
   long val = random ();
 #if VALBITS > RAND_BITS
@@ -2459,9 +2319,7 @@ strerror (errnum)
 #endif /* ! HAVE_STRERROR */
 \f
 int
-emacs_open (path, oflag, mode)
-     const char *path;
-     int oflag, mode;
+emacs_open (const char *path, int oflag, int mode)
 {
   register int rtnval;
 
@@ -2472,8 +2330,7 @@ emacs_open (path, oflag, mode)
 }
 
 int
-emacs_close (fd)
-     int fd;
+emacs_close (int fd)
 {
   int did_retry = 0;
   register int rtnval;
@@ -2492,10 +2349,7 @@ emacs_close (fd)
 }
 
 int
-emacs_read (fildes, buf, nbyte)
-     int fildes;
-     char *buf;
-     unsigned int nbyte;
+emacs_read (int fildes, char *buf, unsigned int nbyte)
 {
   register int rtnval;
 
@@ -2506,10 +2360,7 @@ emacs_read (fildes, buf, nbyte)
 }
 
 int
-emacs_write (fildes, buf, nbyte)
-     int fildes;
-     const char *buf;
-     unsigned int nbyte;
+emacs_write (int fildes, const char *buf, unsigned int nbyte)
 {
   register int rtnval, bytes_written;
 
@@ -2526,10 +2377,7 @@ emacs_write (fildes, buf, nbyte)
 #ifdef SYNC_INPUT
              /* I originally used `QUIT' but that might causes files to
                 be truncated if you hit C-g in the middle of it.  --Stef  */
-             if (interrupt_input_pending)
-               handle_async_input ();
-              if (pending_atimers)
-                do_pending_atimers ();
+             process_pending_signals ();
 #endif
              continue;
            }
@@ -2573,11 +2421,10 @@ emacs_write (fildes, buf, nbyte)
 #ifndef HAVE_GETWD
 
 char *
-getwd (pathname)
-     char *pathname;
+getwd (char *pathname)
 {
   char *npath, *spath;
-  extern char *getcwd ();
+  extern char *getcwd (char *, size_t);
 
   BLOCK_INPUT;                 /* getcwd uses malloc */
   spath = npath = getcwd ((char *) 0, MAXPATHLEN);
@@ -2606,9 +2453,8 @@ getwd (pathname)
 
 #ifndef HAVE_RENAME
 
-rename (from, to)
-     const char *from;
-     const char *to;
+int
+rename (const char *from, const char *to)
 {
   if (access (from, 0) == 0)
     {
@@ -2628,7 +2474,8 @@ rename (from, to)
 /* HPUX curses library references perror, but as far as we know
    it won't be called.  Anyway this definition will do for now.  */
 
-perror ()
+void
+perror (void)
 {
 }
 #endif /* HPUX and not HAVE_PERROR */
@@ -2641,9 +2488,8 @@ perror ()
  *     until we are, then close the unsuccessful ones.
  */
 
-dup2 (oldd, newd)
-     int oldd;
-     int newd;
+int
+dup2 (int oldd, int newd)
 {
   register int fd, ret;
 
@@ -2677,11 +2523,9 @@ dup2 (oldd, newd)
 
 /* ARGSUSED */
 int
-gettimeofday (tp, tzp)
-     struct timeval *tp;
-     struct timezone *tzp;
+gettimeofday (struct timeval *tp, struct timezone *tzp)
 {
-  extern long time ();
+  extern long time (long);
 
   tp->tv_sec = time ((long *)0);
   tp->tv_usec = 0;
@@ -2699,8 +2543,7 @@ gettimeofday (tp, tzp)
  */
 
 void
-croak (badfunc)
-     char *badfunc;
+croak (char *badfunc)
 {
   printf ("%s not yet implemented\r\n", badfunc);
   reset_all_sys_modes ();
@@ -2723,13 +2566,6 @@ closedir (DIR *dirp /* stream from opendir */)
   int rtnval;
 
   rtnval = emacs_close (dirp->dd_fd);
-
-  /* Some systems (like Solaris) allocate the buffer and the DIR all
-     in one block.  Why in the world are we freeing this ourselves
-     anyway?  */
-#if ! defined (SOLARIS2)
-  xfree ((char *) dirp->dd_buf); /* directory block defined in <dirent.h> */
-#endif
   xfree ((char *) dirp);
 
   return rtnval;
@@ -2739,9 +2575,7 @@ closedir (DIR *dirp /* stream from opendir */)
 
 \f
 int
-set_file_times (filename, atime, mtime)
-     const char *filename;
-     EMACS_TIME atime, mtime;
+set_file_times (const char *filename, EMACS_TIME atime, EMACS_TIME mtime)
 {
 #ifdef HAVE_UTIMES
   struct timeval tv[2];
@@ -2777,14 +2611,8 @@ set_file_times (filename, atime, mtime)
 /*
  * Make a directory.
  */
-#ifdef MKDIR_PROTOTYPE
-MKDIR_PROTOTYPE
-#else
 int
-mkdir (dpath, dmode)
-     char *dpath;
-     int dmode;
-#endif
+mkdir (char *dpath, int dmode)
 {
   int cpid, status, fd;
   struct stat statbuf;
@@ -2842,8 +2670,7 @@ mkdir (dpath, dmode)
 
 #ifndef HAVE_RMDIR
 int
-rmdir (dpath)
-     char *dpath;
+rmdir (char *dpath)
 {
   int cpid, status, fd;
   struct stat statbuf;
@@ -2888,58 +2715,62 @@ rmdir (dpath)
 #endif /* !HAVE_RMDIR */
 
 \f
-#ifndef BSTRING
-
-#ifndef bzero
-
-void
-bzero (b, length)
-     register char *b;
-     register int length;
+#ifndef HAVE_MEMSET
+void *
+memset (void *b, int n, size_t length)
 {
+  unsigned char *p = b;
   while (length-- > 0)
-    *b++ = 0;
+    *p++ = n;
+  return b;
 }
+#endif /* !HAVE_MEMSET */
 
-#endif /* no bzero */
-#endif /* BSTRING */
-
-#if (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY)
-#undef bcopy
-
-/* Saying `void' requires a declaration, above, where bcopy is used
-   and that declaration causes pain for systems where bcopy is a macro.  */
-bcopy (b1, b2, length)
-     register char *b1;
-     register char *b2;
-     register int length;
+#ifndef HAVE_MEMCPY
+void *
+memcpy (void *b1, void *b2, size_t length)
 {
+  unsigned char *p1 = b1, *p2 = b2;
   while (length-- > 0)
-    *b2++ = *b1++;
+    *p1++ = *p2++;
+  return b1;
+}
+#endif /* !HAVE_MEMCPY */
+
+#ifndef HAVE_MEMMOVE
+void *
+memmove (void *b1, void *b2, size_t length)
+{
+  unsigned char *p1 = b1, *p2 = b2;
+  if (p1 < p2 || p1 >= p2 + length)
+    while (length-- > 0)
+      *p1++ = *p2++;
+  else
+    {
+      p1 += length;
+      p2 += length;
+      while (length-- > 0)
+       *--p1 = *--p2;
+    }
+  return b1;
 }
-#endif /* (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY) */
+#endif /* !HAVE_MEMCPY */
 
-#ifndef BSTRING
-#ifndef bcmp
+#ifndef HAVE_MEMCMP
 int
-bcmp (b1, b2, length)  /* This could be a macro! */
-     register char *b1;
-     register char *b2;
-     register int length;
+memcmp (void *b1, void *b2, size_t length)
 {
+  unsigned char *p1 = b1, *p2 = b2;
   while (length-- > 0)
-    if (*b1++ != *b2++)
-      return 1;
-
+    if (*p1++ != *p2++)
+      return p1[-1] < p2[-1] ? -1 : 1;
   return 0;
 }
-#endif /* no bcmp */
-#endif /* not BSTRING */
+#endif /* !HAVE_MEMCMP */
 \f
 #ifndef HAVE_STRSIGNAL
 char *
-strsignal (code)
-     int code;
+strsignal (int code)
 {
   char *signame = 0;
 
@@ -2955,7 +2786,8 @@ strsignal (code)
 \f
 #ifdef HAVE_TERMIOS
 /* For make-serial-process  */
-int serial_open (char *port)
+int
+serial_open (char *port)
 {
   int fd = -1;
 
@@ -2988,7 +2820,8 @@ int serial_open (char *port)
 #if !defined (HAVE_CFMAKERAW)
 /* Workaround for targets which are missing cfmakeraw.  */
 /* Pasted from man page.  */
-static void cfmakeraw (struct termios *termios_p)
+static void
+cfmakeraw (struct termios *termios_p)
 {
     termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
     termios_p->c_oflag &= ~OPOST;
@@ -3000,7 +2833,8 @@ static void cfmakeraw (struct termios *termios_p)
 
 #if !defined (HAVE_CFSETSPEED)
 /* Workaround for targets which are missing cfsetspeed.  */
-static int cfsetspeed (struct termios *termios_p, speed_t vitesse)
+static int
+cfsetspeed (struct termios *termios_p, speed_t vitesse)
 {
   return (cfsetispeed (termios_p, vitesse)
          + cfsetospeed (termios_p, vitesse));
@@ -3010,7 +2844,7 @@ static int cfsetspeed (struct termios *termios_p, speed_t vitesse)
 /* For serial-process-configure  */
 void
 serial_configure (struct Lisp_Process *p,
-                     Lisp_Object contact)
+                 Lisp_Object contact)
 {
   Lisp_Object childp2 = Qnil;
   Lisp_Object tem = Qnil;
@@ -3029,7 +2863,7 @@ serial_configure (struct Lisp_Process *p,
   attr.c_cflag |= CLOCAL;
 #endif
 #if defined (CREAD)
-  attr.c_cflag | CREAD;
+  attr.c_cflag |= CREAD;
 #endif
 
   /* Configure speed.  */
@@ -3053,7 +2887,7 @@ serial_configure (struct Lisp_Process *p,
   CHECK_NUMBER (tem);
   if (XINT (tem) != 7 && XINT (tem) != 8)
     error (":bytesize must be nil (8), 7, or 8");
-  summary[0] = XINT(tem) + '0';
+  summary[0] = XINT (tem) + '0';
 #if defined (CSIZE) && defined (CS7) && defined (CS8)
   attr.c_cflag &= ~CSIZE;
   attr.c_cflag |= ((XINT (tem) == 7) ? CS7 : CS8);
@@ -3169,6 +3003,598 @@ serial_configure (struct Lisp_Process *p,
 
 }
 #endif /* TERMIOS  */
+\f
+/* System depended enumeration of and access to system processes a-la ps(1).  */
+
+#ifdef HAVE_PROCFS
+
+/* Process enumeration and access via /proc.  */
+
+Lisp_Object
+list_system_processes (void)
+{
+  Lisp_Object procdir, match, proclist, next;
+  struct gcpro gcpro1, gcpro2;
+  register Lisp_Object tail;
+
+  GCPRO2 (procdir, match);
+  /* For every process on the system, there's a directory in the
+     "/proc" pseudo-directory whose name is the numeric ID of that
+     process.  */
+  procdir = build_string ("/proc");
+  match = build_string ("[0-9]+");
+  proclist = directory_files_internal (procdir, Qnil, match, Qt, 0, Qnil);
+
+  /* `proclist' gives process IDs as strings.  Destructively convert
+     each string into a number.  */
+  for (tail = proclist; CONSP (tail); tail = next)
+    {
+      next = XCDR (tail);
+      XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil));
+    }
+  UNGCPRO;
+
+  /* directory_files_internal returns the files in reverse order; undo
+     that.  */
+  proclist = Fnreverse (proclist);
+  return proclist;
+}
+
+/* The WINDOWSNT implementation is in w32.c.
+   The MSDOS implementation is in dosfns.c.  */
+#elif !defined (WINDOWSNT) && !defined (MSDOS)
+
+Lisp_Object
+list_system_processes (void)
+{
+  return Qnil;
+}
+
+#endif /* !defined (WINDOWSNT) */
+
+#ifdef GNU_LINUX
+static void
+time_from_jiffies (unsigned long long tval, long hz,
+                  time_t *sec, unsigned *usec)
+{
+  unsigned long long ullsec;
+
+  *sec = tval / hz;
+  ullsec = *sec;
+  tval -= ullsec * hz;
+  /* Careful: if HZ > 1 million, then integer division by it yields zero.  */
+  if (hz <= 1000000)
+    *usec = tval * 1000000 / hz;
+  else
+    *usec = tval / (hz / 1000000);
+}
+
+static Lisp_Object
+ltime_from_jiffies (unsigned long long tval, long hz)
+{
+  time_t sec;
+  unsigned usec;
+
+  time_from_jiffies (tval, hz, &sec, &usec);
+
+  return list3 (make_number ((sec >> 16) & 0xffff),
+               make_number (sec & 0xffff),
+               make_number (usec));
+}
+
+static void
+get_up_time (time_t *sec, unsigned *usec)
+{
+  FILE *fup;
+
+  *sec = *usec = 0;
+
+  BLOCK_INPUT;
+  fup = fopen ("/proc/uptime", "r");
+
+  if (fup)
+    {
+      double uptime, idletime;
+
+      /* The numbers in /proc/uptime use C-locale decimal point, but
+        we already set ourselves to the C locale (see `fixup_locale'
+        in emacs.c).  */
+      if (2 <= fscanf (fup, "%lf %lf", &uptime, &idletime))
+       {
+         *sec = uptime;
+         *usec = (uptime - *sec) * 1000000;
+       }
+      fclose (fup);
+    }
+  UNBLOCK_INPUT;
+}
+
+#define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff)
+#define MINOR(d) (((unsigned)(d) & 0xff) | (((unsigned)(d) & 0xfff00000) >> 12))
+
+static Lisp_Object
+procfs_ttyname (int rdev)
+{
+  FILE *fdev = NULL;
+  char name[PATH_MAX];
+
+  BLOCK_INPUT;
+  fdev = fopen ("/proc/tty/drivers", "r");
+
+  if (fdev)
+    {
+      unsigned major;
+      unsigned long minor_beg, minor_end;
+      char minor[25];  /* 2 32-bit numbers + dash */
+      char *endp;
+
+      while (!feof (fdev) && !ferror (fdev))
+       {
+         if (3 <= fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor)
+             && major == MAJOR (rdev))
+           {
+             minor_beg = strtoul (minor, &endp, 0);
+             if (*endp == '\0')
+               minor_end = minor_beg;
+             else if (*endp == '-')
+               minor_end = strtoul (endp + 1, &endp, 0);
+             else
+               continue;
+
+             if (MINOR (rdev) >= minor_beg && MINOR (rdev) <= minor_end)
+               {
+                 sprintf (name + strlen (name), "%u", MINOR (rdev));
+                 break;
+               }
+           }
+       }
+      fclose (fdev);
+    }
+  UNBLOCK_INPUT;
+  return build_string (name);
+}
+
+static unsigned long
+procfs_get_total_memory (void)
+{
+  FILE *fmem = NULL;
+  unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */
+
+  BLOCK_INPUT;
+  fmem = fopen ("/proc/meminfo", "r");
+
+  if (fmem)
+    {
+      unsigned long entry_value;
+      char entry_name[20];     /* the longest I saw is 13+1 */
+
+      while (!feof (fmem) && !ferror (fmem))
+       {
+         if (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value)
+             && strcmp (entry_name, "MemTotal:") == 0)
+           {
+             retval = entry_value;
+             break;
+           }
+       }
+      fclose (fmem);
+    }
+  UNBLOCK_INPUT;
+  return retval;
+}
+
+Lisp_Object
+system_process_attributes (Lisp_Object pid)
+{
+  char procfn[PATH_MAX], fn[PATH_MAX];
+  struct stat st;
+  struct passwd *pw;
+  struct group *gr;
+  long clocks_per_sec;
+  char *procfn_end;
+  char procbuf[1025], *p, *q;
+  int fd;
+  ssize_t nread;
+  const char *cmd = NULL;
+  char *cmdline = NULL;
+  size_t cmdsize = 0, cmdline_size;
+  unsigned char c;
+  int proc_id, ppid, uid, gid, pgrp, sess, tty, tpgid, thcount;
+  unsigned long long utime, stime, cutime, cstime, start;
+  long priority, nice, rss;
+  unsigned long minflt, majflt, cminflt, cmajflt, vsize;
+  time_t sec;
+  unsigned usec;
+  EMACS_TIME tnow, tstart, tboot, telapsed;
+  double pcpu, pmem;
+  Lisp_Object attrs = Qnil;
+  Lisp_Object cmd_str, decoded_cmd, tem;
+  struct gcpro gcpro1, gcpro2;
+  EMACS_INT uid_eint, gid_eint;
+
+  CHECK_NUMBER_OR_FLOAT (pid);
+  proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
+  sprintf (procfn, "/proc/%u", proc_id);
+  if (stat (procfn, &st) < 0)
+    return attrs;
+
+  GCPRO2 (attrs, decoded_cmd);
+
+  /* euid egid */
+  uid = st.st_uid;
+  /* Use of EMACS_INT stops GCC whining about limited range of data type.  */
+  uid_eint = uid;
+  attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid_eint)), attrs);
+  BLOCK_INPUT;
+  pw = getpwuid (uid);
+  UNBLOCK_INPUT;
+  if (pw)
+    attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
+
+  gid = st.st_gid;
+  gid_eint = gid;
+  attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid_eint)), attrs);
+  BLOCK_INPUT;
+  gr = getgrgid (gid);
+  UNBLOCK_INPUT;
+  if (gr)
+    attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
+
+  strcpy (fn, procfn);
+  procfn_end = fn + strlen (fn);
+  strcpy (procfn_end, "/stat");
+  fd = emacs_open (fn, O_RDONLY, 0);
+  if (fd >= 0 && (nread = emacs_read (fd, procbuf, sizeof (procbuf) - 1)) > 0)
+    {
+      procbuf[nread] = '\0';
+      p = procbuf;
+
+      p = strchr (p, '(');
+      if (p != NULL)
+       {
+         q = strrchr (p + 1, ')');
+         /* comm */
+         if (q != NULL)
+           {
+             cmd = p + 1;
+             cmdsize = q - cmd;
+           }
+       }
+      else
+       q = NULL;
+      if (cmd == NULL)
+       {
+         cmd = "???";
+         cmdsize = 3;
+       }
+      /* Command name is encoded in locale-coding-system; decode it.  */
+      cmd_str = make_unibyte_string (cmd, cmdsize);
+      decoded_cmd = code_convert_string_norecord (cmd_str,
+                                                 Vlocale_coding_system, 0);
+      attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
+
+      if (q)
+       {
+         EMACS_INT ppid_eint, pgrp_eint, sess_eint, tpgid_eint, thcount_eint;
+         p = q + 2;
+         /* state ppid pgrp sess tty tpgid . minflt cminflt majflt cmajflt utime stime cutime cstime priority nice thcount . start vsize rss */
+         sscanf (p, "%c %d %d %d %d %d %*u %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld %d %*d %Lu %lu %ld",
+                 &c, &ppid, &pgrp, &sess, &tty, &tpgid,
+                 &minflt, &cminflt, &majflt, &cmajflt,
+                 &utime, &stime, &cutime, &cstime,
+                 &priority, &nice, &thcount, &start, &vsize, &rss);
+         {
+           char state_str[2];
+
+           state_str[0] = c;
+           state_str[1] = '\0';
+           tem =  build_string (state_str);
+           attrs = Fcons (Fcons (Qstate, tem), attrs);
+         }
+         /* Stops GCC whining about limited range of data type.  */
+         ppid_eint = ppid;
+         pgrp_eint = pgrp;
+         sess_eint = sess;
+         tpgid_eint = tpgid;
+         thcount_eint = thcount;
+         attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (ppid_eint)), attrs);
+         attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pgrp_eint)), attrs);
+         attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (sess_eint)), attrs);
+         attrs = Fcons (Fcons (Qttname, procfs_ttyname (tty)), attrs);
+         attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (tpgid_eint)), attrs);
+         attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (minflt)), attrs);
+         attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (majflt)), attrs);
+         attrs = Fcons (Fcons (Qcminflt, make_fixnum_or_float (cminflt)), attrs);
+         attrs = Fcons (Fcons (Qcmajflt, make_fixnum_or_float (cmajflt)), attrs);
+         clocks_per_sec = sysconf (_SC_CLK_TCK);
+         if (clocks_per_sec < 0)
+           clocks_per_sec = 100;
+         attrs = Fcons (Fcons (Qutime,
+                               ltime_from_jiffies (utime, clocks_per_sec)),
+                        attrs);
+         attrs = Fcons (Fcons (Qstime,
+                               ltime_from_jiffies (stime, clocks_per_sec)),
+                        attrs);
+         attrs = Fcons (Fcons (Qtime,
+                               ltime_from_jiffies (stime+utime, clocks_per_sec)),
+                        attrs);
+         attrs = Fcons (Fcons (Qcutime,
+                               ltime_from_jiffies (cutime, clocks_per_sec)),
+                        attrs);
+         attrs = Fcons (Fcons (Qcstime,
+                               ltime_from_jiffies (cstime, clocks_per_sec)),
+                        attrs);
+         attrs = Fcons (Fcons (Qctime,
+                               ltime_from_jiffies (cstime+cutime, clocks_per_sec)),
+                        attrs);
+         attrs = Fcons (Fcons (Qpri, make_number (priority)), attrs);
+         attrs = Fcons (Fcons (Qnice, make_number (nice)), attrs);
+         attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs);
+         EMACS_GET_TIME (tnow);
+         get_up_time (&sec, &usec);
+         EMACS_SET_SECS (telapsed, sec);
+         EMACS_SET_USECS (telapsed, usec);
+         EMACS_SUB_TIME (tboot, tnow, telapsed);
+         time_from_jiffies (start, clocks_per_sec, &sec, &usec);
+         EMACS_SET_SECS (tstart, sec);
+         EMACS_SET_USECS (tstart, usec);
+         EMACS_ADD_TIME (tstart, tboot, tstart);
+         attrs = Fcons (Fcons (Qstart,
+                               list3 (make_number
+                                      ((EMACS_SECS (tstart) >> 16) & 0xffff),
+                                      make_number
+                                      (EMACS_SECS (tstart) & 0xffff),
+                                      make_number
+                                      (EMACS_USECS (tstart)))),
+                        attrs);
+         attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs);
+         attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs);
+         EMACS_SUB_TIME (telapsed, tnow, tstart);
+         attrs = Fcons (Fcons (Qetime,
+                               list3 (make_number
+                                      ((EMACS_SECS (telapsed) >> 16) & 0xffff),
+                                      make_number
+                                      (EMACS_SECS (telapsed) & 0xffff),
+                                      make_number
+                                      (EMACS_USECS (telapsed)))),
+                        attrs);
+         time_from_jiffies (utime + stime, clocks_per_sec, &sec, &usec);
+         pcpu = (sec + usec / 1000000.0) / (EMACS_SECS (telapsed) + EMACS_USECS (telapsed) / 1000000.0);
+         if (pcpu > 1.0)
+           pcpu = 1.0;
+         attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs);
+         pmem = 4.0 * 100 * rss / procfs_get_total_memory ();
+         if (pmem > 100)
+           pmem = 100;
+         attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs);
+       }
+    }
+  if (fd >= 0)
+    emacs_close (fd);
+
+  /* args */
+  strcpy (procfn_end, "/cmdline");
+  fd = emacs_open (fn, O_RDONLY, 0);
+  if (fd >= 0)
+    {
+      for (cmdline_size = 0; emacs_read (fd, &c, 1) == 1; cmdline_size++)
+       {
+         if (isspace (c) || c == '\\')
+           cmdline_size++;     /* for later quoting, see below */
+       }
+      if (cmdline_size)
+       {
+         cmdline = xmalloc (cmdline_size + 1);
+         lseek (fd, 0L, SEEK_SET);
+         cmdline[0] = '\0';
+         if ((nread = read (fd, cmdline, cmdline_size)) >= 0)
+           cmdline[nread++] = '\0';
+         else
+           {
+             /* Assigning zero to `nread' makes us skip the following
+                two loops, assign zero to cmdline_size, and enter the
+                following `if' clause that handles unknown command
+                lines.  */
+             nread = 0;
+           }
+         /* We don't want trailing null characters.  */
+         for (p = cmdline + nread - 1; p > cmdline && !*p; p--)
+           nread--;
+         for (p = cmdline; p < cmdline + nread; p++)
+           {
+             /* Escape-quote whitespace and backslashes.  */
+             if (isspace (*p) || *p == '\\')
+               {
+                 memmove (p + 1, p, nread - (p - cmdline));
+                 nread++;
+                 *p++ = '\\';
+               }
+             else if (*p == '\0')
+               *p = ' ';
+           }
+         cmdline_size = nread;
+       }
+      if (!cmdline_size)
+       {
+         if (!cmd)
+           cmd = "???";
+         if (!cmdsize)
+           cmdsize = strlen (cmd);
+         cmdline_size = cmdsize + 2;
+         cmdline = xmalloc (cmdline_size + 1);
+         strcpy (cmdline, "[");
+         strcat (strncat (cmdline, cmd, cmdsize), "]");
+       }
+      emacs_close (fd);
+      /* Command line is encoded in locale-coding-system; decode it.  */
+      cmd_str = make_unibyte_string (cmdline, cmdline_size);
+      decoded_cmd = code_convert_string_norecord (cmd_str,
+                                                 Vlocale_coding_system, 0);
+      xfree (cmdline);
+      attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
+    }
+
+  UNGCPRO;
+  return attrs;
+}
+
+#elif defined (SOLARIS2) && defined (HAVE_PROCFS)
+
+/* The <procfs.h> header does not like to be included if _LP64 is defined and
+   __FILE_OFFSET_BITS == 64.  This is an ugly workaround that.  */
+#if !defined (_LP64) && defined (_FILE_OFFSET_BITS) &&  (_FILE_OFFSET_BITS  ==  64)
+#define PROCFS_FILE_OFFSET_BITS_HACK 1
+#undef _FILE_OFFSET_BITS
+#else
+#define PROCFS_FILE_OFFSET_BITS_HACK 0
+#endif
+
+#include <procfs.h>
+
+#if PROCFS_FILE_OFFSET_BITS_HACK ==  1
+#define _FILE_OFFSET_BITS 64
+#endif /* PROCFS_FILE_OFFSET_BITS_HACK ==  1 */
+
+Lisp_Object
+system_process_attributes (Lisp_Object pid)
+{
+  char procfn[PATH_MAX], fn[PATH_MAX];
+  struct stat st;
+  struct passwd *pw;
+  struct group *gr;
+  char *procfn_end;
+  struct psinfo pinfo;
+  int fd;
+  ssize_t nread;
+  int proc_id, uid, gid;
+  Lisp_Object attrs = Qnil;
+  Lisp_Object decoded_cmd, tem;
+  struct gcpro gcpro1, gcpro2;
+  EMACS_INT uid_eint, gid_eint;
+
+  CHECK_NUMBER_OR_FLOAT (pid);
+  proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
+  sprintf (procfn, "/proc/%u", proc_id);
+  if (stat (procfn, &st) < 0)
+    return attrs;
+
+  GCPRO2 (attrs, decoded_cmd);
+
+  /* euid egid */
+  uid = st.st_uid;
+  /* Use of EMACS_INT stops GCC whining about limited range of data type.  */
+  uid_eint = uid;
+  attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid_eint)), attrs);
+  BLOCK_INPUT;
+  pw = getpwuid (uid);
+  UNBLOCK_INPUT;
+  if (pw)
+    attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
+
+  gid = st.st_gid;
+  gid_eint = gid;
+  attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid_eint)), attrs);
+  BLOCK_INPUT;
+  gr = getgrgid (gid);
+  UNBLOCK_INPUT;
+  if (gr)
+    attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
+
+  strcpy (fn, procfn);
+  procfn_end = fn + strlen (fn);
+  strcpy (procfn_end, "/psinfo");
+  fd = emacs_open (fn, O_RDONLY, 0);
+  if (fd >= 0
+      && (nread = read (fd, (char*)&pinfo, sizeof (struct psinfo)) > 0))
+    {
+          attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (pinfo.pr_ppid)), attrs);
+         attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pinfo.pr_pgid)), attrs);
+         attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (pinfo.pr_sid)), attrs);
+
+         {
+           char state_str[2];
+           state_str[0] =  pinfo.pr_lwp.pr_sname;
+           state_str[1] =  '\0';
+           tem =   build_string (state_str);
+           attrs =  Fcons (Fcons (Qstate,  tem),  attrs);
+         }
+
+         /* FIXME: missing Qttyname. psinfo.pr_ttydev is a dev_t,
+            need to get a string from it. */
+
+         /* FIXME: missing: Qtpgid */
+
+         /* FIXME: missing:
+               Qminflt
+               Qmajflt
+               Qcminflt
+               Qcmajflt
+
+               Qutime
+               Qcutime
+               Qstime
+               Qcstime
+               Are they available? */
+
+         attrs = Fcons (Fcons (Qtime,
+                               list3 (make_number (pinfo.pr_time.tv_sec >> 16),
+                                      make_number (pinfo.pr_time.tv_sec & 0xffff),
+                                      make_number (pinfo.pr_time.tv_nsec))),
+                        attrs);
+
+         attrs = Fcons (Fcons (Qctime,
+                               list3 (make_number (pinfo.pr_ctime.tv_sec >> 16),
+                                      make_number (pinfo.pr_ctime.tv_sec & 0xffff),
+                                      make_number (pinfo.pr_ctime.tv_nsec))),
+                        attrs);
+
+         attrs = Fcons (Fcons (Qpri, make_number (pinfo.pr_lwp.pr_pri)), attrs);
+         attrs = Fcons (Fcons (Qnice, make_number (pinfo.pr_lwp.pr_nice)), attrs);
+         attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (pinfo.pr_nlwp)), attrs);
+
+         attrs = Fcons (Fcons (Qstart,
+                               list3 (make_number (pinfo.pr_start.tv_sec >> 16),
+                                      make_number (pinfo.pr_start.tv_sec & 0xffff),
+                                      make_number (pinfo.pr_start.tv_nsec))),
+                        attrs);
+         attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (pinfo.pr_size)), attrs);
+         attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (pinfo.pr_rssize)), attrs);
+
+         /* pr_pctcpu and pr_pctmem are encoded as a fixed point 16 bit number in  [0 ... 1].  */
+         attrs = Fcons (Fcons (Qpcpu, (pinfo.pr_pctcpu * 100.0) / (double)0x8000), attrs);
+         attrs = Fcons (Fcons (Qpmem, (pinfo.pr_pctmem * 100.0) / (double)0x8000), attrs);
+
+         decoded_cmd
+           =  code_convert_string_norecord (make_unibyte_string (pinfo.pr_fname,
+                                                                 strlen (pinfo.pr_fname)),
+                                            Vlocale_coding_system,  0);
+         attrs =  Fcons (Fcons (Qcomm,  decoded_cmd),  attrs);
+         decoded_cmd
+           =  code_convert_string_norecord (make_unibyte_string (pinfo.pr_psargs,
+                                                                 strlen (pinfo.pr_psargs)),
+                                            Vlocale_coding_system,  0);
+         attrs =  Fcons (Fcons (Qargs,  decoded_cmd),  attrs);
+    }
+
+  if (fd >= 0)
+    emacs_close (fd);
+
+  UNGCPRO;
+  return attrs;
+}
+
+/* The WINDOWSNT implementation is in w32.c.
+   The MSDOS implementation is in dosfns.c.  */
+#elif !defined (WINDOWSNT) && !defined (MSDOS)
+
+Lisp_Object
+system_process_attributes (Lisp_Object pid)
+{
+  return Qnil;
+}
+
+#endif /* !defined (WINDOWSNT) */
+
 
 /* arch-tag: edb43589-4e09-4544-b325-978b5b121dcf
    (do not change this comment) */