/* "posix.c" functions only in Posix (unix).
   Copyright (C) 1994 Aubrey Jaffer.

This program 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 1, or (at your option)
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

The author can be reached at jaffer@ai.mit.edu or
Aubrey Jaffer, 84 Pleasant St., Wakefield MA 01880
*/

#include "scm.h"

#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <time.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif

#include <sys/stat.h>


#include <pwd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

#ifdef FD_SET

#define SELECT_TYPE fd_set
#define SELECT_SET_SIZE FD_SETSIZE

#else /* no FD_SET */

/* Define the macros to access a single-int bitmap of descriptors.  */
#define SELECT_SET_SIZE 32
#define SELECT_TYPE int
#define FD_SET(n, p) (*(p) |= (1 << (n)))
#define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
#define FD_ISSET(n, p) (*(p) & (1 << (n)))
#define FD_ZERO(p) (*(p) = 0)

#endif /* no FD_SET */
#ifndef STDC_HEADERS
  	char *ttyname P((int fd));
 	FILE *popen P((const char* command, const char* type));
 	int pclose P((FILE* stream));
#endif

 /* Only the superuser can successfully execute this call */
static char s_chown[] = "%chown";
SCM 
scm_chown (path, owner, group)
     SCM path, owner, group;
{
  int val;
  ASSERT (NIMP (path) && STRINGP (path), path, ARG1, s_chown);
  ASSERT (INUMP (owner), owner, ARG2, s_chown);
  ASSERT (INUMP (group), group, ARG3, s_chown);
  SYSCALL (val = chown (CHARS (path), INUM (owner), INUM (group)));
  return val ? BOOL_F : BOOL_T;
}

static char s_link[] = "%link";
SCM 
scm_link (oldpath, newpath)
     SCM oldpath, newpath;
{
  int val;
  ASSERT (NIMP (oldpath) && STRINGP (oldpath), oldpath, ARG1, s_link);
  ASSERT (NIMP (newpath) && STRINGP (newpath), newpath, ARG2, s_link);
  SYSCALL (val = link (CHARS (oldpath), CHARS (newpath)));
  return val ? BOOL_F : BOOL_T;
}

static char s_pipe[] = "%pipe";
SCM 
scm_pipe ()
{
  int fd[2], rv;
  FILE *f_rd, *f_wt;
  SCM p_rd, p_wt;
  NEWCELL (p_rd);
  NEWCELL (p_wt);
  rv = pipe (fd);
  if (rv)
    {
      ALLOW_INTS;
      return BOOL_F;
    }
  f_rd = fdopen (fd[0], "r");
  if (!f_rd)
    {
      SYSCALL (close (fd[0]));
      SYSCALL (close (fd[1]));
      ALLOW_INTS;
      return BOOL_F;
    }
  f_wt = fdopen (fd[1], "w");
  if (!f_wt)
    {
      fclose (f_rd);
      SYSCALL (close (fd[1]));
      ALLOW_INTS;
      return BOOL_F;
    }
  CAR (p_rd) = tc16_fport | scm_mode_bits ("r");
  CAR (p_wt) = tc16_fport | scm_mode_bits ("w");
  SETSTREAM (p_rd, f_rd);
  SETSTREAM (p_wt, f_wt);
  scm_add_to_port_table (p_rd);
  scm_add_to_port_table (p_wt);
  ALLOW_INTS;
  return scm_cons (p_rd, p_wt);
}


/* FIXME: pipe streams are not currently added to the scm_list of ports.
 * If pipe streams are to be kept then some things need to be changed.
 * open-pipe should also be given a exception wrapper.
 */
char s_op_pipe[] = "open-pipe";
SCM 
scm_open_pipe (pipestr, modes)
     SCM pipestr, modes;
{
  FILE *f;
  register SCM z;
  ASSERT (NIMP (pipestr) && STRINGP (pipestr), pipestr, ARG1, s_op_pipe);
  ASSERT (NIMP (modes) && STRINGP (modes), modes, ARG2, s_op_pipe);
  NEWCELL (z);
  /* DEFER_INTS, SYSCALL, and ALLOW_INTS are probably paranoid here*/
  DEFER_INTS;
  scm_ignore_signals ();
  SYSCALL (f = popen (CHARS (pipestr), CHARS (modes)));
  scm_unignore_signals ();
  if (!f)
    z = BOOL_F;
  else
    {
      CAR (z) = tc16_pipe | OPN | (strchr (CHARS (modes), 'r') ? RDNG : WRTNG);
      SETSTREAM (z, f);
    }
  ALLOW_INTS;
  return z;
}

SCM l_open_input_pipe(pipestr)
     SCM pipestr;
{
  return scm_open_pipe(pipestr, scm_makfromstr("r", (sizeof "r")-1, 0));
}
SCM l_open_output_pipe(pipestr)
     SCM pipestr;
{
  return scm_open_pipe(pipestr, scm_makfromstr("w", (sizeof "w")-1, 0));
}
static int prinpipe(exp, port, writing)
     SCM exp; SCM port; int writing;
{
  scm_prinport(exp, port, s_pipe);
  return !0;
}

static char s_getgroups[] = "%getgroups";
SCM scm_getgroups()
{
  SCM grps, ans;
  int ngroups = getgroups (0, NULL);
  if (!ngroups) return BOOL_F;
  NEWCELL(grps);
  DEFER_INTS;
  {
    gid_t *groups = (gid_t *)scm_must_malloc(ngroups * sizeof(gid_t),
					     s_getgroups);
    int val = getgroups(ngroups, groups);
    if (val < 0) {
      scm_must_free((char *)groups);
      ALLOW_INTS;
      return BOOL_F;
    }
    SETCHARS(grps, groups);	/* set up grps as a GC protect */
    SETLENGTH(grps, 0L + ngroups * sizeof(gid_t), tc7_string);
    ALLOW_INTS;
    ans = scm_make_vector(MAKINUM(ngroups), SCM_UNDEFINED);
    while (--ngroups >= 0) VELTS(ans)[ngroups] = MAKINUM(groups[ngroups]);
    SETCHARS(grps, groups);	/* to make sure grps stays around. */
    return ans;
  }
}  

/* These 2 routines are not protected against `entry' being reused
   before access to that structure is completed */

static char s_getpwuid[] = "%getpwuid";
SCM 
scm_getpwuid (user)
     SCM user;
{
  SCM result;
  struct passwd *entry;
  SCM *ve;

  result = scm_make_vector (MAKINUM (7), UNSPECIFIED);
  ve = VELTS (result);
  if (UNBNDP (user) || FALSEP (user))
    SYSCALL (entry = getpwent ());
  else if (INUMP (user))
    entry = getpwuid (INUM (user));
  else
    {
      ASSERT (NIMP (user) && STRINGP (user), user, ARG1, s_getpwuid);
      entry = getpwnam (CHARS (user));
    }
  if (!entry)
    return BOOL_F;
  ve[0] = makfrom0str (entry->pw_name);
  ve[1] = makfrom0str (entry->pw_passwd);
  ve[2] = scm_ulong2num ((unsigned long) entry->pw_uid);
  ve[3] = scm_ulong2num ((unsigned long) entry->pw_gid);
  ve[4] = makfrom0str (entry->pw_gecos);
  if (!entry->pw_dir)
    ve[5] = makfrom0str ("");
  else
    ve[5] = makfrom0str (entry->pw_dir);
  if (!entry->pw_shell)
    ve[6] = makfrom0str ("");
  else
    ve[6] = makfrom0str (entry->pw_shell);
  return result;
}

static char s_setpwent[] = "setpwent";
SCM 
scm_setpwent (arg)
     SCM arg;
{
  if (UNBNDP (arg) || FALSEP (arg))
    endpwent ();
  else
    setpwent ();
  return UNSPECIFIED;
}


/* Combines getgrgid and getgrnam.  */
#include <grp.h>
static char s_getgrgid[] = "%getgrgid";
SCM 
scm_getgrgid (name)
     SCM name;
{
  SCM result;
  struct group *entry;
  SCM *ve;
  result = scm_make_vector (MAKINUM (4), UNSPECIFIED);
  ve = VELTS (result);
  DEFER_INTS;
  if (UNBNDP (name) || (name == BOOL_F))
    SYSCALL (entry = getgrent ());
  else if (INUMP (name))
    SYSCALL (entry = getgrgid (INUM (name)));
  else
    {
      ASSERT (NIMP (name) && STRINGP (name), name, ARG1, s_getgrgid);
      SYSCALL (entry = getgrnam (CHARS (name)));
    }
  ALLOW_INTS;
  if (!entry)
    return BOOL_F;
  ve[0] = makfrom0str (entry->gr_name);
  ve[1] = makfrom0str (entry->gr_passwd);
  ve[2] = scm_ulong2num ((unsigned long) entry->gr_gid);
  ve[3] = makfromstrs (-1, entry->gr_mem);
  return result;
}


static char s_setgrent[] = "setgrent";
SCM 
scm_setgrent (arg)
     SCM arg;
{
  if (UNBNDP (arg) || FALSEP (arg))
    endgrent ();
  else
    setgrent ();
  return UNSPECIFIED;
}

static char s_kill[] = "%kill";

SCM 
scm_kill (pid, sig)
     SCM pid, sig;
{
  int i;
  ASSERT (INUMP (pid), pid, ARG1, s_kill);
  ASSERT (INUMP (sig), sig, ARG2, s_kill);
  /* Signal values are interned in scm_init_posix().  */
  SYSCALL (i = kill ((int) INUM (pid), (int) INUM (sig)));
  return i ? BOOL_F : BOOL_T;
}

static char s_waitpid[] = "%waitpid";
SCM 
scm_waitpid (pid, options)
     SCM pid, options;
{
  int i;
  int status;
  int ioptions;
  ASSERT (INUMP (pid), pid, ARG1, s_waitpid);
  if (UNBNDP (options))
    ioptions = 0;
  else
    {
      ASSERT (INUMP (options), options, ARG2, s_waitpid);
      /* Flags are interned in scm_init_posix.  */
      ioptions = INUM (options);
    }
  SYSCALL (i = waitpid (INUM (pid), &status, ioptions));
  return ((i == -1)
	  ? BOOL_F
	  : scm_cons (MAKINUM (0L + i), MAKINUM (0L + status)));
}

static char s_getppid[] = "getppid";
SCM 
scm_getppid ()
{
  return MAKINUM (0L + getppid ());
}

static char s_getuid[] = "getuid";
SCM 
scm_getuid ()
{
  return MAKINUM (0L + getuid ());
}

static char s_getgid[] = "getgid";
SCM 
scm_getgid ()
{
  return MAKINUM (0L + getgid ());
}

#ifndef LACK_E_IDs


static char s_geteuid[] = "geteuid";
SCM 
scm_geteuid ()
{
  return MAKINUM (0L + geteuid ());
}

static char s_getegid[] = "getegid";
SCM 
scm_getegid ()
{
  return MAKINUM (0L + getegid ());
}
#endif

static char s_setuid[] = "%setuid";
SCM 
scm_setuid (id)
     SCM id;
{
  ASSERT (INUMP (id), id, ARG1, s_setuid);
  return setuid (INUM (id)) ? BOOL_F : BOOL_T;
}

static char s_setgid[] = "%setgid";
SCM 
scm_setgid (id)
     SCM id;
{
  ASSERT (INUMP (id), id, ARG1, s_setgid);
  return setgid (INUM (id)) ? BOOL_F : BOOL_T;
}

#ifndef LACK_E_IDs
static char s_seteuid[] = "%seteuid";
SCM 
scm_seteuid (id)
     SCM id;
{
  ASSERT (INUMP (id), id, ARG1, s_seteuid);
  return seteuid (INUM (id)) ? BOOL_F : BOOL_T;
}

static char s_setegid[] = "%setegid";
SCM 
scm_setegid (id)
     SCM id;
{
  ASSERT (INUMP (id), id, ARG1, s_setegid);
  return setegid (INUM (id)) ? BOOL_F : BOOL_T;
}
#endif

#ifndef ttyname
extern char * ttyname();
#endif

static char s_ttyname[] = "%ttyname";
SCM 
scm_ttyname (port)
     SCM port;
{
  char *ans;
  int fd;
  ASSERT (NIMP (port) && OPPORTP (port), port, ARG1, s_ttyname);
  if (tc16_fport != TYP16 (port))
    return BOOL_F;
  fd = fileno (STREAM (port));
  if (fd != -1)
    SYSCALL (ans = ttyname (fd));
  /* ans could be overwritten by another call to ttyname */
  return (((fd != -1) && ans)
	  ? makfrom0str (ans)
	  : BOOL_F);
}

/* Copy exec args from an SCM vector into a new C array.  */
static char **
scm_convert_exec_args (args)
     SCM args;
{
  char **execargv;
  int num_args;
  int i;
  DEFER_INTS;
  num_args = scm_ilength (args);
  execargv = (char **) 
    scm_must_malloc ((num_args + 1) * sizeof (char *), s_vector);
  for (i = 0; NNULLP (args); args = CDR (args), ++i)
    {
      sizet len;
      char *dst;
      char *src;
      ASSERT (NIMP (CAR (args)) && STRINGP (CAR (args)), CAR (args),
	      "wrong type in ARG", "exec arg");
      len = 1 + LENGTH (CAR (args));
      dst = (char *) scm_must_malloc ((long) len, s_string);
      src = CHARS (CAR (args));
      while (len--) 
	dst[len] = src[len];
      execargv[i] = dst;
    }
  execargv[i] = 0;
  ALLOW_INTS;
  return execargv;
}

char scm_s_execl[] = "%execl";
SCM
scm_execl (args)
     SCM args;
{
  char **execargv;
  SCM filename = CAR (args);
  ASSERT (NIMP (filename) && STRINGP (filename), filename, ARG1, scm_s_execl);
  args = CDR (args);
  execargv = scm_convert_exec_args (args);
  execv (CHARS (filename), execargv);
  return BOOL_F;
}

char scm_s_execlp[] = "%execlp";
SCM
scm_execlp (args)
     SCM args;
{
  char **execargv;
  SCM filename = CAR (args);
  ASSERT (NIMP (filename) && STRINGP (filename), filename, ARG1, scm_s_execlp);
  args = CDR (args);
  execargv = scm_convert_exec_args (args);
  execvp (CHARS (filename), execargv);
  return BOOL_F;
}

/* Flushing streams etc., is not done here.  */
static char s_fork[] = "%fork";
SCM scm_fork()
{
  pid_t pid;
  pid = fork ();
  if (pid == -1)
    return BOOL_F;
  else
    return MAKINUM (0L+pid);
}




void
fill_select_type (set, list)
     SELECT_TYPE * set;
     SCM list;
{
  while (list != EOL)
    {
      if (   NIMP (CAR (list))
	  && (tc16_fport == TYP16 (CAR (list)))
	  && OPPORTP (CAR (list)))
	FD_SET (fileno (STREAM (CAR (list))), set);
      else if (INUMP (CAR (list)))
	FD_SET (INUM (CAR (list)), set);
      list = CDR (list);
    }
}

SCM 
retrieve_select_type (set, list)
     SELECT_TYPE * set;
     SCM list;
{
  SCM answer;
  answer = EOL;
  while (list != EOL)
    {
      if (   NIMP (CAR (list))
	  && (tc16_fport == TYP16 (CAR (list)))
	  && OPPORTP (CAR (list)))
	{
	  if (FD_ISSET (fileno (STREAM (CAR (list))), set))
	    answer = scm_cons (CAR (list), answer);
	}
      else if (INUMP (CAR (list)))
	{
	  if (FD_ISSET (INUM (CAR (list)), set))
	    answer = scm_cons (CAR (list), answer);
	}
      list = CDR (list);
    }
  return answer;
}

static char s_select[] = "%select";

SCM
scm_select (reads, writes, excepts, secs, msecs)
     SCM reads;
     SCM writes;
     SCM excepts;
     SCM secs;
     SCM msecs;
{
  int ret;
  struct timeval timeout;
  struct timeval * time_p;
  SELECT_TYPE read_set;
  SELECT_TYPE write_set;
  SELECT_TYPE except_set;
  SCM answer;
  int sreturn;

  ASSERT (-1 < scm_ilength (reads), reads, ARG1, s_select);
  ASSERT (-1 < scm_ilength (writes), reads, ARG1, s_select);
  ASSERT (-1 < scm_ilength (excepts), reads, ARG1, s_select);
  ASSERT (INUMP (secs), secs, ARG4, s_select);
  ASSERT (INUMP (msecs), msecs, ARG5, s_select);

  FD_ZERO (&read_set);
  FD_ZERO (&write_set);
  FD_ZERO (&except_set);

  fill_select_type (&read_set, reads);
  fill_select_type (&write_set, writes);
  fill_select_type (&except_set, excepts);

  if (INUM (secs) || INUM (msecs))
    {
      timeout.tv_sec = INUM (secs);
      timeout.tv_usec = 1000 * INUM (msecs);
      time_p = &timeout;
    }
  else
    time_p = 0;

  DEFER_INTS;
  sreturn = select (SELECT_SET_SIZE,
		    &read_set, &write_set, &except_set, time_p);
  ALLOW_INTS;
  if (sreturn < 0)
    return MAKINUM (sreturn);
  else
    return scm_listify (retrieve_select_type (&read_set, reads),
			retrieve_select_type (&write_set, writes),
			retrieve_select_type (&except_set, excepts),
			SCM_UNDEFINED);
}






#include <sys/utsname.h>
static char s_uname[] = "%uname";
SCM 
scm_uname ()
{
  struct utsname buf;
  SCM ans = scm_make_vector(MAKINUM(5), UNSPECIFIED);
  SCM *ve = VELTS (ans);
  if (uname (&buf))
    return BOOL_F;
  ve[0] = makfrom0str (buf.sysname);
  ve[1] = makfrom0str (buf.nodename);
  ve[2] = makfrom0str (buf.release);
  ve[3] = makfrom0str (buf.version);
  ve[4] = makfrom0str (buf.machine);
/* 
  FIXME
  ve[5] = makfrom0str (buf.domainname);
*/
  return ans;
}

static char s_environ[] = "environ";
extern char ** environ;
SCM
scm_environ (env)
     SCM env;
{
  if (UNBNDP (env))
    return makfromstrs (-1, environ);
  else
    {
      int num_strings;
      char **new_environ;
      int i = 0;
      ASSERT (NIMP (env) && CONSP (env), env, ARG1, s_environ);
      num_strings = scm_ilength (env);
      new_environ = (char **) scm_must_malloc ((num_strings + 1)
					       * sizeof (char *),
					       s_environ);
      while (NNULLP (env))
	{
	  int len;
	  char *src;
	  ASSERT (NIMP (CAR (env)) && STRINGP (CAR (env)), env, ARG1,
		  s_environ);
	  len = 1 + LENGTH (CAR (env));
	  new_environ[i] = scm_must_malloc ((long) len, s_environ);
	  src = CHARS (CAR (env));
	  while (len--) 
	    new_environ[i][len] = src[len];
	  env = CDR (env);
	  i++;
	}
      new_environ[i] = 0;
      /* Free the old environment, except when called for the first
       * time.
       */
      {
	char **ep;
	static int first = 1;
	if (!first)
	  {
	    for (ep = environ; *ep != NULL; ep++)
	      scm_must_free (*ep);
	    scm_must_free ((char *) environ);
	  }
	first = 0;
      }
      environ = new_environ;
      return UNSPECIFIED;
    }
}

static scm_iproc subr0s[] =
{
  {s_pipe, scm_pipe},
  {s_setpwent, scm_setpwent},
  {s_getppid,  scm_getppid},
  {s_getuid,   scm_getuid},
  {s_getgid,   scm_getgid},
#ifndef LACK_E_IDs
  {s_getegid,  scm_getegid},
  {s_geteuid,  scm_geteuid},
#endif
  {s_uname, scm_uname},
  {s_fork, scm_fork},
  {0, 0}};

static scm_iproc subr1os[] =
{
  {s_environ, scm_environ},
  {0, 0}
};

static scm_iproc subr1s[] =
{
  {s_getpwuid, scm_getpwuid},
  {s_getgrgid, scm_getgrgid},
  {s_setuid,   scm_setuid},
  {s_setgid,   scm_setgid},
#ifndef LACK_E_IDs
  {s_setegid,  scm_setegid},
  {s_seteuid,  scm_seteuid},
#endif
  {s_ttyname,  scm_ttyname},
  {0, 0}};

static scm_iproc subr2os[] =
{
  {s_waitpid, scm_waitpid},
  {0, 0}};

static scm_iproc subr2s[] =
{
  {s_link, scm_link},
  {s_kill, scm_kill},
  {0, 0}};

static scm_iproc subr3s[] =
{
  {s_chown, scm_chown},
  {0, 0}};

void 
scm_init_posix ()
{
  scm_init_iprocs (subr0s, tc7_subr_0);
  scm_init_iprocs (subr1s, tc7_subr_1);
  scm_init_iprocs (subr1os, tc7_subr_1o);
  scm_init_iprocs (subr2os, tc7_subr_2o);
  scm_init_iprocs (subr2s, tc7_subr_2);
  scm_init_iprocs (subr3s, tc7_subr_3);
  scm_make_subr (scm_s_execl, tc7_lsubr, scm_execl);
  scm_make_subr (scm_s_execlp, tc7_lsubr, scm_execlp);
  scm_make_gsubr (s_select, 5, 0, 0, scm_select);

#if 0
  /* not portable */
  scm_sysintern ("WAIT_ANY", MAKINUM (WAIT_ANY));
  scm_sysintern ("WAIT_MYPGRP", MAKINUM (WAIT_MYPGRP));
#endif

  scm_sysintern ("WNOHANG", MAKINUM (WNOHANG));
  scm_sysintern ("WUNTRACED", MAKINUM (WUNTRACED));

#ifdef SIGHUP
  scm_sysintern ("SIGHUP", MAKINUM (SIGHUP));
#endif
#ifdef SIGINT
  scm_sysintern ("SIGINT", MAKINUM (SIGINT));
#endif
#ifdef SIGQUIT
  scm_sysintern ("SIGQUIT", MAKINUM (SIGQUIT));
#endif
#ifdef SIGILL
  scm_sysintern ("SIGILL", MAKINUM (SIGILL));
#endif
#ifdef SIGTRAP
  scm_sysintern ("SIGTRAP", MAKINUM (SIGTRAP));
#endif
#ifdef SIGABRT
  scm_sysintern ("SIGABRT", MAKINUM (SIGABRT));
#endif
#ifdef SIGIOT
  scm_sysintern ("SIGIOT", MAKINUM (SIGIOT));
#endif
#ifdef SIGBUS
  scm_sysintern ("SIGBUS", MAKINUM (SIGBUS));
#endif
#ifdef SIGFPE
  scm_sysintern ("SIGFPE", MAKINUM (SIGFPE));
#endif
#ifdef SIGKILL
  scm_sysintern ("SIGKILL", MAKINUM (SIGKILL));
#endif
#ifdef SIGUSR1
  scm_sysintern ("SIGUSR1", MAKINUM (SIGUSR1));
#endif
#ifdef SIGSEGV
  scm_sysintern ("SIGSEGV", MAKINUM (SIGSEGV));
#endif
#ifdef SIGUSR2
  scm_sysintern ("SIGUSR2", MAKINUM (SIGUSR2));
#endif
#ifdef SIGPIPE
  scm_sysintern ("SIGPIPE", MAKINUM (SIGPIPE));
#endif
#ifdef SIGALRM
  scm_sysintern ("SIGALRM", MAKINUM (SIGALRM));
#endif
#ifdef SIGTERM
  scm_sysintern ("SIGTERM", MAKINUM (SIGTERM));
#endif
#ifdef SIGSTKFLT
  scm_sysintern ("SIGSTKFLT", MAKINUM (SIGSTKFLT));
#endif
#ifdef SIGCHLD
  scm_sysintern ("SIGCHLD", MAKINUM (SIGCHLD));
#endif
#ifdef SIGCONT
  scm_sysintern ("SIGCONT", MAKINUM (SIGCONT));
#endif
#ifdef SIGSTOP
  scm_sysintern ("SIGSTOP", MAKINUM (SIGSTOP));
#endif
#ifdef SIGTSTP
  scm_sysintern ("SIGTSTP", MAKINUM (SIGTSTP));
#endif
#ifdef SIGTTIN
  scm_sysintern ("SIGTTIN", MAKINUM (SIGTTIN));
#endif
#ifdef SIGTTOU
  scm_sysintern ("SIGTTOU", MAKINUM (SIGTTOU));
#endif
#ifdef SIGIO
  scm_sysintern ("SIGIO", MAKINUM (SIGIO));
#endif
#ifdef SIGPOLL
  scm_sysintern ("SIGPOLL", MAKINUM (SIGPOLL));
#endif
#ifdef SIGURG
  scm_sysintern ("SIGURG", MAKINUM (SIGURG));
#endif
#ifdef SIGXCPU
  scm_sysintern ("SIGXCPU", MAKINUM (SIGXCPU));
#endif
#ifdef SIGXFSZ
  scm_sysintern ("SIGXFSZ", MAKINUM (SIGXFSZ));
#endif
#ifdef SIGVTALRM
  scm_sysintern ("SIGVTALRM", MAKINUM (SIGVTALRM));
#endif
#ifdef SIGPROF
  scm_sysintern ("SIGPROF", MAKINUM (SIGPROF));
#endif
#ifdef SIGWINCH
  scm_sysintern ("SIGWINCH", MAKINUM (SIGWINCH));
#endif
#ifdef SIGLOST
  scm_sysintern ("SIGLOST", MAKINUM (SIGLOST));
#endif
#ifdef SIGPWR
  scm_sysintern ("SIGPWR", MAKINUM (SIGPWR));
#endif
  
  scm_add_feature ("posix");
}
