From 1cebcf5f4803d562e4a683f93ebd4f2ed5e29356 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jeremy@system76.com>
Date: Mon, 28 Jan 2019 14:06:51 -0700
Subject: [PATCH] Fix bash recipe

---
 recipes/bash/01-redox-hacks.patch            |  108 --
 recipes/bash/02-path-separator.patch         |   35 -
 recipes/bash/03-autotools-relibc-stuff.patch |   73 -
 recipes/bash/04-execute-cmd.patch            |   21 -
 recipes/bash/recipe.sh                       |   13 +-
 recipes/bash/redox.patch                     | 1461 ++++++++++++++++++
 6 files changed, 1472 insertions(+), 239 deletions(-)
 delete mode 100644 recipes/bash/01-redox-hacks.patch
 delete mode 100644 recipes/bash/02-path-separator.patch
 delete mode 100644 recipes/bash/03-autotools-relibc-stuff.patch
 delete mode 100644 recipes/bash/04-execute-cmd.patch
 create mode 100644 recipes/bash/redox.patch

diff --git a/recipes/bash/01-redox-hacks.patch b/recipes/bash/01-redox-hacks.patch
deleted file mode 100644
index fb2d19915..000000000
--- a/recipes/bash/01-redox-hacks.patch
+++ /dev/null
@@ -1,108 +0,0 @@
-diff -ru source/general.c source-new/general.c
---- source/general.c	2016-08-11 08:16:56.000000000 -0700
-+++ source-new/general.c	2017-08-07 19:55:47.437464359 -0700
-@@ -476,6 +476,7 @@
- void
- check_dev_tty ()
- {
-+#if 0
-   int tty_fd;
-   char *tty;
-
-@@ -490,6 +491,7 @@
-     }
-   if (tty_fd >= 0)
-     close (tty_fd);
-+#endif
- }
-
- /* Return 1 if PATH1 and PATH2 are the same file.  This is kind of
-diff -ru source/include/posixwait.h source-new/include/posixwait.h
---- source/include/posixwait.h	2008-08-12 07:03:03.000000000 -0700
-+++ source-new/include/posixwait.h	2017-08-07 18:37:29.854754332 -0700
-@@ -34,7 +34,7 @@
-
- /* How to get the status of a job.  For Posix, this is just an
-    int, but for other systems we have to crack the union wait. */
--#if !defined (_POSIX_VERSION)
-+#if 0
- typedef union wait WAIT;
- #  define WSTATUS(t)  (t.w_status)
- #else /* _POSIX_VERSION */
-@@ -50,7 +50,7 @@
-
- /* More Posix P1003.1 definitions.  In the POSIX versions, the parameter is
-    passed as an `int', in the non-POSIX version, as `union wait'. */
--#if defined (_POSIX_VERSION)
-+#if 1
-
- #  if !defined (WSTOPSIG)
- #    define WSTOPSIG(s)       ((s) >> 8)
-diff -ru source/lib/sh/getcwd.c source-new/lib/sh/getcwd.c
---- source/lib/sh/getcwd.c	2012-03-10 07:48:50.000000000 -0800
-+++ source-new/lib/sh/getcwd.c	2017-08-07 19:53:52.379759811 -0700
-@@ -20,7 +20,7 @@
-
- #include <config.h>
-
--#if !defined (HAVE_GETCWD)
-+#if 0
-
- #if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
-   #pragma alloca
-diff -ru source/lib/sh/oslib.c source-new/lib/sh/oslib.c
---- source/lib/sh/oslib.c	2013-10-14 06:12:57.000000000 -0700
-+++ source-new/lib/sh/oslib.c	2017-08-07 19:10:21.375838312 -0700
-@@ -236,10 +236,10 @@
- #if !defined (HAVE_MKFIFO) && defined (PROCESS_SUBSTITUTION)
- int
- mkfifo (path, mode)
--     char *path;
--     int mode;
-+     const char *path;
-+     mode_t mode;
- {
--#if defined (S_IFIFO)
-+#if 0
-   return (mknod (path, (mode | S_IFIFO), 0));
- #else /* !S_IFIFO */
-   return (-1);
-diff -ru source/lib/sh/winsize.c source-new/lib/sh/winsize.c
---- source/lib/sh/winsize.c	2016-01-25 10:24:45.000000000 -0800
-+++ source-new/lib/sh/winsize.c	2017-08-07 19:14:41.571576687 -0700
-@@ -28,7 +28,6 @@
- #  include <unistd.h>
- #endif
-
--#include <sys/ioctl.h>
-
- /* Try to find the definitions of `struct winsize' and TIOGCWINSZ */
-
-diff -ru source/sig.c source-new/sig.c
---- source/sig.c	2016-02-11 12:02:45.000000000 -0800
-+++ source-new/sig.c	2017-08-07 19:56:13.637701224 -0700
-@@ -684,7 +684,9 @@
-
- /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
- sigprocmask (operation, newset, oldset)
--     int operation, *newset, *oldset;
-+     int operation;
-+     const sigset_t *newset;
-+     sigset_t *oldset;
- {
-   int old, new;
-
-@@ -696,11 +698,11 @@
-   switch (operation)
-     {
-     case SIG_BLOCK:
--      old = sigblock (new);
-+      //old = sigblock (new);
-       break;
-
-     case SIG_SETMASK:
--      old = sigsetmask (new);
-+      //old = sigsetmask (new);
-       break;
-
-     default:
diff --git a/recipes/bash/02-path-separator.patch b/recipes/bash/02-path-separator.patch
deleted file mode 100644
index 55aff5f0f..000000000
--- a/recipes/bash/02-path-separator.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-diff -ru source/general.c source-new/general.c
---- source/general.c	2016-08-11 08:16:56.000000000 -0700
-+++ source-new/general.c	2017-08-07 20:22:31.581566466 -0700
-@@ -909,10 +909,10 @@
-      `:'.  If I is 0, then the path has a leading colon.  Trailing colons
-      are handled OK by the `else' part of the if statement; an empty
-      string is returned in that case. */
--  if (i && string[i] == ':')
-+  if (i && string[i] == ';')
-     i++;
- 
--  for (start = i; string[i] && string[i] != ':'; i++)
-+  for (start = i; string[i] && string[i] != ';'; i++)
-     ;
- 
-   *p_index = i;
---- source/config-top.h	2016-05-19 20:34:02.000000000 +0200
-+++ build/config-top.h	2018-08-07 15:00:14.440837632 +0200
-@@ -63,14 +63,14 @@
- /* The default value of the PATH variable. */
- #ifndef DEFAULT_PATH_VALUE
- #define DEFAULT_PATH_VALUE \
--  "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:."
-+  "/usr/local/bin;/usr/local/sbin;/usr/bin;/usr/sbin;/bin;/sbin;."
- #endif
- 
- /* The value for PATH when invoking `command -p'.  This is only used when
-    the Posix.2 confstr () function, or CS_PATH define are not present. */
- #ifndef STANDARD_UTILS_PATH
- #define STANDARD_UTILS_PATH \
--  "/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"
-+  "/bin;/usr/bin;/sbin;/usr/sbin;/etc;/usr/etc"
- #endif
- 
- /* Default primary and secondary prompt strings. */
diff --git a/recipes/bash/03-autotools-relibc-stuff.patch b/recipes/bash/03-autotools-relibc-stuff.patch
deleted file mode 100644
index c3dc542a9..000000000
--- a/recipes/bash/03-autotools-relibc-stuff.patch
+++ /dev/null
@@ -1,73 +0,0 @@
---- a/aclocal.m4	2015-12-02 15:22:19.000000000 +0100
-+++ b/aclocal.m4	2018-08-03 17:26:40.798221239 +0200
-@@ -576,49 +576,7 @@
- fi
- ])
- 
--AC_DEFUN(BASH_FUNC_GETENV,
--[AC_MSG_CHECKING(to see if getenv can be redefined)
--AC_CACHE_VAL(bash_cv_getenv_redef,
--[AC_TRY_RUN([
--#ifdef HAVE_UNISTD_H
--#  include <unistd.h>
--#endif
--#ifndef __STDC__
--#  ifndef const
--#    define const
--#  endif
--#endif
--char *
--getenv (name)
--#if defined (__linux__) || defined (__bsdi__) || defined (convex)
--     const char *name;
--#else
--     char const *name;
--#endif /* !__linux__ && !__bsdi__ && !convex */
--{
--return "42";
--}
--main()
--{
--char *s;
--/* The next allows this program to run, but does not allow bash to link
--   when it redefines getenv.  I'm not really interested in figuring out
--   why not. */
--#if defined (NeXT)
--exit(1);
--#endif
--s = getenv("ABCDE");
--exit(s == 0);	/* force optimizer to leave getenv in */
--}
--], bash_cv_getenv_redef=yes, bash_cv_getenv_redef=no,
--   [AC_MSG_WARN(cannot check getenv redefinition if cross compiling -- defaulting to yes)
--    bash_cv_getenv_redef=yes]
--)])
--AC_MSG_RESULT($bash_cv_getenv_redef)
--if test $bash_cv_getenv_redef = yes; then
--AC_DEFINE(CAN_REDEFINE_GETENV)
--fi
--])
-+bash_cv_getenv_redef=no
- 
- # We should check for putenv before calling this
- AC_DEFUN(BASH_FUNC_STD_PUTENV,
-@@ -1200,7 +1158,7 @@
-   AC_TRY_LINK([#include <signal.h>],[
-     sigset_t ss;
-     struct sigaction sa;
--    sigemptyset(&ss); sigsuspend(&ss);
-+    sigemptyset(&ss); /* sigsuspend(&ss); */
-     sigaction(SIGINT, &sa, (struct sigaction *) 0);
-     sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
-   ], bash_cv_signal_vintage=posix,
---- a/configure.ac	2016-09-07 22:56:28.000000000 +0200
-+++ b/configure.ac	2018-08-03 09:10:42.818015670 +0200
-@@ -52,7 +52,7 @@
- AC_CANONICAL_BUILD
- 
- dnl configure defaults
--opt_bash_malloc=yes
-+opt_bash_malloc=no
- opt_afs=no
- opt_curses=no
- opt_with_installed_readline=no
diff --git a/recipes/bash/04-execute-cmd.patch b/recipes/bash/04-execute-cmd.patch
deleted file mode 100644
index 27ff6978b..000000000
--- a/recipes/bash/04-execute-cmd.patch
+++ /dev/null
@@ -1,21 +0,0 @@
---- source/execute_cmd.c	2016-08-26 05:10:08.000000000 -0600
-+++ source-new/execute_cmd.c	2018-11-17 07:32:59.626764573 -0700
-@@ -1335,15 +1335,17 @@
-   nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0);
-   if (posixly_correct && nullcmd)
-     {
--#if defined (HAVE_GETRUSAGE)
-+#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
-       selfb.ru_utime.tv_sec = kidsb.ru_utime.tv_sec = selfb.ru_stime.tv_sec = kidsb.ru_stime.tv_sec = 0;
-       selfb.ru_utime.tv_usec = kidsb.ru_utime.tv_usec = selfb.ru_stime.tv_usec = kidsb.ru_stime.tv_usec = 0;
-       before.tv_sec = shell_start_time;
-       before.tv_usec = 0;
- #else
-+#  if defined (HAVE_TIMES)
-       before.tms_utime = before.tms_stime = before.tms_cutime = before.tms_cstime = 0;
-       tbefore = shell_start_time;
- #endif
-+#endif
-     }
- 
-   old_flags = command->flags;
diff --git a/recipes/bash/recipe.sh b/recipes/bash/recipe.sh
index 4479616c4..03464a66b 100644
--- a/recipes/bash/recipe.sh
+++ b/recipes/bash/recipe.sh
@@ -1,5 +1,6 @@
 VERSION=4.4
 TAR=http://ftp.gnu.org/gnu/bash/bash-$VERSION.tar.gz
+BUILD_DEPENDS=(gettext)
 
 function recipe_version {
     echo "$VERSION"
@@ -12,9 +13,17 @@ function recipe_update {
 }
 
 function recipe_build {
+    sysroot="$PWD/../sysroot"
+    export LDFLAGS="-L$sysroot/lib"
+    export CPPFLAGS="-I$sysroot/include"
     wget -O support/config.sub http://git.savannah.gnu.org/cgit/config.git/plain/config.sub
-    ./configure --build=${BUILD} --host=${HOST} --prefix=/ --disable-readline
-    make -j"$(nproc)"
+    ./configure \
+        --build=${BUILD} \
+        --host=${HOST} \
+        --prefix=/ \
+        --disable-readline \
+        bash_cv_getenv_redef=no
+    make # -j"$(nproc)"
     skip=1
 }
 
diff --git a/recipes/bash/redox.patch b/recipes/bash/redox.patch
new file mode 100644
index 000000000..7dba459f3
--- /dev/null
+++ b/recipes/bash/redox.patch
@@ -0,0 +1,1461 @@
+diff -ruwN source/config-top.h source-new/config-top.h
+--- source/config-top.h	2016-05-19 12:34:02.000000000 -0600
++++ source-new/config-top.h	2019-01-28 12:42:45.660815213 -0700
+@@ -63,14 +63,14 @@
+ /* The default value of the PATH variable. */
+ #ifndef DEFAULT_PATH_VALUE
+ #define DEFAULT_PATH_VALUE \
+-  "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:."
++  "/usr/local/bin;/usr/local/sbin;/usr/bin;/usr/sbin;/bin;/sbin;."
+ #endif
+ 
+ /* The value for PATH when invoking `command -p'.  This is only used when
+    the Posix.2 confstr () function, or CS_PATH define are not present. */
+ #ifndef STANDARD_UTILS_PATH
+ #define STANDARD_UTILS_PATH \
+-  "/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"
++  "/bin;/usr/bin;/sbin;/usr/sbin;/etc;/usr/etc"
+ #endif
+ 
+ /* Default primary and secondary prompt strings. */
+diff -ruwN source/configure.ac source-new/configure.ac
+--- source/configure.ac	2016-09-07 14:56:28.000000000 -0600
++++ source-new/configure.ac	2019-01-28 13:53:45.000616985 -0700
+@@ -90,6 +90,7 @@
+ *-opennt*|*-interix*)	opt_bash_malloc=no ;;	# Interix, now owned by Microsoft
+ *-nsk*)		opt_bash_malloc=no ;;	# HP NonStop
+ *-haiku*)	opt_bash_malloc=no ;;	# Haiku OS
++*-redox*)	opt_bash_malloc=no ;;	# Redox OS
+ esac
+ 
+ # memory scrambling on free()
+diff -ruwN source/execute_cmd.c source-new/execute_cmd.c
+--- source/execute_cmd.c	2016-08-26 05:10:08.000000000 -0600
++++ source-new/execute_cmd.c	2019-01-28 12:42:52.680865726 -0700
+@@ -1335,15 +1335,17 @@
+   nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0);
+   if (posixly_correct && nullcmd)
+     {
+-#if defined (HAVE_GETRUSAGE)
++#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
+       selfb.ru_utime.tv_sec = kidsb.ru_utime.tv_sec = selfb.ru_stime.tv_sec = kidsb.ru_stime.tv_sec = 0;
+       selfb.ru_utime.tv_usec = kidsb.ru_utime.tv_usec = selfb.ru_stime.tv_usec = kidsb.ru_stime.tv_usec = 0;
+       before.tv_sec = shell_start_time;
+       before.tv_usec = 0;
+ #else
++#  if defined (HAVE_TIMES)
+       before.tms_utime = before.tms_stime = before.tms_cutime = before.tms_cstime = 0;
+       tbefore = shell_start_time;
+ #endif
++#endif
+     }
+ 
+   old_flags = command->flags;
+diff -ruwN source/general.c source-new/general.c
+--- source/general.c	2016-08-11 09:16:56.000000000 -0600
++++ source-new/general.c	2019-01-28 12:45:41.801895779 -0700
+@@ -476,6 +476,7 @@
+ void
+ check_dev_tty ()
+ {
++#if !defined(__redox__)
+   int tty_fd;
+   char *tty;
+ 
+@@ -490,6 +491,7 @@
+     }
+   if (tty_fd >= 0)
+     close (tty_fd);
++#endif
+ }
+ 
+ /* Return 1 if PATH1 and PATH2 are the same file.  This is kind of
+@@ -909,10 +911,10 @@
+      `:'.  If I is 0, then the path has a leading colon.  Trailing colons
+      are handled OK by the `else' part of the if statement; an empty
+      string is returned in that case. */
+-  if (i && string[i] == ':')
++  if (i && string[i] == ';')
+     i++;
+ 
+-  for (start = i; string[i] && string[i] != ':'; i++)
++  for (start = i; string[i] && string[i] != ';'; i++)
+     ;
+ 
+   *p_index = i;
+diff -ruwN source/general.c.orig source-new/general.c.orig
+--- source/general.c.orig	1969-12-31 17:00:00.000000000 -0700
++++ source-new/general.c.orig	2019-01-28 12:42:40.972781097 -0700
+@@ -0,0 +1,1325 @@
++/* general.c -- Stuff that is used by all files. */
++
++/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
++
++   This file is part of GNU Bash, the Bourne Again SHell.
++
++   Bash 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 3 of the License, or
++   (at your option) any later version.
++
++   Bash 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 Bash.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "config.h"
++
++#include "bashtypes.h"
++#if defined (HAVE_SYS_PARAM_H)
++#  include <sys/param.h>
++#endif
++#include "posixstat.h"
++
++#if defined (HAVE_UNISTD_H)
++#  include <unistd.h>
++#endif
++
++#include "filecntl.h"
++#include "bashansi.h"
++#include <stdio.h>
++#include "chartypes.h"
++#include <errno.h>
++
++#include "bashintl.h"
++
++#include "shell.h"
++#include "test.h"
++#include "trap.h"
++
++#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
++#  include <mbstr.h>		/* mbschr */
++#endif
++
++#include <tilde/tilde.h>
++
++#if !defined (errno)
++extern int errno;
++#endif /* !errno */
++
++extern int expand_aliases;
++extern int interactive_comments;
++extern int check_hashed_filenames;
++extern int source_uses_path;
++extern int source_searches_cwd;
++extern int posixly_correct;
++extern int inherit_errexit;
++
++static char *bash_special_tilde_expansions __P((char *));
++static int unquoted_tilde_word __P((const char *));
++static void initialize_group_array __P((void));
++
++/* A standard error message to use when getcwd() returns NULL. */
++const char * const bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
++
++/* Do whatever is necessary to initialize `Posix mode'. */
++void
++posix_initialize (on)
++     int on;
++{
++  /* Things that should be turned on when posix mode is enabled. */
++  if (on != 0)
++    {
++      interactive_comments = source_uses_path = expand_aliases = 1;
++      inherit_errexit = 1;
++      source_searches_cwd = 0;
++    }
++
++  /* Things that should be turned on when posix mode is disabled. */
++  if (on == 0)
++    {
++      source_searches_cwd = 1;
++      expand_aliases = interactive_shell;
++    }
++}
++
++/* **************************************************************** */
++/*								    */
++/*  Functions to convert to and from and display non-standard types */
++/*								    */
++/* **************************************************************** */
++
++#if defined (RLIMTYPE)
++RLIMTYPE
++string_to_rlimtype (s)
++     char *s;
++{
++  RLIMTYPE ret;
++  int neg;
++
++  ret = 0;
++  neg = 0;
++  while (s && *s && whitespace (*s))
++    s++;
++  if (s && (*s == '-' || *s == '+'))
++    {
++      neg = *s == '-';
++      s++;
++    }
++  for ( ; s && *s && DIGIT (*s); s++)
++    ret = (ret * 10) + TODIGIT (*s);
++  return (neg ? -ret : ret);
++}
++
++void
++print_rlimtype (n, addnl)
++     RLIMTYPE n;
++     int addnl;
++{
++  char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p;
++
++  p = s + sizeof(s);
++  *--p = '\0';
++
++  if (n < 0)
++    {
++      do
++	*--p = '0' - n % 10;
++      while ((n /= 10) != 0);
++
++      *--p = '-';
++    }
++  else
++    {
++      do
++	*--p = '0' + n % 10;
++      while ((n /= 10) != 0);
++    }
++
++  printf ("%s%s", p, addnl ? "\n" : "");
++}
++#endif /* RLIMTYPE */
++
++/* **************************************************************** */
++/*								    */
++/*		       Input Validation Functions		    */
++/*								    */
++/* **************************************************************** */
++
++/* Return non-zero if all of the characters in STRING are digits. */
++int
++all_digits (string)
++     const char *string;
++{
++  register const char *s;
++
++  for (s = string; *s; s++)
++    if (DIGIT (*s) == 0)
++      return (0);
++
++  return (1);
++}
++
++/* Return non-zero if the characters pointed to by STRING constitute a
++   valid number.  Stuff the converted number into RESULT if RESULT is
++   not null. */
++int
++legal_number (string, result)
++     const char *string;
++     intmax_t *result;
++{
++  intmax_t value;
++  char *ep;
++
++  if (result)
++    *result = 0;
++
++  if (string == 0)
++    return 0;
++
++  errno = 0;
++  value = strtoimax (string, &ep, 10);
++  if (errno || ep == string)
++    return 0;	/* errno is set on overflow or underflow */
++
++  /* Skip any trailing whitespace, since strtoimax does not. */
++  while (whitespace (*ep))
++    ep++;
++
++  /* If *string is not '\0' but *ep is '\0' on return, the entire string
++     is valid. */
++  if (*string && *ep == '\0')
++    {
++      if (result)
++	*result = value;
++      /* The SunOS4 implementation of strtol() will happily ignore
++	 overflow conditions, so this cannot do overflow correctly
++	 on those systems. */
++      return 1;
++    }
++    
++  return (0);
++}
++
++/* Return 1 if this token is a legal shell `identifier'; that is, it consists
++   solely of letters, digits, and underscores, and does not begin with a
++   digit. */
++int
++legal_identifier (name)
++     const char *name;
++{
++  register const char *s;
++  unsigned char c;
++
++  if (!name || !(c = *name) || (legal_variable_starter (c) == 0))
++    return (0);
++
++  for (s = name + 1; (c = *s) != 0; s++)
++    {
++      if (legal_variable_char (c) == 0)
++	return (0);
++    }
++  return (1);
++}
++
++/* Return 1 if NAME is a valid value that can be assigned to a nameref
++   variable.  FLAGS can be 2, in which case the name is going to be used
++   to create a variable.  Other values are currently unused, but could
++   be used to allow values to be stored and indirectly referenced, but
++   not used in assignments. */
++int
++valid_nameref_value (name, flags)
++     const char *name;
++     int flags;
++{
++  if (name == 0 || *name == 0)
++    return 0;
++
++  /* valid identifier */
++#if defined (ARRAY_VARS)  
++  if (legal_identifier (name) || (flags != 2 && valid_array_reference (name, 0)))
++#else
++  if (legal_identifier (name))
++#endif
++    return 1;
++
++  return 0;
++}
++
++int
++check_selfref (name, value, flags)
++     const char *name;
++     char *value;
++     int flags;
++{
++  char *t;
++
++  if (STREQ (name, value))
++    return 1;
++
++#if defined (ARRAY_VARS)
++  if (valid_array_reference (value, 0))
++    {
++      t = array_variable_name (value, (char **)NULL, (int *)NULL);
++      if (t && STREQ (name, t))
++	{
++	  free (t);
++	  return 1;
++	}
++      free (t);
++    }
++#endif
++
++  return 0;	/* not a self reference */
++}
++
++/* Make sure that WORD is a valid shell identifier, i.e.
++   does not contain a dollar sign, nor is quoted in any way.  Nor
++   does it consist of all digits.  If CHECK_WORD is non-zero,
++   the word is checked to ensure that it consists of only letters,
++   digits, and underscores. */
++int
++check_identifier (word, check_word)
++     WORD_DESC *word;
++     int check_word;
++{
++  if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
++    {
++      internal_error (_("`%s': not a valid identifier"), word->word);
++      return (0);
++    }
++  else if (check_word && legal_identifier (word->word) == 0)
++    {
++      internal_error (_("`%s': not a valid identifier"), word->word);
++      return (0);
++    }
++  else
++    return (1);
++}
++
++/* Return 1 if STRING is a function name that the shell will import from
++   the environment.  Currently we reject attempts to import shell functions
++   containing slashes, beginning with newlines or containing blanks.  In
++   Posix mode, we require that STRING be a valid shell identifier.  Not
++   used yet. */
++int
++importable_function_name (string, len)
++     const char *string;
++     size_t len;
++{
++  if (absolute_program (string))	/* don't allow slash */
++    return 0;
++  if (*string == '\n')			/* can't start with a newline */
++    return 0;
++  if (shellblank (*string) || shellblank(string[len-1]))
++    return 0;
++  return (posixly_correct ? legal_identifier (string) : 1);
++}
++
++int
++exportable_function_name (string)
++     const char *string;
++{
++  if (absolute_program (string))
++    return 0;
++  if (mbschr (string, '=') != 0)
++    return 0;
++  return 1;
++}
++
++/* Return 1 if STRING comprises a valid alias name.  The shell accepts
++   essentially all characters except those which must be quoted to the
++   parser (which disqualifies them from alias expansion anyway) and `/'. */
++int
++legal_alias_name (string, flags)
++     const char *string;
++     int flags;
++{
++  register const char *s;
++
++  for (s = string; *s; s++)
++    if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/'))
++      return 0;
++  return 1;
++}
++
++/* Returns non-zero if STRING is an assignment statement.  The returned value
++   is the index of the `=' sign. */
++int
++assignment (string, flags)
++     const char *string;
++     int flags;
++{
++  register unsigned char c;
++  register int newi, indx;
++
++  c = string[indx = 0];
++
++#if defined (ARRAY_VARS)
++  if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */
++#else
++  if (legal_variable_starter (c) == 0)
++#endif
++    return (0);
++
++  while (c = string[indx])
++    {
++      /* The following is safe.  Note that '=' at the start of a word
++	 is not an assignment statement. */
++      if (c == '=')
++	return (indx);
++
++#if defined (ARRAY_VARS)
++      if (c == '[')
++	{
++	  newi = skipsubscript (string, indx, 0);
++	  if (string[newi++] != ']')
++	    return (0);
++	  if (string[newi] == '+' && string[newi+1] == '=')
++	    return (newi + 1);
++	  return ((string[newi] == '=') ? newi : 0);
++	}
++#endif /* ARRAY_VARS */
++
++      /* Check for `+=' */
++      if (c == '+' && string[indx+1] == '=')
++	return (indx + 1);
++
++      /* Variable names in assignment statements may contain only letters,
++	 digits, and `_'. */
++      if (legal_variable_char (c) == 0)
++	return (0);
++
++      indx++;
++    }
++  return (0);
++}
++
++/* **************************************************************** */
++/*								    */
++/*	     Functions to manage files and file descriptors	    */
++/*								    */
++/* **************************************************************** */
++
++/* A function to unset no-delay mode on a file descriptor.  Used in shell.c
++   to unset it on the fd passed as stdin.  Should be called on stdin if
++   readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
++
++#if !defined (O_NDELAY)
++#  if defined (FNDELAY)
++#    define O_NDELAY FNDELAY
++#  endif
++#endif /* O_NDELAY */
++
++/* Make sure no-delay mode is not set on file descriptor FD. */
++int
++sh_unset_nodelay_mode (fd)
++     int fd;
++{
++  int flags, bflags;
++
++  if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
++    return -1;
++
++  bflags = 0;
++
++  /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
++     and O_NDELAY is defined. */
++#ifdef O_NONBLOCK
++  bflags |= O_NONBLOCK;
++#endif
++
++#ifdef O_NDELAY
++  bflags |= O_NDELAY;
++#endif
++
++  if (flags & bflags)
++    {
++      flags &= ~bflags;
++      return (fcntl (fd, F_SETFL, flags));
++    }
++
++  return 0;
++}
++
++/* Return 1 if file descriptor FD is valid; 0 otherwise. */
++int
++sh_validfd (fd)
++     int fd;
++{
++  return (fcntl (fd, F_GETFD, 0) >= 0);
++}
++
++int
++fd_ispipe (fd)
++     int fd;
++{
++  errno = 0;
++  return ((lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE));
++}
++
++/* There is a bug in the NeXT 2.1 rlogind that causes opens
++   of /dev/tty to fail. */
++
++#if defined (__BEOS__)
++/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it
++   into a no-op.  This should probably go away in the future. */
++#  undef O_NONBLOCK
++#  define O_NONBLOCK 0
++#endif /* __BEOS__ */
++
++void
++check_dev_tty ()
++{
++#if 0
++  int tty_fd;
++  char *tty;
++
++  tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
++
++  if (tty_fd < 0)
++    {
++      tty = (char *)ttyname (fileno (stdin));
++      if (tty == 0)
++	return;
++      tty_fd = open (tty, O_RDWR|O_NONBLOCK);
++    }
++  if (tty_fd >= 0)
++    close (tty_fd);
++#endif
++}
++
++/* Return 1 if PATH1 and PATH2 are the same file.  This is kind of
++   expensive.  If non-NULL STP1 and STP2 point to stat structures
++   corresponding to PATH1 and PATH2, respectively. */
++int
++same_file (path1, path2, stp1, stp2)
++     const char *path1, *path2;
++     struct stat *stp1, *stp2;
++{
++  struct stat st1, st2;
++
++  if (stp1 == NULL)
++    {
++      if (stat (path1, &st1) != 0)
++	return (0);
++      stp1 = &st1;
++    }
++
++  if (stp2 == NULL)
++    {
++      if (stat (path2, &st2) != 0)
++	return (0);
++      stp2 = &st2;
++    }
++
++  return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
++}
++
++/* Move FD to a number close to the maximum number of file descriptors
++   allowed in the shell process, to avoid the user stepping on it with
++   redirection and causing us extra work.  If CHECK_NEW is non-zero,
++   we check whether or not the file descriptors are in use before
++   duplicating FD onto them.  MAXFD says where to start checking the
++   file descriptors.  If it's less than 20, we get the maximum value
++   available from getdtablesize(2). */
++int
++move_to_high_fd (fd, check_new, maxfd)
++     int fd, check_new, maxfd;
++{
++  int script_fd, nfds, ignore;
++
++  if (maxfd < 20)
++    {
++      nfds = getdtablesize ();
++      if (nfds <= 0)
++	nfds = 20;
++      if (nfds > HIGH_FD_MAX)
++	nfds = HIGH_FD_MAX;		/* reasonable maximum */
++    }
++  else
++    nfds = maxfd;
++
++  for (nfds--; check_new && nfds > 3; nfds--)
++    if (fcntl (nfds, F_GETFD, &ignore) == -1)
++      break;
++
++  if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
++    {
++      if (check_new == 0 || fd != fileno (stderr))	/* don't close stderr */
++	close (fd);
++      return (script_fd);
++    }
++
++  /* OK, we didn't find one less than our artificial maximum; return the
++     original file descriptor. */
++  return (fd);
++}
++ 
++/* Return non-zero if the characters from SAMPLE are not all valid
++   characters to be found in the first line of a shell script.  We
++   check up to the first newline, or SAMPLE_LEN, whichever comes first.
++   All of the characters must be printable or whitespace. */
++
++int
++check_binary_file (sample, sample_len)
++     const char *sample;
++     int sample_len;
++{
++  register int i;
++  unsigned char c;
++
++  for (i = 0; i < sample_len; i++)
++    {
++      c = sample[i];
++      if (c == '\n')
++	return (0);
++      if (c == '\0')
++	return (1);
++    }
++
++  return (0);
++}
++
++/* **************************************************************** */
++/*								    */
++/*		    Functions to manipulate pipes		    */
++/*								    */
++/* **************************************************************** */
++
++int
++sh_openpipe (pv)
++     int *pv;
++{
++  int r;
++
++  if ((r = pipe (pv)) < 0)
++    return r;
++
++  pv[0] = move_to_high_fd (pv[0], 1, 64);
++  pv[1] = move_to_high_fd (pv[1], 1, 64);
++
++  return 0;  
++}
++
++int
++sh_closepipe (pv)
++     int *pv;
++{
++  if (pv[0] >= 0)
++    close (pv[0]);
++
++  if (pv[1] >= 0)
++    close (pv[1]);
++
++  pv[0] = pv[1] = -1;
++  return 0;
++}
++
++/* **************************************************************** */
++/*								    */
++/*		    Functions to inspect pathnames		    */
++/*								    */
++/* **************************************************************** */
++
++int
++file_exists (fn)
++     const char *fn;
++{
++  struct stat sb;
++
++  return (stat (fn, &sb) == 0);
++}
++
++int
++file_isdir (fn)
++     const char *fn;
++{
++  struct stat sb;
++
++  return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode));
++}
++
++int
++file_iswdir (fn)
++     const char *fn;
++{
++  return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0);
++}
++
++/* Return 1 if STRING is "." or "..", optionally followed by a directory
++   separator */
++int
++path_dot_or_dotdot (string)
++     const char *string;
++{
++  if (string == 0 || *string == '\0' || *string != '.')
++    return (0);
++
++  /* string[0] == '.' */
++  if (PATHSEP(string[1]) || (string[1] == '.' && PATHSEP(string[2])))
++    return (1);
++
++  return (0);
++}
++
++/* Return 1 if STRING contains an absolute pathname, else 0.  Used by `cd'
++   to decide whether or not to look up a directory name in $CDPATH. */
++int
++absolute_pathname (string)
++     const char *string;
++{
++  if (string == 0 || *string == '\0')
++    return (0);
++
++  if (ABSPATH(string))
++    return (1);
++
++  if (string[0] == '.' && PATHSEP(string[1]))	/* . and ./ */
++    return (1);
++
++  if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2]))	/* .. and ../ */
++    return (1);
++
++  return (0);
++}
++
++/* Return 1 if STRING is an absolute program name; it is absolute if it
++   contains any slashes.  This is used to decide whether or not to look
++   up through $PATH. */
++int
++absolute_program (string)
++     const char *string;
++{
++  return ((char *)mbschr (string, '/') != (char *)NULL);
++}
++
++/* **************************************************************** */
++/*								    */
++/*		    Functions to manipulate pathnames		    */
++/*								    */
++/* **************************************************************** */
++
++/* Turn STRING (a pathname) into an absolute pathname, assuming that
++   DOT_PATH contains the symbolic location of `.'.  This always
++   returns a new string, even if STRING was an absolute pathname to
++   begin with. */
++char *
++make_absolute (string, dot_path)
++     const char *string, *dot_path;
++{
++  char *result;
++
++  if (dot_path == 0 || ABSPATH(string))
++#ifdef __CYGWIN__
++    {
++      char pathbuf[PATH_MAX + 1];
++
++      cygwin_conv_to_full_posix_path (string, pathbuf);
++      result = savestring (pathbuf);
++    }
++#else
++    result = savestring (string);
++#endif
++  else
++    result = sh_makepath (dot_path, string, 0);
++
++  return (result);
++}
++
++/* Return the `basename' of the pathname in STRING (the stuff after the
++   last '/').  If STRING is `/', just return it. */
++char *
++base_pathname (string)
++     char *string;
++{
++  char *p;
++
++#if 0
++  if (absolute_pathname (string) == 0)
++    return (string);
++#endif
++
++  if (string[0] == '/' && string[1] == 0)
++    return (string);
++
++  p = (char *)strrchr (string, '/');
++  return (p ? ++p : string);
++}
++
++/* Return the full pathname of FILE.  Easy.  Filenames that begin
++   with a '/' are returned as themselves.  Other filenames have
++   the current working directory prepended.  A new string is
++   returned in either case. */
++char *
++full_pathname (file)
++     char *file;
++{
++  char *ret;
++
++  file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
++
++  if (ABSPATH(file))
++    return (file);
++
++  ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
++  free (file);
++
++  return (ret);
++}
++
++/* A slightly related function.  Get the prettiest name of this
++   directory possible. */
++static char tdir[PATH_MAX];
++
++/* Return a pretty pathname.  If the first part of the pathname is
++   the same as $HOME, then replace that with `~'.  */
++char *
++polite_directory_format (name)
++     char *name;
++{
++  char *home;
++  int l;
++
++  home = get_string_value ("HOME");
++  l = home ? strlen (home) : 0;
++  if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
++    {
++      strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
++      tdir[0] = '~';
++      tdir[sizeof(tdir) - 1] = '\0';
++      return (tdir);
++    }
++  else
++    return (name);
++}
++
++/* Trim NAME.  If NAME begins with `~/', skip over tilde prefix.  Trim to
++   keep any tilde prefix and PROMPT_DIRTRIM trailing directory components
++   and replace the intervening characters with `...' */
++char *
++trim_pathname (name, maxlen)
++     char *name;
++     int maxlen;
++{
++  int nlen, ndirs;
++  intmax_t nskip;
++  char *nbeg, *nend, *ntail, *v;
++
++  if (name == 0 || (nlen = strlen (name)) == 0)
++    return name;
++  nend = name + nlen;
++
++  v = get_string_value ("PROMPT_DIRTRIM");
++  if (v == 0 || *v == 0)
++    return name;
++  if (legal_number (v, &nskip) == 0 || nskip <= 0)
++    return name;
++
++  /* Skip over tilde prefix */
++  nbeg = name;
++  if (name[0] == '~')
++    for (nbeg = name; *nbeg; nbeg++)
++      if (*nbeg == '/')
++	{
++	  nbeg++;
++	  break;
++	}
++  if (*nbeg == 0)
++    return name;
++
++  for (ndirs = 0, ntail = nbeg; *ntail; ntail++)
++    if (*ntail == '/')
++      ndirs++;
++  if (ndirs < nskip)
++    return name;
++
++  for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--)
++    {
++      if (*ntail == '/')
++	nskip--;
++      if (nskip == 0)
++	break;
++    }
++  if (ntail == nbeg)
++    return name;
++
++  /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */
++  nlen = ntail - nbeg;
++  if (nlen <= 3)
++    return name;
++
++  *nbeg++ = '.';
++  *nbeg++ = '.';
++  *nbeg++ = '.';
++
++  nlen = nend - ntail;
++  memmove (nbeg, ntail, nlen);
++  nbeg[nlen] = '\0';
++
++  return name;
++}
++
++/* Return a printable representation of FN without special characters.  The
++   caller is responsible for freeing memory if this returns something other
++   than its argument.  If FLAGS is non-zero, we are printing for portable
++   re-input and should single-quote filenames appropriately. */
++char *
++printable_filename (fn, flags)
++     char *fn;
++     int flags;
++{
++  char *newf;
++
++  if (ansic_shouldquote (fn))
++    newf = ansic_quote (fn, 0, NULL);
++  else if (flags && sh_contains_shell_metas (fn))
++    newf = sh_single_quote (fn);
++  else
++    newf = fn;
++
++  return newf;
++}
++
++/* Given a string containing units of information separated by colons,
++   return the next one pointed to by (P_INDEX), or NULL if there are no more.
++   Advance (P_INDEX) to the character after the colon. */
++char *
++extract_colon_unit (string, p_index)
++     char *string;
++     int *p_index;
++{
++  int i, start, len;
++  char *value;
++
++  if (string == 0)
++    return (string);
++
++  len = strlen (string);
++  if (*p_index >= len)
++    return ((char *)NULL);
++
++  i = *p_index;
++
++  /* Each call to this routine leaves the index pointing at a colon if
++     there is more to the path.  If I is > 0, then increment past the
++     `:'.  If I is 0, then the path has a leading colon.  Trailing colons
++     are handled OK by the `else' part of the if statement; an empty
++     string is returned in that case. */
++  if (i && string[i] == ':')
++    i++;
++
++  for (start = i; string[i] && string[i] != ':'; i++)
++    ;
++
++  *p_index = i;
++
++  if (i == start)
++    {
++      if (string[i])
++	(*p_index)++;
++      /* Return "" in the case of a trailing `:'. */
++      value = (char *)xmalloc (1);
++      value[0] = '\0';
++    }
++  else
++    value = substring (string, start, i);
++
++  return (value);
++}
++
++/* **************************************************************** */
++/*								    */
++/*		    Tilde Initialization and Expansion		    */
++/*								    */
++/* **************************************************************** */
++
++#if defined (PUSHD_AND_POPD)
++extern char *get_dirstack_from_string __P((char *));
++#endif
++
++static char **bash_tilde_prefixes;
++static char **bash_tilde_prefixes2;
++static char **bash_tilde_suffixes;
++static char **bash_tilde_suffixes2;
++
++/* If tilde_expand hasn't been able to expand the text, perhaps it
++   is a special shell expansion.  This function is installed as the
++   tilde_expansion_preexpansion_hook.  It knows how to expand ~- and ~+.
++   If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
++   directory stack. */
++static char *
++bash_special_tilde_expansions (text)
++     char *text;
++{
++  char *result;
++
++  result = (char *)NULL;
++
++  if (text[0] == '+' && text[1] == '\0')
++    result = get_string_value ("PWD");
++  else if (text[0] == '-' && text[1] == '\0')
++    result = get_string_value ("OLDPWD");
++#if defined (PUSHD_AND_POPD)
++  else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
++    result = get_dirstack_from_string (text);
++#endif
++
++  return (result ? savestring (result) : (char *)NULL);
++}
++
++/* Initialize the tilde expander.  In Bash, we handle `~-' and `~+', as
++   well as handling special tilde prefixes; `:~" and `=~' are indications
++   that we should do tilde expansion. */
++void
++tilde_initialize ()
++{
++  static int times_called = 0;
++
++  /* Tell the tilde expander that we want a crack first. */
++  tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
++
++  /* Tell the tilde expander about special strings which start a tilde
++     expansion, and the special strings that end one.  Only do this once.
++     tilde_initialize () is called from within bashline_reinitialize (). */
++  if (times_called++ == 0)
++    {
++      bash_tilde_prefixes = strvec_create (3);
++      bash_tilde_prefixes[0] = "=~";
++      bash_tilde_prefixes[1] = ":~";
++      bash_tilde_prefixes[2] = (char *)NULL;
++
++      bash_tilde_prefixes2 = strvec_create (2);
++      bash_tilde_prefixes2[0] = ":~";
++      bash_tilde_prefixes2[1] = (char *)NULL;
++
++      tilde_additional_prefixes = bash_tilde_prefixes;
++
++      bash_tilde_suffixes = strvec_create (3);
++      bash_tilde_suffixes[0] = ":";
++      bash_tilde_suffixes[1] = "=~";	/* XXX - ?? */
++      bash_tilde_suffixes[2] = (char *)NULL;
++
++      tilde_additional_suffixes = bash_tilde_suffixes;
++
++      bash_tilde_suffixes2 = strvec_create (2);
++      bash_tilde_suffixes2[0] = ":";
++      bash_tilde_suffixes2[1] = (char *)NULL;
++    }
++}
++
++/* POSIX.2, 3.6.1:  A tilde-prefix consists of an unquoted tilde character
++   at the beginning of the word, followed by all of the characters preceding
++   the first unquoted slash in the word, or all the characters in the word
++   if there is no slash...If none of the characters in the tilde-prefix are
++   quoted, the characters in the tilde-prefix following the tilde shell be
++   treated as a possible login name. */
++
++#define TILDE_END(c)	((c) == '\0' || (c) == '/' || (c) == ':')
++
++static int
++unquoted_tilde_word (s)
++     const char *s;
++{
++  const char *r;
++
++  for (r = s; TILDE_END(*r) == 0; r++)
++    {
++      switch (*r)
++	{
++	case '\\':
++	case '\'':
++	case '"':
++	  return 0;
++	}
++    }
++  return 1;
++}
++
++/* Find the end of the tilde-prefix starting at S, and return the tilde
++   prefix in newly-allocated memory.  Return the length of the string in
++   *LENP.  FLAGS tells whether or not we're in an assignment context --
++   if so, `:' delimits the end of the tilde prefix as well. */
++char *
++bash_tilde_find_word (s, flags, lenp)
++     const char *s;
++     int flags, *lenp;
++{
++  const char *r;
++  char *ret;
++  int l;
++
++  for (r = s; *r && *r != '/'; r++)
++    {
++      /* Short-circuit immediately if we see a quote character.  Even though
++	 POSIX says that `the first unquoted slash' (or `:') terminates the
++	 tilde-prefix, in practice, any quoted portion of the tilde prefix
++	 will cause it to not be expanded. */
++      if (*r == '\\' || *r == '\'' || *r == '"')  
++	{
++	  ret = savestring (s);
++	  if (lenp)
++	    *lenp = 0;
++	  return ret;
++	}
++      else if (flags && *r == ':')
++	break;
++    }
++  l = r - s;
++  ret = xmalloc (l + 1);
++  strncpy (ret, s, l);
++  ret[l] = '\0';
++  if (lenp)
++    *lenp = l;
++  return ret;
++}
++    
++/* Tilde-expand S by running it through the tilde expansion library.
++   ASSIGN_P is 1 if this is a variable assignment, so the alternate
++   tilde prefixes should be enabled (`=~' and `:~', see above).  If
++   ASSIGN_P is 2, we are expanding the rhs of an assignment statement,
++   so `=~' is not valid. */
++char *
++bash_tilde_expand (s, assign_p)
++     const char *s;
++     int assign_p;
++{
++  int old_immed, old_term, r;
++  char *ret;
++
++#if 0
++  old_immed = interrupt_immediately;
++  old_term = terminate_immediately;
++  /* We want to be able to interrupt tilde expansion. Ordinarily, we can just
++     jump to top_level, but we don't want to run any trap commands in a signal
++     handler context.  We might be able to get away with just checking for
++     things like SIGINT and SIGQUIT. */
++  if (any_signals_trapped () < 0)
++    interrupt_immediately = 1;
++  terminate_immediately = 1;
++#endif
++
++  tilde_additional_prefixes = assign_p == 0 ? (char **)0
++  					    : (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes);
++  if (assign_p == 2)
++    tilde_additional_suffixes = bash_tilde_suffixes2;
++
++  r = (*s == '~') ? unquoted_tilde_word (s) : 1;
++  ret = r ? tilde_expand (s) : savestring (s);
++
++#if 0
++  interrupt_immediately = old_immed;
++  terminate_immediately = old_term;
++#endif
++
++  QUIT;
++
++  return (ret);
++}
++
++/* **************************************************************** */
++/*								    */
++/*	  Functions to manipulate and search the group list	    */
++/*								    */
++/* **************************************************************** */
++
++static int ngroups, maxgroups;
++
++/* The set of groups that this user is a member of. */
++static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
++
++#if !defined (NOGROUP)
++#  define NOGROUP (gid_t) -1
++#endif
++
++static void
++initialize_group_array ()
++{
++  register int i;
++
++  if (maxgroups == 0)
++    maxgroups = getmaxgroups ();
++
++  ngroups = 0;
++  group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
++
++#if defined (HAVE_GETGROUPS)
++  ngroups = getgroups (maxgroups, group_array);
++#endif
++
++  /* If getgroups returns nothing, or the OS does not support getgroups(),
++     make sure the groups array includes at least the current gid. */
++  if (ngroups == 0)
++    {
++      group_array[0] = current_user.gid;
++      ngroups = 1;
++    }
++
++  /* If the primary group is not in the groups array, add it as group_array[0]
++     and shuffle everything else up 1, if there's room. */
++  for (i = 0; i < ngroups; i++)
++    if (current_user.gid == (gid_t)group_array[i])
++      break;
++  if (i == ngroups && ngroups < maxgroups)
++    {
++      for (i = ngroups; i > 0; i--)
++	group_array[i] = group_array[i - 1];
++      group_array[0] = current_user.gid;
++      ngroups++;
++    }
++
++  /* If the primary group is not group_array[0], swap group_array[0] and
++     whatever the current group is.  The vast majority of systems should
++     not need this; a notable exception is Linux. */
++  if (group_array[0] != current_user.gid)
++    {
++      for (i = 0; i < ngroups; i++)
++	if (group_array[i] == current_user.gid)
++	  break;
++      if (i < ngroups)
++	{
++	  group_array[i] = group_array[0];
++	  group_array[0] = current_user.gid;
++	}
++    }
++}
++
++/* Return non-zero if GID is one that we have in our groups list. */
++int
++#if defined (__STDC__) || defined ( _MINIX)
++group_member (gid_t gid)
++#else
++group_member (gid)
++     gid_t gid;
++#endif /* !__STDC__ && !_MINIX */
++{
++#if defined (HAVE_GETGROUPS)
++  register int i;
++#endif
++
++  /* Short-circuit if possible, maybe saving a call to getgroups(). */
++  if (gid == current_user.gid || gid == current_user.egid)
++    return (1);
++
++#if defined (HAVE_GETGROUPS)
++  if (ngroups == 0)
++    initialize_group_array ();
++
++  /* In case of error, the user loses. */
++  if (ngroups <= 0)
++    return (0);
++
++  /* Search through the list looking for GID. */
++  for (i = 0; i < ngroups; i++)
++    if (gid == (gid_t)group_array[i])
++      return (1);
++#endif
++
++  return (0);
++}
++
++char **
++get_group_list (ngp)
++     int *ngp;
++{
++  static char **group_vector = (char **)NULL;
++  register int i;
++
++  if (group_vector)
++    {
++      if (ngp)
++	*ngp = ngroups;
++      return group_vector;
++    }
++
++  if (ngroups == 0)
++    initialize_group_array ();
++
++  if (ngroups <= 0)
++    {
++      if (ngp)
++	*ngp = 0;
++      return (char **)NULL;
++    }
++
++  group_vector = strvec_create (ngroups);
++  for (i = 0; i < ngroups; i++)
++    group_vector[i] = itos (group_array[i]);
++
++  if (ngp)
++    *ngp = ngroups;
++  return group_vector;
++}
++
++int *
++get_group_array (ngp)
++     int *ngp;
++{
++  int i;
++  static int *group_iarray = (int *)NULL;
++
++  if (group_iarray)
++    {
++      if (ngp)
++	*ngp = ngroups;
++      return (group_iarray);
++    }
++
++  if (ngroups == 0)
++    initialize_group_array ();    
++
++  if (ngroups <= 0)
++    {
++      if (ngp)
++	*ngp = 0;
++      return (int *)NULL;
++    }
++
++  group_iarray = (int *)xmalloc (ngroups * sizeof (int));
++  for (i = 0; i < ngroups; i++)
++    group_iarray[i] = (int)group_array[i];
++
++  if (ngp)
++    *ngp = ngroups;
++  return group_iarray;
++}
++
++/* **************************************************************** */
++/*								    */
++/*	  Miscellaneous functions				    */
++/*								    */
++/* **************************************************************** */
++
++/* Return a value for PATH that is guaranteed to find all of the standard
++   utilities.  This uses Posix.2 configuration variables, if present.  It
++   uses a value defined in config.h as a last resort. */
++char *
++conf_standard_path ()
++{
++#if defined (_CS_PATH) && defined (HAVE_CONFSTR)
++  char *p;
++  size_t len;
++
++  len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
++  if (len > 0)
++    {
++      p = (char *)xmalloc (len + 2);
++      *p = '\0';
++      confstr (_CS_PATH, p, len);
++      return (p);
++    }
++  else
++    return (savestring (STANDARD_UTILS_PATH));
++#else /* !_CS_PATH || !HAVE_CONFSTR  */
++#  if defined (CS_PATH)
++  return (savestring (CS_PATH));
++#  else
++  return (savestring (STANDARD_UTILS_PATH));
++#  endif /* !CS_PATH */
++#endif /* !_CS_PATH || !HAVE_CONFSTR */
++}
+diff -ruwN source/include/posixwait.h source-new/include/posixwait.h
+--- source/include/posixwait.h	2008-08-12 08:03:03.000000000 -0600
++++ source-new/include/posixwait.h	2019-01-28 12:42:40.972781097 -0700
+@@ -34,7 +34,7 @@
+ 
+ /* How to get the status of a job.  For Posix, this is just an
+    int, but for other systems we have to crack the union wait. */
+-#if !defined (_POSIX_VERSION)
++#if 0
+ typedef union wait WAIT;
+ #  define WSTATUS(t)  (t.w_status)
+ #else /* _POSIX_VERSION */
+@@ -50,7 +50,7 @@
+ 
+ /* More Posix P1003.1 definitions.  In the POSIX versions, the parameter is
+    passed as an `int', in the non-POSIX version, as `union wait'. */
+-#if defined (_POSIX_VERSION)
++#if 1
+ 
+ #  if !defined (WSTOPSIG)
+ #    define WSTOPSIG(s)       ((s) >> 8)
+diff -ruwN source/lib/sh/getcwd.c source-new/lib/sh/getcwd.c
+--- source/lib/sh/getcwd.c	2012-03-10 08:48:50.000000000 -0700
++++ source-new/lib/sh/getcwd.c	2019-01-28 14:02:28.573259186 -0700
+@@ -20,7 +20,7 @@
+ 
+ #include <config.h>
+ 
+-#if !defined (HAVE_GETCWD)
++#if !defined (HAVE_GETCWD) && !defined(__redox__)
+ 
+ #if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
+   #pragma alloca
+diff -ruwN source/sig.c source-new/sig.c
+--- source/sig.c	2016-02-11 13:02:45.000000000 -0700
++++ source-new/sig.c	2019-01-28 13:48:08.303876705 -0700
+@@ -680,7 +680,9 @@
+ }
+ 
+ /* Signal functions used by the rest of the code. */
+-#if !defined (HAVE_POSIX_SIGNALS)
++#if defined(__redox__)
++// Redox already has sigprocmask
++#elif !defined (HAVE_POSIX_SIGNALS)
+ 
+ /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
+ sigprocmask (operation, newset, oldset)
-- 
GitLab