


# Patch containing DJGPP specific changes.
# Must be applied after bash patches have been applied.
# CD into bash-4.3 and apply the patch like this:
#   patch -p0 < ${PATCH_DIR}\diffs
# where PATCH_DIR is the directory where the patch is stored.



#######################################################################



2023-03-o4  Juan Manuel Guerrero <juan.guerrero@gmx.de>


	* bshspawn.c: New file that is part of the DJGPP port.

	* dosdebug.c: New file that is part of the DJGPP port.

	* dosdebug.h: New file that is part of the DJGPP port.

	* dosmalloc.h: New file that is part of the DJGPP port.

	* dospath.c: New file that is part of the DJGPP port.

	* dospath.h: New file that is part of the DJGPP port.

	* dospipe.c: New file that is part of the DJGPP port.

	* dospipe.h: New file that is part of the DJGPP port.

	* dospipe_internal.h: New file that is part of the DJGPP port.

	* nofork.c: New file that is part of the DJGPP port.

	* nofork.h: New file that is part of the DJGPP port.

	* doscolor.c [__DJGPP__]: New file that is part of the DJGPP port.
	DJGPP specific functions to provide colorization support with a
	loaded ANSI.SYS driver, in the same way this has been done in other
	programs like grep and file utils.






diff -aprNU5 bash-4.4.orig/bshspawn.c bash-4.4/bshspawn.c
--- bash-4.4.orig/bshspawn.c	1970-01-01 00:00:00 +0000
+++ bash-4.4/bshspawn.c	2023-03-04 20:54:00 +0000
@@ -0,0 +1,240 @@
+#include <config.h>
+
+#if defined (__DJGPP__)
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <process.h>
+#include <sys/system.h>
+#include <sys/exceptn.h>
+
+#include "command.h"
+#include "general.h"
+#include "externs.h"
+#include "dospath.h"
+#include "dosmalloc.h"
+
+static char *spawn_make_response_file(char **argv);
+#if 0
+static void reset_console(void);
+#endif /* 0 */
+
+static const char * dos_ext_names[] =
+{ "exe", "bat", "com", "btm" };
+
+int bash_spawnve(const char *path, char **args, char **envp)
+{
+  int status;
+  char oldcwd[PATH_MAX];
+  int errno_save;
+  int i, is_dos_ext;
+  int old_ctrl_c;
+  char *base, *dot;
+
+  /* Force scripts not starting with #! to be invoked with Bash.  */
+  is_dos_ext = 0;
+  base = basename(path);
+  dot = strchr(base, '.');
+
+  if (dot && dot[1] != '\0')
+  {
+    ++dot;
+    for (i = 0; i < sizeof (dos_ext_names) / sizeof (dos_ext_names[0]); ++i)
+    {
+      if (strcmp(dot, dos_ext_names[i]) == 0)
+      {
+        is_dos_ext = 1;
+        break;
+      }
+    }
+  }
+
+  if (!is_dos_ext)
+  {
+    char sample[2];
+    int fd = open(path, O_RDONLY | O_BINARY);
+    if (fd > -1)
+    {
+      int sample_len = read(fd, sample, 2);
+      close(fd);
+      if (sample_len == 2)
+      {
+        if (sample[0] == 0x4c || sample[1] == 0x01)
+        {
+          /* Unstubbed COFF. Check for a file with .exe and
+             use it if it exists.  */
+          const char *exe_path = find_one_extension(path, "exe");
+          if (exe_path)
+            path = exe_path;
+        }
+        else if (!(sample[0] == 'M' || sample[1] == 'Z')
+                 && !(sample[0] == '#' || sample[1] == '!'))
+        {
+          /* Let Bash insert the shell name into argv[0] so
+             scripts without #! will run.  */
+          errno = ENOEXEC;
+          return -1;
+        }
+      }
+    }
+  }
+
+  /* keep cwd on exec */
+  getcwd(oldcwd, sizeof oldcwd);
+
+  /* Expand 'path'.  */
+  if (strncmp(path, "/dev/", sizeof("/dev/") - 1) == 0)
+    path = get_real_path(path);
+
+  /* disable interrupt */
+  old_ctrl_c = __djgpp_set_ctrl_c(0);
+
+  errno = 0;
+
+  /* Run child process.  */
+  status = __djgpp_spawn(P_WAIT, path, args, envp, SPAWN_NO_EXTENSION_SRCH);
+
+  /* make response file if E2BIG */
+  if (errno == E2BIG && args != NULL && args[1] != NULL && args[1][0] != '@')
+  {
+    char *tname;
+
+    tname = spawn_make_response_file(args);
+    if (tname != NULL)
+    {
+      char *xargs[3];
+
+      xargs[0] = args[0];
+      xargs[1] = xmalloc(1 + strlen(tname) + 2);
+      if (xargs[1])
+      {
+        char *resp = xargs[1];
+        resp[0] = '@';
+        strcpy(resp + 1, tname);
+
+        xargs[2] = NULL;
+
+        errno = 0;
+
+        /* try again */
+        status = __djgpp_spawn(P_WAIT, path, xargs, envp,
+                               SPAWN_NO_EXTENSION_SRCH);
+
+        /* cleanup */
+        free(xargs[1]);
+        remove(tname);
+        free(tname);
+      }
+    }
+  }
+
+  /* Reset standard input */
+#if 0
+  reset_console();
+#endif /* 0 */
+
+  /* enable interrupt */
+  __djgpp_set_ctrl_c(old_ctrl_c);
+
+  errno_save = errno;
+  if (status > -1)
+    chdir(oldcwd);
+  errno = errno_save;
+
+  return status;
+}
+
+static char *
+spawn_make_response_file(char **argv)
+{
+  char *tname;
+
+  tname = sh_mktmpname("rs", MT_USERANDOM | MT_USETMPDIR);
+
+  if (tname != NULL)
+  {
+    FILE *fp;
+    char *p;
+    int i;
+
+    fp = fopen(tname, "wt");
+    if (fp == NULL)
+    {
+      free(tname);
+      return NULL;
+    }
+
+    for (i = 1; (p = argv[i]) != NULL; i++)
+    {
+      if (i != 1)
+        fputc(' ', fp);
+      if (strchr(p, '"') == NULL)
+      {
+        fputc('"', fp);
+        fputs(p, fp);
+        fputc('"', fp);
+      }
+      else
+      {
+        fputc('"', fp);
+        for (; *p; p++)
+        {
+          if (*p == '"')
+            fputc('\\', fp);
+          fputc(*p, fp);
+        }
+        fputc('"', fp);
+      }
+    }
+    fclose(fp);
+  }
+
+  return tname;
+}
+
+#if 0
+#include <libc/getdinfo.h>
+
+#define _DEV_EOF    0x0040
+
+#define _REG_STATUS_CF 0x01
+#define _REG_STATUS_ZF 0x40
+
+/* XXX: Is this needed? */
+void
+reset_console (void)
+{
+  unsigned short devinfo;
+  int handle;
+  __dpmi_regs r;
+
+  handle = 0; /* STDIN (CON) */
+
+  r.x.ax = 0x4400;
+  r.x.bx = handle;
+  __dpmi_int(0x21, &r);
+  if (r.x.flags & _REG_STATUS_CF)
+    return;
+  devinfo = r.x.dx;
+
+  if ((devinfo & _DEV_CDEV) && (devinfo & _DEV_STDIN) && (devinfo & _DEV_EOF) == 0)
+  {
+    r.x.ax = 0x4000; /* WRITE */
+    r.x.bx = handle; /* STDIN (CON) */
+    r.x.cx = 0; /* zero byte */
+    r.x.dx = 0; /* dummy offset */
+    r.x.ds = 0; /* dummy segment */
+    __dpmi_int(0x21, &r);
+    if (r.x.flags & _REG_STATUS_CF)
+      return;
+  }
+}
+#endif /* 0 */
+
+#endif /* __DJGPP__ */
diff -aprNU5 bash-4.4.orig/doscolor.c bash-4.4/doscolor.c
--- bash-4.4.orig/doscolor.c	1970-01-01 00:00:00 +0000
+++ bash-4.4/doscolor.c	2023-03-04 20:54:00 +0000
@@ -0,0 +1,362 @@
+#if defined (__DJGPP__)
+/*  If compiled with DJGPP do not check for the term environment
+    variable to decided which value should color_option have.
+*/
+#define IS_TERMINAL     (isatty(STDOUT_FILENO))
+
+
+/*  Screen write redirection.  We need this to support colorization
+    without requiring ANSI.SYS driver (or its work-alike) to be loaded.
+
+    This function uses the DJGPP filesystem extensions mechanism.  It is
+    installed as a handler for handle-based functions (read/write/close)
+    for the standard output (but actually only handles writes, only if
+    the standard output is connected to the terminal, and only if user
+    asked for colorization).  When a buffer is written to the screen by
+    low-level functions of the DJGPP C library, our handler will be
+    called.  For any request that doesn't require colored screen writes
+    we return a zero to the caller, in which case the caller will handle
+    the output in the usual way (by eventually calling DOS).
+
+    When colorization *is* required, the buffer is written directly to
+    the screen while converting the ANSI escape sequences into calls to
+    DJGPP conio functions which change text attributes.  A non-zero value is
+    then returned to the caller to signal that the output has been handled.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <conio.h>
+#include <sys/fsext.h>
+#include <go32.h> /* for `_dos_ds' */
+#include <sys/farptr.h>
+#include <pc.h> /* for `ScreenGetCursor' */
+#include "dosmalloc.h" /* for `xmalloc' and `xrealloc' */
+
+static int norm_blink = -1, cur_blink = -1;
+static unsigned char norm_attr = 0, cur_attr = 0;
+static int isatty_stdout = -1;
+static size_t leftover = 0;
+
+
+/* Restore the BIOS blinking bit to its original value.  Called at exit.  */
+static void
+restore_blink_bit (void)
+{
+  if (cur_blink != norm_blink)
+    {
+      if (norm_blink > 0)
+        blinkvideo ();
+      else
+        intensevideo ();
+    }
+}
+
+
+/* Write a buffer to the screen video memory.  This expands the TAB
+   characters to the appropriate number of spaces, and also does TRT
+   with null characters and other non-printable characters, if
+   any.  */
+static void
+screen_puts (char *buf, char *buf_end)
+{
+  register char *p = buf, *q = p;
+  int row, col;
+  unsigned char c;
+
+  while (p < buf_end)
+    {
+      if (*p < ' ')
+        {
+          switch (*p)
+            {
+              case '\b':
+              case '\r':
+              case '\n':
+                /* nothing: cputs already does TRT with these */
+                break;
+              case '\t':
+                *p = '\0';
+                cputs (q);
+                ScreenGetCursor (&row, &col);
+                for (cputs (" "), col += 1; col % 8; col++)
+                  cputs (" ");
+                q = p + 1;
+                *p = '\t';
+                break;
+              default:
+                c = *p;
+                *p = '\0';
+                cputs (q);
+                cputs ("^");
+                putch (c | 0x40);
+                q = p + 1;
+                *p = c;
+                break;
+            }
+        }
+      p++;
+    }
+  /* Output whatever is left.  */
+  cputs (q);
+}
+
+
+#define ESC '\033'
+#define IS_SGR(s) (((s)[1] == '[') && ((s)[2] == 'm'))
+#define IS_EL(s)  (((s)[1] == '[') && ((s)[2] == 'K'))
+
+/* Screen writes redirector function.  */
+static int
+msdos_screen_write (__FSEXT_Fnumber func, int *retval, va_list rest_args)
+{
+  static char *cbuf = NULL;
+  static size_t cbuf_len = 0;
+  /* Only dark colors mentioned here, so that bold has visible effect.  */
+  static enum COLORS screen_color[] = {
+    BLACK,
+    RED,
+    GREEN,
+    BROWN,
+    BLUE,
+    MAGENTA,
+    CYAN,
+    LIGHTGRAY
+  };
+  char *anchor, *p_next;
+  unsigned char fg, bg;
+
+  int handle;
+  char *buf, *buf_end;
+  size_t buflen;
+#if 0
+  /*  Do not care about TERM.
+      If STDOUT is connected to a TTY
+      use colors.  */
+  char *term = get_string_value ("TERM");
+#endif
+
+  /* Avoid direct screen writes unless colorization was actually requested.
+     Otherwise, we will break programs that catch I/O from their children.  */
+  handle = va_arg (rest_args, int);
+  if (!IS_TERMINAL || func != __FSEXT_write ||
+       !(handle == STDOUT_FILENO ? isatty_stdout : isatty (handle)))
+    return 0;
+
+  buf = va_arg (rest_args, char *);
+  if (!buf)
+    {
+      errno = EINVAL;
+      *retval = -1;
+      return 1;
+    }
+
+  /* Allocate a sufficiently large buffer to hold the output.  */
+  buflen = va_arg (rest_args, size_t);
+  if (!cbuf)
+    {
+      struct text_info txtinfo;
+
+      cbuf_len = buflen + 1;
+      cbuf = (char *)xmalloc (cbuf_len);
+      gettextinfo (&txtinfo);
+      norm_attr = txtinfo.attribute; /* save the original text attribute */
+      cur_attr = norm_attr;
+      /* Does it normally blink when bg has its 3rd bit set?  */
+      norm_blink = (_farpeekb (_dos_ds, 0x465) & 0x20) ? 1 : 0;
+      cur_blink = norm_blink;
+    }
+  else if (buflen >= cbuf_len)
+    {
+      cbuf_len = buflen + 1 + leftover;
+      cbuf = (char *)xrealloc (cbuf, cbuf_len);
+    }
+  memcpy (cbuf + leftover, buf, buflen);
+  buf_end = cbuf + buflen + leftover;
+  *buf_end = '\0';
+
+  /* Current text attributes are used as baseline.  */
+  fg = cur_attr & 15;
+  bg = (cur_attr >> 4) & 15;
+
+  /* Walk the buffer, writing text directly to video RAM,
+     changing color attributes when an escape sequence is seen.  */
+  for (anchor = p_next = cbuf;
+       (p_next = memchr (p_next, ESC, buflen - (p_next - cbuf))) != 0; )
+    {
+      char *p = p_next;
+
+      /* If some chars seen since the last escape sequence,
+         write it out to the screen using current text attributes.  */
+      if (p > anchor)
+        {
+          *p = '\0'; /* `cputs' needs ASCIIZ string */
+          screen_puts (anchor, p);
+          *p = ESC; /* restore the ESC character */
+          anchor = p;
+        }
+
+      /* Handle the null escape sequence (ESC-[m), which is used to
+         restore the original color. */
+      if (IS_SGR(p))
+        {
+          textattr (norm_attr);
+          p += 3;
+          anchor = p_next = p;
+          continue;
+        }
+
+      /* Handle the erase in line to the right escape sequence (ESC-[K). */
+      if (IS_EL(p))
+        {
+          clreol();
+          p += 3;
+          anchor = p_next = p;
+          continue;
+        }
+
+      if (p[1] == '[') /* "Esc-[" sequence */
+        {
+          p += 2; /* get past "Esc-[" sequence */
+          p_next = p;
+          while (*p != 'm') /* `m' ends the escape sequence */
+            {
+              char *q;
+              long code = strtol (p, &q, 10);
+
+              if (!*q)
+                {
+                  /* Incomplete escape sequence.  Remember the part
+                     we've seen for the next time.  */
+                  leftover = q - anchor;
+                  if (leftover >= cbuf_len)
+                    {
+                      cbuf_len += 1 + leftover;
+                      cbuf = (char *)xrealloc (cbuf, cbuf_len);
+                    }
+                  strcpy (cbuf, anchor);
+                  *retval = buflen; /* that's a lie, but we have to! */
+                  return 1;
+                }
+
+              /* 
+                 Sanity checks:
+
+                 q > p unless p doesn't point to a number;
+                 SGR codes supported by ANSI.SYS are between 0 and 49;
+                 Each SGR code ends with a `;' or an `m'.
+
+                 If any of the above is violated, we just ignore the bogon.
+              */
+              if (q == p || code > 49 || code < 0 || (*q != 'm' && *q != ';'))
+                {
+                  p_next = q;
+                  break;
+                }
+              if (*q == ';') /* more codes to follow */
+                q++;
+
+              /* Convert ANSI codes to color fore- and background.  */
+              switch (code)
+                {
+                  case 0: /* all attributes off */
+                    fg = norm_attr & 15;
+                    bg = (norm_attr >> 4) & 15;
+                    break;
+                  case 1: /* intensity on */
+                    fg |= 8;
+                    break;
+                  case 4: /* underline on */
+                    fg |= 8; /* we can't, so make it bold instead */
+                    break;
+                  case 5: /* blink */
+                    if (cur_blink != 1)
+                      {
+                        blinkvideo (); /* ensure we are'nt in bright bg mode */
+                        cur_blink = 1;
+                      }
+                    bg |= 8;
+                    break;
+                  case 7: /* reverse video */
+                    {
+                      unsigned char t = fg;
+                      fg = bg;
+                      bg = t;
+
+                      /* If it was blinking before, let it blink after.  */
+                      if (fg & 8)
+                        bg |= 8;
+
+                      /* If the fg was bold, let the background be bold.  */
+                      if ((t & 8) && cur_blink != 0)
+                        {
+                          intensevideo ();
+                          cur_blink = 0;
+                        }
+                    }
+                    break;
+                  case 8: /* concealed on */
+                    fg = (bg & 7) | 8; /* make fg be like bg, only bright */
+                    break;
+                  case 30: case 31: case 32: case 33: /* foreground color */
+                  case 34: case 35: case 36: case 37:
+                    fg = (fg & 8) | (screen_color[code - 30] & 15);
+                    break;
+                  case 40: case 41: case 42: case 43: /* background color */
+                  case 44: case 45: case 46: case 47:
+                    bg = (bg & 8) | (screen_color[code - 40] & 15);
+                    break;
+                  case 39: /* default fg */
+                    fg = norm_attr & 15;
+                    break;
+                  case 49:
+                    bg = (norm_attr >> 4) & 15;
+                    break;
+                  default:
+                    p_next = q; /* ignore unknown codes */
+                    break;
+                }
+              p = q;
+            } /* while loop */
+
+          if (*p == 'm' && p > p_next)
+            {
+              /* They don't *really* want it invisible, do they?  */
+              if (fg == (bg & 7))
+                fg |= 8; /* make it concealed instead */
+
+              /* Construct the text attribute and set it.  */
+              cur_attr = (bg << 4) | fg;
+              textattr (cur_attr);
+              p_next = anchor = p + 1;
+            }
+          else
+            break;
+        }
+      else
+        p_next++;
+    }  /* for loop */
+
+  /* Output what's left in the buffer.  */
+  screen_puts (anchor, buf_end);
+  leftover = 0;
+  *retval = buflen;
+  return 1;
+}
+
+
+/* This is called before `main' to install our STDOUT redirector.  */
+static void __attribute__((constructor))
+djgpp_bash_startup (void)
+{
+  __FSEXT_set_function (STDOUT_FILENO, msdos_screen_write);
+  isatty_stdout = isatty (STDOUT_FILENO);
+  atexit (restore_blink_bit);
+}
+
+#endif  /* __DJGPP__ */
diff -aprNU5 bash-4.4.orig/dosdebug.c bash-4.4/dosdebug.c
--- bash-4.4.orig/dosdebug.c	1970-01-01 00:00:00 +0000
+++ bash-4.4/dosdebug.c	2023-03-04 20:54:00 +0000
@@ -0,0 +1,295 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include "dosdebug.h"
+#include "dosmalloc.h"
+
+
+#if (DOS_PIPE_DEBUG - 1) == 0
+#define CHECK_ENV_VALUE(s)    ((s) && ((s)[0] == 'Y' || (s)[0] == 'y') && ((s)[1] == 'E' || (s)[1] == 'e') && ((s)[2] == 'S' || (s)[2] == 's'))
+#define PIPE_LOG_BUFFER_SIZE  (256 * 1024)
+
+#define PIPE_LOG_FILENAME     "bshpipe0.log"
+
+static bool delete_pipe_log_file = true;
+static int pipe_log_buffer_size = PIPE_LOG_BUFFER_SIZE;
+
+
+static void
+print_text(char *text_line, const int line_length)
+{
+  if (EOF != line_length)
+  {
+    const int consumed = pipe_log_buffer_ptr - pipe_log_buffer;
+    if (pipe_log_buffer_size <= line_length + consumed)
+    {
+      FILE *pipe_log_file = fopen(pipe_log_filename, "a");
+      if (!pipe_log_file)
+      {
+        xfree(text_line);
+        return;
+      }
+      else
+      {
+        *pipe_log_buffer_ptr = '\0';
+        fprintf(pipe_log_file, "%s", pipe_log_buffer);
+        fclose(pipe_log_file);
+        pipe_log_buffer_ptr = pipe_log_buffer;
+      }
+    }
+    if (pipe_log_buffer_size <= line_length)
+    {
+      pipe_log_buffer_ptr = pipe_log_buffer;
+      pipe_log_buffer = xrealloc(pipe_log_buffer, line_length + 1);
+      if (pipe_log_buffer)
+        pipe_log_buffer_ptr = pipe_log_buffer;
+      else
+      {
+        pipe_log_buffer = pipe_log_buffer_ptr;
+        xfree(text_line);
+        return;
+      }
+    }
+    memcpy(pipe_log_buffer_ptr, text_line, line_length);
+    pipe_log_buffer_ptr += line_length;
+    xfree(text_line);
+  }
+}
+
+void
+log_pipe_creation(const int index, const struct pipe_t *pipe_line)
+{
+  if (log_pipe_files)
+  {
+    char *log_line;
+    int line_length;
+    if (previous_script_name != bash_script_name)
+    {
+      const char format_string[] = "\n\n"
+                                   "================================================================================\n"
+                                   "                    script: %s\n"
+                                   "================================================================================\n"
+                                   "\n\n";
+      line_length  = sizeof(format_string);
+      line_length += strlen(bash_script_name);
+      log_line = xmalloc(line_length + 1);
+      if (log_line)
+      {
+        line_length = sprintf(log_line, format_string, bash_script_name);
+        print_text(log_line, line_length);
+      }
+      if (previous_script_name)
+        xfree(previous_script_name);
+      previous_script_name = bash_script_name;
+    }
+
+    if (previous_script_command_line != bash_script_command_line)
+    {
+      const char format_string[] = "\n"
+                                   "--------------------------------------------------------------------------------\n"
+                                   "                    script line%s: %s\n"
+                                   "--------------------------------------------------------------------------------\n"
+                                   "\n";
+#define SIZE 32
+      char line_number[SIZE] = "";
+      if (bash_script_line_number > -1)
+        snprintf(line_number, SIZE, " %d", bash_script_line_number);
+      bash_script_line_number = -1;
+#undef SIZE
+      line_length  = sizeof(format_string);
+      line_length += strlen(line_number);
+      line_length += strlen(bash_script_command_line);
+      log_line = xmalloc(line_length + 1);
+      if (log_line)
+      {
+        line_length = sprintf(log_line, format_string, line_number, bash_script_command_line);
+        print_text(log_line, line_length);
+      }
+      if (previous_script_command_line)
+        xfree(previous_script_command_line);
+      previous_script_command_line = bash_script_command_line;
+    }
+
+    {
+      const char format_string[] = "creating pipe #%d: %s\n"
+                                   "  read  fd: %d\n"
+                                   "  write fd: %d\n"
+                                   "  bckup fd: %d\n";
+      line_length  = sizeof(format_string);
+      line_length += 3;
+      line_length += strlen(pipe_line->name);
+      line_length += 4 + 4 + 4;
+      log_line = xmalloc(line_length + 1);
+      if (log_line)
+      {
+        line_length = sprintf(log_line, format_string,
+                                        index, pipe_line->name,
+                                        pipe_line->fds[READ_END],
+                                        pipe_line->fds[WRITE_END],
+                                        pipe_line->fds[BACK_UP]);
+        print_text(log_line, line_length);
+      }
+    }
+  }
+
+  delete_pipe_log_file = false;
+}
+
+void
+log_pipe_operation(const int index, const char *operation, const char *status, const struct pipe_t *pipe_line)
+{
+  if (log_pipe_files)
+  {
+    char *log_line;
+    int line_length;
+    const char format_string[] = "%s of pipe #%d: %s\n"
+                                 "  read  fd: %d\n"
+                                 "  write fd: %d\n"
+                                 "  bckup fd: %d\n"
+                                 "  status: %s\n";
+    line_length  = sizeof(format_string);
+    line_length += strlen(operation);
+    line_length += 3;
+    line_length += strlen(pipe_line->name);
+    line_length += 4 + 4 + 4;
+    line_length += strlen(status);
+    log_line = xmalloc(line_length + 1);
+    if (log_line)
+    {
+      line_length = sprintf(log_line, format_string,
+                                      operation, index,
+                                      pipe_line->name,
+                                      pipe_line->fds[READ_END],
+                                      pipe_line->fds[WRITE_END],
+                                      pipe_line->fds[BACK_UP],
+                                      status);
+      print_text(log_line, line_length);
+    }
+  }
+}
+
+void
+log_pipe_dump_used_fd_array(const bool *const fd_in_use)
+{
+  if (log_pipe_files)
+  {
+    int i;
+    for (i = 20; i < OPEN_MAX; i++)
+    {
+      if (fd_in_use[i] == true)
+      {
+        char *log_line;
+        int line_length;
+        const char format_string[] = "    fd_in_use[%03d] = TRUE\n";
+        log_line = xmalloc(sizeof(format_string) + 1);
+        if (log_line)
+        {
+          line_length = sprintf(log_line, format_string, i);
+          print_text(log_line, line_length);
+        }
+      }
+    }
+  }
+}
+
+void
+create_log_pipe_files(void)
+{
+  char *env_variable;
+
+  /*  For debuging purposes only.  */
+  env_variable = getenv("BASH_KEEP_PIPE_FILES");
+  keep_pipe_files = CHECK_ENV_VALUE(env_variable) ? true : false;
+  env_variable = getenv("BASH_LOG_PIPE_FILES");
+  log_pipe_files = CHECK_ENV_VALUE(env_variable) ? true : false;
+
+  if (log_pipe_files)
+  {
+    int length;
+    char *filename, *tmpdir = "/dev/env/TMPDIR";
+    if (access(tmpdir, D_OK))
+    {
+      tmpdir = "/dev/env/TMP";
+      if (access(tmpdir, D_OK))
+      {
+        tmpdir = "/dev/env/TEMP";
+        if (access(tmpdir, D_OK))
+        {
+          tmpdir = P_tmpdir;
+          if (access(tmpdir, D_OK))
+            tmpdir = ".";
+        }
+      }
+    }
+    filename = xmalloc(length = strlen(tmpdir) + sizeof("/"PIPE_LOG_FILENAME));
+    if (!filename)
+      log_pipe_files = false;
+    else
+    {
+      FILE *pipe_log_file;
+      char *numeric_tail = filename + length - sizeof("0.log");
+      char *dot = numeric_tail + 1;
+      int rc;
+
+      sprintf(filename, "%s/%s", tmpdir, PIPE_LOG_FILENAME);
+      if (0 == (rc = access(filename, F_OK)))
+      {
+        int i;
+        for (i = 0; 0 == rc && i < 16777216; numeric_tail--)
+        {
+          do {
+            sprintf(numeric_tail, "%x", ++i);
+            *dot = '.';
+          } while (0 == (rc = access(filename, F_OK)) && i % 15);
+        }
+
+        if (i == 16777216)
+        {
+          xfree(filename);
+          log_pipe_files = false;
+          return;
+        }
+      }
+      pipe_log_file = fopen(filename, "w");
+      if (!pipe_log_file)
+      {
+        xfree(filename);
+        log_pipe_files = false;
+        return;
+      }
+      fclose(pipe_log_file);
+
+      pipe_log_buffer = xmalloc(PIPE_LOG_BUFFER_SIZE);
+      if (!pipe_log_buffer)
+        log_pipe_files = false;
+      else
+      {
+        pipe_log_buffer_ptr = pipe_log_buffer;
+        pipe_log_filename = filename;
+        log_pipe_files = true;
+      }
+    }
+  }
+}
+
+void
+close_log_pipe_files(void)
+{
+  if (delete_pipe_log_file)
+    remove(pipe_log_filename);
+  else if (log_pipe_files && pipe_log_filename)
+  {
+    FILE *pipe_log_file = fopen(pipe_log_filename, "a");
+    if (pipe_log_file)
+    {
+      *pipe_log_buffer_ptr = '\0';
+      fprintf(pipe_log_file, "%s", pipe_log_buffer);
+      fclose(pipe_log_file);
+    }
+    xfree(pipe_log_buffer);
+  }
+  xfree(pipe_log_filename);
+}
+#endif /* DOS_PIPE_DEBUG */
diff -aprNU5 bash-4.4.orig/dosdebug.h bash-4.4/dosdebug.h
--- bash-4.4.orig/dosdebug.h	1970-01-01 00:00:00 +0000
+++ bash-4.4/dosdebug.h	2023-03-04 20:54:00 +0000
@@ -0,0 +1,14 @@
+#ifndef DOS_DEBUG_SUPPORT
+#define DOS_DEBUG_SUPPORT
+
+#include "config.h"
+#include "dospipe_internal.h"
+
+# if (DOS_PIPE_DEBUG - 1) == 0
+void log_pipe_creation(const int index, const struct pipe_t *pipe_line);
+void log_pipe_operation(const int index, const char *operation, const char *status, const struct pipe_t *pipe_line);
+void log_pipe_dump_used_fd_array(const bool *const fd_in_use);
+void create_log_pipe_files(void);
+void close_log_pipe_files(void);
+# endif /* DOS_PIPE_DEBUG */
+#endif /* DOS_DEBUG_SUPPORT */
diff -aprNU5 bash-4.4.orig/dosmalloc.h bash-4.4/dosmalloc.h
--- bash-4.4.orig/dosmalloc.h	1970-01-01 00:00:00 +0000
+++ bash-4.4/dosmalloc.h	2023-03-04 20:54:00 +0000
@@ -0,0 +1,32 @@
+#ifndef DOS_MALLOC_SUPPORT
+#define DOS_MALLOC_SUPPORT
+
+#include "config.h"
+
+/* Functions for use by the shell to do malloc debugging and tracking. */
+#if defined (USING_BASH_MALLOC)
+# include "xmalloc.h"
+
+# if !defined (DISABLE_MALLOC_WRAPPERS)
+#  undef  malloc
+#  define malloc(x)      sh_xmalloc((x), __FILE__, __LINE__)
+
+#  undef  realloc
+#  define realloc(x, n)  sh_xrealloc((x), (n), __FILE__, __LINE__)
+
+#  undef  free
+#  define free(x)        sh_xfree((x), __FILE__, __LINE__)
+# endif /* !DISABLE_MALLOC_WRAPPERS */
+#else  /* !USING_BASH_MALLOC */
+/* Provide prototypes for xmalloc, xrealloc, xfree
+   and  prototypes for malloc, realloc, free.  */
+
+# include <stdlib.h>
+
+void  xfree(void *_ptr);
+void *xmalloc(size_t _size);
+void *xrealloc(void *ptr, size_t _size);
+
+#endif /* !USING_BASH_MALLOC */
+
+#endif /* DOS_MALLOC_SUPPORT */
diff -aprNU5 bash-4.4.orig/dospath.c bash-4.4/dospath.c
--- bash-4.4.orig/dospath.c	1970-01-01 00:00:00 +0000
+++ bash-4.4/dospath.c	2023-03-04 20:54:00 +0000
@@ -0,0 +1,662 @@
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#include "config.h"
+#include "command.h"
+#include "general.h"
+#include "variables.h"
+#include "dospath.h"
+#include "dosmalloc.h"
+
+#define ARRAY_INIT_LEN 32
+
+struct dynamic_array
+{
+  char *start;
+  char *ptr;
+  char *end;
+};
+
+struct dos_var_info
+{
+  const char *name;
+  void (*init_func)(const char *);
+  char found;
+};
+
+char path_separator = ';';
+int path_expand = 0;
+int test_finds_exe = 0;
+
+static void path_separator_init (const char *);
+static void path_expand_init (const char *);
+static void test_finds_exe_init (const char *);
+static int make_bash_path (const char *in, struct dynamic_array *buffer,
+                           char stop_char, char **in_end);
+static int make_bash_path_var (const char *in, struct dynamic_array *buffer);
+static int make_dos_path (const char *in, struct dynamic_array *buffer,
+                          char stop_char, char **in_end);
+static int make_dos_path_var (const char *in, struct dynamic_array *buffer);
+static int make_export_path_var (const char *in, struct dynamic_array *buffer);
+static void restore_cwd (void);
+
+static void array_resize(struct dynamic_array *array);
+static const char *array_puts(struct dynamic_array *array, const char *s);
+static void array_putc(struct dynamic_array *array, const char ch);
+static void array_init(struct dynamic_array *array, const char *s, size_t size);
+static void array_done(struct dynamic_array *array);
+static int array_len(struct dynamic_array *array);
+
+static const char * path_sep_vars[] =
+{
+/*  "CDPATH", */
+  "COMSPEC",
+  "HOME",
+  "MAILPATH",
+  "OLDPWD",
+  "PATH",
+  "PWD",
+  "TMPDIR",
+};
+
+static char path_var_found[] =
+{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static struct dos_var_info dos_var_init[] =
+{
+  { "PATH_EXPAND", &path_expand_init, 0},
+  { "TEST_FINDS_EXE", &test_finds_exe_init, 0},
+};
+
+static char path_buffer[256];
+
+static char *init_cwd;
+
+/* Called at startup. Certain variables containing a list of path like PATH and
+   are used by Bash must be in a form that Bash understands.
+   When PATH_SEPARATOR=:, the list is separated by ':' and uses the special
+   '/dev/x/' form understood by DJGPP. When PATH_SEPARATOR=;, the list is
+   separated by ';' as normal but backslashes are converted to slashes.  */
+int try_init_path_var(const char *name, char **val)
+{
+  int i;
+  struct dynamic_array buffer;
+
+  for (i = 0; i < sizeof (path_sep_vars) / sizeof (path_sep_vars[0]); i++)
+  {
+    if (!path_var_found[i] && strcmp (name, path_sep_vars[i]) == 0)
+    {
+      path_var_found[i] = 1;
+      array_init(&buffer, 0, ARRAY_INIT_LEN);
+      make_bash_path_var(*val, &buffer);
+      *val = buffer.start;
+      return 1;
+    }
+  }
+  for (i = 0; i < sizeof (dos_var_init) / sizeof (dos_var_init[0]); i++)
+  {
+    if (!dos_var_init[i].found && strcmp (name, dos_var_init[i].name) == 0)
+    {
+      dos_var_init[i].found = 1;
+      if ((*val)[0] != '\0')
+        (dos_var_init[i].init_func)(*val);
+      break;
+    }
+  }
+  return 0;
+}
+
+void init_path_separator(void)
+{
+  char *path_sep = getenv("PATH_SEPARATOR");
+  if (path_sep)
+    path_separator_init(path_sep);
+}
+
+/* Put a path variable to be exported Bash into a form that native DOS programs
+   can understand. Do that by changing paths containing '/dev/x/foo' path to
+   canonical form and change slashes to backslashes. */
+char *
+export_path_var(const char *name, const char *val)
+{
+  int out_len;
+  struct dynamic_array buffer;
+
+  array_init(&buffer, 0, ARRAY_INIT_LEN);
+  array_puts(&buffer, name);
+  array_putc(&buffer, '=');
+
+  out_len = make_export_path_var(val, &buffer);
+  array_putc(&buffer, '\0');
+
+  return buffer.start;
+}
+
+void expand_argv_words(WORD_LIST *list)
+{
+  struct dynamic_array buffer;
+
+  if (!path_expand)
+    return;
+
+  list = list->next;
+
+  while (list)
+  {
+    if (list->word->flags != W_QUOTED)
+    {
+      char *arg = list->word->word;
+
+      if (strncmp(arg, "/dev/", 5) == 0 && arg[5]
+          && (arg[6] == '/' || arg[6] == '\0'))
+      {
+        /* Setup a fake dynamic buffer. Set end to 0 to ensure
+           no attempt is made to increase the size of the array.  */
+        buffer.start = arg;
+        buffer.ptr = arg;
+        buffer.end = (char *)0 - 1;
+        make_dos_path(arg, &buffer, '\0', NULL);
+        array_putc(&buffer, '\0');
+      }
+    }
+    list = list->next;
+  }
+
+  return;
+}
+
+
+void make_path_vars_bash(void)
+{
+  int i;
+  struct dynamic_array buffer;
+  SHELL_VAR *var;
+
+  array_init(&buffer, 0, ARRAY_INIT_LEN);
+
+  for (i = 0; i < sizeof(path_sep_vars) / sizeof(path_sep_vars[0]); i++)
+  {
+    var = find_variable((char *)path_sep_vars[i]);
+    if (!var || !var->value)
+      continue;
+    buffer.ptr = buffer.start;
+    make_bash_path_var(var->value, &buffer);
+    free(var->value);
+    var->value = malloc(array_len(&buffer) + 1);
+    strcpy(var->value, buffer.start);
+  }
+  array_done(&buffer);
+}
+
+void make_path_vars_dos(void)
+{
+  int i;
+  struct dynamic_array buffer;
+  SHELL_VAR *var;
+
+  array_init(&buffer, 0, ARRAY_INIT_LEN);
+
+  for (i = 0; i < sizeof(path_sep_vars) / sizeof(path_sep_vars[0]); i++)
+  {
+    var = find_variable((char *)path_sep_vars[i]);
+    if (!var || !var->value)
+      continue;
+    buffer.ptr = buffer.start;
+    make_dos_path_var(var->value, &buffer);
+    free(var->value);
+    var->value = malloc(array_len(&buffer) + 1);
+    strcpy(var->value, buffer.start);
+  }
+  array_done(&buffer);
+}
+
+char *make_posix_path_from_filename(const char *in)
+{
+  struct dynamic_array buffer;
+
+  array_init(&buffer, 0, ARRAY_INIT_LEN);
+
+  if (in[1] == ':')
+  {
+    array_puts(&buffer, "/dev/");
+    array_putc(&buffer, in[0]);
+    in += 2;
+  }
+  while (*in)
+  {
+     array_putc(&buffer, ((*in != '\\') ? *in : '/'));
+     ++in;
+  }
+
+  array_putc(&buffer, '\0');
+  return buffer.start;
+
+}
+
+void save_cwd(void)
+{
+  if (init_cwd == NULL)
+    init_cwd = rpl_getcwd(NULL, FILENAME_MAX + 1);
+  atexit (restore_cwd);
+}
+
+char *dospath_getcwd(char *buf, size_t size)
+{
+  char ch;
+
+  if (buf == NULL)
+  {
+    buf = (char *)xmalloc(PATH_MAX + 1);
+    buf[0] = '\0';
+  }
+  if (size == 0)
+    size = PATH_MAX;
+
+  if (path_separator == ';')
+    return rpl_getcwd(buf, size);
+
+  rpl_getcwd(buf + 4, size - 4);
+  ch = *(buf + 4);
+  strcpy(buf, "/dev/");
+  buf[5] = ch;
+  buf[6] = '/';
+
+  return buf;
+}
+
+/* This shall replace lib/sh/getcwd and ensure
+   that always DJGPP's own implementation is used.  */
+char *rpl_getcwd(char *buf, size_t size)
+{
+  size_t buf_size = size ? size : PATH_MAX;
+
+  return getcwd(buf, buf_size);
+}
+
+static const char *exec_extensions[] =
+{"exe", "bat", "com", "btm"};
+
+const char *
+find_extension(const char *path)
+{
+  char *ptr, *ext, *file;
+  int dot, i;
+
+  dot = 0;
+  ptr = (char *)path;
+  ext = file = path_buffer;
+
+  while (*ptr)
+  {
+    *ext = *ptr;
+    if (*ext == '.')
+      dot = 1;
+    else if (*ext == '/')
+    {
+      dot = 0;
+      file = ext;
+      ++file;
+    }
+    ++ext;
+    ++ptr;
+  }
+
+  if (dot)
+    return NULL;
+
+  *ext = '\0';
+  if (access(path_buffer, F_OK) == 0 && !(access(path_buffer, D_OK) == 0))
+    return path_buffer;
+
+  *ext = '.';
+  ++ext;
+
+  for (i = 0; i < sizeof (exec_extensions) / sizeof (exec_extensions[0]); i++)
+  {
+    strcpy (ext, exec_extensions[i]);
+    if (access(path_buffer, F_OK) == 0 && !(access(path_buffer, D_OK) == 0))
+      return path_buffer;
+  }
+  return NULL;
+}
+
+const char *find_path_extension(const char *path, const char *file)
+{
+  char *ext, *file_ptr;
+  int dot, i;
+
+  ext = path_buffer;
+
+  while (*path)
+  {
+    *ext = *((char *)(path));
+    ++path;
+    ++ext;
+  }
+  if (ext[-1] != '/')
+  {
+    *ext = '/';
+    ++ext;
+  }
+  dot = 0;
+  file_ptr = ext;
+
+  while (*file)
+  {
+    *ext = *(char *)file;
+    if (*ext == '.')
+      dot = 1;
+    ++file;
+    ++ext;
+  }
+  if (dot)
+    return NULL;
+
+  *ext = '\0';
+  if (access(path_buffer, F_OK) == 0 && !(access(path_buffer, D_OK) == 0))
+    return file_ptr;
+
+  *ext = '.';
+  ++ext;
+
+  for (i = 0; i < sizeof (exec_extensions) / sizeof (exec_extensions[0]); i++)
+  {
+    strcpy(ext, exec_extensions[i]);
+    if (access(path_buffer, F_OK) == 0 && !(access(path_buffer, D_OK) == 0))
+      return file_ptr;
+  }
+  return NULL;
+}
+
+const char *find_one_extension(const char *path, const char *extension)
+{
+  char *ptr, *ext, *file;
+  int dot;
+
+  dot = 0;
+  ptr = (char *)path;
+  ext = file = path_buffer;
+
+  while (*ptr)
+  {
+    *ext = *ptr;
+    if (*ext == '.')
+      dot = 1;
+    else if (*ext == '/')
+    {
+      dot = 0;
+      file = ext;
+      ++file;
+    }
+    ++ext;
+    ++ptr;
+  }
+
+  if (dot)
+    return NULL;
+
+#if 0
+  *ext = '\0';
+  if (access(path_buffer, F_OK) == 0 && !(access(path_buffer, D_OK) == 0))
+    return path_buffer;
+#endif /* 0 */
+
+  *ext = '.';
+  ++ext;
+
+  strcpy(ext, extension);
+
+  if (access(path_buffer, F_OK) == 0 && !(access(path_buffer, D_OK) == 0))
+    return path_buffer;
+
+  return NULL;
+}
+
+char *
+get_real_path(const char *path)
+{
+  _fixpath(path, path_buffer);
+  return path_buffer;
+}
+
+char *
+encode_drive_letter(char *buffer, const char letter)
+{
+  if (path_separator == ':')
+  {
+    strcpy(buffer, "/dev/");
+    buffer[5] = letter;
+    buffer[6] = '\0';
+  }
+  else
+  {
+    buffer[0] = letter;
+    buffer[1] = ':';
+    buffer[2] = '\0';
+  }
+  return buffer;
+}
+
+static void restore_cwd(void)
+{
+  if (init_cwd && init_cwd[0] != '\0')
+    chdir(init_cwd);
+}
+
+static void
+path_separator_init(const char *val)
+{
+  char ch = *val;
+  if (ch == ':' || ch == ';')
+    path_separator = ch;
+}
+
+static void
+path_expand_init(const char *val)
+{
+  char ch = *val;
+  if (tolower(ch) == 'y')
+    path_expand = 1;
+}
+
+static void
+test_finds_exe_init(const char *val)
+{
+  char ch = *val;
+  if (tolower(ch) == 'y')
+    test_finds_exe = 1;
+  else
+    test_finds_exe = 0;
+}
+
+static int
+make_bash_path(const char *in, struct dynamic_array *buffer, char stop_char, char **in_end)
+{
+  if (in == NULL)
+    return 0;
+
+  if (path_separator == ':' && *in && *in != '.' && in[1] == ':')
+  {
+    if (in[2] == '\\' || in[2] == '/')
+    {
+      array_puts(buffer, "/dev/");
+      array_putc(buffer, *in);
+      in += 2;
+    }
+    else
+    {
+      char ch;
+      char *eop = (char *)in + 2;
+      char fixbuf[PATH_MAX];
+
+      while (*eop && *eop != stop_char)
+        ++eop;
+      ch = *eop;
+      *eop = '\0';
+      _fixpath(in, fixbuf);
+      *eop = ch;
+      ch = fixbuf[0];
+      array_puts(buffer, "/dev/");
+      array_putc(buffer, ch);
+      in = eop;
+    }
+  }
+  while (*in && *in != stop_char)
+  {
+    array_putc(buffer, (*in != '\\') ? *in : '/');
+    ++in;
+  }
+
+  if (in_end)
+    *in_end = (char *)in;
+
+  return 0;
+}
+
+static int
+make_bash_path_var(const char *in, struct dynamic_array *buffer)
+{
+  char *in_ptr = (char *)in;
+
+  while (*in_ptr)
+  {
+    make_bash_path(in_ptr, buffer, ';', &in_ptr);
+    if (*in_ptr == ';')
+    {
+      array_putc(buffer, path_separator);
+      ++in_ptr;
+    }
+  }
+  array_putc(buffer, '\0');
+  return buffer->ptr - buffer->start;
+}
+
+static int
+make_dos_path(const char *in, struct dynamic_array *buffer, char stop_char, char **in_end)
+{
+  if (in == NULL)
+    return 0;
+
+  if (strncmp(in, "/dev/", 5) == 0)
+  {
+    array_putc(buffer, in[5]);
+    array_putc(buffer, ':');
+    in += 6;
+  }
+
+  while (*in && *in != stop_char)
+  {
+    array_putc(buffer, (*in != '/') ? *in : '\\');
+    ++in;
+  }
+
+  if (in_end)
+    *in_end = (char *)in;
+
+  return buffer->ptr - buffer->start;
+}
+
+static int
+make_dos_path_var(const char *in, struct dynamic_array *buffer)
+{
+  char *in_ptr = (char *)in;
+
+  while (*in_ptr)
+  {
+    make_dos_path(in_ptr, buffer, ':', &in_ptr);
+    if (*in_ptr == ':')
+    {
+      array_putc(buffer, path_separator);
+      ++in_ptr;
+    }
+  }
+  array_putc(buffer, '\0');
+  return buffer->ptr - buffer->start;
+}
+
+static int
+make_export_path_var(const char *in, struct dynamic_array *buffer)
+{
+  char *in_ptr = (char *)in;
+
+  while (*in_ptr)
+  {
+    make_dos_path(in_ptr, buffer, path_separator, &in_ptr);
+    if (*in_ptr == path_separator)
+    {
+      array_putc(buffer, ';');
+      ++in_ptr;
+    }
+  }
+  array_putc(buffer, '\0');
+  return buffer->ptr - buffer->start;
+}
+
+static void
+array_resize(struct dynamic_array *array)
+{
+  char *xstart;
+  size_t len;
+
+  len = (array->end - array->start);
+  len *= 2;
+
+  xstart = realloc(array->start, len + 1);
+  array->ptr = xstart + (array->ptr - array->start);
+  array->start = xstart;
+  array->end = xstart + len;
+}
+
+static const char *
+array_puts(struct dynamic_array *array, const char *s)
+{
+  while (*s)
+  {
+    while (*s && (array->ptr < array->end))
+    {
+      *(array->ptr) = *s;
+      ++(array->ptr);
+      ++s;
+    }
+    if (*s)
+      array_resize(array);
+  }
+
+  return array->ptr;
+}
+
+static void
+array_putc(struct dynamic_array *array, const char ch)
+{
+  if (array->ptr >= array->end)
+    array_resize(array);
+  *(array->ptr) = ch;
+  ++(array->ptr);
+}
+
+static void
+array_init(struct dynamic_array *array, const char *s, size_t size)
+{
+  array->start = malloc(size + 1);
+  array->ptr = array->start;
+  array->end = array->start + size;
+  if (s)
+    array_puts(array, s);
+}
+
+static void
+array_done(struct dynamic_array *array)
+{
+  free(array->start);
+}
+
+static int
+array_len(struct dynamic_array *array)
+{
+  return array->ptr - array->start + 1;
+}
diff -aprNU5 bash-4.4.orig/dospath.h bash-4.4/dospath.h
--- bash-4.4.orig/dospath.h	1970-01-01 00:00:00 +0000
+++ bash-4.4/dospath.h	2023-03-04 20:54:00 +0000
@@ -0,0 +1,39 @@
+#ifndef DOS_PATH_SUPPORT
+#define DOS_PATH_SUPPORT
+
+#include <string.h>
+#include "stdc.h"
+#include "command.h"
+
+extern char path_separator;
+extern int path_expand;
+extern int test_finds_exe;
+
+void initialize_dos_vars __P (());
+void expand_argv_words __P ((WORD_LIST *list));
+int try_init_path_var __P ((const char *name, char **val));
+char *export_path_var __P ((const char *name, const char *val));
+char *make_posix_path_from_filename __P ((const char *in));
+void save_cwd __P (());
+void make_path_vars_bash __P (());
+void make_path_vars_dos __P (());
+const char * find_extension __P ((const char *path));
+const char * find_path_extension __P ((const char *path, const char *file));
+const char * find_one_extension __P ((const char *path, const char *ext));
+char * get_real_path __P ((const char *path));
+void reserve_fds __P ((void));
+void init_path_separator __P ((void));
+char *rpl_getcwd __P ((char *buf, size_t size));
+char *dospath_getcwd __P ((char *buf, size_t size));
+char *encode_drive_letter __P ((char *buffer, const char letter));
+static inline
+int is_dev_drive_path (const char *path)
+{
+  if (strncmp ("/dev/", path, 5) == 0 && path[5]
+      && (path[6] == '/' || path[6] == '\0'))
+    return 1;
+  return 0;
+}
+
+#endif /* DOS_PATH_SUPPORT */
+
diff -aprNU5 bash-4.4.orig/dospipe.c bash-4.4/dospipe.c
--- bash-4.4.orig/dospipe.c	1970-01-01 00:00:00 +0000
+++ bash-4.4/dospipe.c	2023-03-04 20:54:00 +0000
@@ -0,0 +1,432 @@
+/* A cheap pipe emulation for DOS.
+   Uses one read file descriptor and one write file descriptor. */
+
+
+#if defined (__DJGPP__)
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <io.h>
+
+extern int line_number;
+
+#define CLOSE_RD_END(FD)  (pipes[i].name && fd_in_use[(FD)] == true && pipes[i].fds[BACK_UP] == (FD) && pipes[i].fds[READ_END] == (FD))
+#define CLOSE_WR_END(FD)  (pipes[i].name && fd_in_use[(FD)] == true && pipes[i].fds[BACK_UP] == (FD) && pipes[i].fds[WRITE_END] == (FD))
+#define IS_CLOSED(FD)     (((pipes[i].fds[READ_END] == -(FD) && pipes[i].fds[WRITE_END] < -1) || (pipes[i].fds[READ_END] < -1 && pipes[i].fds[WRITE_END] == -(FD))) \
+                           && fd_in_use[pipes[i].fds[READ_END] < -1 ? -1 * pipes[i].fds[READ_END] : pipes[i].fds[READ_END]] == true \
+                           && fd_in_use[pipes[i].fds[WRITE_END] < -1 ? -1 * pipes[i].fds[WRITE_END] : pipes[i].fds[WRITE_END]] == true \
+                           && pipes[i].name)
+#define SWITCH_MODE(FD)   (pipes[i].fds[READ_END] > -1 && pipes[i].fds[WRITE_END] == -(FD) && pipes[i].fds[BACK_UP] == (FD) \
+                           && fd_in_use[(FD)] == true && fd_in_use[pipes[i].fds[READ_END]] == true)
+#define PIPE_FOUND(FD)    (((pipes[i].fds[READ_END] == (FD) || pipes[i].fds[WRITE_END] == (FD)) && fd_in_use[(FD)] == true \
+                           && pipes[i].name) || IS_CLOSED((FD)))
+
+#include "dospipe_internal.h"
+#include "dosdebug.h"
+#include "dosmalloc.h"
+
+
+static struct pipe_t pipes[OPEN_MAX];
+static bool fd_in_use[256];
+static int open_pipes = 0;
+static int table_size = 0;
+#if (DOS_PIPE_DEBUG - 1) == 0
+bool keep_pipe_files = false;
+bool log_pipe_files = false;
+char *pipe_log_filename = NULL;
+char *pipe_log_buffer = NULL;
+char *pipe_log_buffer_ptr = NULL;
+char *bash_script_command_line = NULL;
+char *previous_script_command_line = NULL;
+char *bash_script_name = NULL;
+char *previous_script_name = NULL;
+int bash_script_line_number = -1;
+#endif /* DOS_PIPE_DEBUG */
+
+
+static int
+register_fd(int fd)
+{
+  while (fd_in_use[fd] == true || fd < 20)
+  {
+    int i, tfd;
+
+    for (i = fd; i < OPEN_MAX; i++)
+      if (fd_in_use[i] == false)
+        break;
+    if (i == OPEN_MAX)
+      return -1;
+
+    tfd = fcntl(fd, F_DUPFD, i);
+    close(fd);
+    if (tfd < 0)
+      return -1;
+    fd = tfd;
+  }
+  fd_in_use[fd] = true;
+
+  return fd;
+}
+
+void
+remove_pipe(int fd)
+{
+  int i, orig_errno = errno;
+
+  for (i = 0; i < table_size; i++)
+  {
+    if (PIPE_FOUND(fd))
+    {
+      int tfd;
+      close(fd);
+      fd_in_use[fd] = false;
+      if ((tfd = pipes[i].fds[READ_END]) != -1)
+      {
+        if (tfd < -1)
+          tfd *= -1;
+        else if (tfd > -1 && tfd != fd)
+          close(tfd);
+        pipes[i].fds[READ_END] = -1;
+        fd_in_use[tfd] = false;
+      }
+      if ((tfd = pipes[i].fds[WRITE_END]) != -1)
+      {
+        if (tfd < -1)
+          tfd *= -1;
+        else if (tfd > -1 && tfd != fd)
+          close(tfd);
+        pipes[i].fds[WRITE_END] = -1;
+        fd_in_use[tfd] = false;
+      }
+#if (DOS_PIPE_DEBUG - 1) == 0
+      if (keep_pipe_files || 0 == remove(pipes[i].name))
+#else  /* !DOS_PIPE_DEBUG */
+      if (0 == remove(pipes[i].name))
+#endif /* !DOS_PIPE_DEBUG */
+      {
+        pipes[i].fds[BACK_UP] = -1;
+#if (DOS_PIPE_DEBUG - 1) == 0
+        log_pipe_operation(i, "removing", keep_pipe_files ? "pipe file will not be removed." : "\"remove_pipe\"" " successfully removed pipe file.", pipes + i);
+        log_pipe_dump_used_fd_array(fd_in_use);
+#endif /* DOS_PIPE_DEBUG */
+        free(pipes[i].name);
+        pipes[i].name = NULL;
+      }
+      else
+#if (DOS_PIPE_DEBUG - 1) == 0
+      {
+        pipes[i].fds[BACK_UP] = fd;
+        log_pipe_operation(i, "removing", "\"remove_pipe\"" " failed to remove pipe file.", pipes + i);
+        log_pipe_dump_used_fd_array(fd_in_use);
+      }
+#else  /* !DOS_PIPE_DEBUG */
+        pipes[i].fds[BACK_UP] = fd;
+#endif /* !DOS_PIPE_DEBUG */
+      if (!pipes[i].name)
+      {
+        open_pipes--;
+        if (++i == table_size)
+          table_size--;
+      }
+      break;
+    }
+  }
+
+  errno = orig_errno;
+}
+
+int
+rpl_close(int fd)
+{
+  int i;
+
+  for (i = 0; i < table_size; i++)
+  {
+    if (CLOSE_RD_END(fd))
+    {
+      /* read end closed.  */
+      pipes[i].fds[READ_END] *= -1;
+#if (DOS_PIPE_DEBUG - 1) == 0
+      log_pipe_operation(i, "closing read end", "OK.", pipes + i);
+      log_pipe_dump_used_fd_array(fd_in_use);
+#endif /* DOS_PIPE_DEBUG */
+      break;
+    }
+    else
+    if (CLOSE_WR_END(fd))
+    {
+      /* write end closed.  */
+      pipes[i].fds[WRITE_END] *= -1;
+      close(fd);
+      if (pipes[i].fds[READ_END] != -1)
+      {
+        int ifd, ifd_orig = pipes[i].fds[READ_END];
+        int orig_errno = errno;
+
+        close(ifd_orig);
+        ifd = open(pipes[i].name, O_RDONLY, 0666);
+        if (ifd < 0)
+#if (DOS_PIPE_DEBUG - 1) == 0
+        {
+          log_pipe_operation(i, "closing write end", "failed to open read end.", pipes + i);
+          log_pipe_dump_used_fd_array(fd_in_use);
+          return -1;
+        }
+#else  /* !DOS_PIPE_DEBUG */
+          return -1;
+#endif /* !DOS_PIPE_DEBUG */
+
+        if (ifd != ifd_orig && ifd_orig > -1)
+        {
+          int ifd_new = dup2(ifd, ifd_orig);
+          close(ifd);
+          if (ifd_new != ifd_orig)
+#if (DOS_PIPE_DEBUG - 1) == 0
+          {
+            log_pipe_operation(i, "closing write end", "failed to dup2 read end to original read fd.", pipes + i);
+            log_pipe_dump_used_fd_array(fd_in_use);
+            return -1;
+          }
+#else  /* !DOS_PIPE_DEBUG */
+            return -1;
+#endif /* !DOS_PIPE_DEBUG */
+        }
+#if (DOS_PIPE_DEBUG - 1) == 0
+        log_pipe_operation(i, "closing write end", "OK.", pipes + i);
+        log_pipe_dump_used_fd_array(fd_in_use);
+#endif /* DOS_PIPE_DEBUG */
+        errno = orig_errno;
+        return 0;
+      }
+      break;
+    }
+    else
+    if (IS_CLOSED(fd))
+    {
+      /* both pipe ends closed; pipe file removed.  */
+      int orig_errno = errno;
+#if (DOS_PIPE_DEBUG - 1) == 0
+      if (keep_pipe_files || 0 == remove(pipes[i].name))
+#else  /* !DOS_PIPE_DEBUG */
+      if (0 == remove(pipes[i].name))
+#endif /* !DOS_PIPE_DEBUG */
+      {
+        fd_in_use[pipes[i].fds[READ_END] < -1 ? -1 * pipes[i].fds[READ_END] : pipes[i].fds[READ_END]] = false;
+        fd_in_use[pipes[i].fds[WRITE_END] < -1 ? -1 * pipes[i].fds[WRITE_END] : pipes[i].fds[WRITE_END]] = false;
+        pipes[i].fds[READ_END] = -1;
+        pipes[i].fds[WRITE_END] = -1;
+        pipes[i].fds[BACK_UP] = -1;
+#if (DOS_PIPE_DEBUG - 1) == 0
+        log_pipe_operation(i, "removing", keep_pipe_files ? "pipe file will not be removed." : "\"rpl_close\"" " successfully removed pipe file.", pipes + i);
+        log_pipe_dump_used_fd_array(fd_in_use);
+#endif /* DOS_PIPE_DEBUG */
+        free(pipes[i].name);
+        pipes[i].name = NULL;
+      }
+#if (DOS_PIPE_DEBUG - 1) == 0
+      else
+      {
+        log_pipe_operation(i, "removing", "\"rpl_close\"" " failed to remove pipe file.", pipes + i);
+        log_pipe_dump_used_fd_array(fd_in_use);
+      }
+#endif /* DOS_PIPE_DEBUG */
+      if (!pipes[i].name)
+      {
+        open_pipes--;
+        if (++i == table_size)
+          table_size--;
+      }
+
+      errno = orig_errno;
+      return 0;
+    }
+    else
+    if (SWITCH_MODE(fd))
+    {
+      /* switch from write mode into read mode.  */
+      int ifd, ifd_orig = pipes[i].fds[READ_END];
+      int orig_errno = errno;
+
+      close(ifd_orig);
+      ifd = open(pipes[i].name, O_RDONLY, 0666);
+      if (ifd < 0)
+#if (DOS_PIPE_DEBUG - 1) == 0
+      {
+        log_pipe_operation(i, "switching from write to read mode", "failed to open read end.", pipes + i);
+        log_pipe_dump_used_fd_array(fd_in_use);
+        return -1;
+      }
+#else  /* !DOS_PIPE_DEBUG */
+        return -1;
+#endif /* !DOS_PIPE_DEBUG */
+
+      if (ifd != ifd_orig && ifd_orig > -1)
+      {
+        int ifd_new = dup2(ifd, ifd_orig);
+        close(ifd);
+        if (ifd_new != ifd_orig)
+#if (DOS_PIPE_DEBUG - 1) == 0
+        {
+          log_pipe_operation(i, "switching from write to read mode", "failed to dup2 read end to original read fd.", pipes + i);
+          log_pipe_dump_used_fd_array(fd_in_use);
+          return -1;
+        }
+#else  /* !DOS_PIPE_DEBUG */
+          return -1;
+#endif /* !DOS_PIPE_DEBUG */
+      }
+      pipes[i].fds[BACK_UP] = pipes[i].fds[READ_END];
+      errno = orig_errno;
+
+#if (DOS_PIPE_DEBUG - 1) == 0
+      log_pipe_operation(i, "switching from write to read mode", "OK.", pipes + i);
+      log_pipe_dump_used_fd_array(fd_in_use);
+#endif /* DOS_PIPE_DEBUG */
+      return 0;
+    }
+  }
+
+  return close(fd);
+}
+
+int
+rpl_pipe(int fds[2])
+{
+  int ifd, ofd, i;
+  char *tmpdir;
+  char *filename;
+
+  if (open_pipes >= OPEN_MAX && table_size >= OPEN_MAX)
+  {
+    errno = EMFILE;
+    return -1;
+  }
+
+  tmpdir = "/dev/env/TMPDIR";
+  if (access(tmpdir, D_OK))
+  {
+    tmpdir = "/dev/env/TMP";
+    if (access(tmpdir, D_OK))
+    {
+      tmpdir = "/dev/env/TEMP";
+      if (access(tmpdir, D_OK))
+      {
+        tmpdir = P_tmpdir;
+        if (access(tmpdir, D_OK))
+          tmpdir = ".";
+      }
+    }
+  }
+  filename = malloc(strlen(tmpdir) + sizeof("/spXXXXXX"));
+  if (filename == NULL)
+    return -1;
+  sprintf(filename, "%s/spXXXXXX", tmpdir);
+  filename = mktemp(filename);
+  if (filename == NULL)
+    return -1;
+
+  ofd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+  if (ofd < 0)
+  {
+    free(filename);
+    return -1;
+  }
+  if ((ofd = register_fd(ofd)) < 0)
+  {
+    remove(filename);
+    free(filename);
+    return -1;
+  }
+
+  ifd = open(filename, O_RDONLY, 0666);
+  if (ifd < 0)
+  {
+    free(filename);
+    return -1;
+  }
+  if ((ifd = register_fd(ifd)) < 0)
+  {
+    remove(filename);
+    free(filename);
+    return -1;
+  }
+
+  for (i = 0; i < table_size; i++)
+    if (pipes[i].name == NULL)
+      break;
+  if (i == table_size)
+    table_size++;
+
+  pipes[i].name = filename;
+  pipes[i].fds[BACK_UP] = ofd;
+  fds[0] = pipes[i].fds[READ_END] = ifd;
+  fds[1] = pipes[i].fds[WRITE_END] = ofd;
+  open_pipes++;
+
+#if (DOS_PIPE_DEBUG - 1) == 0
+  log_pipe_creation(i, pipes + i);
+  log_pipe_dump_used_fd_array(fd_in_use);
+#endif /* DOS_PIPE_DEBUG */
+
+  return 0;
+}
+
+static void
+remove_pipe_files(void)
+{
+  int i;
+
+  for (i = 0; i < OPEN_MAX; i++)
+  {
+#if (DOS_PIPE_DEBUG - 1) == 0
+    int rc = 0;
+#endif /* DOS_PIPE_DEBUG */
+    if (pipes[i].name)
+    {
+      int fd = pipes[i].fds[READ_END] < -1 ? -1 * pipes[i].fds[READ_END] : pipes[i].fds[READ_END];
+      if (fd != -1)
+        close(fd);
+      fd = pipes[i].fds[WRITE_END] < -1 ? -1 * pipes[i].fds[WRITE_END] : pipes[i].fds[WRITE_END];
+      if (fd != -1)
+        close(fd);
+#if (DOS_PIPE_DEBUG - 1) == 0
+      if (!keep_pipe_files)
+        rc = remove(pipes[i].name);
+      log_pipe_operation(i, "removing", keep_pipe_files ? "pipe file will not be removed." : rc ? "\"remove_pipe_files\"" " failed to remove pipe file." : "\"remove_pipe_files\"" " successfully removed pipe file.", pipes + i);
+#else  /* !DOS_PIPE_DEBUG */
+      remove(pipes[i].name);
+#endif /* !DOS_PIPE_DEBUG */
+    }
+  }
+#if (DOS_PIPE_DEBUG - 1) == 0
+  close_log_pipe_files();
+#endif /* DOS_PIPE_DEBUG */
+}
+
+/* This is called before `main' to install the temporary file deleter at exit.  */
+static void __attribute__((constructor))
+djgpp_bash_startup (void)
+{
+  /* Initialize FD table.  */
+  int i;
+  for (i = 0; i < 20; i++)
+    fd_in_use[i] = true;  /* Verboten.  */
+  for (; i < OPEN_MAX; i++)
+    fd_in_use[i] = false;
+
+#if (DOS_PIPE_DEBUG - 1) == 0
+  create_log_pipe_files();
+#endif /* DOS_PIPE_DEBUG */
+
+  /* Clean disk from temporary files.  */
+  atexit(remove_pipe_files);
+}
+
+#endif /* __DJGPP__ */
diff -aprNU5 bash-4.4.orig/dospipe.h bash-4.4/dospipe.h
--- bash-4.4.orig/dospipe.h	1970-01-01 00:00:00 +0000
+++ bash-4.4/dospipe.h	2023-03-04 20:54:00 +0000
@@ -0,0 +1,25 @@
+#ifndef DOS_PIPE_SUPPORT
+#define DOS_PIPE_SUPPORT
+
+/* Always use DJGPP's implementations of these functions.
+   In a sequence of headers, this header must be included as last! */
+
+
+#if (DOS_PIPE_DEBUG - 1) == 0
+extern char *bash_script_command_line;
+extern const char *bash_script_name;
+extern int bash_script_line_number;
+#endif /* DOS_PIPE_DEBUG */
+
+
+void remove_pipe(int fd);
+
+#undef  close
+#define close rpl_close
+int rpl_close(int fd);
+
+#undef  pipe
+#define pipe rpl_pipe
+int rpl_pipe(int fds[2]);
+
+#endif /* DOS_PIPE_SUPPORT */
diff -aprNU5 bash-4.4.orig/dospipe_internal.h bash-4.4/dospipe_internal.h
--- bash-4.4.orig/dospipe_internal.h	1970-01-01 00:00:00 +0000
+++ bash-4.4/dospipe_internal.h	2023-03-04 20:54:00 +0000
@@ -0,0 +1,33 @@
+#ifndef DOS_PIPE_INTERNAL
+#define DOS_PIPE_INTERNAL
+
+#if (DOS_PIPE_DEBUG - 1) == 0
+extern bool keep_pipe_files;
+extern bool log_pipe_files;
+extern char *pipe_log_filename;
+
+extern char *pipe_log_buffer;
+extern char *pipe_log_buffer_ptr;
+
+extern char *bash_script_command_line;
+extern char *previous_script_command_line;
+extern char *bash_script_name;
+extern char *previous_script_name;
+extern int bash_script_line_number;
+#endif /* DOS_PIPE_DEBUG */
+
+struct pipe_t
+{
+  int fds[3];
+  char *name;
+};
+
+#define READ_END   0
+#define WRITE_END  1
+#define BACK_UP    2
+
+#if !defined (OPEN_MAX)
+#define OPEN_MAX (256 - 10)  /*  Bash uses the upper FD to open its script.  */
+#endif
+
+#endif /* DOS_PIPE_INTERNAL */
diff -aprNU5 bash-4.4.orig/nofork.c bash-4.4/nofork.c
--- bash-4.4.orig/nofork.c	1970-01-01 00:00:00 +0000
+++ bash-4.4/nofork.c	2023-03-04 20:54:00 +0000
@@ -0,0 +1,345 @@
+#include <config.h>
+
+#if !defined (HAVE_WORKING_FORK)
+
+#include <ctype.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dpmi.h>
+#include <sys/system.h>
+
+#include "nofork.h"
+#include "dospath.h"
+
+#include "command.h"
+#include "general.h"
+#include "error.h"
+#include "variables.h"
+#include "subst.h"
+#include "externs.h"
+#include "builtins/common.h"
+#include "hashcmd.h"
+#include "flags.h"
+#include "bashjmp.h"
+
+#define SAVESTRING(p)  ((p != NULL) ? savestring (p) : NULL)
+#define FREE_AND_CLEAR(p)  (free (p), p = NULL)
+
+#define CURRENT_PID ((pid_t) 1)
+
+pid_t nofork_current_pid = CURRENT_PID;
+int nofork_wait_status = -1;
+OLDENVBUF *current_environment = NULL;
+
+static void
+save_jmp_buf(jmp_buf save, jmp_buf now)
+{
+  memcpy((char *)save, (char *)now, sizeof(jmp_buf));
+}
+
+static void
+restore_jmp_buf(jmp_buf save, jmp_buf now)
+{
+  memcpy((char *)now, (char *)save, sizeof(jmp_buf));
+}
+
+extern jmp_buf top_level, subshell_top_level;
+extern int interactive, interactive_shell, login_shell;
+extern int subshell_environment;
+extern int subshell_exit_builtin, exit_immediately_on_error;
+extern int dollar_dollar_pid;
+extern int array_needs_making;
+extern SHELL_VAR *ifs_var;
+
+static void
+save_current_directory (OLDENVBUF *envp)
+{
+  envp->pwd    = SAVESTRING (get_string_value ("PWD"));
+  envp->curdir = getcwd (NULL, PATH_MAX);
+}
+
+static void
+restore_current_directory(OLDENVBUF *envp)
+{
+  /* change old directory */
+  if (envp->curdir != NULL)
+  {
+    chdir(envp->curdir);
+    if (envp->pwd != NULL)
+      set_working_directory(envp->pwd);
+    else
+      set_working_directory(envp->curdir);
+    FREE_AND_CLEAR (envp->curdir);
+  }
+  else if (envp->pwd != NULL)
+  {
+    chdir(envp->pwd);
+    set_working_directory(envp->pwd);
+  }
+
+  if (envp->pwd)
+    FREE_AND_CLEAR(envp->pwd);
+}
+
+extern WORD_LIST *subst_assign_varlist;
+
+static void
+save_global_variables(OLDENVBUF *envp)
+{
+  envp->interactive               = interactive;
+  envp->interactive_shell         = interactive_shell;
+  envp->login_shell               = login_shell;
+  envp->subshell_environment      = subshell_environment;
+  envp->subshell_exit_builtin     = subshell_exit_builtin;
+  envp->exit_immediately_on_error = exit_immediately_on_error;
+  envp->variable_context          = variable_context;
+  envp->dollar_dollar_pid         = dollar_dollar_pid;
+  envp->subst_assign_varlist      = subst_assign_varlist;
+  envp->echo_command_at_execute   = echo_command_at_execute;
+  subst_assign_varlist = NULL;
+}
+
+static void
+restore_global_variables(OLDENVBUF *envp)
+{
+  interactive               = envp->interactive;
+  interactive_shell         = envp->interactive_shell;
+  login_shell               = envp->login_shell;
+  subshell_environment      = envp->subshell_environment;
+  subshell_exit_builtin     = envp->subshell_exit_builtin;
+  exit_immediately_on_error = envp->exit_immediately_on_error;
+  variable_context          = envp->variable_context;
+  dollar_dollar_pid         = envp->dollar_dollar_pid;
+  subst_assign_varlist      = envp->subst_assign_varlist;
+  echo_command_at_execute   = envp->echo_command_at_execute;
+}
+
+
+static VAR_CONTEXT *
+copy_var_context(VAR_CONTEXT *fvc)
+{
+  VAR_CONTEXT *vc;
+
+  vc = (VAR_CONTEXT *)xmalloc(sizeof(VAR_CONTEXT));
+  vc->name = fvc->name ? savestring(fvc->name) : (char *)NULL;
+  vc->scope = fvc->scope;
+  vc->flags = fvc->flags & ~(VC_COPYONCHANGE);
+
+  vc->table = hash_copy(fvc->table, (sh_string_func_t *)copy_variable);
+  vc->up = vc->down = (VAR_CONTEXT *)NULL;
+
+  return vc;
+}
+
+static void
+save_all_var_contexts(OLDENVBUF *envp)
+{
+  VAR_CONTEXT *vc;
+  VAR_CONTEXT *vc_copy, *sv, *vc_copy_prev;
+
+  vc = shell_variables;
+  sv = vc_copy = copy_var_context(vc);
+
+  while (vc->down)
+  {
+    vc_copy_prev = vc_copy;
+    vc = vc->down;
+    vc_copy = copy_var_context(vc);
+    vc_copy_prev->down = vc_copy;
+    vc_copy->up = vc_copy_prev;
+  }
+
+#if NOFORK_COPY_ON_CHANGE
+  envp->global_variables = vc_copy;
+  envp->shell_variables = sv;
+#else
+  envp->shell_variables = shell_variables;
+  envp->global_variables = global_variables;
+  shell_variables = sv;
+  global_variables = vc_copy;
+#endif
+}
+
+static void
+restore_all_var_contexts(OLDENVBUF *envp)
+{
+  delete_all_contexts(shell_variables);
+  dispose_var_context(global_variables);
+
+  global_variables = envp->global_variables;
+  shell_variables = envp->shell_variables;
+  delete_all_variables(shell_functions);
+  hash_dispose(shell_functions);
+  shell_functions = envp->shell_functions;
+}
+
+void
+copy_var_contexts_on_change(void)
+{
+  if (current_environment == NULL)
+    return;
+
+  save_all_var_contexts(current_environment);
+  global_variables->flags &= ~(VC_COPYONCHANGE);
+}
+
+
+static void
+save_shell_variables(OLDENVBUF *envp)
+{
+#if NOFORK_COPY_ON_CHANGE
+  SHELL_VAR *lastarg_var;
+#endif
+
+  maybe_make_export_env();
+
+  envp->global_variables = NULL;
+  envp->shell_variables = NULL;
+  global_variables->flags |= VC_COPYONCHANGE;
+
+#if NOFORK_COPY_ON_CHANGE || 1
+  /* Must be copied to be restored later because the shell variables
+     may be modified by the subshell call. */
+  save_all_var_contexts(envp);
+#endif
+
+  envp->shell_functions = shell_functions;
+  shell_functions = hash_copy(envp->shell_functions, (sh_string_func_t *)copy_variable);
+
+  envp->temporary_env = temporary_env;
+  if (temporary_env)
+    temporary_env = hash_copy(envp->temporary_env, (sh_string_func_t *)copy_variable);
+
+#if NOFORK_COPY_ON_CHANGE
+  lastarg_var = find_variable("_");
+  if (lastarg_var)
+    envp->lastarg = savestring(value_cell(lastarg_var));
+#endif
+
+  envp->rest_of_args = list_rest_of_args();
+}
+
+static void
+restore_shell_variables(OLDENVBUF *envp)
+{
+  SHELL_VAR *temp_ifs;
+
+  if (envp->global_variables)
+    restore_all_var_contexts(envp);
+  else
+    global_variables->flags &= ~(VC_COPYONCHANGE);
+
+  if (temporary_env)
+  {
+    delete_all_variables(temporary_env);
+    hash_dispose(temporary_env);
+  }
+  temporary_env = envp->temporary_env;
+
+  temp_ifs = find_variable("IFS");
+  setifs(temp_ifs);
+
+#if NOFORK_COPY_ON_CHANGE
+  bind_variable("_", envp->lastarg);
+  free(envp->lastarg);
+#endif
+
+  remember_args(envp->rest_of_args, 1);
+
+  array_needs_making = 1;
+  maybe_make_export_env();
+}
+
+extern int return_catch_flag;
+
+int
+nofork_save_all_environment(OLDENVBUF *envp)
+{
+  save_jmp_buf(envp->return_catch, return_catch);
+  envp->return_catch_flag = return_catch_flag;
+  save_jmp_buf(envp->top_level, top_level);
+  save_jmp_buf(envp->subshell_top_level, subshell_top_level);
+  nofork_save_std_fds(envp->fds);
+  save_current_directory(envp);
+  save_global_variables(envp);
+  save_shell_variables(envp);
+
+  envp->prev_environment = current_environment;
+  current_environment = envp;
+
+  return 0;
+}
+
+int
+nofork_restore_all_environment(OLDENVBUF *envp)
+{
+  restore_shell_variables(envp);
+  restore_global_variables(envp);
+  restore_current_directory(envp);
+  nofork_restore_std_fds(envp->fds);
+  restore_jmp_buf(envp->top_level, top_level);
+  restore_jmp_buf(envp->subshell_top_level, subshell_top_level);
+
+  restore_jmp_buf(envp->return_catch, return_catch);
+  return_catch_flag = envp->return_catch_flag;
+
+  current_environment = envp->prev_environment;
+
+  return 0;
+}
+
+#include <sys/param.h>
+#if !defined (MAXPID)
+#define MAXPID ((pid_t) 30000)
+#endif
+
+static pid_t last_pid = CURRENT_PID;
+
+pid_t
+nofork_make_child_pid(void)
+{
+  if (++last_pid > MAXPID)
+    last_pid = CURRENT_PID + 1;
+
+  return last_pid;
+}
+
+void
+nofork_save_std_fds(int fds[3])
+{
+  int i;
+
+  /* save stdin/out/err */
+  for (i = 0; i < 3; i++)
+#if defined (F_DUPFD)
+    if ((fds[i] = fcntl(i, F_DUPFD, 20)) < 0)
+#else
+    if ((fds[i] = dup(i)) < 0)
+#endif
+      internal_error("Cannot duplicate fd %d: %s", i, strerror(errno));
+}
+
+void
+nofork_restore_std_fds(int fds[3])
+{
+  int i;
+
+  /* restore stdin/out/err */
+  for (i = 0; i < 3; i++)
+    if (fds[i] >= 0)
+    {
+      if (dup2(fds[i], i) < 0)
+        internal_error("cannot duplicate fd %d to fd %d: %s", fds[i], i, strerror(errno));
+      close (fds[i]);
+      fds[i] = -1;
+    }
+}
+
+#endif /* !HAVE_WORKING_FORK */
diff -aprNU5 bash-4.4.orig/nofork.h bash-4.4/nofork.h
--- bash-4.4.orig/nofork.h	1970-01-01 00:00:00 +0000
+++ bash-4.4/nofork.h	2023-03-04 20:54:00 +0000
@@ -0,0 +1,83 @@
+#ifndef BASH_NOFORK_H
+#define BASH_NOFORK_H
+
+#define NOFORK_COPY_ON_CHANGE 0
+
+#include <setjmp.h>
+
+#include "command.h"
+#include "general.h"
+#include "hashlib.h"
+#include "variables.h"
+#include "stdc.h"
+
+typedef struct oldenvbuf
+{
+  int fds[3];
+
+  jmp_buf top_level;
+  jmp_buf subshell_top_level;
+
+  int return_catch_flag;
+  jmp_buf return_catch;
+
+  VAR_CONTEXT *global_variables;
+  VAR_CONTEXT *shell_variables;
+  HASH_TABLE *shell_functions;
+
+  HASH_TABLE *temporary_env;
+  char **non_unsettable_vars;
+
+  char *dollar_vars[10];
+  WORD_LIST *rest_of_args;
+
+  char *pwd;
+  char *oldpwd;
+  char *curdir;
+
+  int interactive;
+  int interactive_shell;
+  int login_shell;
+  int subshell_environment;
+  int subshell_exit_builtin;
+  int exit_immediately_on_error;
+  int variable_context;
+  int dollar_dollar_pid;
+  WORD_LIST *subst_assign_varlist;
+  int echo_command_at_execute;
+
+  SHELL_VAR *ifs_var;
+  char *ifs_value;
+
+  char *lastarg;
+
+  struct oldenvbuf *prev_environment;
+} OLDENVBUF;
+
+typedef struct
+{
+  char *trap_val;
+  int signal_mode;
+} TRAPBUF;
+
+extern int subshell_exit_value;
+extern int subshell_exit_builtin;
+extern int subshell_skip_commands;
+extern int nofork_wait_status;
+extern pid_t nofork_current_pid;
+
+pid_t nofork_make_child_pid __P ((void));
+void nofork_save_std_fds __P ((int fds[3]));
+void nofork_restore_std_fds __P ((int fds[3]));
+int nofork_save_all_environment __P ((OLDENVBUF *));
+int nofork_restore_all_environment __P ((OLDENVBUF *));
+void save_trap __P ((TRAPBUF *));
+void restore_trap __P ((TRAPBUF *));
+void copy_var_contexts_on_change(void);
+
+int get_signal_modes __P ((int sig));
+int set_signal_modes __P ((int sig, int modes));
+
+int bash_spawnve __P ((char *path, char **args, char **envp));
+
+#endif /* BASH_NOFORK_H */



#######################################################################



2023-03-04  Juan Manuel Guerrero <juan.guerrero@gmx.de>


	* builtins/cd.def: DJGPP specific stuff.

	* builtins/common.c: DJGPP specific stuff.

	* builtins/evalstring.c: DJGPP specific stuff.

	* builtins/exec.def: DJGPP specific stuff.

	* builtins/exit.def: DJGPP specific stuff.

	* builtins/psize.c: DJGPP specific stuff.

	* builtins/shopt.def: DJGPP specific stuff.






diff -aprNU5 bash-4.4.orig/builtins/cd.def bash-4.4/builtins/cd.def
--- bash-4.4.orig/builtins/cd.def	2016-05-11 19:21:46 +0000
+++ bash-4.4/builtins/cd.def	2023-03-04 21:11:36 +0000
@@ -48,10 +48,14 @@ $PRODUCES cd.c
 #include "../flags.h"
 #include "maxpath.h"
 #include "common.h"
 #include "bashgetopt.h"
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#endif /* __DJGPP__ */
+
 #if !defined (errno)
 extern int errno;
 #endif /* !errno */
 
 extern int posixly_correct;
@@ -355,13 +359,20 @@ cd_builtin (list)
     }
   else if (absolute_pathname (list->word->word))
     dirname = list->word->word;
   else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
     {
+#if defined (__DJGPP__)
+      char cur_path_separator = path_separator;
+#endif /* __DJGPP__ */
       dirname = list->word->word;
 
       /* Find directory in $CDPATH. */
+#if defined (__DJGPP__)
+      /* CDPATH is not affected by PATH_SEPARATOR.  */
+      path_separator=':';
+#endif /* __DJGPP__ */
       path_index = 0;
       while (path = extract_colon_unit (cdpath, &path_index))
 	{
 	  /* OPT is 1 if the path element is non-empty */
 	  opt = path[0] != '\0';
@@ -381,17 +392,23 @@ cd_builtin (list)
 #if 0
 	      /* Posix.2 says that after using CDPATH, the resultant
 		 value of $PWD will not contain `.' or `..'. */
 	      return (bindpwd (posixly_correct || no_symlinks));
 #else
+#if defined (__DJGPP__)
+	      path_separator = cur_path_separator;
+#endif /* __DJGPP__ */
 	      return (bindpwd (no_symlinks));
 #endif
 	    }
 	  else
 	    free (temp);
 	}
 
+#if defined (__DJGPP__)
+        path_separator = cur_path_separator;
+#endif /* __DJGPP__ */
 #if 0
       /* changed for bash-4.2 Posix cd description steps 5-6 */
       /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
 	 try the current directory, so we just punt now with an error
 	 message if POSIXLY_CORRECT is non-zero.  The check for cdpath[0]
@@ -612,10 +629,28 @@ change_to_directory (newdir, nolinks, xa
 	  errno = err;
 	  return (0);		/* no xattr */
 	}
     }
   else
+#else
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (tdir && tdir[1] == ':' && !ISDIRSEP(tdir[2]))
+    {
+      /* Relative path on another drive. Attempt to chdir to it and
+         retrieve its current directory.  */
+      r = chdir (nolinks ? newdir : tdir);
+      if (r == 0)
+        {
+          FREE (the_current_working_directory);
+          the_current_working_directory = (char *)NULL;
+          tdir = get_working_directory ("cd");
+          FREE (tdir);
+          return (1);
+        }
+    }
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+  else
 #endif
     {
       r = chdir (nolinks ? newdir : tdir);
       if (r >= 0)
 	resetxattr ();
diff -aprNU5 bash-4.4.orig/builtins/common.c bash-4.4/builtins/common.c
--- bash-4.4.orig/builtins/common.c	2016-01-25 18:29:16 +0000
+++ bash-4.4/builtins/common.c	2023-03-04 20:59:02 +0000
@@ -61,10 +61,17 @@
 
 #if defined (HISTORY)
 #  include "../bashhist.h"
 #endif
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+   /* Must be redefined after externs.h have been included!  */
+#  undef getcwd
+#  define getcwd dospath_getcwd
+#endif
+
 #if !defined (errno)
 extern int errno;   
 #endif /* !errno */
 
 extern int indirection_level, subshell_environment;
diff -aprNU5 bash-4.4.orig/builtins/evalstring.c bash-4.4/builtins/evalstring.c
--- bash-4.4.orig/builtins/evalstring.c	2023-03-04 20:52:12 +0000
+++ bash-4.4/builtins/evalstring.c	2023-03-04 21:11:36 +0000
@@ -148,11 +148,18 @@ parse_prologue (string, flags, tag)
      char *tag;
 {
   char *orig_string, *lastcom;
   int x;
 
+#if !defined (HAVE_WORKING_FORK)
+  /* The duplicate the string so it can be added to the
+     unwind_protect_list and later be freed without having
+     to care in the calling context.  */
+  orig_string = savestring (string);
+#else  /* HAVE_WORKING_FORK */
   orig_string = string;
+#endif /* HAVE_WORKING_FORK */
   /* Unwind protect this invocation of parse_and_execute (). */
   begin_unwind_frame (tag);
   unwind_protect_int (parse_and_execute_level);
   unwind_protect_jmp_buf (top_level);
   unwind_protect_int (indirection_level);
diff -aprNU5 bash-4.4.orig/builtins/exec.def bash-4.4/builtins/exec.def
--- bash-4.4.orig/builtins/exec.def	2016-01-25 18:31:02 +0000
+++ bash-4.4/builtins/exec.def	2023-03-04 20:59:02 +0000
@@ -76,10 +76,14 @@ extern int errno;
 
 extern int subshell_environment;
 extern REDIRECT *redirection_undo_list;
 extern char *exec_argv0;
 
+#if !defined (HAVE_WORKING_FORK)
+extern int subshell_exit_builtin;
+#endif /* !HAVE_WORKING_FORK */
+
 int no_exit_on_failed_exec;
 
 /* If the user wants this to look like a login shell, then
    prepend a `-' onto NAME and return the new name. */
 static char *
@@ -143,12 +147,21 @@ exec_builtin (list)
 #endif /* RESTRICTED_SHELL */
 
   args = strvec_from_word_list (list, 1, 0, (int *)NULL);
   env = (char **)0;
 
+#if !defined (__DJGPP__)
   /* A command with a slash anywhere in its name is not looked up in $PATH. */
   command = absolute_program (args[0]) ? args[0] : search_for_command (args[0], 1);
+#else  /* __DJGPP__ */
+  command = search_for_command (args[0], 1);
+  if (command)
+    {
+      free (args[0]);
+      args[0] = strdup (command);
+    }
+#endif /* __DJGPP__ */
 
   if (command == 0)
     {
       if (file_isdir (args[0]))
 	{
@@ -217,11 +230,28 @@ exec_builtin (list)
     end_job_control ();
   if (interactive || job_control)
     default_tty_job_signals ();		/* undo initialize_job_signals */
 #endif /* JOB_CONTROL */
 
+#if defined (HAVE_WORKING_FORK)
   exit_value = shell_execve (command, args, env);
+#else  /* !HAVE_WORKING_FORK */
+  if (!subshell_exit_builtin)
+    {
+      exit_value = shell_execve (command, args, env);
+      if (exit_value >= 0)
+	  exit (exit_value);
+      exit_value = EXECUTION_FAILURE;
+    }
+  else
+    {
+      exit_value = shell_execve (command, args, env);
+      if (cleanenv == 0)
+	  adjust_shell_level (1);
+      goto failed_exec;
+    }
+#endif /* !HAVE_WORKING_FORK */
 
   /* We have to set this to NULL because shell_execve has called realloc()
      to stuff more items at the front of the array, which may have caused
      the memory to be freed by realloc().  We don't want to free it twice. */
   args = (char **)NULL;
@@ -239,19 +269,26 @@ exec_builtin (list)
     file_error (command);
 
 failed_exec:
   FREE (command);
 
+#if defined (HAVE_WORKING_FORK)
   if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
     exit_shell (exit_value);
+#endif /* HAVE_WORKING_FORK */
 
   if (args)
     strvec_dispose (args);
 
   if (env && env != export_env)
     strvec_dispose (env);
 
+#if !defined (HAVE_WORKING_FORK)
+  if (!subshell_environment && (interactive == 0 && no_exit_on_failed_exec == 0))
+    exit_shell (exit_value);
+#endif /* !HAVE_WORKING_FORK */
+
   initialize_traps ();
   initialize_signals (1);
 
 #if defined (JOB_CONTROL)
   if (interactive_shell || job_control)
diff -aprNU5 bash-4.4.orig/builtins/exit.def bash-4.4/builtins/exit.def
--- bash-4.4.orig/builtins/exit.def	2014-09-07 21:54:02 +0000
+++ bash-4.4/builtins/exit.def	2023-03-04 20:59:02 +0000
@@ -51,10 +51,16 @@ extern int last_command_exit_value;
 extern int running_trap, trap_saved_exit_value;
 extern int subshell_environment;
 extern sh_builtin_func_t *this_shell_builtin;
 extern sh_builtin_func_t *last_shell_builtin;
 
+#if !defined (HAVE_WORKING_FORK)
+int subshell_exit_value = 0;
+int subshell_exit_builtin = 0;
+int subshell_skip_commands = 0;
+#endif /* !HAVE_WORKING_FORK */
+
 static int exit_or_logout __P((WORD_LIST *));
 static int sourced_logout;
 
 int
 exit_builtin (list)
@@ -152,20 +158,33 @@ exit_or_logout (list)
   bash_logout ();
 
   last_command_exit_value = exit_value;
 
   /* Exit the program. */
+#if !defined (HAVE_WORKING_FORK)
+  if (subshell_exit_builtin)
+    {
+      subshell_exit_value = exit_value;
+      subshell_exit_builtin = 0;
+      subshell_skip_commands = 1;
+      return (EXECUTION_SUCCESS);
+    }
+#endif /* !HAVE_WORKING_FORK */
   jump_to_top_level (EXITPROG);
   /*NOTREACHED*/
 }
 
 void
 bash_logout ()
 {
   /* Run our `~/.bash_logout' file if it exists, and this is a login shell. */
   if (login_shell && sourced_logout++ == 0 && subshell_environment == 0)
     {
+#if defined (__MSDOS__)
+      if (maybe_execute_file ("~/_blogout", 1) == 0)
+        if (pathconf (NULL, _PC_NAME_MAX) > 12)
+#endif /* __MSDOS__ */
       maybe_execute_file ("~/.bash_logout", 1);
 #ifdef SYS_BASH_LOGOUT
       maybe_execute_file (SYS_BASH_LOGOUT, 1);
 #endif
     }
diff -aprNU5 bash-4.4.orig/builtins/psize.c bash-4.4/builtins/psize.c
--- bash-4.4.orig/builtins/psize.c	2008-08-14 19:56:52 +0000
+++ bash-4.4/builtins/psize.c	2023-03-04 20:59:02 +0000
@@ -28,10 +28,14 @@
 #    include <sys/types.h>
 #  endif
 #  include <unistd.h>
 #endif
 
+#if defined (HAVE_LIMITS_H)
+#  include <limits.h>
+#endif
+
 #include <stdio.h>
 #ifndef _MINIX
 #include "../bashtypes.h"
 #endif
 #include <signal.h>
@@ -58,10 +62,15 @@ sigpipe (sig)
 int
 main (argc, argv)
      int argc;
      char **argv;
 {
+#if defined (PIPE_BUF)
+  /* If the POSIX standard PIPE_BUF is defined, just report its value.  */
+  sigpipe (PIPE_BUF);
+#else  /* !PIPE_BUF */
+#error PIPE_BUF not defined
   char buf[128];
   register int i;
 
   for (i = 0; i < 128; i++)
     buf[i] = ' ';
@@ -73,7 +82,8 @@ main (argc, argv)
     {
       int n;
       n = write (1, buf, 128);
       nw += n;
     }
+#endif /* !PIPE_BUF */
   return (0);
 }
diff -aprNU5 bash-4.4.orig/builtins/shopt.def bash-4.4/builtins/shopt.def
--- bash-4.4.orig/builtins/shopt.def	2016-05-06 19:00:02 +0000
+++ bash-4.4/builtins/shopt.def	2023-03-04 21:11:36 +0000
@@ -579,11 +579,15 @@ shopt_set_debug_mode (option_name, mode)
 static int
 shopt_enable_hostname_completion (option_name, mode)
      char *option_name;
      int mode;
 {
+#if defined (READLINE)
   return (enable_hostname_completion (mode));
+#else
+  return 0;
+#endif
 }
 
 static int
 set_compatibility_level (option_name, mode)
      char *option_name;



#######################################################################



2023-03-04  Juan Manuel Guerrero <juan.guerrero@gmx.de>


	* lib/glob/glob.c: DJGPP specific stuff.

	* lib/malloc/imalloc.h: DJGPP specific stuff.

	* lib/malloc/malloc.c: DJGPP specific stuff.

	* lib/malloc/stats.c: DJGPP specific stuff.

	* lib/malloc/trace.c: DJGPP specific stuff.

	* lib/readline/bind.c: DJGPP specific stuff.

	* lib/readline/chardefs.h: DJGPP specific stuff.

	* lib/readline/colors.c: DJGPP specific stuff.

	* lib/readline/complete.c: DJGPP specific stuff.

	* lib/readline/display.c: DJGPP specific stuff.

	* lib/readline/funmap.c: DJGPP specific stuff.

	* lib/readline/histfile.c: DJGPP specific stuff.

	* lib/readline/kill.c: DJGPP specific stuff.

	* lib/readline/readline.c: DJGPP specific stuff.

	* lib/readline/readline.h: DJGPP specific stuff.

	* lib/readline/signals.c: DJGPP specific stuff.

	* lib/readline/tcap.h: DJGPP specific stuff.

	* lib/readline/terminal.c: DJGPP specific stuff.

	* lib/readline/tminit.c: New file that is part of the DJGPP port.

	* lib/sh/getcwd.c: DJGPP specific stuff.

	* lib/sh/netopen.c: DJGPP specific stuff.

	* lib/sh/pathcanon.c: DJGPP specific stuff.

	* lib/sh/pathphys.c: DJGPP specific stuff.

	* lib/sh/tmpfile.c: DJGPP specific stuff.

	* lib/sh/zread.c: DJGPP specific stuff.

	* lib/termcap/termcap.c: DJGPP specific stuff.

	* lib/termcap/tparam.c: DJGPP specific stuff.

	* lib/tilde/tilde.c: DJGPP specific stuff.






diff -aprNU5 bash-4.4.orig/lib/glob/glob.c bash-4.4/lib/glob/glob.c
--- bash-4.4.orig/lib/glob/glob.c	2016-08-11 14:15:28 +0000
+++ bash-4.4/lib/glob/glob.c	2023-03-04 21:41:38 +0000
@@ -581,10 +581,13 @@ glob_vector (pat, dir, flags)
   int mflags;		/* Flags passed to strmatch (). */
   int pflags;		/* flags passed to sh_makepath () */
   int nalloca;
   struct globval *firstmalloc, *tmplink;
   char *convfn;
+#if defined (__DJGPP__)
+  int use_lfn = (pathconf (NULL, _PC_NAME_MAX) > 12);
+#endif /* __DJGPP__ */
 
   lastlink = 0;
   count = lose = skip = add_current = 0;
 
   firstmalloc = 0;
@@ -692,10 +695,30 @@ glob_vector (pat, dir, flags)
       /* Compute the flags that will be passed to strmatch().  We don't
 	 need to do this every time through the loop. */
       mflags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
 
 #ifdef FNM_CASEFOLD
+#if defined (__DJGPP__)
+      /* DJGPP's globbing does not ignore case
+         when in an LFN environment and either FNCASE=Y
+         or an uppercase letter is in the pattern. */
+
+      glob_ignore_case = !(use_lfn && (_preserve_fncase() != 0));
+      if (glob_ignore_case && use_lfn)
+        {
+          char *cur_pat = pat;
+          char ch;
+          while ((ch = *cur_pat++))
+            {
+              if ((ch >= 'A') && (ch <= 'Z'))
+                {
+                  glob_ignore_case = 0;
+                  break;
+                }
+            }
+        }
+#endif /* __DJGPP__ */
       if (glob_ignore_case)
 	mflags |= FNM_CASEFOLD;
 #endif
 
       if (extended_glob)
@@ -707,10 +730,13 @@ glob_vector (pat, dir, flags)
 	 For each name that matches, allocate a struct globval
 	 on the stack and store the name in it.
 	 Chain those structs together; lastlink is the front of the chain.  */
       while (1)
 	{
+#if defined (__DJGPP__)
+	  char short_name[13];
+#endif /* __DJGPP__ */
 	  /* Make globbing interruptible in the shell. */
 	  if (interrupt_state || terminating_signal)
 	    {
 	      lose = 1;
 	      break;
@@ -737,10 +763,28 @@ glob_vector (pat, dir, flags)
 #if HANDLE_MULTIBYTE
 	  if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name, flags))
 	    continue;
 	  else
 #endif
+#if defined (__DJGPP__)
+         /* Downcase if the short name and long name are equal and
+            case is being ignored.  */
+
+         if (glob_ignore_case
+             && (strcmp(dp->d_name, _lfn_gen_short_fname (dp->d_name, short_name)) == 0)
+             )
+           {
+             /* Downcase when the SFN matches the LFN */
+             int i;
+             char c;
+             for (i = 0; dp->d_name[i]; i++)
+               {
+                 c = dp->d_name[i];
+                 dp->d_name[i] = ((c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c);
+               }
+           }
+#endif /* __DJGPP__ */
 	  if (skipname (pat, dp->d_name, flags))
 	    continue;
 
 	  /* If we're only interested in directories, don't bother with files */
 	  if (flags & (GX_MATCHDIRS|GX_ALLDIRS))
@@ -957,11 +1001,15 @@ glob_dir_to_array (dir, array, flags)
 	      }
 	  }
       return (array);
     }
 
+#if defined (HAVE_DOS_STYLE_FILE_SYSTEM)
+  add_slash = dir[l - 1] != '/' && dir[l - 1] != ':';
+#else  /* !HAVE_DOS_STYLE_FILE_SYSTEM */
   add_slash = dir[l - 1] != '/';
+#endif /* !HAVE_DOS_STYLE_FILE_SYSTEM */
 
   i = 0;
   while (array[i] != NULL)
     ++i;
 
@@ -1045,10 +1093,15 @@ glob_filename (pathname, flags)
 	fprintf (stderr, "glob_filename: glob_dirscan: fn (%s) != filename (%s)\n", fn ? fn : "(null)", filename);
 #endif
       filename = fn;
     }
 #endif
+#if defined (HAVE_DOS_STYLE_FILE_SYSTEM)
+  /* Skip drive name.  */
+  if (filename == NULL && isalpha (pathname[0]) && pathname[1] == ':')
+    filename = pathname + 1;
+#endif /* HAVE_DOS_STYLE_FILE_SYSTEM */
 
   if (filename == NULL)
     {
       filename = pathname;
       directory_name = "";
@@ -1336,13 +1389,19 @@ only_filename:
 	     dlen == 0 */
 #endif
 	  if (directory_len == 0 && (flags & GX_ALLDIRS) == 0)
 	    dflags &= ~GX_ADDCURDIR;
 	}
+#if defined (__DJGPP__)
+      __opendir_flags = __OPENDIR_PRESERVE_CASE;
+#endif /* __DJGPP__ */
       temp_results = glob_vector (filename,
 				  (directory_len == 0 ? "." : directory_name),
 				  dflags);
+#if defined (__DJGPP__)
+      __opendir_flags = 0;
+#endif /* __DJGPP__ */
 
       if (temp_results == NULL || temp_results == (char **)&glob_error_return)
 	{
 	  if (free_dirname)
 	    free (directory_name);
diff -aprNU5 bash-4.4.orig/lib/malloc/imalloc.h bash-4.4/lib/malloc/imalloc.h
--- bash-4.4.orig/lib/malloc/imalloc.h	2012-11-16 02:11:54 +0000
+++ bash-4.4/lib/malloc/imalloc.h	2023-03-04 21:41:38 +0000
@@ -118,11 +118,11 @@ do { 								\
 } while (0)
 
 #define MALLOC_MEMSET(charp, xch, nbytes)				\
 do {									\
   if ((nbytes) <= 32) {							\
-    register char * mzp = (charp);					\
+    register unsigned char *mzp = (charp);				\
     unsigned long mctmp = (nbytes);					\
     register long mcn;							\
     if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp &= 7; }	\
     switch (mctmp) {							\
       case 0: for(;;) { *mzp++ = xch;					\
diff -aprNU5 bash-4.4.orig/lib/malloc/malloc.c bash-4.4/lib/malloc/malloc.c
--- bash-4.4.orig/lib/malloc/malloc.c	2015-07-28 18:25:54 +0000
+++ bash-4.4/lib/malloc/malloc.c	2023-03-04 21:41:38 +0000
@@ -213,10 +213,14 @@ typedef union _malloc_guard {
 
 /* Use this when we want to be sure that NB is in bucket NU. */
 #define RIGHT_BUCKET(nb, nu) \
 	(((nb) > binsizes[(nu)-1]) && ((nb) <= binsizes[(nu)]))
 
+#ifndef SIGCHLD
+#define SIGCHLD SIGINT
+#endif
+
 /* nextf[i] is free list of blocks of size 2**(i + 3)  */
 
 static union mhead *nextf[NBUCKETS];
 
 /* busy[i] is nonzero while allocation or free of block size i is in progress. */
@@ -811,11 +815,11 @@ internal_malloc (n, file, line, flags)
   m = (char *) (p + 1) + n;
   *m++ = *z++, *m++ = *z++, *m++ = *z++, *m++ = *z++;
 
 #ifdef MEMSCRAMBLE
   if (n)
-    MALLOC_MEMSET ((char *)(p + 1), 0xdf, n);	/* scramble previous contents */
+    MALLOC_MEMSET ((unsigned char *)(p + 1), 0xdf, n);	/* scramble previous contents */
 #endif
 #ifdef MALLOC_STATS
   _mstats.nmalloc[nunits]++;
   _mstats.tmalloc[nunits]++;
   _mstats.nmal++;
diff -aprNU5 bash-4.4.orig/lib/malloc/stats.c bash-4.4/lib/malloc/stats.c
--- bash-4.4.orig/lib/malloc/stats.c	2016-01-15 13:47:06 +0000
+++ bash-4.4/lib/malloc/stats.c	2023-03-04 21:41:38 +0000
@@ -132,11 +132,17 @@ fprint_malloc_stats (s, fp)
      FILE *fp;
 {
   _print_malloc_stats (s, fp);
 }
 
-#define TRACEROOT "/var/tmp/maltrace/stats."
+#ifndef TRACEROOT
+#  ifdef __DJGPP__
+#    define TRACEROOT "/dev/env/TMPDIR/trace."
+#  else
+#    define TRACEROOT "/var/tmp/maltrace/trace."
+#  endif
+#endif /* !TRACEROOT */
 
 void
 trace_malloc_stats (s, fn)
      char *s, *fn;
 {
diff -aprNU5 bash-4.4.orig/lib/malloc/trace.c bash-4.4/lib/malloc/trace.c
--- bash-4.4.orig/lib/malloc/trace.c	2016-01-15 13:48:22 +0000
+++ bash-4.4/lib/malloc/trace.c	2023-03-04 21:24:44 +0000
@@ -106,11 +106,17 @@ malloc_trace_bin (n)
 #ifdef MALLOC_TRACE
   _malloc_trace_buckets[n] = 1;
 #endif
 }
 
-#define TRACEROOT "/var/tmp/maltrace/trace."
+#ifndef TRACEROOT
+# ifdef __DJGPP__
+#  define TRACEROOT "/dev/env/TMPDIR/trace."
+# else
+#  define TRACEROOT "/var/tmp/maltrace/trace."
+# endif
+#endif /* !TRACEROOT */
 
 void
 malloc_set_tracefn (s, fn)
      char *s;
      char *fn;
diff -aprNU5 bash-4.4.orig/lib/readline/bind.c bash-4.4/lib/readline/bind.c
--- bash-4.4.orig/lib/readline/bind.c	2016-07-27 15:15:30 +0000
+++ bash-4.4/lib/readline/bind.c	2023-03-04 21:41:38 +0000
@@ -67,10 +67,24 @@ extern int errno;
 
 #if !defined (strchr) && !defined (__STDC__)
 extern char *strchr (), *strrchr ();
 #endif /* !strchr && !__STDC__ */
 
+/* DJGPP allows to detect at runtime if the used file system provides (LFN)
+   long file name support or not.  If LFN support is available then first look
+   for ".inputrc".  If a file with that file name does not exists try "_inputrc".
+   If only SFN is available then only try "_inputrc" as init file name.  */
+#if defined (__MSDOS__)
+#  if defined (__DJGPP__)
+#    define HAVE_LFN_SUPPORT(name)  ((pathconf((name), _PC_NAME_MAX) > 12) ? 1 : 0)
+#    undef  SYS_INPUTRC
+#    define SYS_INPUTRC             "/dev/env/DJDIR/etc/inputrc"
+#  else  /* !__DJGPP__ */
+#    define HAVE_LFN_SUPPORT(name)  (0)
+#  endif /* !__DJGPP__ */
+#endif /* !__MSDOS__ */
+
 /* Variables exported by this file. */
 Keymap rl_binding_keymap;
 
 static int _rl_skip_to_delim PARAMS((char *, int, int));
 
@@ -918,10 +932,13 @@ rl_read_init_file (filename)
     }
 
 #if defined (__MSDOS__)
   if (_rl_read_init_file (filename, 0) == 0)
     return 0;
+  filename = HAVE_LFN_SUPPORT(".inputrc") ? "~/.inputrc" : "~/_inputrc";
+  if (_rl_read_init_file (filename, 0) == 0)
+    return 0;
   filename = "~/_inputrc";
 #endif
   return (_rl_read_init_file (filename, 0));
 }
 
diff -aprNU5 bash-4.4.orig/lib/readline/chardefs.h bash-4.4/lib/readline/chardefs.h
--- bash-4.4.orig/lib/readline/chardefs.h	2016-01-25 15:37:46 +0000
+++ bash-4.4/lib/readline/chardefs.h	2023-03-04 21:41:38 +0000
@@ -53,11 +53,11 @@
 #define control_character_threshold 0x020   /* Smaller than this is control. */
 #define control_character_mask 0x1f	    /* 0x20 - 1 */
 #define meta_character_threshold 0x07f	    /* Larger than this is Meta. */
 #define control_character_bit 0x40	    /* 0x000000, must be off. */
 #define meta_character_bit 0x080	    /* x0000000, must be on. */
-#define largest_char 255		    /* Largest character value. */
+#define largest_char 0xFF		    /* Largest character value. */
 
 #define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0))
 #define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char)
 
 #define CTRL(c) ((c) & control_character_mask)
diff -aprNU5 bash-4.4.orig/lib/readline/colors.c bash-4.4/lib/readline/colors.c
--- bash-4.4.orig/lib/readline/colors.c	2016-01-25 15:38:00 +0000
+++ bash-4.4/lib/readline/colors.c	2023-03-04 21:24:44 +0000
@@ -213,12 +213,14 @@ _rl_print_color_indicator (const char *f
         }
       else if (S_ISLNK (mode))
         colored_filetype = C_LINK;
       else if (S_ISFIFO (mode))
         colored_filetype = C_FIFO;
+#if defined (S_ISSOCK)
       else if (S_ISSOCK (mode))
         colored_filetype = C_SOCK;
+#endif
       else if (S_ISBLK (mode))
         colored_filetype = C_BLK;
       else if (S_ISCHR (mode))
         colored_filetype = C_CHR;
       else
diff -aprNU5 bash-4.4.orig/lib/readline/complete.c bash-4.4/lib/readline/complete.c
--- bash-4.4.orig/lib/readline/complete.c	2016-04-24 23:39:32 +0000
+++ bash-4.4/lib/readline/complete.c	2023-03-04 21:41:38 +0000
@@ -115,10 +115,16 @@ static int colored_stat_start PARAMS((co
 static void colored_stat_end PARAMS((void));
 static int colored_prefix_start PARAMS((void));
 static void colored_prefix_end PARAMS((void));
 #endif
 
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#  define IS_SLASH(c)  ((c) == '/' || (c) == '\\')
+#else  /* !HAVE_DOS_BASED_FILE_SYSTEM */
+#  define IS_SLASH(c)  ((c) == '/')
+#endif /* !HAVE_DOS_BASED_FILE_SYSTEM */
+
 static int path_isdir PARAMS((const char *));
 
 static char *rl_quote_filename PARAMS((char *, int, char *));
 
 static void _rl_complete_sigcleanup PARAMS((int, void *));
@@ -650,10 +656,12 @@ stat_char (filename)
   else if (S_ISFIFO (finfo.st_mode))
     character = '|';
 #endif
   else if (S_ISREG (finfo.st_mode))
     {
+// JMG: Bin mir nicht mehr sicher.
+//#if (defined (_WIN32) || defined (__DJGPP__)) && !defined (__CYGWIN__)
 #if defined (_WIN32) && !defined (__CYGWIN__)
       char *ext;
 
       /* Windows doesn't do access and X_OK; check file extension instead */
       ext = strrchr (fn, '.');
@@ -717,13 +725,18 @@ printable_part (pathname)
 {
   char *temp, *x;
 
   if (rl_filename_completion_desired == 0)	/* don't need to do anything */
     return (pathname);
+//JMG: bin mir nicht mehr sicher.
+#if 0  //defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  temp = basename(pathname);
+  return temp;
+#endif
 
   temp = strrchr (pathname, '/');
-#if defined (__MSDOS__) || defined (_WIN32)
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
   if (temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':')
     temp = pathname + 1;
 #endif
 
   if (temp == 0 || *temp == '\0')
@@ -735,13 +748,13 @@ printable_part (pathname)
      following that slash.  If there's no previous slash, just return the
      pathname we were passed. */
   else if (temp[1] == '\0')
     {
       for (x = temp - 1; x > pathname; x--)
-        if (*x == '/')
+        if (IS_SLASH(*x))
           break;
-      return ((*x == '/') ? x + 1 : pathname);
+      return (IS_SLASH(*x) ? x + 1 : pathname);
     }
   else
     return ++temp;
 }
 
@@ -805,19 +818,18 @@ fnprint (to_print, prefix_bytes, real_pa
      int prefix_bytes;
      const char *real_pathname;
 {
   int printed_len, w;
   const char *s;
-  int common_prefix_len, print_len;
+  int common_prefix_len, print_len = strlen (to_print);
 #if defined (HANDLE_MULTIBYTE)
   mbstate_t ps;
   const char *end;
   size_t tlen;
   int width;
   wchar_t wc;
 
-  print_len = strlen (to_print);
   end = to_print + print_len + 1;
   memset (&ps, 0, sizeof (mbstate_t));
 #endif
 
   printed_len = common_prefix_len = 0;
@@ -1157,10 +1169,16 @@ _rl_find_completion_word (fp, dp)
 	  scan = rl_line_buffer[rl_point];
 
 	  if (strchr (brkchars, scan) == 0)
 	    continue;
 
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+          /* Ignore colons.  */
+          if (scan == ':' && (rl_completion_entry_function == NULL
+	      || (rl_completion_entry_function == rl_filename_completion_function)))
+	    continue;
+#endif
 	  /* Call the application-specific function to tell us whether
 	     this word break character is quoted and should be skipped. */
 	  if (rl_char_is_quoted_p && found_quote &&
 	      (*rl_char_is_quoted_p) (rl_line_buffer, rl_point))
 	    continue;
@@ -1814,13 +1832,25 @@ make_quoted_replacement (match, mtype, q
   if (should_quote)
     {
       /* If there is a single match, see if we need to quote it.
          This also checks whether the common prefix of several
 	 matches needs to be quoted. */
+#if !defined (HAVE_DOS_BASED_FILE_SYSTEM)
       should_quote = rl_filename_quote_characters
 			? (_rl_strpbrk (match, rl_filename_quote_characters) != 0)
 			: 0;
+#else  /* HAVE_DOS_BASED_FILE_SYSTEM */
+      /* To get here, the match must be a filename.
+         Do not allow ':' to be quoted in DOS-style filenames,
+         to avoid confusing people.  */
+      char *token = NULL;
+      should_quote = rl_filename_quote_characters
+                      ? ((token = _rl_strpbrk (match, rl_filename_quote_characters)) != 0)
+                      : 0;
+      if (token && *token == ':')
+        should_quote = 0;
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
 
       do_replace = should_quote ? mtype : NO_MATCH;
       /* Quote the replacement, since we found an embedded
 	 word break character in a potential match. */
       if (do_replace != NO_MATCH && rl_filename_quoting_function)
@@ -2505,22 +2535,28 @@ rl_filename_completion_function (text, s
 	text = ".";
       dirname = savestring (text);
 
       temp = strrchr (dirname, '/');
 
-#if defined (__MSDOS__) || defined (_WIN32)
+#if defined (__MSDOS__) && !defined (__DJGPP__) || defined (_WIN32)
       /* special hack for //X/... */
       if (dirname[0] == '/' && dirname[1] == '/' && ISALPHA ((unsigned char)dirname[2]) && dirname[3] == '/')
         temp = strrchr (dirname + 3, '/');
+#elif defined (__DJGPP__)
+      /* special hack for /dev/X/ */
+      if (dirname[0] == '/'
+          && (dirname[1] == 'd') && (dirname[2] == 'e') && (dirname[3] == 'v')
+          && (dirname[4] == '/') && dirname[5]          && (dirname[6] == '/'))
+        temp = strrchr (dirname + 6, '/'); 
 #endif
 
       if (temp)
 	{
 	  strcpy (filename, ++temp);
 	  *temp = '\0';
 	}
-#if defined (__MSDOS__) || (defined (_WIN32) && !defined (__CYGWIN__))
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM) || (defined (_WIN32) && !defined (__CYGWIN__))
       /* searches from current directory on the drive */
       else if (ISALPHA ((unsigned char)dirname[0]) && dirname[1] == ':')
         {
           strcpy (filename, dirname + 2);
           dirname[2] = '\0';
diff -aprNU5 bash-4.4.orig/lib/readline/display.c bash-4.4/lib/readline/display.c
--- bash-4.4.orig/lib/readline/display.c	2023-03-04 21:55:18 +0000
+++ bash-4.4/lib/readline/display.c	2023-03-04 21:41:38 +0000
@@ -1189,11 +1189,11 @@ rl_redisplay ()
 	      _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt)
 #else
 	      _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt)
 #endif
 	    {
-#if defined (__MSDOS__)
+#if !defined (HAVE_TERMCAP_API)
 	      putc ('\r', rl_outstream);
 #else
 	      if (_rl_term_cr)
 		tputs (_rl_term_cr, 1, _rl_output_character_function);
 #endif
@@ -1682,11 +1682,11 @@ update_line (old, new, current_line, oma
   if (current_line == 0 && !_rl_horizontal_scroll_mode &&
       _rl_term_cr && lendiff > prompt_visible_length && _rl_last_c_pos > 0 &&
       (((od > 0 || nd > 0) && (od <= prompt_last_invisible || nd <= prompt_last_invisible)) ||
 		((od >= lendiff) && _rl_last_c_pos < PROMPT_ENDING_INDEX)))
     {
-#if defined (__MSDOS__)
+#if !defined (HAVE_TERMCAP_API)
       putc ('\r', rl_outstream);
 #else
       tputs (_rl_term_cr, 1, _rl_output_character_function);
 #endif
       if (modmark)
@@ -2254,15 +2254,15 @@ _rl_move_cursor_relative (new, data)
 #endif
   i = _rl_last_c_pos - woff;
   if (dpos == 0 || CR_FASTER (dpos, _rl_last_c_pos) ||
       (_rl_term_autowrap && i == _rl_screenwidth))
     {
-#if defined (__MSDOS__)
+#if !defined (HAVE_TERMCAP_API)
       putc ('\r', rl_outstream);
 #else
       tputs (_rl_term_cr, 1, _rl_output_character_function);
-#endif /* !__MSDOS__ */
+#endif
       cpos = _rl_last_c_pos = 0;
     }
 
   if (cpos < dpos)
     {
@@ -2283,18 +2283,22 @@ _rl_move_cursor_relative (new, data)
 	 in the buffer and we have to go back to the beginning of the screen
 	 line.  In this case, we can use the terminal sequence to move forward
 	 if it's available. */
       if (mb_cur_max > 1 && rl_byte_oriented == 0)
 	{
+#if defined (HAVE_TERMCAP_API)
 	  if (_rl_term_forward_char)
 	    {
 	      for (i = cpos; i < dpos; i++)
 	        tputs (_rl_term_forward_char, 1, _rl_output_character_function);
 	    }
 	  else
+#endif
 	    {
+#if defined (HAVE_TERMCAP_API)
 	      tputs (_rl_term_cr, 1, _rl_output_character_function);
+#endif
 	      for (i = 0; i < new; i++)
 		putc (data[i], rl_outstream);
 	    }
 	}
       else
@@ -2326,31 +2330,31 @@ _rl_move_vert (to)
 
   if ((delta = to - _rl_last_v_pos) > 0)
     {
       for (i = 0; i < delta; i++)
 	putc ('\n', rl_outstream);
-#if defined (__MSDOS__)
+#if !defined (HAVE_TERMCAP_API)
       putc ('\r', rl_outstream);
 #else
       tputs (_rl_term_cr, 1, _rl_output_character_function);
 #endif
       _rl_last_c_pos = 0;
     }
   else
     {			/* delta < 0 */
-#ifdef __DJGPP__
+#if !defined (HAVE_TERMCAP_API)
       int row, col;
 
       fflush (rl_outstream);
       ScreenGetCursor (&row, &col);
       ScreenSetCursor (row + delta, col);
       i = -delta;
 #else
       if (_rl_term_up && *_rl_term_up)
 	for (i = 0; i < -delta; i++)
 	  tputs (_rl_term_up, 1, _rl_output_character_function);
-#endif /* !__DJGPP__ */
+#endif
     }
 
   _rl_last_v_pos = to;		/* Now TO is here */
 }
 
@@ -2641,11 +2645,11 @@ _rl_erase_at_end_of_line (l)
    number of character spaces to clear, */
 void
 _rl_clear_to_eol (count)
      int count;
 {
-#ifndef __MSDOS__
+#if defined (HAVE_TERMCAP_API)
   if (_rl_term_clreol)
     tputs (_rl_term_clreol, 1, _rl_output_character_function);
   else
 #endif
     if (count)
@@ -2667,19 +2671,19 @@ space_to_eol (count)
 }
 
 void
 _rl_clear_screen ()
 {
-#ifndef __DJGPP__
+#if defined (HAVE_TERMCAP_API)
   if (_rl_term_clrpag)
     tputs (_rl_term_clrpag, 1, _rl_output_character_function);
   else
     rl_crlf ();
 #else
   ScreenClear ();
   ScreenSetCursor (0, 0);
-#endif /* __DJGPP__ */
+#endif
 }
 
 /* Insert COUNT characters from STRING to the output stream at column COL. */
 static void
 insert_some_chars (string, count, col)
@@ -2695,11 +2699,11 @@ insert_some_chars (string, count, col)
    by itself.  We assume there will either be ei or we don't need to use it. */
 static void
 open_some_spaces (col)
      int col;
 {
-#if !defined (__MSDOS__) && (!defined (__MINGW32__) || defined (NCURSES_VERSION))
+#if defined (HAVE_TERMCAP_API) && (!defined (__MINGW32__) || defined (NCURSES_VERSION))
   char *buffer;
   register int i;
 
   /* If IC is defined, then we do not have to "enter" insert mode. */
   if (_rl_term_IC)
@@ -2724,22 +2728,22 @@ open_some_spaces (col)
       /* If there is a special command for inserting characters, then
 	 use that first to open up the space. */
       for (i = col; i--; )
 	tputs (_rl_term_ic, 1, _rl_output_character_function);
     }
-#endif /* !__MSDOS__ && (!__MINGW32__ || NCURSES_VERSION)*/
+#endif /* HAVE_TERMCAP_API && (!__MINGW32__ || NCURSES_VERSION)*/
 }
 
 /* Delete COUNT characters from the display line. */
 static void
 delete_chars (count)
      int count;
 {
   if (count > _rl_screenwidth)	/* XXX */
     return;
 
-#if !defined (__MSDOS__) && (!defined (__MINGW32__) || defined (NCURSES_VERSION))
+#if defined (HAVE_TERMCAP_API) && (!defined (__MINGW32__) || defined (NCURSES_VERSION))
   if (_rl_term_DC && *_rl_term_DC)
     {
       char *buffer;
       buffer = tgoto (_rl_term_DC, count, count);
       tputs (buffer, count, _rl_output_character_function);
@@ -2748,11 +2752,11 @@ delete_chars (count)
     {
       if (_rl_term_dc && *_rl_term_dc)
 	while (count--)
 	  tputs (_rl_term_dc, 1, _rl_output_character_function);
     }
-#endif /* !__MSDOS__ && (!__MINGW32__ || NCURSES_VERSION)*/
+#endif /* HAVE_TERMCAP_API && (!__MINGW32__ || NCURSES_VERSION)*/
 }
 
 void
 _rl_update_final ()
 {
@@ -2789,11 +2793,11 @@ _rl_update_final ()
 static void
 cr ()
 {
   if (_rl_term_cr)
     {
-#if defined (__MSDOS__)
+#if !defined (HAVE_TERMCAP_API)
       putc ('\r', rl_outstream);
 #else
       tputs (_rl_term_cr, 1, _rl_output_character_function);
 #endif
       _rl_last_c_pos = 0;
@@ -2839,17 +2843,17 @@ _rl_redisplay_after_sigwinch ()
      screen line. */
   if (_rl_term_cr)
     {
       _rl_move_vert (_rl_vis_botlin);
 
-#if defined (__MSDOS__)
+#if !defined (HAVE_TERMCAP_API)
       putc ('\r', rl_outstream);
 #else
       tputs (_rl_term_cr, 1, _rl_output_character_function);
 #endif
       _rl_last_c_pos = 0;
-#if defined (__MSDOS__)
+#if !defined (HAVE_TERMCAP_API)
       space_to_eol (_rl_screenwidth);
       putc ('\r', rl_outstream);
 #else
       if (_rl_term_clreol)
 	tputs (_rl_term_clreol, 1, _rl_output_character_function);
diff -aprNU5 bash-4.4.orig/lib/readline/funmap.c bash-4.4/lib/readline/funmap.c
--- bash-4.4.orig/lib/readline/funmap.c	2016-02-27 22:14:18 +0000
+++ bash-4.4/lib/readline/funmap.c	2023-03-04 21:24:44 +0000
@@ -114,11 +114,11 @@ static const FUNMAP default_funmap[] = {
   { "non-incremental-reverse-search-history", rl_noninc_reverse_search },
   { "non-incremental-forward-search-history-again", rl_noninc_forward_search_again },
   { "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again },
   { "old-menu-complete", rl_old_menu_complete },
   { "overwrite-mode", rl_overwrite_mode },
-#if defined (_WIN32)
+#if defined (__CYGWIN__) || defined (__WIN32__) || defined (__DJGPP__)
   { "paste-from-clipboard", rl_paste_from_clipboard },
 #endif
   { "possible-completions", rl_possible_completions },
   { "previous-history", rl_get_previous_history },
   { "print-last-kbd-macro", rl_print_last_kbd_macro },
diff -aprNU5 bash-4.4.orig/lib/readline/histfile.c bash-4.4/lib/readline/histfile.c
--- bash-4.4.orig/lib/readline/histfile.c	2016-01-25 15:34:02 +0000
+++ bash-4.4/lib/readline/histfile.c	2023-03-04 21:41:38 +0000
@@ -78,21 +78,35 @@
 #  endif
 
 #endif /* HISTORY_USE_MMAP */
 
 /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
-   on win 95/98/nt), we want to open files with O_BINARY mode so that there
-   is no \n -> \r\n conversion performed.  On other systems, we don't want to
-   mess around with O_BINARY at all, so we ensure that it's defined to 0. */
-#if defined (__EMX__) || defined (__CYGWIN__)
+   on win 95/98/nt), or DJGPP (DOS), we want to open files with O_BINARY mode
+   so that there is no \n -> \r\n conversion performed.  On other systems,
+   we don't want to mess around with O_BINARY at all, so we ensure that
+   it's defined to 0. */
+#if defined (__EMX__) || defined (__CYGWIN__) || defined (__DJGPP__)
 #  ifndef O_BINARY
 #    define O_BINARY 0
 #  endif
-#else /* !__EMX__ && !__CYGWIN__ */
+#else /* !__EMX__ && !__CYGWIN__ && !__DJGPP__ */
 #  undef O_BINARY
 #  define O_BINARY 0
-#endif /* !__EMX__ && !__CYGWIN__ */
+#endif /* !__EMX__ && !__DJGPP__ && !__CYGWIN__ */
+
+/* DJGPP allows to detect at runtime if the file system used provides (LFN)
+   long file name support or not.  If LFN support is available then look first
+   for ".history".  If a file with that file name does not exists try "_history".
+   If only SFN support is available then only try "_history" as history file name.  */
+#if defined (__MSDOS__)
+#  if defined (__DJGPP__)
+#    define HAVE_LFN_SUPPORT(name)   ((pathconf((name), _PC_NAME_MAX) > 12) ? 1 : 0)
+#    define FILE_EXISTS(name)        (access((name), F_OK) == 0)
+#  else  /* !__DJGPP__ */
+#    define HAVE_LFN_SUPPORT(name)   (0)
+#  endif /* !__DJGPP__ */
+#endif /* !__MSDOS__ */
 
 #include <errno.h>
 #if !defined (errno)
 extern int errno;
 #endif /* !errno */
@@ -168,11 +182,14 @@ history_filename (filename)
 
   return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
   strcpy (return_val, home);
   return_val[home_len] = '/';
 #if defined (__MSDOS__)
-  strcpy (return_val + home_len + 1, "_history");
+  if (HAVE_LFN_SUPPORT(".history"))
+    strcpy (return_val + home_len + 1, FILE_EXISTS(".history") ? ".history" : "_history");
+  else
+    strcpy (return_val + home_len + 1, "_history");
 #else
   strcpy (return_val + home_len + 1, ".history");
 #endif
 
   return (return_val);
@@ -204,11 +221,11 @@ history_backupfile (filename)
   strcpy (ret, fn);
   ret[len] = '-';
   ret[len+1] = '\0';
   return ret;
 }
-  
+
 static char *
 history_tempfile (filename)
      const char *filename;
 {
   const char *fn;
diff -aprNU5 bash-4.4.orig/lib/readline/kill.c bash-4.4/lib/readline/kill.c
--- bash-4.4.orig/lib/readline/kill.c	2016-01-25 15:38:44 +0000
+++ bash-4.4/lib/readline/kill.c	2023-03-04 21:41:38 +0000
@@ -774,5 +774,78 @@ rl_paste_from_clipboard (count, key)
       CloseClipboard ();
     }
   return (0);
 }
 #endif /* _WIN32 */
+
+/* A special paste command to allow DJGPP users to paste
+   from the Windows clipboard. */
+#if defined (__DJGPP__)
+#  include <dpmi.h>
+#  include <sys/farptr.h>
+#  include <go32.h>
+
+int
+rl_paste_from_clipboard (count, key)
+     int count, key;
+{
+  char *ptr;
+  int len, index;
+  __dpmi_regs r;
+  unsigned long offset;
+  char ch;
+ 
+  /* Open the Windows clipboard.  */
+  r.x.ax = 0x1701;
+  __dpmi_int(0x2f, &r);
+  if (r.x.ax == 0)
+    return 0;
+
+  /* Get the size of the text in the clipboard.  */
+  r.x.ax = 0x1704;
+  r.x.dx = 1; /* Select plain text.  */
+  __dpmi_int(0x2f, &r);
+  len = r.x.ax + 65536 * r.x.dx;
+  if (len == 0)
+    return 0;
+
+  /* Get a pointer to the text.  */
+  r.x.ax = 0x1705;
+  r.x.dx = 1;
+  __dpmi_int(0x2f, &r);
+
+  offset = r.x.bx + 16 * r.x.es;
+  if (offset == 0)
+    return 0;
+
+  _farsetsel(_dos_ds);
+  while ((ch = _farnspeekb(offset++)) != '\0')
+  {
+    if (ch == '\r')
+      break;
+  }
+  len = offset - (r.x.bx + 16 * r.x.es);
+  if (ch == '\r')
+    --len;
+
+  ptr = xmalloc(len + 1);
+  offset = r.x.bx + 16 * r.x.es;
+
+  index = 0;
+  _farsetsel(_dos_ds);
+  while (index < len)
+  {
+    ch = _farnspeekb(offset++);
+    ptr[index++] = ch;
+  }
+  ptr[len] = '\0';
+
+  /* Close the clipboard.  */
+  r.x.ax = 0x1708;
+  __dpmi_int(0x2f, &r);
+
+  rl_insert_text(ptr);
+  free(ptr);
+
+  return 0;
+}
+#endif /* __DJGPP__ */
diff -aprNU5 bash-4.4.orig/lib/readline/readline.c bash-4.4/lib/readline/readline.c
--- bash-4.4.orig/lib/readline/readline.c	2023-03-04 21:55:18 +0000
+++ bash-4.4/lib/readline/readline.c	2023-03-04 21:41:38 +0000
@@ -62,10 +62,15 @@ extern int errno;
 #if defined (__EMX__)
 #  define INCL_DOSPROCESS
 #  include <os2.h>
 #endif /* __EMX__ */
 
+#if defined (__DJGPP__)
+#  include <sys/exceptn.h>
+extern int __libc_termios_enable_function_and_arrow_keys (void);
+#endif /* __DJGPP__ */
+
 /* Some standard library routines. */
 #include "readline.h"
 #include "history.h"
 
 #include "rlprivate.h"
@@ -648,11 +653,11 @@ readline_internal_charloop ()
 
 #if defined (READLINE_CALLBACKS)
 static int
 readline_internal_charloop ()
 {
-  int eof = 1;
+  int eof = -1;
 
   while (rl_done == 0)
     eof = readline_internal_char ();
   return (eof);
 }
@@ -1197,10 +1202,13 @@ readline_initialize_everything ()
   if (rl_terminal_name == 0)
     rl_terminal_name = sh_get_env_value ("TERM");
   _rl_init_terminal_io (rl_terminal_name);
 
   /* Bind tty characters to readline functions. */
+#if defined (__DJGPP__)
+  __libc_termios_enable_function_and_arrow_keys ();
+#endif /* __DJGPP__ */
   readline_default_bindings ();
 
   /* Initialize the function names. */
   rl_initialize_funmap ();
 
@@ -1273,11 +1281,11 @@ bind_arrow_keys_internal (map)
   Keymap xkeymap;
 
   xkeymap = _rl_keymap;
   _rl_keymap = map;
 
-#if defined (__MSDOS__)
+#if defined (__MSDOS__) /* && !defined (__DJGPP__) */
   rl_bind_keyseq_if_unbound ("\033[0A", rl_get_previous_history);
   rl_bind_keyseq_if_unbound ("\033[0B", rl_backward_char);
   rl_bind_keyseq_if_unbound ("\033[0C", rl_forward_char);
   rl_bind_keyseq_if_unbound ("\033[0D", rl_get_next_history);
 #endif
@@ -1429,11 +1437,13 @@ rl_restore_state (sp)
   rl_outstream = sp->outf;
   rl_pending_input = sp->pendingin;
   rl_executing_macro = sp->macro;
 
   rl_catch_signals = sp->catchsigs;
+#ifdef SIGWINCH
   rl_catch_sigwinch = sp->catchsigwinch;
+#endif
 
   rl_completion_entry_function = sp->entryfunc;
   rl_menu_completion_entry_function = sp->menuentryfunc;
   rl_ignore_some_completions_function = sp->ignorefunc;
   rl_attempted_completion_function = sp->attemptfunc;
diff -aprNU5 bash-4.4.orig/lib/readline/readline.h bash-4.4/lib/readline/readline.h
--- bash-4.4.orig/lib/readline/readline.h	2016-07-17 20:17:14 +0000
+++ bash-4.4/lib/readline/readline.h	2023-03-04 21:41:38 +0000
@@ -171,12 +171,12 @@ extern int rl_copy_backward_word PARAMS(
 extern int rl_yank PARAMS((int, int));
 extern int rl_yank_pop PARAMS((int, int));
 extern int rl_yank_nth_arg PARAMS((int, int));
 extern int rl_yank_last_arg PARAMS((int, int));
 extern int rl_bracketed_paste_begin PARAMS((int, int));
-/* Not available unless _WIN32 is defined. */
-#if defined (_WIN32)
+/* Not available unless _WIN32 or __DJGPP__ is defined. */
+#if defined (_WIN32) || defined (__DJGPP__)
 extern int rl_paste_from_clipboard PARAMS((int, int));
 #endif
 
 /* Bindable commands for incremental searching. */
 extern int rl_reverse_search_history PARAMS((int, int));
diff -aprNU5 bash-4.4.orig/lib/readline/signals.c bash-4.4/lib/readline/signals.c
--- bash-4.4.orig/lib/readline/signals.c	2016-08-26 12:28:50 +0000
+++ bash-4.4/lib/readline/signals.c	2023-03-04 21:41:38 +0000
@@ -246,13 +246,15 @@ _rl_handle_signal (sig)
 #endif
       rl_echo_signal_char (sig);
       rl_cleanup_after_signal ();
 
 #if defined (HAVE_POSIX_SIGNALS)
+#  if defined (SIGTSTP)
       /* Unblock SIGTTOU blocked above */
       if (sig == SIGTTIN || sig == SIGTSTP)
 	sigprocmask (SIG_UNBLOCK, &set, (sigset_t *)NULL);
+#  endif
 
       sigemptyset (&set);
       sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
       sigdelset (&set, sig);
 #else /* !HAVE_POSIX_SIGNALS */
@@ -278,11 +280,11 @@ _rl_handle_signal (sig)
 #  if defined (HAVE_BSD_SIGNALS)
       sigsetmask (omask & ~(sigmask (sig)));
 #  endif /* HAVE_BSD_SIGNALS */
 #endif /* !HAVE_POSIX_SIGNALS */
 
-      rl_reset_after_signal ();      
+      rl_reset_after_signal ();
     }
 
   RL_UNSETSTATE(RL_STATE_SIGHANDLER);
   SIGHANDLER_RETURN;
 }
diff -aprNU5 bash-4.4.orig/lib/readline/tcap.h bash-4.4/lib/readline/tcap.h
--- bash-4.4.orig/lib/readline/tcap.h	2016-01-25 15:36:14 +0000
+++ bash-4.4/lib/readline/tcap.h	2023-03-04 21:41:38 +0000
@@ -24,18 +24,34 @@
 
 #if defined (HAVE_CONFIG_H)
 #  include "config.h"
 #endif
 
+#if !defined (__MSDOS__)
+#  define HAVE_TERMCAP_API
+#else  /* __MSDOS__ */
+/* On MS-DOS, no termcap is needed/available. */
+#  undef HAVE_TERMCAP_API
+
+#  if defined (__DJGPP__)
+/* When not standalone (as in using Bash),
+   the termcap API is always available.  */
+#    if defined (HAVE_PDCURSES_TERMCAP_API) && !defined (RL_LIBRARY_VERSION)
+#      define HAVE_TERMCAP_API
+#    endif
+#  endif
+#endif
+
 #if defined (HAVE_TERMCAP_H)
 #  if defined (__linux__) && !defined (SPEED_T_IN_SYS_TYPES)
 #    include "rltty.h"
 #  endif
 #  include <termcap.h>
 #elif defined (HAVE_NCURSES_TERMCAP_H)
 #  include <ncurses/termcap.h>
 #else
+#  if defined (HAVE_TERMCAP_API)
 
 /* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
    Unfortunately, PC is a global variable used by the termcap library. */
 #ifdef PC
 #  undef PC
@@ -52,9 +68,10 @@ extern int tgetnum ();
 extern char *tgetstr ();
 
 extern int tputs ();
 
 extern char *tgoto ();
+#  endif /* HAVE_TERMCAP_API */
 
 #endif /* HAVE_TERMCAP_H */
 
 #endif /* !_RLTCAP_H_ */
diff -aprNU5 bash-4.4.orig/lib/readline/terminal.c bash-4.4/lib/readline/terminal.c
--- bash-4.4.orig/lib/readline/terminal.c	2016-01-25 15:36:20 +0000
+++ bash-4.4/lib/readline/terminal.c	2023-03-04 21:41:38 +0000
@@ -49,14 +49,10 @@
 #include <stdio.h>
 
 /* System-specific feature definitions and include files. */
 #include "rldefs.h"
 
-#ifdef __MSDOS__
-#  include <pc.h>
-#endif
-
 #include "rltty.h"
 #if defined (HAVE_SYS_IOCTL_H)
 #  include <sys/ioctl.h>		/* include for declaration of ioctl */
 #endif
 #include "tcap.h"
@@ -67,10 +63,17 @@
 
 #include "rlprivate.h"
 #include "rlshell.h"
 #include "xmalloc.h"
 
+#if defined (__MSDOS__)
+#  include <pc.h>
+#  include <conio.h>
+
+static void _dos_get_screensize PARAMS((int *, int *));
+#endif
+
 #if defined (__MINGW32__)
 #  include <windows.h>
 #  include <wincon.h>
 
 static void _win_get_screensize PARAMS((int *, int *));
@@ -220,10 +223,25 @@ _win_get_screensize (swp, shp)
 	}
     }
 }
 #endif
 
+#if defined (__MSDOS__)
+static void
+_dos_get_screensize (swp, shp)
+     int *swp, *shp;
+{
+  struct text_info screen_info;
+  gettextinfo (&screen_info);
+  *swp = (int)screen_info.screenwidth;
+  *shp = (int)screen_info.screenheight;
+}
+#  ifdef __DJGPP__
+#    undef gettextinfo
+#  endif
+#endif
+
 /* Get readline's idea of the screen size.  TTY is a file descriptor open
    to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
    values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
    non-null serve to check whether or not we have initialized termcap. */
 void
@@ -245,10 +263,12 @@ _rl_get_screen_size (tty, ignore_env)
     }
 #endif /* TIOCGWINSZ */
 
 #if defined (__EMX__)
   _emx_get_screensize (&wc, &wr);
+#elif defined (__MSDOS__)
+  _dos_get_screensize (&wc, &wr);
 #elif defined (__MINGW32__)
   _win_get_screensize (&wc, &wr);
 #endif
 
   if (ignore_env || rl_prefer_env_winsize == 0)
@@ -268,11 +288,11 @@ _rl_get_screen_size (tty, ignore_env)
 	_rl_screenwidth = atoi (ss);
 
       if (_rl_screenwidth <= 0)
         _rl_screenwidth = wc;
 
-#if defined (__DJGPP__)
+#if !defined (HAVE_TERMCAP_API)
       if (_rl_screenwidth <= 0)
 	_rl_screenwidth = ScreenCols ();
 #else
       if (_rl_screenwidth <= 0 && term_string_buffer)
 	_rl_screenwidth = tgetnum ("co");
@@ -287,11 +307,11 @@ _rl_get_screen_size (tty, ignore_env)
 	_rl_screenheight = atoi (ss);
 
       if (_rl_screenheight <= 0)
         _rl_screenheight = wr;
 
-#if defined (__DJGPP__)
+#if !defined (HAVE_TERMCAP_API)
       if (_rl_screenheight <= 0)
 	_rl_screenheight = ScreenRows ();
 #else
       if (_rl_screenheight <= 0 && term_string_buffer)
 	_rl_screenheight = tgetnum ("li");
@@ -363,11 +383,11 @@ rl_reset_screen_size ()
 void
 _rl_sigwinch_resize_terminal ()
 {
   _rl_get_screen_size (fileno (rl_instream), 1);
 }
-	
+
 void
 rl_resize_terminal ()
 {
   _rl_get_screen_size (fileno (rl_instream), 1);
   if (_rl_echoing_p)
@@ -425,11 +445,11 @@ static const struct _tc_string tc_string
    are described in the TC_STRINGS table. */
 static void
 get_term_capabilities (bp)
      char **bp;
 {
-#if !defined (__DJGPP__)	/* XXX - doesn't DJGPP have a termcap library? */
+#if defined (HAVE_TERMCAP_API)	/* XXX - doesn't DJGPP have a termcap library? */
   register int i;
 
   for (i = 0; i < NUM_TC_STRINGS; i++)
     *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp);
 #endif
@@ -449,11 +469,11 @@ _rl_init_terminal_io (terminal_name)
   tty = rl_instream ? fileno (rl_instream) : 0;
 
   if (term == 0)
     term = "dumb";
 
-#ifdef __MSDOS__
+#if defined (__MSDOS__)
   _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
   _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
   _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
   _rl_term_mm = _rl_term_mo = (char *)NULL;
   _rl_terminal_can_insert = term_has_meta = _rl_term_autowrap = 0;
@@ -501,10 +521,13 @@ _rl_init_terminal_io (terminal_name)
       if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
 	{
 #if defined (__EMX__)
 	  _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
 	  _rl_screenwidth--;
+#elif defined (__MSDOS__)
+	  _dos_get_screensize (&_rl_screenwidth, &_rl_screenheight);
+	  _rl_screenwidth--;
 #else /* !__EMX__ */
 	  _rl_get_screen_size (tty, 0);
 #endif /* !__EMX__ */
 	}
 
@@ -663,11 +686,11 @@ int
 _rl_backspace (count)
      int count;
 {
   register int i;
 
-#ifndef __MSDOS__
+#if defined (HAVE_TERMCAP_API)
   if (_rl_term_backspace)
     for (i = 0; i < count; i++)
       tputs (_rl_term_backspace, 1, _rl_output_character_function);
   else
 #endif
@@ -700,11 +723,11 @@ rl_ding ()
 	default:
 	  break;
 	case VISIBLE_BELL:
 	  if (_rl_visible_bell)
 	    {
-#ifdef __DJGPP__
+#if !defined (HAVE_TERMCAP_API)
 	      ScreenVisualBell ();
 #else
 	      tputs (_rl_visible_bell, 1, _rl_output_character_function);
 #endif
 	      break;
@@ -729,11 +752,11 @@ rl_ding ()
 static int enabled_meta = 0;	/* flag indicating we enabled meta mode */
 
 void
 _rl_enable_meta_key ()
 {
-#if !defined (__DJGPP__)
+#if defined (HAVE_TERMCAP_API)
   if (term_has_meta && _rl_term_mm)
     {
       tputs (_rl_term_mm, 1, _rl_output_character_function);
       enabled_meta = 1;
     }
@@ -741,11 +764,11 @@ _rl_enable_meta_key ()
 }
 
 void
 _rl_disable_meta_key ()
 {
-#if !defined (__DJGPP__)
+#if defined (HAVE_TERMCAP_API)
   if (term_has_meta && _rl_term_mo && enabled_meta)
     {
       tputs (_rl_term_mo, 1, _rl_output_character_function);
       enabled_meta = 0;
     }
@@ -754,11 +777,11 @@ _rl_disable_meta_key ()
 
 void
 _rl_control_keypad (on)
      int on;
 {
-#if !defined (__DJGPP__)
+#if defined (HAVE_TERMCAP_API)
   if (on && _rl_term_ks)
     tputs (_rl_term_ks, 1, _rl_output_character_function);
   else if (!on && _rl_term_ke)
     tputs (_rl_term_ke, 1, _rl_output_character_function);
 #endif
@@ -776,11 +799,11 @@ _rl_control_keypad (on)
    anything if we have both capabilities. */
 void
 _rl_set_cursor (im, force)
      int im, force;
 {
-#ifndef __MSDOS__
+#if defined (HAVE_TERMCAP_API)
   if (_rl_term_ve && _rl_term_vs)
     {
       if (force || im != rl_insert_mode)
 	{
 	  if (im == RL_IM_OVERWRITE)
diff -aprNU5 bash-4.4.orig/lib/readline/tminit.c bash-4.4/lib/readline/tminit.c
--- bash-4.4.orig/lib/readline/tminit.c	1970-01-01 00:00:00 +0000
+++ bash-4.4/lib/readline/tminit.c	2023-03-04 21:41:38 +0000
@@ -0,0 +1,1532 @@
+/*
+ * tminit.c - initializer and main part of termios emulation.
+ *   designed for DJGPP by Daisuke Aoyama <jack@st.rim.or.jp>
+ *   special thanks to Ryo Shimizu
+ */
+
+#if defined (__DJGPP__)
+
+#include <libc/stubs.h>
+#include <conio.h>
+#include <fcntl.h>
+#include <go32.h>
+#include <io.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/farptr.h>
+#include <sys/fsext.h>
+#include <libc/bss.h>
+#include <libc/file.h>
+#include <libc/dosio.h>
+#include <libc/ttyprvt.h>
+#include <sys/version.h>
+
+#if __DJGPP_MINOR__ < 4
+# define _DEV_STDIN  0x0001
+# define _DEV_STDOUT 0x0002
+# define _DEV_NUL    0x0004
+# define _DEV_CLOCK  0x0008
+# define _DEV_RAW    0x0020
+# define _DEV_CDEV   0x0080
+# define _DEV_IOCTRL 0x4000
+#else
+# include <libc/getdinfo.h>
+#endif
+
+#define CPMEOF 0x1a /* Ctrl+Z */
+
+#define _REG_STATUS_CF 0x01
+#define _REG_STATUS_ZF 0x40
+#define _KEY_INS  0x80
+#define _KEY_CAPS 0x40
+#define _KEY_NUM  0x20
+#define _KEY_SCRL 0x10
+#define _KEY_ALT  0x08
+#define _KEY_CTRL 0x04
+#define _KEY_LSFT 0x02
+#define _KEY_RSFT 0x01
+#define _KEYE_SYSRQ 0x80
+#define _KEYE_CAPS  0x40
+#define _KEYE_NUM   0x20
+#define _KEYE_SCRL  0x10
+#define _KEYE_RALT  0x08
+#define _KEYE_RCTRL 0x04
+#define _KEYE_LALT  0x02
+#define _KEYE_LCTRL 0x01
+
+#define CHECKBYTES 32
+
+/* tty buffers */
+unsigned char __libc_tty_queue_buffer[_TTY_QUEUE_SIZE];
+struct tty __libc_tty_internal = TTYDEFAULT;
+struct tty *__libc_tty_p = &__libc_tty_internal;
+struct tty_editline __libc_tty_editline = { 0, { 0 }, { 0 }, };
+
+/* global only in the termios functions */
+int __libc_termios_hook_common_count = -1;
+
+/* static variables */
+static int __libc_use_function_and_arrow_keys = 0;
+static int __libc_has_enhanced_keyboard = 0;
+static int __libc_has_extended_keystroke = 0;
+static unsigned char __libc_extended_keystroke[16] = { 0, };
+static ssize_t __libc_termios_check_bytes = CHECKBYTES;
+
+/* static functions */
+static void __libc_termios_fflushall (void);
+static void __libc_termios_init_direct_functions (void);
+static ssize_t __libc_termios_read (int handle, void *buffer, size_t count, ssize_t *rv);
+static ssize_t __libc_termios_read_cooked_tty (int handle, void *buffer, size_t count);
+static ssize_t __libc_termios_read_raw_tty (int handle, void *buffer, size_t count);
+static ssize_t __libc_termios_write (int handle, const void *buffer, size_t count, ssize_t *rv);
+static ssize_t __libc_termios_write_cooked_tty (int handle, const void *buffer, size_t count);
+static ssize_t __libc_termios_write_raw_tty (int handle, const void *buffer, size_t count);
+static int __libc_termios_fsext (__FSEXT_Fnumber n, int *rv, va_list ap);
+static void __libc_termios_echo_ctrl (unsigned char ch);
+static void __libc_termios_maybe_echo_ctrl (unsigned char ch);
+static void __libc_termios_maybe_echo (unsigned char ch);
+static void __libc_termios_maybe_erase1 (void);
+static void __libc_termios_erase_editline (void);
+static void __libc_termios_kill_editline (void);
+static void __libc_termios_insert_editline (unsigned char ch);
+#if __DJGPP_MINOR__ < 4
+static int __libc_termios_exist_queue (void);
+#endif
+static void __libc_termios_clear_queue (void);
+static int __libc_termios_get_queue (void);
+static int __libc_termios_put_queue (unsigned char ch);
+static void __libc_termios_raise_signal (unsigned char ch, int sig);
+static void __libc_termios_fill_queue (void);
+
+/* direct I/O functions */
+static void __direct_add_keystroke (int c);
+static void __direct_add_keystrokes (char *s);
+static void __direct_check_extened_keystroke_at (int scan);
+/* AT keyboard */
+static int __direct_keysense_at (void);
+static unsigned char __direct_keyinput_at (void);
+static int __direct_ctrlsense_at (void);
+/* AT enhanced keyboard */
+static int __direct_keysense_ate (void);
+static unsigned char __direct_keyinput_ate (void);
+static int __direct_ctrlsense_ate (void);
+/* Output functions */
+static void __direct_output_tab_at (void);
+static void __direct_output_at (unsigned char ch);
+static void __direct_outputns_at (int n, const unsigned char *s);
+static void __direct_outputs_at (const unsigned char *s);
+/* function pointers */
+static int (*__direct_keysense) (void) = __direct_keysense_at;
+static unsigned char (*__direct_keyinput) (void) = __direct_keyinput_at;
+static int (*__direct_ctrlsense) (void) = __direct_ctrlsense_at;
+static void (*__direct_output) (unsigned char ch) = __direct_output_at;
+static void (*__direct_outputns) (int n, const unsigned char *s) = __direct_outputns_at;
+static void (*__direct_outputs) (const unsigned char *s) = __direct_outputs_at;
+
+/******************************************************************************/
+/* initialize function ********************************************************/
+
+static void
+__libc_termios_fflushall(void)
+{
+#if 0 /* don't work on djgpp */
+  fflush(NULL);
+#else
+  _fwalk((void (*) (FILE*)) fflush);
+#endif
+}
+
+static void
+__libc_termios_init_direct_functions(void)
+{
+  __libc_has_enhanced_keyboard = 0;
+  __libc_has_extended_keystroke = 0;
+
+  if (_farpeekb(_dos_ds, 0x496) & 0x10)
+    __libc_has_enhanced_keyboard = 1;
+
+  if (__libc_has_enhanced_keyboard)
+    {
+      __direct_keysense = __direct_keysense_ate;
+      __direct_keyinput = __direct_keyinput_ate;
+      __direct_ctrlsense = __direct_ctrlsense_ate;
+    }
+  else
+    {
+      __direct_keysense = __direct_keysense_at;
+      __direct_keyinput = __direct_keyinput_at;
+      __direct_ctrlsense = __direct_ctrlsense_at;
+    }
+  __direct_output = __direct_output_at;
+  __direct_outputs = __direct_outputs_at;
+}
+
+void
+__libc_termios_init(void)
+{
+  if (__libc_termios_hook_common_count != __bss_count)
+    {
+      __libc_termios_hook_common_count = __bss_count;
+
+      /* flush all buffered streams */
+      __libc_termios_fflushall();
+
+      /* check enhanced keyboard, etc */
+      __libc_termios_init_direct_functions();
+
+      /* set special hooks */
+      __libc_read_termios_hook = __libc_termios_read;
+      __libc_write_termios_hook = __libc_termios_write;
+
+      /* import parameters */
+      /* __libc_tty_p = ...; */
+
+      /* fsext */
+      (void) __FSEXT_set_function(0, __libc_termios_fsext);
+      (void) __FSEXT_set_function(1, __libc_termios_fsext);
+      (void) __FSEXT_set_function(2, __libc_termios_fsext);
+      __libc_termios_check_bytes = CHECKBYTES;
+    }
+}
+
+int
+__libc_termios_disable_function_and_arrow_keys(void)
+{
+  int old_value;
+
+  old_value = __libc_use_function_and_arrow_keys;
+  __libc_use_function_and_arrow_keys = 0;
+
+  return old_value;
+}
+
+int
+__libc_termios_enable_function_and_arrow_keys(void)
+{
+  int old_value;
+
+  old_value = __libc_use_function_and_arrow_keys;
+  __libc_use_function_and_arrow_keys = 1;
+
+  return old_value;
+}
+
+/******************************************************************************/
+/* direct I/O function ********************************************************/
+
+/* function key trans function */
+static void
+__direct_add_keystroke(int c)
+{
+  if (__libc_has_extended_keystroke + 1 > sizeof (__libc_extended_keystroke))
+    return;
+
+  __libc_extended_keystroke[__libc_has_extended_keystroke++] = (unsigned char) c;
+}
+
+static void
+__direct_add_keystrokes(char *s)
+{
+  int len;
+
+  len = strlen(s);
+  if (__libc_has_extended_keystroke + len > sizeof (__libc_extended_keystroke))
+    return;
+
+  while (--len >= 0)
+    __libc_extended_keystroke[__libc_has_extended_keystroke++] = (unsigned char) s[len];
+}
+
+#define _NDUMMY (0xffU)
+#define _N(c) (0x00U|(c)) /* no shift */
+#define _S(c) (0x40U|(c)) /* w/shift */
+#define _C(c) (0x80U|(c)) /* w/ctrl */
+#define _A(c) (0xc0U|(c)) /* w/alt */
+#define _TRANS_NOSHIFT "\x1b[0"
+#define _TRANS_SHIFT "\x1b[1"
+#define _TRANS_CTRL "\x1b[2"
+#define _TRANS_ALT "\x1b[3"
+
+static unsigned char trans_alphabet_chars[64] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
+
+static unsigned char trans_mapping_chars_at[] =
+{
+  /* 000-037: A-Z, 040-077: XA-XZ */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 00-07 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 08-0F */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 10-17 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 18-1F */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 20-27 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 28-2F */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 30-37 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _N(040), _N(041), _N(042), _N(043), _N(044), /* 38-3F */
+  _N(045), _N(046), _N(047), _N(050), _N(051), _NDUMMY, _NDUMMY, _N(006), /* 40-47 */
+  _N(000), _N(010), _NDUMMY, _N(001), _NDUMMY, _N(002), _NDUMMY, _N(007), /* 48-4F */
+  _N(003), _N(011), _N(004), _N(005), _S(040), _S(041), _S(042), _S(043), /* 50-57 */
+  _S(044), _S(045), _S(046), _S(047), _S(050), _S(051), _C(040), _C(041), /* 58-5F */
+  _C(042), _C(043), _C(044), _C(045), _C(046), _C(047), _C(050), _C(051), /* 60-67 */
+  _A(040), _A(041), _A(042), _A(043), _A(044), _A(045), _A(046), _A(047), /* 68-6F */
+  _A(050), _A(051), _NDUMMY, _C(001), _C(002), _C(007), _C(011), _C(006), /* 70-77 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 78-7F */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _C(010), _N(052), _N(053), _S(052), /* 80-87 */
+  _S(053), _C(052), _C(053), _A(052), _A(053), _C(000), _NDUMMY, _NDUMMY, /* 88-8F */
+  _NDUMMY, _C(003), _C(004), _C(005), _NDUMMY, _NDUMMY, _NDUMMY, _A(006), /* 90-97 */
+  _A(000), _A(010), _NDUMMY, _A(001), _NDUMMY, _A(002), _NDUMMY, _A(007), /* 98-9F */
+  _A(003), _A(011), _A(004), _A(005), _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* A0-A7 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* A8-AF */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* B0-B7 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* B8-BF */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* C0-C7 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* C8-CF */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* D0-D7 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* D8-DF */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* E0-E7 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* E8-EF */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* F0-F7 */
+  _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* F8-FF */
+};
+
+static void
+__direct_check_extened_keystroke_at(int scan)
+{
+  int c, shift;
+
+  if (!__libc_use_function_and_arrow_keys || scan < 0 || scan > 0xff)
+    return;
+
+  c = (int) trans_mapping_chars_at[scan];
+  if (c == (int) _NDUMMY)
+    return;
+
+  shift = c & 0xc0;
+  c &= ~0xc0;
+  __direct_add_keystroke(trans_alphabet_chars[c]);
+  if (c >= 040)
+    __direct_add_keystroke ('X');
+  if (shift == 0x00)
+    __direct_add_keystrokes(_TRANS_NOSHIFT);
+  else if (shift == 0x40)
+    __direct_add_keystrokes(_TRANS_SHIFT);
+  else if (shift == 0x80)
+    __direct_add_keystrokes(_TRANS_CTRL);
+  else if (shift == 0xc0)
+    __direct_add_keystrokes(_TRANS_ALT);
+}
+
+/* Input form AT keyboard */
+static int
+__direct_keysense_at (void)
+{
+  __dpmi_regs r;
+
+  if (__libc_has_extended_keystroke)
+    return 1;
+
+  r.h.ah = 0x01;
+  __dpmi_int(0x16, &r);
+  if (r.x.flags & _REG_STATUS_ZF)
+    return 0;
+
+  return 1;
+}
+
+static unsigned char
+__direct_keyinput_at(void)
+{
+  __dpmi_regs r;
+
+  if (__libc_has_extended_keystroke)
+    return __libc_extended_keystroke[--__libc_has_extended_keystroke];
+
+  r.h.ah = 0x00;
+  __dpmi_int (0x16, &r);
+  if (r.h.al != 0x00)
+    return r.h.al;
+
+  __direct_check_extened_keystroke_at(r.h.ah);
+  if (__libc_has_extended_keystroke)
+    return __libc_extended_keystroke[--__libc_has_extended_keystroke];
+
+  return 0;
+}
+
+static int
+__direct_ctrlsense_at(void)
+{
+  __dpmi_regs r;
+
+  if (__libc_has_extended_keystroke)
+    return 0;
+
+  r.h.ah = 0x02;
+  __dpmi_int (0x16, &r);
+  if (r.h.al & _KEY_CTRL)
+    return 1;
+
+  return 0;
+}
+
+/* Input from AT enhanced keyboard */
+static int
+__direct_keysense_ate(void)
+{
+  __dpmi_regs r;
+
+  if (__libc_has_extended_keystroke)
+    return 1;
+
+  r.h.ah = 0x11;
+  __dpmi_int (0x16, &r);
+  if (r.x.flags & _REG_STATUS_ZF)
+    return 0;
+
+  return 1;
+}
+
+static unsigned char
+__direct_keyinput_ate (void)
+{
+  __dpmi_regs r;
+
+  if (__libc_has_extended_keystroke)
+    return __libc_extended_keystroke[--__libc_has_extended_keystroke];
+
+  r.h.ah = 0x10;
+  __dpmi_int (0x16, &r);
+  if (r.h.al != 0x00 && (r.h.al < 0xe0U
+			 || (r.h.al != 0xe0 && r.h.al != 0xf0)))
+    return r.h.al;
+
+  __direct_check_extened_keystroke_at(r.h.ah);
+  if (__libc_has_extended_keystroke)
+    return __libc_extended_keystroke[--__libc_has_extended_keystroke];
+
+  return 0;
+}
+
+static int
+__direct_ctrlsense_ate(void)
+{
+  __dpmi_regs r;
+
+  if (__libc_has_extended_keystroke)
+    return 0;
+
+  r.h.ah = 0x12;
+  __dpmi_int(0x16, &r);
+  if (r.h.al & _KEY_CTRL) /* either CTRL */
+    return 1;
+
+  return 0;
+}
+
+/* output to Screen */
+static void
+__direct_output_tab_at (void)
+{
+  __dpmi_regs r;
+  int page, col;
+  int x, y;
+
+  page = _farpeekb(_dos_ds, 0x462);
+  col = _farpeekw(_dos_ds, 0x44a);
+
+  r.h.ah = 3;
+  r.h.bh = page;
+  __dpmi_int(0x10, &r);
+  x = r.h.dl;
+  y = r.h.dh;
+
+  x += 8;
+  x &= ~7;
+  if (x > col)
+    {
+#if 1
+      r.h.al = '\r';
+      __dpmi_int(0x29, &r);
+      r.h.al = '\n';
+      __dpmi_int(0x29, &r);
+#else
+      (void) putch ('\r');
+      (void) putch ('\n');
+#endif
+    }
+  else
+    {
+      r.h.ah = 2;
+      r.h.bh = page;
+      r.h.dl = x;
+      r.h.dh = y;
+      __dpmi_int(0x10, &r);
+    }
+}
+
+static void
+__direct_output_at(unsigned char ch)
+{
+#if 1
+  __dpmi_regs r;
+#endif
+
+  if (ch == 0x09)
+    {
+      __direct_output_tab_at();
+      return;
+    }
+  else if (ch == 0xff)
+    return;
+
+#if 1
+  r.h.al = ch;
+  __dpmi_int(0x29, &r);
+#else
+  (void) putch(ch);
+#endif
+}
+
+static void
+__direct_outputns_at(int n, const unsigned char *s)
+{
+#if 1
+  __dpmi_regs r;
+#endif
+  unsigned char ch;
+
+  while (--n >= 0)
+    {
+      ch = *s++;
+      if (ch == 0x09)
+	__direct_output_tab_at();
+      else if (ch != 0xff)
+	{
+#if 1
+	  r.h.al = ch;
+	  __dpmi_int(0x29, &r);
+#else
+	  (void) putch(ch);
+#endif
+	}
+    }
+}
+
+static void
+__direct_outputs_at(const unsigned char *s)
+{
+  while (*s)
+    __direct_output_at(*s++);
+}
+
+/******************************************************************************/
+/* special read function ******************************************************/
+
+static ssize_t
+__libc_termios_read (int handle, void *buffer, size_t count, ssize_t *rv)
+{
+  short devmod;
+  ssize_t bytes;
+
+  /* check handle whether valid or not */
+  devmod = _get_dev_info (handle);
+  if (devmod == -1)
+    {
+      *rv = -1;
+      return 1;
+    }
+
+  /* special case */
+  if (count == 0)
+    {
+      *rv = 0;
+      return 1;
+    }
+
+  /* console only... */
+  if ((devmod & _DEV_CDEV) && (devmod & (_DEV_STDIN|_DEV_STDOUT)))
+    {
+      /* character device */
+      if (devmod & _DEV_RAW)
+	*rv = __libc_termios_read_raw_tty (handle, buffer, count);
+      else
+	*rv = __libc_termios_read_cooked_tty (handle, buffer, count);
+      return 1;
+    }
+
+  if (__file_handle_modes[handle] & O_BINARY)
+    {
+      bytes = _read (handle, buffer, count);
+      if (bytes < 0)
+	{
+	  *rv = -1;
+	  return 1;
+	}
+    }
+  else
+    {
+      unsigned char *rp, *wp;
+      ssize_t n;
+
+      bytes = _read (handle, buffer, count);
+      if (bytes < 0)
+	{
+	  *rv = -1;
+	  return 1;
+	}
+
+      rp = wp = buffer;
+      n = bytes;
+      while (--n >= 0)
+	{
+	  unsigned char ch;
+
+	  ch = *rp++;
+	  if (ch == CPMEOF)
+	    {
+	      ++n;
+	      (void) lseek (handle, -n, SEEK_CUR);
+	      break;
+	    }
+	  else if (ch == '\r')
+	    {
+	      if (n > 0)
+		{
+		  /* peek next character */
+		  if (*rp == '\n')
+		    {
+		      /* if found '\n', delete '\r' */
+		      ch = *rp++;
+		      --n;
+		    }
+		}
+	      else
+		{
+		  unsigned char tmpch;
+
+		  /* read a character to peek */
+		  if (_read (handle, &tmpch, 1) == 1)
+		    {
+		      if (tmpch == '\n')
+			ch = tmpch;
+		      else
+			(void) lseek (handle, -1, SEEK_CUR);
+		    }
+		}
+	    }
+	  *wp++ = ch;
+	}
+      bytes = wp - (unsigned char *) buffer;
+    }
+
+  /* result of read() */
+  *rv =  bytes;
+  return 1;
+}
+
+static ssize_t
+__libc_termios_read_cooked_tty (int handle, void *buffer, size_t count)
+{
+  unsigned char *wp;
+  ssize_t n;
+
+  wp = buffer;
+  n = count;
+
+#if 0
+  /* clear cooked queue */
+  if (__libc_termios_exist_queue ())
+    __libc_termios_clear_queue ();
+#endif
+
+  if (__libc_tty_p->t_lflag & ICANON)
+    {
+      /* get inputs (wait for NL or EOT) */
+      if (! __libc_termios_exist_queue ())
+	__libc_termios_fill_queue ();
+
+      while (--n >= 0)
+	{
+	  if (! __libc_termios_exist_queue ())
+	    break;
+
+	  *wp++ = __libc_termios_get_queue ();
+	}
+    }
+  else
+    {
+      /* block until getting inputs */
+      while (! __libc_termios_exist_queue ())
+	{
+	  __dpmi_yield ();
+	  __libc_termios_fill_queue ();
+	}
+
+      while (--n >= 0)
+	{
+	  *wp++ = __libc_termios_get_queue ();
+
+	  if (! __libc_termios_exist_queue ())
+	    {
+	      __libc_termios_fill_queue ();
+	      if (! __libc_termios_exist_queue ())
+		break;
+	    }
+	}
+    }
+
+  return (ssize_t) (wp - (unsigned char *) buffer);
+}
+
+static ssize_t
+__libc_termios_read_raw_tty (int handle, void *buffer, size_t count)
+{
+  unsigned char *wp;
+  unsigned char ch;
+  ssize_t n;
+
+  n = count;
+  wp = buffer;
+
+  /* clear cooked queue */
+  if (__libc_termios_exist_queue ())
+    __libc_termios_clear_queue ();
+
+  /* block until getting inputs */
+  while (! __direct_keysense ())
+    __dpmi_yield ();
+
+  while (--n >= 0)
+    {
+      /* exhaust inputs ? */
+      if (! __direct_keysense ())
+	break;
+
+      /* realy get */
+      ch = __direct_keyinput ();
+
+      /* replace CTRL+SPACE with 0x00 */
+      if (ch == ' ' && __direct_ctrlsense ())
+	ch = '\0';
+
+      /* copy a character into buffer and echo */
+      *wp++ = ch;
+      __libc_termios_maybe_echo (ch);
+    }
+
+  return (ssize_t) (wp - (unsigned char *) buffer);
+}
+
+/******************************************************************************/
+/* special write function *****************************************************/
+
+static unsigned char __libc_termios_write_sbuf_internal[64];
+static unsigned char *__libc_termios_write_sbuf = NULL;
+static size_t __libc_termios_write_sbuflen = 0;
+static int __libc_termios_write_count = -1;
+
+void
+__libc_termios_check_signals (void);
+
+static ssize_t
+__libc_termios_write (int handle, const void *buffer, size_t count, ssize_t *rv)
+{
+  short devmod;
+  ssize_t bytes;
+
+  /* check handle whether valid or not */
+  devmod = _get_dev_info (handle);
+  if (devmod == -1)
+    {
+      *rv = -1;
+      return 1;
+    }
+
+  /* special case */
+  if (count == 0)
+    {
+      *rv = 0;
+      return 1;
+    }
+
+  /* console only... */
+  if ((devmod & _DEV_CDEV) && (devmod & (_DEV_STDIN|_DEV_STDOUT)))
+    {
+      /* character device */
+      if (devmod & _DEV_RAW)
+	*rv = __libc_termios_write_raw_tty (handle, buffer, count);
+      else
+	*rv = __libc_termios_write_cooked_tty (handle, buffer, count);
+      return 1;
+    }
+
+  if (__file_handle_modes[handle] & O_BINARY)
+    {
+      bytes = _write (handle, buffer, count);
+      if (bytes < 0)
+	{
+	  *rv = -1;
+	  return 1;
+	}
+    }
+  else
+    {
+      const unsigned char *rp;
+      unsigned char *tp, *ep;
+      ssize_t n;
+
+      /* initialize local buffer */
+      if (__libc_termios_write_count != __bss_count)
+	{
+	  __libc_termios_write_count = __bss_count;
+	  __libc_termios_write_sbuflen = _go32_info_block.size_of_transfer_buffer;
+	  __libc_termios_write_sbuf = malloc (__libc_termios_write_sbuflen);
+	  if (__libc_termios_write_sbuf == NULL)
+	    {
+	      __libc_termios_write_sbuf = &__libc_termios_write_sbuf_internal[0];
+	      __libc_termios_write_sbuflen = sizeof (__libc_termios_write_sbuf_internal);
+	    }
+	}
+
+      rp = buffer;
+      tp = __libc_termios_write_sbuf;
+      ep = tp + __libc_termios_write_sbuflen;
+      n = count;
+      bytes = 0;
+      while (n >= 0)
+	{
+	  unsigned char *wp;
+	  unsigned char ch;
+	  ssize_t ncr, wbytes;
+
+	  /* fill local buffer */
+	  wp = tp;
+	  ncr = 0;
+	  while ((wp < ep) && (--n >= 0))
+	    {
+	      /* get character */
+	      ch = *rp++;
+
+	      /* LF conversion */
+	      if (ch == '\n')
+		{
+		  if (wp == (ep - 1))
+		    {
+		      n++;
+		      rp--;
+		      break;
+		    }
+		  *wp++ = '\r';
+		  ncr++;
+		}
+
+	      /* put character */
+	      *wp++ = ch;
+	    }
+
+	  /* write on handle */
+	  wbytes = _write (handle, tp, (size_t) (wp - tp));
+	  if (wbytes < 0)
+	    {
+	      *rv = -1;
+	      return 1;
+	    }
+	  if (wbytes < (ssize_t) (wp - tp))
+	    {
+	      /* detected disk full, but the result is not reality */
+	      *rv = bytes + (wbytes > ncr ? wbytes - ncr : 0);
+	      return 1;
+	    }
+
+	  /* don't count CR */
+	  bytes += wbytes - ncr;
+	}
+    }
+
+  __libc_termios_check_bytes -= bytes;
+  if (__libc_termios_check_bytes <= 0)
+    {
+      __libc_termios_check_bytes = CHECKBYTES;
+      __libc_termios_check_signals ();
+    }
+
+  /* result of write() */
+  *rv =  bytes;
+  return 1;
+}
+
+static ssize_t
+__libc_termios_write_cooked_tty (int handle, const void *buffer, size_t count)
+{
+  ssize_t bytes;
+
+  /* output process if need */
+  if (__libc_tty_p->t_oflag & OPOST)
+    {
+      const unsigned char *rp;
+      unsigned char ch;
+      ssize_t n, nn;
+
+      rp = buffer;
+      n = count;
+      while (n > 0)
+	{
+	  nn = (n < __libc_termios_check_bytes) ? n : __libc_termios_check_bytes;
+	  n -= nn;
+	  __libc_termios_check_bytes -= nn;
+
+	  while (--nn >= 0)
+	    {
+	      /* get character */
+	      ch = *rp++;
+
+	      /* NOTE: multibyte character don't contain control character */
+	      /* map NL to CRNL */
+	      if (ch == '\n' && (__libc_tty_p->t_oflag & ONLCR))
+		__direct_output ('\r');
+	      /* map CR to NL */
+	      else if (ch == '\r' && (__libc_tty_p->t_oflag & OCRNL))
+		ch = '\n';
+
+	      __direct_output (ch);
+	    }
+
+	  if (__libc_termios_check_bytes <= 0)
+	    {
+	      __libc_termios_check_bytes = CHECKBYTES;
+	      __libc_termios_check_signals ();
+	    }
+	}
+
+      /* don't count CR */
+      bytes = count;
+    }
+  else
+    {
+      /* output with no effect */
+      bytes = __libc_termios_write_raw_tty (handle, buffer, count);
+    }
+
+  return bytes;
+}
+
+static ssize_t
+__libc_termios_write_raw_tty (int handle, const void *buffer, size_t count)
+{
+  const unsigned char *rp;
+  ssize_t n;
+
+  rp = buffer;
+  n = count;
+  while (n > 0)
+    {
+      if (n < __libc_termios_check_bytes)
+	{
+	  __libc_termios_check_bytes -= n;
+	  __direct_outputns (n, rp);
+	  rp += n;
+	  break;
+	}
+      else
+	{
+	  n -= __libc_termios_check_bytes;
+	  __direct_outputns (__libc_termios_check_bytes, rp);
+	  rp += __libc_termios_check_bytes;
+	  __libc_termios_check_bytes = CHECKBYTES;
+	  __libc_termios_check_signals ();
+	}
+    }
+
+  return count;
+}
+
+/******************************************************************************/
+/* special fsext function *****************************************************/
+
+static int
+__libc_termios_fsext (__FSEXT_Fnumber n, int *rv, va_list ap)
+{
+  short devmod;
+  ssize_t bytes;
+  int handle;
+
+  handle = va_arg (ap, int);
+  devmod = _get_dev_info (handle);
+  if (devmod == -1)
+    return 0;
+  if (!(devmod & _DEV_CDEV) || !(devmod & (_DEV_STDIN|_DEV_STDOUT)))
+    return 0;
+
+  /* console only... */
+  switch (n)
+    {
+#if 0
+    case __FSEXT_read:
+      {
+	void *buffer;
+	size_t count;
+
+	buffer = va_arg (ap, void *);
+	count = va_arg (ap, size_t);
+	if (devmod & _DEV_RAW)
+	  bytes = __libc_termios_read_raw_tty (handle, buffer, count);
+	else
+	  bytes = __libc_termios_read_cooked_tty (handle, buffer, count);
+
+	/* result of read */
+	*rv = bytes;
+	return 1;
+      }
+    case __FSEXT_write:
+      {
+	const void *buffer;
+	size_t count;
+
+	buffer = va_arg (ap, const void *);
+	count = va_arg (ap, size_t);
+	if (devmod & _DEV_RAW)
+	  bytes = __libc_termios_write_raw_tty (handle, buffer, count);
+	else
+	  bytes = __libc_termios_write_cooked_tty (handle, buffer, count);
+
+	/* result of write */
+	*rv = bytes;
+	return 1;
+      }
+#else
+    case __FSEXT_write:
+      {
+	size_t count;
+	const void *buffer;
+
+	buffer = va_arg (ap, const void *);
+	count = va_arg (ap, size_t);
+	bytes = __libc_termios_write_raw_tty (handle, buffer, count);
+
+	/* result of write */
+	*rv = bytes;
+	return 1;
+      }
+#endif
+    default:
+      break;
+    }
+
+  return 0;
+}
+
+/******************************************************************************/
+/* echo routines **************************************************************/
+
+static void
+__libc_termios_echo_ctrl (unsigned char ch)
+{
+  ch ^= 0x40;
+  __direct_output ('^');
+  __direct_output (ch);
+}
+
+static void
+__libc_termios_maybe_echo_ctrl (unsigned char ch)
+{
+  if (__libc_tty_p->t_lflag & ECHOCTL)
+    __libc_termios_echo_ctrl (ch);
+}
+
+static void
+__libc_termios_maybe_echo (unsigned char ch)
+{
+  if (! (__libc_tty_p->t_lflag & ECHO))
+    {
+      /* don't echo but newline is required ? */
+      if (ch == '\n' && (__libc_tty_p->t_lflag & ECHONL))
+	{
+	  if (__libc_tty_p->t_oflag & ONLCR)
+	    __direct_output ('\r');
+	  __direct_output ('\n');
+	}
+      return;
+    }
+
+  /* check literal flag */
+  if ((__libc_tty_p->t_status & _TS_LNCH) && (ch < 0x20))
+    {
+      __libc_termios_echo_ctrl (ch);
+      return;
+    }
+
+  /* output process if need */
+  if (__libc_tty_p->t_oflag & OPOST)
+    {
+      /* map NL to CRNL */
+      if (ch == '\n' && (__libc_tty_p->t_oflag & ONLCR))
+	{
+	  __direct_output ('\r');
+	  __direct_output ('\n');
+	  return;
+	}
+      /* map CR to NL */
+      else if (ch == '\r' && (__libc_tty_p->t_oflag & OCRNL))
+	{
+	  __direct_output ('\n');
+	  return;
+	}
+      /* discard EOT */
+      else if (_CC_EQU (VEOF, ch) && (__libc_tty_p->t_oflag & ONOEOT))
+	{
+	  return;
+	}
+    }
+
+  /* control character except newline */
+  if ((ch < 0x20 || ch == 0x7f) && (__libc_tty_p->t_lflag & ECHOCTL) && ch != '\n')
+    {
+      __libc_termios_echo_ctrl (ch);
+      return;
+    }
+
+  /* no effect */
+  __direct_output (ch);
+}
+
+/******************************************************************************/
+/* edit routines **************************************************************/
+
+static void
+__libc_termios_maybe_erase1 (void)
+{
+  if (__libc_tty_p->t_lflag & ECHO)
+    {
+      /* eat prev. character by BS SPC BS */
+      __direct_output ('\010');
+      if (__libc_tty_p->t_lflag & ECHOE)
+	{
+	  __direct_output (' ');
+	  __direct_output ('\010');
+	}
+    }
+}
+
+/* erase one prev. character of editline */
+static void
+__libc_termios_erase_editline (void)
+{
+  int col;
+  char pf;
+
+  col = __libc_tty_editline.col;
+  if (col == 0) /* no more */
+    return;
+
+  /* get position flag */
+  pf = __libc_tty_editline.flag[col - 1];
+  if (pf == _TTY_EDITLINE_INVALID || pf < 0)
+    {
+      /* erase all invalid character */
+      while (col > 0 && __libc_tty_editline.flag[col - 1] < 0)
+	{
+	  __libc_termios_maybe_erase1 ();
+	  --col;
+	}
+    }
+  else if (pf == _TTY_EDITLINE_CTRL)
+    {
+      if (__libc_tty_p->t_lflag & ECHOCTL)
+	{
+	  /* erase one of "^X" */
+	  __libc_termios_maybe_erase1 ();
+	  --col;
+	}
+      __libc_termios_maybe_erase1 ();
+      --col;
+    }
+  else
+    {
+      /* erase single or multibyte charcter */
+      while (--pf >= 0)
+	{
+	  __libc_termios_maybe_erase1 ();
+	  --col;
+	}
+    }
+
+  /* set next insert position */
+  __libc_tty_editline.col = col;
+}
+
+/* erase all editline */
+static void
+__libc_termios_kill_editline (void)
+{
+  if (__libc_tty_p->t_lflag & ECHOKE)
+    {
+      while (__libc_tty_editline.col != 0)
+	__libc_termios_erase_editline ();
+    }
+  else
+    __libc_tty_editline.col = 0;
+
+  if (__libc_tty_p->t_lflag & ECHOK)
+    __libc_termios_maybe_echo ('\n');
+}
+
+static void
+__libc_termios_insert_editline (unsigned char ch)
+{
+  int mbsize;
+  int col;
+
+  col = __libc_tty_editline.col;
+  if (col >= _TTY_EDITLINE_SIZE)
+    {
+      /* detected over flow */
+      if (__libc_tty_p->t_iflag & IMAXBEL)
+	__direct_output ('\007');
+      return;
+    }
+
+  __libc_tty_editline.buf[col] = ch;
+  if (col == 0 || ((col > 0)
+		   && __libc_tty_editline.flag[col - 1] != _TTY_EDITLINE_INVALID))
+    {
+      /* check multibyte length */
+      mbsize = mblen (__libc_tty_editline.buf + col, 1);
+      if (mbsize == 1)
+	{
+	  /* single character */
+	  if ((ch < 0x20) || ch == 0x7f)
+	    __libc_tty_editline.flag[col] = _TTY_EDITLINE_CTRL;
+	  else
+	    __libc_tty_editline.flag[col] = _TTY_EDITLINE_SINGLE;
+	  __libc_termios_maybe_echo (ch);
+	}
+      else
+	{
+	  /* first of multibyte or invalid character */
+	  __libc_tty_editline.flag[col] = _TTY_EDITLINE_INVALID;
+	  __libc_tty_p->t_status |= _TS_LNCH;
+	}
+    }
+  else
+    {
+      int pcol;
+
+      /* look for non fixed flag */
+      pcol = col;
+      while (__libc_tty_editline.flag[pcol - 1] == _TTY_EDITLINE_INVALID)
+	if (--pcol <= 0)
+	  break;
+
+      /* check whether it's multibyte sequence */
+      mbsize = mblen (__libc_tty_editline.buf + pcol, (col - pcol + 1));
+      if (mbsize > 1)
+	{
+	  /* multibyte sequence is good */
+	  while (pcol < col)
+	    {
+	      /* set negative size for dividing sequence */
+	      __libc_tty_editline.flag[pcol] = -mbsize;
+	      __libc_termios_maybe_echo (__libc_tty_editline.buf[pcol]);
+	      pcol++;
+	    }
+	  /* last flag is always positive size */
+	  __libc_tty_editline.flag[col] = mbsize;
+	  __libc_termios_maybe_echo (ch);
+	}
+      else
+	{
+	  if ((col - pcol + 1) > MB_CUR_MAX)
+	    {
+	      /* it's terrible... */
+	      while (pcol <= col)
+		{
+		  /* replace all with valid character */
+		  __libc_tty_editline.flag[pcol] = _TTY_EDITLINE_SINGLE;
+		  __libc_tty_editline.buf[pcol] = 'X';
+		  __libc_termios_maybe_echo ('X');
+		  pcol++;
+		}
+	    }
+
+	  /* continuous multibyte character */
+	  __libc_tty_editline.flag[col] = _TTY_EDITLINE_INVALID;
+	  __libc_tty_p->t_status |= _TS_LNCH;
+	}
+    }
+
+  /* set next insert position */
+  col++;
+  __libc_tty_editline.col = col;
+}
+
+/******************************************************************************/
+/* queued input routines ******************************************************/
+
+#if __DJGPP_MINOR__ < 4
+static int
+#else
+int
+#endif
+__libc_termios_exist_queue (void)
+{
+  return __libc_tty_p->t_count;
+}
+
+static void
+__libc_termios_clear_queue (void)
+{
+  __libc_tty_p->t_count = 0;
+  __libc_tty_p->t_rpos = __libc_tty_p->t_top;
+  __libc_tty_p->t_wpos = __libc_tty_p->t_top;
+}
+
+static int
+__libc_termios_get_queue (void)
+{
+  int ch;
+
+  if (__libc_tty_p->t_count == 0)
+    return -1;
+
+  ch = *__libc_tty_p->t_rpos++;
+  __libc_tty_p->t_count--;
+
+  if (__libc_tty_p->t_rpos >= __libc_tty_p->t_bottom)
+    __libc_tty_p->t_rpos = __libc_tty_p->t_top;
+
+  return ch;
+}
+
+static int
+__libc_termios_put_queue (unsigned char ch)
+{
+  if (__libc_tty_p->t_count >= __libc_tty_p->t_size)
+    return -1;
+
+  *__libc_tty_p->t_wpos++ = ch;
+  __libc_tty_p->t_count++;
+
+  if (__libc_tty_p->t_wpos >= __libc_tty_p->t_bottom)
+    __libc_tty_p->t_wpos = __libc_tty_p->t_top;
+
+  return 0;
+}
+
+static void
+__libc_termios_raise_signal (unsigned char ch, int sig)
+{
+#if 0
+  struct sigaction oldact;
+
+  if (sigaction (sig, NULL, &oldact) == 0)
+    if (oldact.sa_handler == SIG_DFL)
+      __libc_termios_maybe_echo_ctrl (ch);
+#else
+  __libc_termios_maybe_echo_ctrl (ch);
+#endif
+  kill (getpid(), sig);
+}
+
+static void
+__libc_termios_fill_queue (void)
+{
+  unsigned char ch;
+
+  while (1)
+    {
+      /* exhaust inputs ? */
+      if (! __direct_keysense ())
+	{
+	  __dpmi_yield ();
+	  /* wait for NL or EOT ? */
+	  if (__libc_tty_p->t_lflag & ICANON)
+	    continue;
+	  return;
+	}
+
+      /* realy get */
+      ch = __direct_keyinput ();
+
+      /* replace CTRL+SPACE with 0x00 */
+      if (ch == ' ' && __direct_ctrlsense ())
+	ch = '\0';
+
+      /* input process if need */
+      if (! (__libc_tty_p->t_status & _TS_LNCH) || ch != (unsigned char) _POSIX_VDISABLE)
+	{
+	  /* software signals */
+	  if (__libc_tty_p->t_lflag & ISIG)
+	    {
+	      if (! (__libc_tty_p->t_iflag & IGNBRK) && _CC_EQU (VINTR, ch))
+		{
+		  if (__libc_tty_p->t_iflag & BRKINT)
+		    {
+		      __libc_termios_raise_signal (ch, SIGINT);
+		      continue;
+		    }
+		  else
+		    {
+		      ch = '\0';
+		      goto proc_skip;
+		    }
+		}
+	      else if (_CC_EQU (VQUIT, ch))
+		{
+		  __libc_termios_raise_signal (ch, SIGQUIT);
+		  continue;
+		}
+	      else if (_CC_EQU (VSUSP, ch))
+		{
+#ifdef SIGTSTP
+		  __libc_termios_raise_signal (ch, SIGTSTP);
+#else /* djgpp don't have ... */
+		  {
+		    char oldcwd[PATH_MAX];
+		    int fds[5] = { -1, -1, -1, -1, -1 };
+		    int i;
+
+		    for (i = 0; i < 5; i++)
+		      if ((fds[i] = fcntl (i, F_DUPFD, 20)) < 0)
+		        __direct_outputs ("Suspend: cannot save fds\r\n");
+
+		    __direct_outputs ("\r\nSuspended\r\n");
+		    /* keep cwd on exec */
+		    getcwd (oldcwd, sizeof (oldcwd));
+		    system (NULL);
+		    chdir (oldcwd);
+
+		    for (i = 0; i < 5; i++)
+		      if (fds[i] >= 0)
+			{
+			  dup2 (fds[i], i);
+			  close (fds[i]);
+			}
+		  }
+#endif /* !SIGTSTP */
+		  continue;
+		}
+	    }
+
+	  /* flow control... */
+	  if (_CC_EQU (VSTART, ch) && (__libc_tty_p->t_iflag & IXOFF))
+	    {
+	      continue;
+	    }
+	  else if (_CC_EQU (VSTOP, ch) && (__libc_tty_p->t_iflag & IXOFF))
+	    {
+	      continue;
+	    }
+
+	  /* CR/LF process */
+	  if (ch == '\r')
+	    {
+	      if (__libc_tty_p->t_iflag & IGNCR)
+		continue;
+	      if (__libc_tty_p->t_iflag & ICRNL)
+		ch = '\n';
+	    }
+	  else if ((ch == '\n') && (__libc_tty_p->t_iflag & INLCR))
+	    ch = '\r';
+
+	  /* strip 8th-bit */
+	  if (__libc_tty_p->t_iflag & ISTRIP)
+	    ch &= 0x7f;
+	}
+
+proc_skip:
+      if (__libc_tty_p->t_lflag & ICANON)
+	{
+	  if (__libc_tty_p->t_status & _TS_LNCH)
+	    {
+	      __libc_tty_p->t_status &= ~_TS_LNCH;
+	      __libc_termios_insert_editline (ch);
+	    }
+	  else
+	    {
+	      if (_CC_EQU (VERASE, ch))
+		__libc_termios_erase_editline ();
+	      else if (_CC_EQU (VKILL, ch))
+		__libc_termios_kill_editline ();
+	      else if (ch == '\n' || _CC_EQU (VEOF, ch) || _CC_EQU (VEOL, ch))
+		{
+		  int col = __libc_tty_editline.col;
+		  unsigned char *p = __libc_tty_editline.buf;
+
+		  /* clear column for next access */
+		  __libc_tty_editline.col = 0;
+
+		  /* copy editline into tty queue */
+		  while (--col >= 0)
+		    __libc_termios_put_queue (*p++);
+
+		  /* echo terminate character and put it */
+		  __libc_termios_maybe_echo (ch);
+		  if (_CC_NEQU (VEOF, ch))
+		    __libc_termios_put_queue (ch);
+
+		  return;
+		}
+	      else
+		__libc_termios_insert_editline (ch);
+	    } /* !_TS_LNCH */
+	}
+      else /* !ICANON */
+	{
+	  __libc_termios_maybe_echo (ch);
+	  __libc_tty_p->t_status &= ~_TS_LNCH;
+	  __libc_termios_put_queue (ch);
+	}
+    } /* end of while (1) */
+}
+
+/******************************************************************************/
+/* software signal checker ****************************************************/
+
+void
+__libc_termios_check_signals (void)
+{
+  unsigned char ch;
+
+  if (! __direct_keysense ())
+    return;
+
+  /* software signals */
+  if (__libc_tty_p->t_lflag & ISIG)
+    {
+      ch = __direct_keyinput ();
+      if (! (__libc_tty_p->t_iflag & IGNBRK) && _CC_EQU (VINTR, ch))
+	{
+	  if (__libc_tty_p->t_iflag & BRKINT)
+	    {
+	      __libc_termios_raise_signal (ch, SIGINT);
+	      return;
+	    }
+	}
+      else if (_CC_EQU (VQUIT, ch))
+	{
+	  __libc_termios_raise_signal (ch, SIGQUIT);
+	  return;
+	}
+
+      /* for compatiblity */
+      if (ch == 0x13 && !(__libc_tty_p->t_iflag & IXOFF))
+	{
+	  /* CTRL+S */
+	  while (! __direct_keysense ())
+	    __dpmi_yield ();
+	  ch = __direct_keyinput ();
+	  return;
+	}
+
+      /* push back */
+      __direct_add_keystroke ((int) ch);
+    }
+}
+
+/******************************************************************************/
+
+#endif	/* __DJGPP__ */
diff -aprNU5 bash-4.4.orig/lib/sh/getcwd.c bash-4.4/lib/sh/getcwd.c
--- bash-4.4.orig/lib/sh/getcwd.c	2012-03-10 15:48:50 +0000
+++ bash-4.4/lib/sh/getcwd.c	2023-03-04 21:24:44 +0000
@@ -18,11 +18,11 @@
    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include <config.h>
 
-#if !defined (HAVE_GETCWD)
+#if !defined (HAVE_GETCWD) && !defined (__DJGPP__)
 
 #if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
   #pragma alloca
 #endif /* _AIX && RISC6000 && !__GNUC__ */
 
diff -aprNU5 bash-4.4.orig/lib/sh/netopen.c bash-4.4/lib/sh/netopen.c
--- bash-4.4.orig/lib/sh/netopen.c	2016-08-21 18:23:26 +0000
+++ bash-4.4/lib/sh/netopen.c	2023-03-04 21:24:44 +0000
@@ -23,10 +23,12 @@
    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include <config.h>
 
+#include "error.h"
+
 #if defined (HAVE_NETWORK)
 
 #if defined (HAVE_UNISTD_H)
 #  include <unistd.h>
 #endif
@@ -342,10 +344,10 @@ udpopen (host, serv)
 
 int
 netopen (path)
      char *path;
 {
-  internal_error (_("network operations not supported"));
+  internal_error ("network operations not supported");
   return -1;
 }
 
 #endif /* !HAVE_NETWORK */
diff -aprNU5 bash-4.4.orig/lib/sh/pathcanon.c bash-4.4/lib/sh/pathcanon.c
--- bash-4.4.orig/lib/sh/pathcanon.c	2012-07-29 23:55:00 +0000
+++ bash-4.4/lib/sh/pathcanon.c	2023-03-04 21:41:38 +0000
@@ -68,10 +68,14 @@ _is_cygdrive (path)
     }
   return !strcasecmp (path, user) || !strcasecmp (path, system);
 }
 #endif /* __CYGWIN__ */	
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#endif /* __DJGPP__ */
+
 /* Return 1 if PATH corresponds to a directory.  A function for debugging. */
 static int
 _path_isdir (path)
      char *path;
 {
@@ -117,10 +121,17 @@ sh_canonpath (path, flags)
   if (rooted = ROOTEDPATH(path))
     {
       stub_char = DIRSEP;
 #if defined (__CYGWIN__)
       base = (ISALPHA((unsigned char)result[0]) && result[1] == ':') ? result + 3 : result + 1;
+#elif defined (__DJGPP__)
+      if ((ISALPHA((unsigned char)result[0])) && result[1] == ':')
+        base = result + 3;
+      else if (is_dev_drive_path (result))
+        base = result + 7;
+      else
+        base = result + 1;
 #else
       base = result + 1;
 #endif
       double_slash_path = DOUBLE_SLASH (path);
       base += double_slash_path;
@@ -128,10 +139,17 @@ sh_canonpath (path, flags)
   else
     {
       stub_char = '.';
 #if defined (__CYGWIN__)
       base = (ISALPHA((unsigned char)result[0]) && result[1] == ':') ? result + 2 : result;
+#elif defined (__DJGPP__)
+      if ((isalpha(result[0])) && result[1] == ':')
+        base = result + 3;
+      else if (is_dev_drive_path (result))
+        base = result + 7;
+      else
+        base = result + 1;
 #else
       base = result;
 #endif
       double_slash_path = 0;
     }
@@ -185,10 +203,52 @@ sh_canonpath (path, flags)
 	      *q++ = '.';
 	      *q++ = '.';
 	      dotdot = q;
 	    }
 	}
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+      /* Handle three or more dots (Windows compatible) */
+      else if (p[0] == '.' && p[1] == '.' && p[2] == '.') 
+	{
+	  p += 1; /* skip `..' */
+	  while (*p == '.')
+	  {
+	  if (q > dotdot)	/* can backtrack */
+	    {
+	      if (flags & PATH_CHECKDOTDOT)
+		{
+		  char c;
+
+		  /* Make sure what we have so far corresponds to a valid
+		     path before we chop some of it off. */
+		  c = *q;
+		  *q = '\0';
+		  if (_path_isdir (result) == 0)
+		    {
+		      if ((flags & PATH_NOALLOC) == 0)
+			free (result);
+		      return ((char *)NULL);
+		    }
+		  *q = c;
+		}
+
+	      while (--q > dotdot && ISDIRSEP(*q) == 0)
+		;
+	    }
+	  else if (rooted == 0)
+	    {
+	      /* /.. is / but ./../ is .. */
+	      if (q != base)
+		*q++ = DIRSEP;
+	      *q++ = '.';
+	      *q++ = '.';
+	      dotdot = q;
+	    }
+	  ++p;
+	  }
+	}
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
       else	/* real path element */
 	{
 	  /* add separator if not at start of work portion of result */
 	  if (q != base)
 	    *q++ = DIRSEP;
diff -aprNU5 bash-4.4.orig/lib/sh/pathphys.c bash-4.4/lib/sh/pathphys.c
--- bash-4.4.orig/lib/sh/pathphys.c	2013-05-28 19:33:58 +0000
+++ bash-4.4/lib/sh/pathphys.c	2023-03-04 21:41:38 +0000
@@ -64,10 +64,14 @@ _path_readlink (path, buf, bufsiz)
 
 /* Look for ROOTEDPATH, PATHSEP, DIRSEP, and ISDIRSEP in ../../general.h */
 
 #define DOUBLE_SLASH(p)	((p[0] == '/') && (p[1] == '/') && p[2] != '/')
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#endif /* __DJGPP__ */
+
 /*
  * Return PATH with all symlinks expanded in newly-allocated memory.
  * This always gets an absolute pathname.
  */
 
@@ -105,10 +109,17 @@ sh_physpath (path, flags)
 
   /* POSIX.2 says to leave a leading `//' alone.  On cygwin, we skip over any
      leading `x:' (dos drive name). */
 #if defined (__CYGWIN__)
   qbase = (ISALPHA((unsigned char)workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1;
+#elif defined (__DJGPP__)
+  if ((ISALPHA((unsigned char)workpath[0])) && workpath[1] == ':')
+    qbase = result + 3;
+  else if (is_dev_drive_path (workpath))
+    qbase = workpath + 7;
+  else
+    qbase = workpath + 1;
 #else
   qbase = workpath + 1;
 #endif
   double_slash_path = DOUBLE_SLASH (workpath);
   qbase += double_slash_path;
@@ -214,10 +225,17 @@ error:
 	    {
 	      q = result;
 	      /* Duplicating some code here... */
 #if defined (__CYGWIN__)
 	      qbase = (ISALPHA((unsigned char)workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1;
+#elif defined (__DJGPP__)
+              if ((ISALPHA((unsigned char)workpath[0])) && workpath[1] == ':')
+                qbase = result + 3;
+              else if (is_dev_drive_path (workpath))
+                qbase = workpath + 7;
+              else
+                qbase = workpath + 1;
 #else
 	      qbase = workpath + 1;
 #endif
 	      double_slash_path = DOUBLE_SLASH (workpath);
 	      qbase += double_slash_path;
diff -aprNU5 bash-4.4.orig/lib/sh/tmpfile.c bash-4.4/lib/sh/tmpfile.c
--- bash-4.4.orig/lib/sh/tmpfile.c	2016-08-11 15:05:58 +0000
+++ bash-4.4/lib/sh/tmpfile.c	2023-03-04 21:41:38 +0000
@@ -40,20 +40,34 @@
 
 #ifndef errno
 extern int errno;
 #endif
 
-#define BASEOPENFLAGS	(O_CREAT | O_TRUNC | O_EXCL | O_BINARY)
+#ifndef O_TEMPORARY
+#define O_TEMPORARY 0
+#endif
+
+#define BASEOPENFLAGS   (O_CREAT | O_TRUNC | O_EXCL | O_TEMPORARY)
 
 #define DEFAULT_TMPDIR		"."	/* bogus default, should be changed */
 #define DEFAULT_NAMEROOT	"shtmp"
 
 /* Use ANSI-C rand() interface if random(3) is not available */
 #if !HAVE_RANDOM
 #define random() rand()
 #endif
 
+#if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
+#  define HAS_LFN_SUPPORT(name)  (pathconf ((name), _PC_NAME_MAX) > 12)
+#else
+#  if defined (__MSDOS__)
+#    define HAS_LFN_SUPPORT(name)  (0)
+#  else  /* !__MSDOS__ */
+#    define HAS_LFN_SUPPORT(name)  (1)
+#  endif /* !__MSDOS__ */
+#endif
+
 extern pid_t dollar_dollar_pid;
 
 static char *get_sys_tmpdir __P((void));
 static char *get_tmpdir __P((int));
 
@@ -72,10 +86,19 @@ get_sys_tmpdir ()
   sys_tmpdir = P_tmpdir;
   if (file_iswdir (sys_tmpdir))
     return sys_tmpdir;
 #endif
 
+#if defined (__DJGPP__)
+  sys_tmpdir = "/dev/env/TEMP";
+  if (access (sys_tmpdir, D_OK) == 0)
+    return sys_tmpdir;
+
+  sys_tmpdir = "/dev/env/TMP";
+  if (access (sys_tmpdir, D_OK) == 0)
+    return sys_tmpdir;
+#else /* !__DJGPP__ */
   sys_tmpdir = "/tmp";
   if (file_iswdir (sys_tmpdir))
     return sys_tmpdir;
 
   sys_tmpdir = "/var/tmp";
@@ -83,10 +106,11 @@ get_sys_tmpdir ()
     return sys_tmpdir;
 
   sys_tmpdir = "/usr/tmp";
   if (file_iswdir (sys_tmpdir))
     return sys_tmpdir;
+#endif /* !__DJGPP__ */
 
   sys_tmpdir = DEFAULT_TMPDIR;
 
   return sys_tmpdir;
 }
@@ -95,10 +119,14 @@ static char *
 get_tmpdir (flags)
      int flags;
 {
   char *tdir;
 
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  flags |= MT_USETMPDIR;
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
   tdir = (flags & MT_USETMPDIR) ? get_string_value ("TMPDIR") : (char *)NULL;
   if (tdir && (file_iswdir (tdir) == 0 || strlen (tdir) > PATH_MAX))
     tdir = 0;
 
   if (tdir == 0)
@@ -145,12 +173,18 @@ sh_mktmpname (nameroot, flags)
   tdir = get_tmpdir (flags);
   tdlen = strlen (tdir);
 
   lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
 
+#if defined (HAS_LFN_SUPPORT)
+  if (!HAS_LFN_SUPPORT(tdir)
+      && lroot[0] && lroot[1] && lroot[2])
+    lroot = "sh";
+#endif /* HAS_LFN_SUPPORT */
+
 #ifdef USE_MKTEMP
-  sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
+  sprintf (filename, HAS_LFN_SUPPORT(".") ? "%s/%s.XXXXXX" : "%s/%sXXXXXX", tdir, lroot);
   if (mktemp (filename) == 0)
     {
       free (filename);
       filename = NULL;
     }
@@ -160,11 +194,11 @@ sh_mktmpname (nameroot, flags)
     {
       filenum = (filenum << 1) ^
 		(unsigned long) time ((time_t *)0) ^
 		(unsigned long) dollar_dollar_pid ^
 		(unsigned long) ((flags & MT_USERANDOM) ? random () : ntmpfiles++);
-      sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
+      sprintf (filename, HAS_LFN_SUPPORT(".") ? "%s/%s-%lu" : "%s/%s%lu", tdir, lroot, filenum);
       if (tmpnamelen > 0 && tmpnamelen < 32)
 	filename[tdlen + 1 + tmpnamelen] = '\0';
 #  ifdef HAVE_LSTAT
       r = lstat (filename, &sb);
 #  else
@@ -184,19 +218,25 @@ sh_mktmpfd (nameroot, flags, namep)
      int flags;
      char **namep;
 {
   char *filename, *tdir, *lroot;
   int fd, tdlen;
-  
+
   filename = (char *)xmalloc (PATH_MAX + 1);
   tdir = get_tmpdir (flags);
   tdlen = strlen (tdir);
 
   lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
 
+#if defined (HAS_LFN_SUPPORT)
+  if (!HAS_LFN_SUPPORT(tdir)
+      && lroot[0] && lroot[1] && lroot[2])
+    lroot = "sh";
+#endif /* HAS_LFN_SUPPORT */
+
 #ifdef USE_MKSTEMP
-  sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
+  sprintf (filename, HAS_LFN_SUPPORT(".") ? "%s/%s.XXXXXX" : "%s/%sXXXXXX", tdir, lroot);
   fd = mkstemp (filename);
   if (fd < 0 || namep == 0)
     {
       free (filename);
       filename = NULL;
diff -aprNU5 bash-4.4.orig/lib/sh/zread.c bash-4.4/lib/sh/zread.c
--- bash-4.4.orig/lib/sh/zread.c	2023-03-04 21:55:18 +0000
+++ bash-4.4/lib/sh/zread.c	2023-03-04 21:24:44 +0000
@@ -27,10 +27,14 @@
 #endif
 
 #include <signal.h>
 #include <errno.h>
 
+#if defined (__DJGPP__)
+#  include <io.h>
+#endif
+
 #if !defined (errno)
 extern int errno;
 #endif
 
 #ifndef SEEK_CUR
@@ -62,10 +66,35 @@ zread (fd, buf, len)
       check_signals ();
 
   return r;
 }
 
+#if defined (__DJGPP__)
+/* Read LEN bytes from FD into BUF.  Retry the read on EINTR.  Any other
+   error causes the loop to break. */
+static ssize_t
+zreadbin (fd, buf, len)
+     int fd;
+     char *buf;
+     size_t len;
+{
+  ssize_t r;
+
+  while ((r = _read (fd, buf, len)) < 0 && errno == EINTR)
+    /* XXX - bash-5.0 */
+    /* We check executing_builtin and run traps here for backwards compatibility */
+    if (executing_builtin)
+      check_signals_and_traps ();	/* XXX - should it be check_signals()? */
+    else
+      check_signals ();
+
+  return r;
+}
+#else  /* !__DJGPP__ */
+#define zreadbin zread
+#endif /* !__DJGPP__ */
+
 /* Read LEN bytes from FD into BUF.  Retry the read on EINTR, up to three
    interrupts.  Any other error causes the loop to break. */
 
 #ifdef NUM_INTR
 #  undef NUM_INTR
@@ -118,23 +147,28 @@ zreadc (fd, cp)
      int fd;
      char *cp;
 {
   ssize_t nr;
 
-  if (lind == lused || lused == 0)
+  do
     {
-      nr = zread (fd, lbuf, sizeof (lbuf));
-      lind = 0;
-      if (nr <= 0)
+      if (lind == lused || lused == 0)
 	{
-	  lused = 0;
-	  return nr;
+	  nr = zreadbin (fd, lbuf, sizeof (lbuf));
+	  lind = 0;
+	  if (nr <= 0)
+	    {
+	      lused = 0;
+	      return nr;
+	    }
+	  lused = nr;
 	}
-      lused = nr;
+      if (cp)
+	*cp = lbuf[lind++];
     }
-  if (cp)
-    *cp = lbuf[lind++];
+  while (*cp == '\r');
+
   return 1;
 }
 
 /* Don't mix calls to zreadc and zreadcintr in the same function, since they
    use the same local buffer. */
@@ -169,25 +203,30 @@ zreadn (fd, cp, len)
      char *cp;
      size_t len;
 {
   ssize_t nr;
 
-  if (lind == lused || lused == 0)
+  do
     {
+      if (lind == lused || lused == 0)
+	{
       if (len > sizeof (lbuf))
 	len = sizeof (lbuf);
-      nr = zread (fd, lbuf, len);
-      lind = 0;
-      if (nr <= 0)
-	{
-	  lused = 0;
-	  return nr;
+	  nr = zreadbin (fd, lbuf, len);
+	  lind = 0;
+	  if (nr <= 0)
+	    {
+	      lused = 0;
+	      return nr;
+	    }
+	  lused = nr;
 	}
-      lused = nr;
+      if (cp)
+	*cp = lbuf[lind++];
     }
-  if (cp)
-    *cp = lbuf[lind++];
+  while (*cp == '\r');
+
   return 1;
 }
 
 void
 zreset ()
diff -aprNU5 bash-4.4.orig/lib/termcap/termcap.c bash-4.4/lib/termcap/termcap.c
--- bash-4.4.orig/lib/termcap/termcap.c	2015-08-06 14:17:08 +0000
+++ bash-4.4/lib/termcap/termcap.c	2023-03-04 21:24:44 +0000
@@ -100,10 +100,14 @@ int bufsize = 128;
 #endif
 #endif
 
 #include "ltcap.h"
 
+#if defined (__DJGPP__)
+#define TERMCAP_FILE "/dev/env/DJDIR/etc/termcap"
+#endif /* __DJGPP__ */
+
 #ifndef TERMCAP_FILE
 #define TERMCAP_FILE "/etc/termcap"
 #endif
 
 #ifndef emacs
@@ -419,21 +423,21 @@ valid_filename_p (fn)
   return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
 }
 
 #else /* !VMS */
 
-#ifdef MSDOS /* MW, May 1993 */
+#if defined (__MSDOS__) /* MW, May 1993 */
 static int
 valid_filename_p (fn)
      char *fn;
 {
   return *fn == '\\' || *fn == '/' ||
     (*fn >= 'A' && *fn <= 'z' && fn[1] == ':');
 }
-#else
+#else  /* !__MSDOS__ */
 #define valid_filename_p(fn) (*(fn) == '/')
-#endif
+#endif  /* !__MSDOS__ */
 
 #endif /* !VMS */
 
 /* Find the termcap entry data for terminal type NAME
    and store it in the block that BP points to.
@@ -525,15 +529,15 @@ tgetent (bp, name)
   if (!termcap_name || !filep)
     termcap_name = TERMCAP_FILE;
 
   /* Here we know we must search a file and termcap_name has its name.  */
 
-#ifdef MSDOS
+#if defined (__MSDOS__)
   fd = open (termcap_name, O_RDONLY|O_TEXT, 0);
-#else
+#else  /* !__MSDOS__ */
   fd = open (termcap_name, O_RDONLY, 0);
-#endif
+#endif /* !__MSDOS__ */
   if (fd < 0)
     return -1;
 
   buf.size = BUFSIZE;
   /* Add 1 to size to ensure room for terminating null.  */
diff -aprNU5 bash-4.4.orig/lib/termcap/tparam.c bash-4.4/lib/termcap/tparam.c
--- bash-4.4.orig/lib/termcap/tparam.c	2009-01-04 19:40:08 +0000
+++ bash-4.4/lib/termcap/tparam.c	2023-03-04 21:24:44 +0000
@@ -20,11 +20,11 @@
 
 /* Emacs config.h may rename various library functions such as malloc.  */
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 
-#ifdef HAVE_STDLIB_H 
+#ifdef HAVE_STDLIB_H
 #  include <stdlib.h>
 #else
 extern char *getenv ();
 extern char *malloc ();
 extern char *realloc ();
@@ -52,10 +52,14 @@ char *malloc ();
 char *realloc ();
 #endif
 
 #endif /* not HAVE_CONFIG_H */
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #include "ltcap.h"
 
 #ifndef NULL
 #define NULL (char *) 0
 #endif
diff -aprNU5 bash-4.4.orig/lib/tilde/tilde.c bash-4.4/lib/tilde/tilde.c
--- bash-4.4.orig/lib/tilde/tilde.c	2016-04-28 12:17:50 +0000
+++ bash-4.4/lib/tilde/tilde.c	2023-03-04 21:24:44 +0000
@@ -241,11 +241,11 @@ tilde_expand (string)
 	expansion = tilde_word;
       else
 	xfree (tilde_word);	
 
       len = strlen (expansion);
-#ifdef __CYGWIN__
+#if defined (__CYGWIN__) || defined (_WIN32) || defined (__MSDOS__)
       /* Fix for Cygwin to prevent ~user/xxx from expanding to //xxx when
 	 $HOME for `user' is /.  On cygwin, // denotes a network drive. */
       if (len > 1 || *expansion != '/' || *string != '/')
 #endif
 	{
@@ -273,15 +273,15 @@ isolate_tilde_prefix (fname, lenp)
 {
   char *ret;
   int i;
 
   ret = (char *)xmalloc (strlen (fname));
-#if defined (__MSDOS__)
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
   for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++)
-#else
+#else  /* !HAVE_DOS_BASED_FILE_SYSTEM */
   for (i = 1; fname[i] && fname[i] != '/'; i++)
-#endif
+#endif /* !HAVE_DOS_BASED_FILE_SYSTEM */
     ret[i - 1] = fname[i];
   ret[i - 1] = '\0';
   if (lenp)
     *lenp = i;
   return ret;



#######################################################################



2023-03-04  Juan Manuel Guerrero <juan.guerrero@gmx.de>


	* config-bot.h: DJGPP specific stuff.

	* config-top.h: DJGPP specific stuff.

	* externs.h: DJGPP specific stuff.

	* general.h: DJGPP specific stuff.

	* include/filecntl.h: DJGPP specific stuff.

	* pathnames.h.in: DJGPP specific stuff.

	* unwind_prot.h: DJGPP specific stuff.

	* variables.h: DJGPP specific stuff.







diff -aprNU5 bash-4.4.orig/config-bot.h bash-4.4/config-bot.h
--- bash-4.4.orig/config-bot.h	2016-05-19 18:34:42 +0000
+++ bash-4.4/config-bot.h	2023-03-04 22:03:16 +0000
@@ -131,10 +131,18 @@
 
 #if !defined (HAVE_SYSLOG) || !defined (HAVE_SYSLOG_H)
 #  undef SYSLOG_HISTORY
 #endif
 
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__OS2__)
+#  define HAVE_DOS_BASED_FILE_SYSTEM
+#endif
+
+#if !(defined (__DJGPP__) || defined (__MINGW__))
+#  define HAVE_WORKING_FORK
+#endif
+
 /************************************************/
 /* check multibyte capability for I18N code	*/
 /************************************************/
 
 /* For platforms which support the ISO C amendement 1 functionality we
diff -aprNU5 bash-4.4.orig/config-top.h bash-4.4/config-top.h
--- bash-4.4.orig/config-top.h	2016-05-19 18:34:02 +0000
+++ bash-4.4/config-top.h	2023-03-04 22:03:16 +0000
@@ -16,10 +16,15 @@
 
    You should have received a copy of the GNU General Public License
    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#if defined (__DJGPP__)
+#define DEFAULT_PATH_VALUE "/dev/env/DJDIR/bin"
+#define STANDARD_UTILS_PATH "/dev/env/DJDIR/bin"
+#endif
+
 /* Define CONTINUE_AFTER_KILL_ERROR if you want the kill command to
    continue processing arguments after one of them fails.  This is
    what POSIX.2 specifies. */
 #define CONTINUE_AFTER_KILL_ERROR
 
diff -aprNU5 bash-4.4.orig/externs.h bash-4.4/externs.h
--- bash-4.4.orig/externs.h	2016-08-11 14:11:30 +0000
+++ bash-4.4/externs.h	2023-03-04 22:03:16 +0000
@@ -226,11 +226,18 @@ extern int fpurge __P((FILE *stream));
 #endif /* HAVE_DECL_FPURGE */
 #endif /* NEED_FPURGE_DECL */
 
 /* Declarations for functions defined in lib/sh/getcwd.c */
 #if !defined (HAVE_GETCWD)
+#if !defined (__DJGPP__)
 extern char *getcwd __P((char *, size_t));
++#else  /* __DJGPP__ */
+/* DJGPP always uses its own getcwd implementation. */
+#undef  getcwd
+#define getcwd rpl_getcwd
+extern char *rpl_getcwd __P((char *, size_t));
+#endif /* __DJGPP__ */
 #endif
 
 /* Declarations for functions defined in lib/sh/input_avail.c */
 extern int input_avail __P((int));
 
diff -aprNU5 bash-4.4.orig/general.h bash-4.4/general.h
--- bash-4.4.orig/general.h	2016-08-11 15:17:12 +0000
+++ bash-4.4/general.h	2023-03-04 22:03:16 +0000
@@ -248,22 +248,26 @@ typedef int QSFUNC ();
 #endif 
 
 /* Some useful definitions for Unix pathnames.  Argument convention:
    x == string, c == character */
 
-#if !defined (__CYGWIN__)
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__OS2__)
+#define HAVE_DRIVE_LETTER_FILE_SYSTEM
+#endif
+
+#if !defined (HAVE_DRIVE_LETTER_FILE_SYSTEM)
 #  define ABSPATH(x)	((x)[0] == '/')
 #  define RELPATH(x)	((x)[0] != '/')
 #else /* __CYGWIN__ */
-#  define ABSPATH(x)	(((x)[0] && ISALPHA((unsigned char)(x)[0]) && (x)[1] == ':') || ISDIRSEP((x)[0]))
+#  define ABSPATH(x)	(((x)[0] && ISALPHA((unsigned char)(x)[0]) && (x)[1] == ':' && ISDIRSEP((x)[2])) || ISDIRSEP((x)[0]))
 #  define RELPATH(x)	(ABSPATH(x) == 0)
 #endif /* __CYGWIN__ */
 
 #define ROOTEDPATH(x)	(ABSPATH(x))
 
 #define DIRSEP	'/'
-#if !defined (__CYGWIN__)
+#if !defined (HAVE_DRIVE_LETTER_FILE_SYSTEM)
 #  define ISDIRSEP(c)	((c) == '/')
 #else
 #  define ISDIRSEP(c)	((c) == '/' || (c) == '\\')
 #endif /* __CYGWIN__ */
 #define PATHSEP(c)	(ISDIRSEP(c) || (c) == 0)
diff -aprNU5 bash-4.4.orig/include/filecntl.h bash-4.4/include/filecntl.h
--- bash-4.4.orig/include/filecntl.h	2011-01-02 20:29:30 +0000
+++ bash-4.4/include/filecntl.h	2023-03-04 22:03:16 +0000
@@ -31,10 +31,18 @@
 #define FD_NCLOEXEC    0
 
 #define SET_CLOSE_ON_EXEC(fd)  (fcntl ((fd), F_SETFD, FD_CLOEXEC))
 #define SET_OPEN_ON_EXEC(fd)   (fcntl ((fd), F_SETFD, FD_NCLOEXEC))
 
+/* DOS applies the inherit bit to fd and any other descriptors that
+   refer to the same file. Bash expects Posix behavior instead, so
+   it's best not to use this feature.  */
+#if defined (__MSDOS__)
+#  undef SET_CLOSE_ON_EXEC
+#  define SET_CLOSE_ON_EXEC(fd)
+#endif /* __MSDOS__ */
+
 /* How to open a file in non-blocking mode, the Posix.1 way. */
 #if !defined (O_NONBLOCK)
 #  if defined (O_NDELAY)
 #    define O_NONBLOCK O_NDELAY
 #  else
diff -aprNU5 bash-4.4.orig/pathnames.h.in bash-4.4/pathnames.h.in
--- bash-4.4.orig/pathnames.h.in	2009-01-04 19:32:40 +0000
+++ bash-4.4/pathnames.h.in	2023-03-04 22:03:16 +0000
@@ -20,14 +20,22 @@
 
 #if !defined (_PATHNAMES_H_)
 #define _PATHNAMES_H_
 
 /* The default file for hostname completion. */
+#if defined (__DJGPP__)
+#define DEFAULT_HOSTS_FILE "/dev/env/DJDIR/etc/hosts"
+#else  /* !__DJGPP__ */
 #define DEFAULT_HOSTS_FILE "/etc/hosts"
+#endif /* !__DJGPP__ */
 
 /* The default login shell startup file. */
+#if defined (__DJGPP__)
+#define SYS_PROFILE "/dev/env/DJDIR/etc/profile"
+#else  /* !__DJGPP__ */
 #define SYS_PROFILE "/etc/profile"
+#endif /* !__DJGPP__ */
 
 /* The default location of the bash debugger initialization/startup file. */
 #define DEBUGGER_START_FILE	"@DEBUGGER_START_FILE@"
 
 #endif /* _PATHNAMES_H */
diff -aprNU5 bash-4.4.orig/unwind_prot.h bash-4.4/unwind_prot.h
--- bash-4.4.orig/unwind_prot.h	2015-04-27 18:43:24 +0000
+++ bash-4.4/unwind_prot.h	2023-03-04 22:03:16 +0000
@@ -32,10 +32,16 @@ extern void remove_unwind_protect __P((v
 extern void run_unwind_protects __P((void));
 extern void clear_unwind_protect_list __P((int));
 extern int have_unwind_protects __P((void));
 extern int unwind_protect_tag_on_stack __P((const char *));
 extern void uwp_init __P((void));
+#if !defined (HAVE_WORKING_FORK)
+extern void clear_unwind_protect_list_entry  __P((void *));
+#endif /* !HAVE_WORKING_FORK */
+#if defined (__DJGPP__)
+extern void dump_unwind_protect_list __P((char *));
+#endif /* __DJGPP__ */
 
 /* Define for people who like their code to look a certain way. */
 #define end_unwind_frame()
 
 /* How to protect a variable.  */
diff -aprNU5 bash-4.4.orig/variables.h bash-4.4/variables.h
--- bash-4.4.orig/variables.h	2016-05-29 15:07:58 +0000
+++ bash-4.4/variables.h	2023-03-04 22:03:16 +0000
@@ -47,20 +47,28 @@ typedef struct var_context {
 #define VC_BLTNENV	0x08	/* builtin_env */
 #define VC_TEMPENV	0x10	/* temporary_env */
 
 #define VC_TEMPFLAGS	(VC_FUNCENV|VC_BLTNENV|VC_TEMPENV)
 
+#if !defined (HAVE_WORKING_FORK)
+#define VC_COPYONCHANGE 0x100
+#endif /* !HAVE_WORKING_FORK */
+
 /* Accessing macros */
 #define vc_isfuncenv(vc)	(((vc)->flags & VC_FUNCENV) != 0)
 #define vc_isbltnenv(vc)	(((vc)->flags & VC_BLTNENV) != 0)
 #define vc_istempenv(vc)	(((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV)
 
 #define vc_istempscope(vc)	(((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0)
 
 #define vc_haslocals(vc)	(((vc)->flags & VC_HASLOCAL) != 0)
 #define vc_hastmpvars(vc)	(((vc)->flags & VC_HASTMPVAR) != 0)
 
+#if !defined (HAVE_WORKING_FORK)
+#define vc_copyonchange(vc)	(((vc)->flags & (VC_COPYONCHANGE)) == VC_COPYONCHANGE)
+#endif /* !HAVE_WORKING_FORK */
+
 /* What a shell variable looks like. */
 
 typedef struct variable *sh_var_value_func_t __P((struct variable *));
 typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t, char *));
 
@@ -426,6 +434,16 @@ extern void sv_tz __P((char *));
 
 #if defined (JOB_CONTROL)
 extern void sv_childmax __P((char *));
 #endif
 
+#if defined (__DJGPP__)
+#define att_pathconv  0x20000    /* Convert a path to use forward slashes and
+                                   use the path separator in PATH_SEPARATOR */
+#define pathconv_p(var)		((((var)->attributes) & (att_pathconv)))
+
+void sv_path_expand __P((char *name));
+void sv_path_separator __P((char *name));
+void sv_test_finds_exe __P((char *name));
+#endif /* __DJGPP__ */
+
 #endif /* !_VARIABLES_H_ */



#######################################################################



2023-03-04  Juan Manuel Guerrero <juan.guerrero@gmx.de>


	* bashline.c: DJGPP specific stuff.

	* execute_cmd.c: DJGPP specific stuff.

	* findcmd.c: DJGPP specific stuff.

	* general.c: DJGPP specific stuff.

	* input.c: DJGPP specific stuff.

	* nojobs.c: DJGPP specific stuff.

	* parse.y: DJGPP specific stuff.

	* print_cmd.c: DJGPP specific stuff.

	* redir.c: DJGPP specific stuff.

	* shell.c: DJGPP specific stuff.

	* sig.c: DJGPP specific stuff.

	* subst.c: DJGPP specific stuff.

	* test.c: DJGPP specific stuff.

	* trap.c: DJGPP specific stuff.

	* unwind_prot.c: DJGPP specific stuff.

	* variables.c: DJGPP specific stuff.







diff -aprNU5 bash-4.4.orig/bashline.c bash-4.4/bashline.c
--- bash-4.4.orig/bashline.c	2023-03-04 21:19:30 +0000
+++ bash-4.4/bashline.c	2023-03-04 22:07:36 +0000
@@ -84,10 +84,24 @@
 #  define VI_EDITING_MODE	 0
 #endif
 
 #define RL_BOOLEAN_VARIABLE_VALUE(s)	((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0')
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#endif /* __DJGPP__ */
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#  define BASH_COMPLETER_WORD_BREAK_CHARACTERS  " \t\n\"'@><=;|&("
+#  define BASH_NOHOSTNAME_WORD_BREAK_CHARACTERS " \t\n\"'><=;|&("
+#  define DEFAULT_FILENAME_QUOTE_CHARACTERS     " \t\n\\\"'@<>=;|&()#$`?*[!{~"
+#else  /* !HAVE_DOS_BASED_FILE_SYSTEM */
+#  define BASH_COMPLETER_WORD_BREAK_CHARACTERS  " \t\n\"'@><=;|&(:"
+#  define BASH_NOHOSTNAME_WORD_BREAK_CHARACTERS " \t\n\"'><=;|&(:"
+#  define DEFAULT_FILENAME_QUOTE_CHARACTERS     " \t\n\\\"'@<>=;|&()#$`?*[!:{~"
+#endif /* !HAVE_DOS_BASED_FILE_SYSTEM */
+
 #if defined (BRACE_COMPLETION)
 extern int bash_brace_completion __P((int, int));
 #endif /* BRACE_COMPLETION */
 
 /* To avoid including curses.h/term.h/termcap.h and that whole mess. */
@@ -288,15 +302,15 @@ int dircomplete_expand_relpath = 0;
    variable referene, so dollar signs in a filename get quoted appropriately.
    Set to zero to remove dollar sign (and braces or parens as needed) from
    the set of characters that will be quoted. */
 int complete_fullquote = 1;
 
-static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:";
-static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:";
+static char *bash_completer_word_break_characters = BASH_COMPLETER_WORD_BREAK_CHARACTERS;
+static char *bash_nohostname_word_break_characters = BASH_NOHOSTNAME_WORD_BREAK_CHARACTERS;
 /* )) */
 
-static const char *default_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~";	/*}*/
+static const char *default_filename_quote_characters = DEFAULT_FILENAME_QUOTE_CHARACTERS;	/*}*/
 static char *custom_filename_quote_characters = 0;
 static char filename_bstab[256];
 
 static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL;
 
@@ -1840,10 +1854,27 @@ command_word_completion_function (hint_t
 
       /* If this is an absolute program name, do not check it against
 	 aliases, reserved words, functions or builtins.  We must check
 	 whether or not it is unique, and, if so, whether that filename
 	 is executable. */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+     if (hint_text && hint_text[1] == ':'
+         && hint_text[2] != '/')
+       {
+         char *buffer = get_real_path (hint_text);
+         hint = strdup (buffer);
+         hint_len = strlen (hint);
+         if (filename_hint)
+           free (filename_hint);
+
+         filename_hint = savestring (hint);
+
+         mapping_over = 4;
+         istate = 0;
+         goto inner;
+       }
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
       if (globpat || absolute_program (hint_text))
 	{
 	  /* Perform tilde expansion on what's passed, so we don't end up
 	     passing filenames with tildes directly to stat().  The rest of
 	     the shell doesn't do variable expansion on the word following
@@ -3125,11 +3156,11 @@ directory_exists (dirname, should_dequot
   r = stat (new_dirname, &sb) == 0;
 #endif
   free (new_dirname);
   return (r);
 }
-  
+
 /* Expand a filename before the readline completion code passes it to stat(2).
    The filename will already have had tilde expansion performed. */
 static int
 bash_filename_stat_hook (dirname)
      char **dirname;
diff -aprNU5 bash-4.4.orig/execute_cmd.c bash-4.4/execute_cmd.c
--- bash-4.4.orig/execute_cmd.c	2023-03-04 21:19:30 +0000
+++ bash-4.4/execute_cmd.c	2023-03-04 22:12:26 +0000
@@ -58,16 +58,28 @@ extern int errno;
 #endif
 
 #define NEED_FPURGE_DECL
 #define NEED_SH_SETLINEBUF_DECL
 
+#if !defined (HAVE_WORKING_FORK)
+#  include "nofork.h"
+#endif /* !HAVE_WORKING_FORK */
+
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#endif
+
 #include "bashansi.h"
 #include "bashintl.h"
 
 #include "memalloc.h"
 #include "shell.h"
+#if defined (__MSDOS__) && !defined (__DJGPP__)
+#include <y_tab.h>	/* use <...> so we pick it up from the build directory */
+#else  /* !__MSDOS__ */
 #include <y.tab.h>	/* use <...> so we pick it up from the build directory */
+#endif /* !__MSDOS__ */
 #include "flags.h"
 #include "builtins.h"
 #include "hashlib.h"
 #include "jobs.h"
 #include "execute_cmd.h"
@@ -103,10 +115,17 @@ extern int errno;
 
 #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
 #  include <mbstr.h>		/* mbschr */
 #endif
 
+#if defined (__DJGPP__)
+/* DJGPP always uses its own pipe implementation.
+   Required for close, dup2 and pipe.  */
+
+#  include "dospipe.h"
+#endif /* __DJGPP__ */
+
 extern int dollar_dollar_pid;
 extern int posixly_correct;
 extern int expand_aliases;
 extern int autocd;
 extern int breaking, continuing, loop_level;
@@ -403,10 +422,17 @@ execute_command (command)
 
   /* Just do the command, but not asynchronously. */
   result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap);
 
   dispose_fd_bitmap (bitmap);
+#if !defined (HAVE_WORKING_FORK)
+  /* The entry corresponding to the fds bitmap that has been
+     diposed must also be removed from the unwind protect list.
+     This avoids that the disposing of the fds bitmap is done
+     multiple times in MSDOS/DJGPP leading to crashes.  */
+  clear_unwind_protect_list_entry (bitmap);
+#endif /* !HAVE_WORKING_FORK */
   discard_unwind_frame ("execute-command");
 
 #if defined (PROCESS_SUBSTITUTION)
   /* don't unlink fifos if we're in a shell function; wait until the function
      returns. */
@@ -557,10 +583,15 @@ execute_command_internal (command, async
 #if defined (PROCESS_SUBSTITUTION)
   volatile int ofifo, nfifo, osize, saved_fifo;
   volatile char *ofifo_list;
 #endif
 
+#if !defined (HAVE_WORKING_FORK)
+  if (subshell_skip_commands)
+    return (EXECUTION_SUCCESS);
+#endif /* !HAVE_WORKING_FORK */
+
   if (breaking || continuing)
     return (last_command_exit_value);
   if (command == 0 || read_but_dont_execute)
     return (EXECUTION_SUCCESS);
 
@@ -614,10 +645,15 @@ execute_command_internal (command, async
 	{
 	  FREE (the_printed_command_except_trap);
 	  the_printed_command_except_trap = savestring (the_printed_command);
 	}
 
+#if !defined (HAVE_WORKING_FORK)
+      /* force execute in parent shell */
+      nofork_wait_status = execute_in_subshell (command, asynchronous, pipe_in,
+                                                pipe_out, fds_to_close);
+#endif /* !HAVE_WORKING_FORK */
       if (paren_pid == 0)
         {
 	  /* We want to run the exit trap for forced {} subshells, and we
 	     want to note this before execute_in_subshell modifies the
 	     COMMAND struct.  Need to keep in mind that execute_in_subshell
@@ -693,10 +729,13 @@ execute_command_internal (command, async
 	      /* Posix 2013 2.9.3.1: "the exit status of an asynchronous list
 		 shall be zero." */
 	      last_command_exit_value = 0;
 	      return (EXECUTION_SUCCESS);
 	    }
+#if !defined (HAVE_WORKING_FORK)
+        return 0;
+#endif /* !HAVE_WORKING_FORK */
 	}
     }
 
 #if defined (COMMAND_TIMING)
   if (command->flags & CMD_TIME_PIPELINE)
@@ -825,19 +864,26 @@ execute_command_internal (command, async
 	/* XXX - this is something to watch out for if there are problems
 	   when the shell is compiled without job control.  Don't worry about
 	   whether or not last_made_pid == last_pid; already_making_children
 	   tells us whether or not there are unwaited-for children to wait
 	   for and reap. */
+#if defined (HAVE_WORKING_FORK)
 	if (already_making_children && pipe_out == NO_PIPE)
+#else  /* !HAVE_WORKING_FORK */
+	if (already_making_children && pipe_out == NO_PIPE && last_made_pid != last_pid)
+#endif /* !HAVE_WORKING_FORK */
 	  {
 	    stop_pipeline (asynchronous, (COMMAND *)NULL);
 
 	    if (asynchronous)
 	      {
 		DESCRIBE_PID (last_made_pid);
 		exec_result = EXECUTION_SUCCESS;
 		invert = 0;		/* async commands always succeed */
+#if !defined (HAVE_WORKING_FORK)
+                last_made_pid = NO_PID;
+#endif /* !HAVE_WORKING_FORK */
 	      }
 	    else
 #if !defined (JOB_CONTROL)
 	      /* Do not wait for asynchronous processes started from
 		 startup files. */
@@ -875,10 +921,19 @@ execute_command_internal (command, async
 	     set -e. Report by Mark Farrell 5/19/2014 */
 	  if (exit_immediately_on_error && signal_is_trapped (0) &&
 		unwind_protect_tag_on_stack ("saved-redirects"))
 	    run_unwind_frame ("saved-redirects");
 
+#if !defined (HAVE_WORKING_FORK)
+          if (subshell_environment)
+            {
+              subshell_exit_value = exec_result;
+              subshell_exit_builtin = 0;
+              subshell_skip_commands = 1;
+              return (EXECUTION_SUCCESS);
+            }
+#endif /* !HAVE_WORKING_FORK */
 	  jump_to_top_level (ERREXIT);
 	}
 
       break;
 
@@ -1437,10 +1492,25 @@ execute_in_subshell (command, asynchrono
 {
   int user_subshell, return_code, function_value, should_redir_stdin, invert;
   int ois, user_coproc;
   int result;
   volatile COMMAND *tcom;
+#if !defined (HAVE_WORKING_FORK)
+  COMMAND *old_command;
+  OLDENVBUF oldenvbuf;
+  char *old_trap_list[1];
+  int old_sigmodes[1];
+#endif /* !HAVE_WORKING_FORK */
+
+#if !defined (HAVE_WORKING_FORK)
+  /* save arg list */
+  old_command = command;
+  command = copy_command (old_command);
+
+  /* Save everything relevant.  */
+  nofork_save_all_environment (&oldenvbuf);
+#endif /* !HAVE_WORKING_FORK */
 
   USE_VAR(user_subshell);
   USE_VAR(user_coproc);
   USE_VAR(invert);
   USE_VAR(tcom);
@@ -1508,10 +1578,11 @@ execute_in_subshell (command, asynchrono
 	subshell_environment |= SUBSHELL_PIPE;
       if (user_coproc)
 	subshell_environment |= SUBSHELL_COPROC;
     }
 
+#if defined (HAVE_WORKING_FORK)
   reset_terminating_signals ();		/* in sig.c */
   /* Cancel traps, in trap.c. */
   /* Reset the signal handlers in the child, but don't free the
      trap strings.  Set a flag noting that we have to free the
      trap strings if we run trap to change a signal disposition. */
@@ -1525,10 +1596,23 @@ execute_in_subshell (command, asynchrono
   if (asynchronous)
     {
       setup_async_signals ();
       asynchronous = 0;
     }
+#else /* ! HAVE_WORKING_FORK */
+  /* Save exit trap and signal. */
+#if 0
+  old_trap_list[0] = trap_list[0] ? savestring (trap_list[0]) : NULL;
+#else
+  old_trap_list[0] = trap_list[0];
+  trap_list[0] = NULL;
+#endif
+  old_sigmodes[0] = get_signal_modes (0);
+
+  /* Cancel exit trap .*/
+  restore_default_signal (0);
+#endif /* ! HAVE_WORKING_FORK */
 
 #if defined (JOB_CONTROL)
   set_sigchld_handler ();
 #endif /* JOB_CONTROL */
 
@@ -1574,11 +1658,18 @@ execute_in_subshell (command, asynchrono
 
   /* Do redirections, then dispose of them before recursive call. */
   if (command->redirects)
     {
       if (do_redirections (command->redirects, RX_ACTIVE) != 0)
+#if defined (HAVE_WORKING_FORK)
 	exit (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+#else /* !HAVE_WORKING_FORK */
+        {
+          return_code = invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
+          goto subshell_exit;
+        }
+#endif /* !HAVE_WORKING_FORK */
 
       dispose_redirects (command->redirects);
       command->redirects = (REDIRECT *)NULL;
     }
 
@@ -1621,10 +1712,21 @@ execute_in_subshell (command, asynchrono
      need to handle a possible `return'. */
   function_value = 0;
   if (return_catch_flag)
     function_value = setjmp_nosigs (return_catch);
 
+#if !defined (HAVE_WORKING_FORK)
+  begin_unwind_frame ("subshell-execute-command");
+  unwind_protect_int (subshell_exit_value);
+  unwind_protect_int (subshell_exit_builtin);
+  unwind_protect_int (subshell_skip_commands);
+
+  subshell_exit_value = 0;
+  subshell_exit_builtin = 1;
+  subshell_skip_commands = 0;
+#endif /* !HAVE_WORKING_FORK */
+
   /* If we're going to exit the shell, we don't want to invert the return
      status. */
   if (result == EXITPROG)
     invert = 0, return_code = last_command_exit_value;
   else if (result)
@@ -1632,10 +1734,19 @@ execute_in_subshell (command, asynchrono
   else if (function_value)
     return_code = return_catch_value;
   else
     return_code = execute_command_internal ((COMMAND *)tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
 
+#if !defined (HAVE_WORKING_FORK)
+  if (subshell_skip_commands)
+    {
+      return_code = subshell_exit_value;
+      last_command_exit_value = return_code;
+    }
+  run_unwind_frame ("subshell-execute-command");
+#endif /* !HAVE_WORKING_FORK */
+
   /* If we are asked to, invert the return value. */
   if (invert)
     return_code = (return_code == EXECUTION_SUCCESS) ? EXECUTION_FAILURE
 						     : EXECUTION_SUCCESS;
 
@@ -1648,10 +1759,24 @@ execute_in_subshell (command, asynchrono
     }
 
 #if 0
   subshell_level--;		/* don't bother, caller will just exit */
 #endif
+#if !defined (HAVE_WORKING_FORK)
+subshell_exit:
+  /* restore exit trap and signal.  */
+  restore_default_signal (0);
+  trap_list[0] = old_trap_list[0];
+  set_signal_modes (0, old_sigmodes[0]);
+
+  /* Restore fd, jmp_buf, current directory, global variables.  */
+  nofork_restore_all_environment (&oldenvbuf);
+
+  /* Restore arg list.  */
+  dispose_command (command);
+  command = old_command;
+#endif /* !HAVE_WORKING_FORK */
   return (return_code);
   /* NOTREACHED */
 }
 
 #if defined (COPROCESS_SUPPORT)
@@ -2362,10 +2487,34 @@ execute_pipeline (command, asynchronous,
   int lstdin, lastpipe_flag, lastpipe_jid;
   COMMAND *cmd;
   struct fd_bitmap *fd_bitmap;
   pid_t lastpid;
 
+#if defined (__DJGPP__)
+  /*  For debugging purposes, store the script line executed
+      and its the line number.  */
+#if (DOS_PIPE_DEBUG - 1) == 0
+  {
+    int i;
+    const char *the_saved_printed_command = the_printed_command ? savestring (the_printed_command) : NULL;
+    bash_script_command_line = savestring (make_command_string (command));
+    if (the_saved_printed_command)
+      for (i = 0; the_printed_command[i] = the_saved_printed_command[i]; i++)
+        ;
+    else
+    {
+      FREE (the_printed_command);
+      the_printed_command = NULL;
+    }
+    FREE (the_saved_printed_command);
+    if (cmd = command, cmd && cmd->type == cm_connection && cmd->value.Connection && cmd->value.Connection->connector == '|' &&
+        cmd->value.Connection->first && cmd->value.Connection->first->type == cm_simple && cmd->value.Connection->first->value.Simple)
+      bash_script_line_number = cmd->value.Connection->first->value.Simple->line;
+  }
+#endif /* DOS_PIPE_DEBUG */
+#endif /* __DJGPP__ */
+
 #if defined (JOB_CONTROL)
   sigset_t set, oset;
   BLOCK_CHILD (set, oset);
 #endif /* JOB_CONTROL */
 
@@ -2415,11 +2564,13 @@ execute_pipeline (command, asynchronous,
 
       /* Now copy the old information into the new bitmap. */
       xbcopy ((char *)fds_to_close->bitmap, (char *)fd_bitmap->bitmap, fds_to_close->size);
 
       /* And mark the pipe file descriptors to be closed. */
+#if defined (HAVE_WORKING_FORK) /* XXX Check on the validity of this.  */
       fd_bitmap->bitmap[fildes[0]] = 1;
+#endif /* HAVE_WORKING_FORK */
 
       /* In case there are pipe or out-of-processes errors, we
 	 want all these file descriptors to be closed when
 	 unwind-protects are run, and the storage used for the
 	 bitmaps freed up. */
@@ -2807,10 +2958,15 @@ execute_for_command (for_command)
 
       retval = execute_command (for_command->action);
       REAP ();
       QUIT;
 
+#if !defined (HAVE_WORKING_FORK)
+      if (subshell_skip_commands)
+        break;
+#endif /* !HAVE_WORKING_FORK */
+
       if (breaking)
 	{
 	  breaking--;
 	  break;
 	}
@@ -2967,10 +3123,15 @@ execute_arith_for_command (arith_for_com
       /* Execute the body of the arithmetic for command. */
       QUIT;
       body_status = execute_command (arith_for_command->action);
       QUIT;
 
+#if !defined (HAVE_WORKING_FORK)
+      if (subshell_skip_commands)
+        break;
+#endif /* !HAVE_WORKING_FORK */
+
       /* Handle any `break' or `continue' commands executed by the body. */
       if (breaking)
 	{
 	  breaking--;
 	  break;
@@ -3306,10 +3467,15 @@ execute_select_command (select_command)
       retval = execute_command (select_command->action);
 
       REAP ();
       QUIT;
 
+#if !defined (HAVE_WORKING_FORK)
+      if (subshell_skip_commands)
+        break;
+#endif /* !HAVE_WORKING_FORK */
+
       if (breaking)
 	{
 	  breaking--;
 	  break;
 	}
@@ -3486,10 +3652,15 @@ execute_while_or_until (while_command, t
   while (1)
     {
       return_value = execute_command (while_command->test);
       REAP ();
 
+#if !defined (HAVE_WORKING_FORK)
+      if (subshell_skip_commands)
+        break;
+#endif /* !HAVE_WORKING_FORK */
+
       /* Need to handle `break' in the test when we would break out of the
          loop.  The job control code will set `breaking' to loop_level
          when a job in a loop is stopped with SIGTSTP.  If the stopped job
          is in the loop test, `breaking' will not be reset unless we do
          this, and the shell will cease to execute commands.  The same holds
@@ -3545,10 +3716,15 @@ execute_if_command (if_command)
   save_line_number = line_number;
   if_command->test->flags |= CMD_IGNORE_RETURN;
   return_value = execute_command (if_command->test);
   line_number = save_line_number;
 
+#if !defined (HAVE_WORKING_FORK)
+  if (subshell_skip_commands)
+     return (EXECUTION_SUCCESS);
+#endif /* !HAVE_WORKING_FORK */
+
   if (return_value == EXECUTION_SUCCESS)
     {
       QUIT;
 
       if (if_command->true_case && (if_command->flags & CMD_IGNORE_RETURN))
@@ -3853,15 +4029,21 @@ execute_null_command (redirects, pipe_in
 
   if (forcefork || pipe_in != NO_PIPE || pipe_out != NO_PIPE || async)
     {
       /* We have a null command, but we really want a subshell to take
 	 care of it.  Just fork, do piping and redirections, and exit. */
+#if defined (HAVE_WORKING_FORK)
       if (make_child ((char *)NULL, async) == 0)
 	{
 	  /* Cancel traps, in trap.c. */
 	  restore_original_signals ();		/* XXX */
 
+#else  /* !HAVE_WORKING_FORK */
+          int ofds[] = { -1, -1, -1 };
+          make_child ((char *)NULL, async);
+          nofork_save_std_fds (ofds);
+#endif /* !HAVE_WORKING_FORK */
 	  do_piping (pipe_in, pipe_out);
 
 #if defined (COPROCESS_SUPPORT)
 	  coproc_closeall ();
 #endif
@@ -3871,23 +4053,37 @@ execute_null_command (redirects, pipe_in
 	    subshell_environment |= SUBSHELL_ASYNC;
 	  if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
 	    subshell_environment |= SUBSHELL_PIPE;
 
 	  if (do_redirections (redirects, RX_ACTIVE) == 0)
+#if defined (HAVE_WORKING_FORK)
 	    exit (EXECUTION_SUCCESS);
 	  else
 	    exit (EXECUTION_FAILURE);
+#else  /* !HAVE_WORKING_FORK */
+	    nofork_wait_status = (EXECUTION_SUCCESS);
+	  else
+	    nofork_wait_status = (EXECUTION_FAILURE);
+#endif /* !HAVE_WORKING_FORK */
+
+#if defined (HAVE_WORKING_FORK)
 	}
       else
 	{
+#endif /* HAVE_WORKING_FORK */
 	  close_pipes (pipe_in, pipe_out);
+#if !defined (HAVE_WORKING_FORK)
+          nofork_restore_std_fds (ofds);
+#endif /* !HAVE_WORKING_FORK */
 #if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
 	  if (pipe_out == NO_PIPE)
 	    unlink_fifo_list ();
 #endif
 	  return (EXECUTION_SUCCESS);
+#if defined (HAVE_WORKING_FORK)
 	}
+#endif /* HAVE_WORKING_FORK */
     }
   else
     {
       /* Even if there aren't any command names, pretend to do the
 	 redirections that are specified.  The user expects the side
@@ -4089,10 +4285,11 @@ execute_simple_command (simple_command,
 	 vast majority of cases. */
       maybe_make_export_env ();
 
       /* Don't let a DEBUG trap overwrite the command string to be saved with
 	 the process/job associated with this child. */
+#if defined (HAVE_WORKING_FORK)
       if (make_child (savestring (the_printed_command_except_trap), async) == 0)
 	{
 	  already_forked = 1;
 	  simple_command->flags |= CMD_NO_FORK;
 
@@ -4141,10 +4338,15 @@ execute_simple_command (simple_command,
 #endif
 	  command_line = (char *)NULL;      /* don't free this. */
 	  bind_lastarg ((char *)NULL);
 	  return (result);
 	}
+#else  /* ! HAVE_WORKING_FORK */
+      /* Just set already_forked and CMD_NO_FORK.  */
+      already_forked = 1;
+      simple_command->flags |= CMD_NO_FORK;
+#endif /* ! HAVE_WORKING_FORK */
     }
 
   QUIT;		/* XXX */
 
   /* If we are re-running this as the result of executing the `command'
@@ -4172,11 +4374,19 @@ execute_simple_command (simple_command,
       this_command_name = 0;
       result = execute_null_command (simple_command->redirects,
 				     pipe_in, pipe_out,
 				     already_forked ? 0 : async);
       if (already_forked)
+#if defined (HAVE_WORKING_FORK)
 	sh_exit (result);
+#else  /* !HAVE_WORKING_FORK */
+        {
+          bind_lastarg ((char *)NULL);
+          FREE (command_line);
+          return (result);
+        }
+#endif /* !HAVE_WORKING_FORK */
       else
 	{
 	  bind_lastarg ((char *)NULL);
 	  set_pipestatus_from_exit (result);
 	  return (result);
@@ -4299,10 +4509,11 @@ run_builtin:
 	  unwind_protect_int (executing_builtin);	/* modified in execute_builtin */
 	  unwind_protect_int (executing_command_builtin);	/* ditto */
         }
       if (already_forked)
 	{
+#if defined (HAVE_WORKING_FORK)
 	  /* reset_terminating_signals (); */	/* XXX */
 	  /* Reset the signal handlers in the child, but don't free the
 	     trap strings.  Set a flag noting that we have to free the
 	     trap strings if we run trap to change a signal disposition. */
 	  reset_signal_handlers ();
@@ -4314,18 +4525,23 @@ run_builtin:
 		    pipe_in == NO_PIPE &&
 		    (stdin_redirects (simple_command->redirects) == 0))
 		async_redirect_stdin ();
 	      setup_async_signals ();
 	    }
+#endif /* HAVE_WORKING_FORK */
 
 	  if (async == 0)
 	    subshell_level++;
 	  execute_subshell_builtin_or_function
 	    (words, simple_command->redirects, builtin, func,
 	     pipe_in, pipe_out, async, fds_to_close,
 	     simple_command->flags);
 	  subshell_level--;
+#if !defined (HAVE_WORKING_FORK)
+          result = nofork_wait_status; 
+          goto return_result;
+#endif /* !HAVE_WORKING_FORK */
 	}
       else
 	{
 	  result = execute_builtin_or_function
 	    (words, builtin, func, simple_command->redirects, fds_to_close,
@@ -4391,14 +4607,37 @@ run_builtin:
 #endif
   result = execute_disk_command (words, simple_command->redirects, command_line,
 			pipe_in, pipe_out, async, fds_to_close,
 			simple_command->flags);
 
+#if !defined (HAVE_WORKING_FORK)
+/* Set result code. */
+  result = nofork_wait_status;
+
+#if 0
+  /* Set result code for sh -c "foo" */
+  if (startup_state == 2)
+    {
+      if ((result & 0x0000ff00) == 0x0000ff00)
+        result &= 0x000000ff;
+    }
+#endif
+  /* lastarg may no longer be valid if path expansion took place.  */
+  lastarg = lastword->word->word;
+#endif /* !HAVE_WORKING_FORK */
+
  return_result:
   bind_lastarg (lastarg);
   FREE (command_line);
   dispose_words (words);
+#if !defined (HAVE_WORKING_FORK)
+  /* The entry corresponding to the word list that has been
+     diposed must also be removed from the unwind protect list.
+     This avoids that the disposing of the word list is done
+     multiple times in MSDOS/DJGPP leading to crashes.  */
+  clear_unwind_protect_list_entry (words);
+#endif /* !HAVE_WORKING_FORK */
   if (builtin)
     {
       executing_builtin = old_builtin;
       executing_command_builtin = old_command_builtin;
     }
@@ -4537,10 +4776,16 @@ execute_builtin (builtin, words, flags,
   /* This shouldn't happen, but in case `return' comes back instead of
      longjmp'ing, we need to unwind. */
   if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env)
     discard_unwind_frame ("return_temp_env");
 
+#if !defined (HAVE_WORKING_FORK)
+  /* check subshell return */
+  if (builtin == exit_builtin && result == EXECUTION_SUCCESS)
+    result = last_command_exit_value;
+#endif /* !HAVE_WORKING_FORK */
+
   if (subshell == 0 && isbltinenv)
     run_unwind_frame ("builtin_env");
 
   if (eval_unwind)
     {
@@ -4876,17 +5121,24 @@ execute_subshell_builtin_or_function (wo
      int pipe_in, pipe_out, async;
      struct fd_bitmap *fds_to_close;
      int flags;
 {
   int result, r, funcvalue;
+#if !defined (HAVE_WORKING_FORK)
+  OLDENVBUF oldenvbuf;
+#endif /* !HAVE_WORKING_FORK */
 #if defined (JOB_CONTROL)
   int jobs_hack;
 
   jobs_hack = (builtin == jobs_builtin) &&
 		((subshell_environment & SUBSHELL_ASYNC) == 0 || pipe_out != NO_PIPE);
 #endif
 
+#if !defined (HAVE_WORKING_FORK)
+  /* save fd, jmp_buf, current directory, global variables */
+  nofork_save_all_environment (&oldenvbuf);
+#endif /* !HAVE_WORKING_FORK */
   /* A subshell is neither a login shell nor interactive. */
   login_shell = interactive = 0;
   if (builtin == eval_builtin)
     evalnest = 0;
   else if (builtin == source_builtin)
@@ -4919,18 +5171,27 @@ execute_subshell_builtin_or_function (wo
     close_fd_bitmap (fds_to_close);
 
   do_piping (pipe_in, pipe_out);
 
   if (do_redirections (redirects, RX_ACTIVE) != 0)
+#if defined (HAVE_WORKING_FORK)
     exit (EXECUTION_FAILURE);
+#else  /* !HAVE_WORKING_FORK */
+    {
+      nofork_wait_status = (EXECUTION_FAILURE);
+      nofork_restore_all_environment (&oldenvbuf);
+      return;
+    }
+#endif /* !HAVE_WORKING_FORK */
 
   if (builtin)
     {
       /* Give builtins a place to jump back to on failure,
 	 so we don't go back up to main(). */
       result = setjmp_nosigs (top_level);
 
+#if defined (HAVE_WORKING_FORK)
       /* Give the return builtin a place to jump to when executed in a subshell
          or pipeline */
       funcvalue = 0;
       if (return_catch_flag && builtin == return_builtin)
         funcvalue = setjmp_nosigs (return_catch);
@@ -4954,10 +5215,28 @@ execute_subshell_builtin_or_function (wo
     {
       r = execute_function (var, words, flags, fds_to_close, async, 1);
       fflush (stdout);
       sh_exit (r);
     }
+#else  /* !HAVE_WORKING_FORK */
+      if (result == EXITPROG)
+	nofork_wait_status = (last_command_exit_value);
+      else if (result)
+	nofork_wait_status = (EXECUTION_FAILURE);
+      else
+	{
+	  r = execute_builtin (builtin, words, flags, 1);
+	  if (r == EX_USAGE)
+	    r = EX_BADUSAGE;
+	  nofork_wait_status = r;
+	}
+    }
+  else
+    nofork_wait_status = (execute_function (var, words, flags, fds_to_close, async, 1));
+  /* restore fd, jmp_buf, current directory, global variables */
+  nofork_restore_all_environment (&oldenvbuf);
+#endif /* !HAVE_WORKING_FORK */
 }
 
 /* Execute a builtin or function in the current shell context.  If BUILTIN
    is non-null, it is the builtin command to execute, otherwise VAR points
    to the body of a function.  WORDS are the command's arguments, REDIRECTS
@@ -5142,10 +5421,13 @@ execute_disk_command (words, redirects,
   char *pathname, *command, **args;
   int nofork, stdpath, result;
   pid_t pid;
   SHELL_VAR *hookf;
   WORD_LIST *wl;
+#if !defined (HAVE_WORKING_FORK)
+  int ofds[3] = { -1, -1, -1 };
+#endif /* !HAVE_WORKING_FORK */
 
   stdpath = (cmdflags & CMD_STDPATH);	/* use command -p path */
   nofork = (cmdflags & CMD_NO_FORK);	/* Don't fork, just exec, if no pipes */
   pathname = words->word->word;
 
@@ -5177,19 +5459,37 @@ execute_disk_command (words, redirects,
 
   /* We have to make the child before we check for the non-existence
      of COMMAND, since we want the error messages to be redirected. */
   /* If we can get away without forking and there are no pipes to deal with,
      don't bother to fork, just directly exec the command. */
+#if defined (HAVE_WORKING_FORK)
   if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE)
     pid = 0;
   else
     pid = make_child (savestring (command_line), async);
+#else  /* !HAVE_WORKING_FORK */
+  if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE)
+    pid = nofork_current_pid;
+  else
+    {
+      pid = make_child (savestring (command_line), async);
+      nofork_save_std_fds (ofds);
+    }
+#endif /* !HAVE_WORKING_FORK */
 
+#if defined (HAVE_WORKING_FORK)
   if (pid == 0)
+#else  /* !HAVE_WORKING_FORK */
+  if (pid)
+#endif /* !HAVE_WORKING_FORK */
     {
       int old_interactive;
+#if !defined (HAVE_WORKING_FORK)
+      int old_subshell_environment = subshell_environment;
+#endif /* !HAVE_WORKING_FORK */
 
+#if defined (HAVE_WORKING_FORK)
       reset_terminating_signals ();	/* XXX */
       /* Cancel traps, in trap.c. */
       restore_original_signals ();
 
       CHECK_SIGTERM;
@@ -5203,10 +5503,11 @@ execute_disk_command (words, redirects,
 		pipe_in == NO_PIPE &&
 		(stdin_redirects (redirects) == 0))
 	    async_redirect_stdin ();
 	  setup_async_signals ();
 	}
+#endif /* HAVE_WORKING_FORK */
 
       /* This functionality is now provided by close-on-exec of the
 	 file descriptors manipulated by redirection and piping.
 	 Some file descriptors still need to be closed in all children
 	 because of the way bash does pipes; fds_to_close is a
@@ -5227,11 +5528,16 @@ execute_disk_command (words, redirects,
 #if defined (PROCESS_SUBSTITUTION)
 	  /* Try to remove named pipes that may have been created as the
 	     result of redirections. */
 	  unlink_fifo_list ();
 #endif /* PROCESS_SUBSTITUTION */
+#if defined (HAVE_WORKING_FORK)
 	  exit (EXECUTION_FAILURE);
+#else  /* !HAVE_WORKING_FORK */
+	  nofork_wait_status = (EXECUTION_FAILURE);
+	  goto return_exit;
+#endif /* !HAVE_WORKING_FORK */
 	}
 
       if (async)
 	interactive = old_interactive;
 
@@ -5241,62 +5547,102 @@ execute_disk_command (words, redirects,
 	  if (hookf == 0)
 	    {
 	      /* Make sure filenames are displayed using printable characters */
 	      pathname = printable_filename (pathname, 0);
 	      internal_error (_("%s: command not found"), pathname);
+#if defined (HAVE_WORKING_FORK)
 	      exit (EX_NOTFOUND);	/* Posix.2 says the exit status is 127 */
+#else  /* !HAVE_WORKING_FORK */
+	  nofork_wait_status = (EX_NOTFOUND);
+	  goto return_exit;
+#endif /* !HAVE_WORKING_FORK */
 	    }
 
 #if defined (JOB_CONTROL)
 	  /* May need to reinitialize more of the job control state here. */
 	  kill_current_pipeline ();
 #endif
 
 	  wl = make_word_list (make_word (NOTFOUND_HOOK), words);
+#if defined (HAVE_WORKING_FORK)
 	  exit (execute_shell_function (hookf, wl));
+#else  /* !HAVE_WORKING_FORK */
+#if 0
+// TO BE DONE!!!!!!!!!!
+ 	  exit (execute_shell_function (hookf, wl));
+#else
+printf("exit (execute_shell_function (hookf, wl));\n");
+printf("%s: %d\n", __FUNCTION__, __LINE__);
+#endif
+	  nofork_wait_status = (EX_NOTFOUND);
+	  goto return_exit;
+#endif /* !HAVE_WORKING_FORK */
 	}
 
       CHECK_SIGTERM;
 
+#if defined (__DJGPP__)
+     if (path_expand)
+       expand_argv_words (words);
+#endif /* __DJGPP__ */
+
       /* Execve expects the command name to be in args[0].  So we
 	 leave it there, in the same format that the user used to
 	 type it in. */
       args = strvec_from_word_list (words, 0, 0, (int *)NULL);
+#if defined (HAVE_WORKING_FORK)
       exit (shell_execve (command, args, export_env));
+#else  /* !HAVE_WORKING_FORK */
+      nofork_wait_status = shell_execve (command, args, export_env);
+      free (args);
+return_exit:
+      nofork_restore_std_fds (ofds);
+
+      /* for parent shell */
+      if (nofork && pid == nofork_current_pid)
+        goto disk_command_nofork;
+
+      /* restore parent environment */
+      subshell_environment = old_subshell_environment;
+      return (result);
     }
   else
     {
+#endif /* !HAVE_WORKING_FORK */
 parent_return:
       QUIT;
 
       /* Make sure that the pipes are closed in the parent. */
       close_pipes (pipe_in, pipe_out);
 #if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
       if (variable_context == 0)
         unlink_fifo_list ();
 #endif
+#if defined (__MSDOS__)
+disk_command_nofork:
+#endif /* __MSDOS__ */
       FREE (command);
       return (result);
     }
 }
 
 /* CPP defines to decide whether a particular index into the #! line
    corresponds to a valid interpreter name or argument character, or
    whitespace.  The MSDOS define is to allow \r to be treated the same
    as \n. */
 
-#if !defined (MSDOS)
+#if !defined (__MSDOS__)
 #  define STRINGCHAR(ind) \
     (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n')
 #  define WHITECHAR(ind) \
     (ind < sample_len && whitespace (sample[ind]))
-#else	/* MSDOS */
+#else	/* __MSDOS__ */
 #  define STRINGCHAR(ind) \
     (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n' && sample[ind] != '\r')
 #  define WHITECHAR(ind) \
     (ind < sample_len && whitespace (sample[ind]))
-#endif	/* MSDOS */
+#endif	/* __MSDOS__ */
 
 static char *
 getinterp (sample, sample_len, endp)
      char *sample;
      int sample_len, *endp;
@@ -5414,11 +5760,19 @@ initialize_subshell ()
      sourced file with a temporary environment supplied to the `source/.'
      builtin.  Such variables are not supposed to be exported (empirical
      testing with sh and ksh).  Just throw it away; don't worry about a
      memory leak. */
   if (vc_isbltnenv (shell_variables))
+#if defined (HAVE_WORKING_FORK)
     shell_variables = shell_variables->down;
+#else  /* !HAVE_WORKING_FORK */
+    {
+      VAR_CONTEXT *sv = shell_variables;
+      shell_variables = shell_variables->down;
+      dispose_var_context (shell_variables);
+    }
+#endif /* !HAVE_WORKING_FORK */
 
   clear_unwind_protect_list (0);
   /* XXX -- are there other things we should be resetting here? */
   parse_and_execute_level = 0;		/* nothing left to restore it */
 
@@ -5465,11 +5819,19 @@ shell_execve (command, args, env)
   int larray, i, fd;
   char sample[HASH_BANG_BUFSIZ];
   int sample_len;
 
   SETOSTYPE (0);		/* Some systems use for USG/POSIX semantics */
+#if defined (HAVE_WORKING_FORK)
   execve (command, args, env);
+#else  /* !HAVE_WORKING_FORK */
+  {
+    int status = bash_spawnve (command, args, env);
+    if (status > -1)
+      return status;
+  }
+#endif /* !HAVE_WORKING_FORK */
   i = errno;			/* error from execve() */
   CHECK_TERMSIG;
   SETOSTYPE (1);
 
   /* If we get to this point, then start checking out the file.
@@ -5563,14 +5925,17 @@ shell_execve (command, args, env)
 
   /* We have committed to attempting to execute the contents of this file
      as shell commands. */
 
   reset_parser ();
+#if defined (HAVE_WORKING_FORK)
   initialize_subshell ();
 
   set_sigint_handler ();
+#endif /* HAVE_WORKING_FORK */
 
+#if defined (HAVE_WORKING_FORK)
   /* Insert the name of this shell into the argument list. */
   larray = strvec_len (args) + 1;
   args = strvec_resize (args, larray + 1);
 
   for (i = larray - 1; i; i--)
@@ -5580,10 +5945,11 @@ shell_execve (command, args, env)
   args[1] = command;
   args[larray] = (char *)NULL;
 
   if (args[0][0] == '-')
     args[0]++;
+#endif /* HAVE_WORKING_FORK */
 
 #if defined (RESTRICTED_SHELL)
   if (restricted)
     change_flag ('r', FLAG_OFF);
 #endif
@@ -5594,10 +5960,11 @@ shell_execve (command, args, env)
       for (i = 1; i < subshell_argc; i++)
 	free (subshell_argv[i]);
       free (subshell_argv);
     }
 
+#if defined (HAVE_WORKING_FORK)
   dispose_command (currently_executing_command);	/* XXX */
   currently_executing_command = (COMMAND *)NULL;
 
   subshell_argc = larray;
   subshell_argv = args;
@@ -5609,10 +5976,37 @@ shell_execve (command, args, env)
   clear_fifo_list ();	/* pipe fds are what they are now */
 #endif
 
   sh_longjmp (subshell_top_level, 1);
   /*NOTREACHED*/
+#else  /* !HAVE_WORKING_FORK */
+  {
+    /* Insert the name of this shell into the argument list.
+       It is necessary to copy the argument list or
+       freeing it will fail in the caller function. */
+    int status;
+    char **args_with_sh_name;
+    larray = strvec_len (args) + 1;
+    args_with_sh_name = strvec_create (larray + 1);
+
+    args_with_sh_name[0] = shell_name;
+    for (int src_idx = 0, dst_idx = 1; dst_idx < larray; src_idx = dst_idx++)
+      args_with_sh_name[dst_idx] = args[src_idx];
+    args_with_sh_name[larray] = (char *)NULL;
+
+    if (args_with_sh_name[0][0] == '-')
+      args_with_sh_name[0]++;
+
+    status = bash_spawnve (shell_name, args_with_sh_name, env);
+
+    for (i = 0; i < larray; i++)
+      args_with_sh_name[i] = NULL;  // do not free multiple times!!!
+    free (args_with_sh_name);
+
+    return status;
+  }
+#endif /* !HAVE_WORKING_FORK */
 }
 
 static int
 execute_intern_function (name, funcdef)
      WORD_DESC *name;
diff -aprNU5 bash-4.4.orig/findcmd.c bash-4.4/findcmd.c
--- bash-4.4.orig/findcmd.c	2016-03-19 17:05:46 +0000
+++ bash-4.4/findcmd.c	2023-03-04 22:07:36 +0000
@@ -42,10 +42,14 @@
 #include "hashlib.h"
 #include "pathexp.h"
 #include "hashcmd.h"
 #include "findcmd.h"	/* matching prototypes and declarations */
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#endif
+
 #include <glob/strmatch.h>
 
 #if !defined (errno)
 extern int errno;
 #endif
@@ -340,10 +344,13 @@ search_for_command (pathname, flags)
      int flags;
 {
   char *hashed_file, *command, *pathlist;
   int temp_path, st;
   SHELL_VAR *path;
+#if defined (__DJGPP__)
+  int bin_cmd = 0;
+#endif /* __DJGPP__ */
 
   hashed_file = command = (char *)NULL;
 
   /* If PATH is in the temporary environment for this command, don't use the
      hash table to search for the full pathname. */
@@ -354,10 +361,19 @@ search_for_command (pathname, flags)
      that is already completely specified or if we're using a command-
      specific value for PATH. */
   if (temp_path == 0 && absolute_program (pathname) == 0)
     hashed_file = phash_search (pathname);
 
+#if defined (__DJGPP__)
+  if (strncmp (pathname, "/bin/", 5) == 0)
+    {
+      bin_cmd = 1;
+      if (path == 0 && !hashed_file)
+        hashed_file = phash_search (pathname);
+    }
+#endif /* __DJGPP__ */
+
   /* If a command found in the hash table no longer exists, we need to
      look for it in $PATH.  Thank you Posix.2.  This forces us to stat
      every command found in the hash table. */
 
   if (hashed_file && (posixly_correct || check_hashed_filenames))
@@ -371,14 +387,43 @@ search_for_command (pathname, flags)
 	}
     }
 
   if (hashed_file)
     command = hashed_file;
+#if defined (__DJGPP__)
+  else if (bin_cmd)
+    {
+      char *base;
+      command = find_absolute_program (pathname, FS_NODIRS | FS_EXISTS);
+      if (command)
+        return command;
+      base = basename (pathname);
+      if (temp_path)
+        {
+          command = find_user_command_in_path (pathname, value_cell (path),
+                                               FS_EXEC_PREFERRED|FS_NODIRS);
+          if (tempvar_p (path))
+            dispose_variable (path);
+        }
+      else
+        command = find_user_command (base);
+      if (command && hashing_enabled && temp_path == 0)
+        phash_insert ((char *)pathname, command, dot_found_in_search, 1);
+
+      return command;
+    }
+  else if (absolute_program (pathname))
+    {
+      const char *path = find_extension (pathname);
+      return path ? savestring (path) : savestring (pathname);
+    }
+#else /* !__DJGPP__ */
   else if (absolute_program (pathname))
     /* A command containing a slash is not looked up in PATH or saved in
        the hash table. */
     command = savestring (pathname);
+#endif /* !__DJGPP__ */
   else
     {
       if (flags & CMDSRCH_STDPATH)
 	pathlist = conf_standard_path ();
       else if (temp_path || path)
@@ -498,10 +543,15 @@ static char *
 find_absolute_program (name, flags)
      const char *name;
      int flags;
 {
   int st;
+#if defined (__DJGPP__)
+  const char *path = find_extension (name);
+  if (path)
+    return (savestring (path));
+#endif /* __DJGPP__ */
 
   st = file_status (name);
 
   /* If the file doesn't exist, quit now. */
   if ((st & FS_EXISTS) == 0)
@@ -523,20 +573,33 @@ find_in_path_element (name, path, flags,
      int flags, name_len;
      struct stat *dotinfop;
 {
   int status;
   char *full_path, *xpath;
+#if defined (__DJGPP__)
+  const char *ext_path;
+#endif /* __DJGPP__ */
 
   xpath = (posixly_correct == 0 && *path == '~') ? bash_tilde_expand (path, 0) : path;
 
   /* Remember the location of "." in the path, in all its forms
      (as long as they begin with a `.', e.g. `./.') */
   if (dot_found_in_search == 0 && *xpath == '.')
     dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL);
 
+#if defined (__DJGPP__)
+  if ((ext_path = find_path_extension (xpath, name)))
+    full_path = sh_makepath (xpath, (char *)ext_path, 0);
+  else
+#endif /* __DJGPP__ */
   full_path = sh_makepath (xpath, name, 0);
 
+#if defined (__DJGPP__)
+  if (ext_path)
+    status = FS_EXISTS | FS_EXECABLE;
+  else
+#endif /* __DJGPP__ */
   status = file_status (full_path);
 
   if (xpath != path)
     free (xpath);
 
diff -aprNU5 bash-4.4.orig/general.c bash-4.4/general.c
--- bash-4.4.orig/general.c	2016-08-11 15:16:56 +0000
+++ bash-4.4/general.c	2023-03-04 22:07:36 +0000
@@ -46,10 +46,21 @@
 #  include <mbstr.h>		/* mbschr */
 #endif
 
 #include <tilde/tilde.h>
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#  include <dos.h>
+#endif /* __DJGPP__ */
+
+#if defined (__DJGPP__)
+#define PATHLISTSEP path_separator
+#else  /* !__DJGPP__ */
+#define PATHLISTSEP ':'
+#endif /* !__DJGPP__ */
+
 #if !defined (errno)
 extern int errno;
 #endif /* !errno */
 
 extern int expand_aliases;
@@ -570,10 +581,25 @@ check_binary_file (sample, sample_len)
      int sample_len;
 {
   register int i;
   unsigned char c;
 
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (sample_len >= 2)
+    {
+      /* Check for MZ EXE signature.  */
+      if (sample[0] == 'M' && sample[1] == 'Z')
+        return 1;
+
+#if defined (__DJGPP__)
+      /* Check for unstubbed COFF signature.  */
+      if (sample[0] == 0x4c && sample[1] == 0x01)
+        return 1;
+#endif /* __DJGPP__ */
+    }
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
   for (i = 0; i < sample_len; i++)
     {
       c = sample[i];
       if (c == '\n')
 	return (0);
@@ -711,10 +737,33 @@ char *
 make_absolute (string, dot_path)
      const char *string, *dot_path;
 {
   char *result;
 
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if ((string && string[1] == ':')
+      || is_dev_drive_path(string))
+    {
+      result = savestring (string);
+      return result;
+    }
+#if defined (__DJGPP__)
+  else if (ISDIRSEP(*string))
+    {
+      char drive;
+      char buffer[10];
+      unsigned int cur_drive;
+
+      _dos_getdrive(&cur_drive);
+      drive = cur_drive - 1 + 'a';
+      encode_drive_letter(buffer, drive);
+      result = sh_makepath (buffer, string + 1, 0);
+    }
+#endif /* __DJGPP__ */
+  else
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
   if (dot_path == 0 || ABSPATH(string))
 #ifdef __CYGWIN__
     {
       char pathbuf[PATH_MAX + 1];
 
@@ -741,11 +790,11 @@ base_pathname (string)
 #if 0
   if (absolute_pathname (string) == 0)
     return (string);
 #endif
 
-  if (string[0] == '/' && string[1] == 0)
+  if (ABSPATH(string) && string[1] == 0)
     return (string);
 
   p = (char *)strrchr (string, '/');
   return (p ? ++p : string);
 }
@@ -907,14 +956,14 @@ extract_colon_unit (string, 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] == ':')
+  if (i && string[i] == PATHLISTSEP)
     i++;
 
-  for (start = i; string[i] && string[i] != ':'; i++)
+  for (start = i; string[i] && string[i] != PATHLISTSEP; i++)
     ;
 
   *p_index = i;
 
   if (i == start)
diff -aprNU5 bash-4.4.orig/input.c bash-4.4/input.c
--- bash-4.4.orig/input.c	2015-09-24 23:49:22 +0000
+++ bash-4.4/input.c	2023-03-04 22:07:36 +0000
@@ -31,10 +31,14 @@
 
 #if defined (HAVE_UNISTD_H)
 #  include <unistd.h>
 #endif
 
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#  include <io.h>  /* for setmode.  */
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
 #include "bashansi.h"
 #include "bashintl.h"
 
 #include "command.h"
 #include "general.h"
@@ -372,11 +376,15 @@ duplicate_buffered_stream (fd1, fd2)
 
   return (fd2);
 }
 
 /* Return 1 if a seek on FD will succeed. */
-#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
+#if __DJGPP__
+#  define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0 && !isatty(fd))
+#else
+#  define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
+#endif
 
 /* Take FD, a file descriptor, and create and return a buffered stream
    corresponding to it.  If something is wrong and the file descriptor
    is invalid, return a NULL stream. */
 BUFFERED_STREAM *
@@ -394,10 +402,14 @@ fd_to_buffered_stream (fd)
     }
 
   size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
   if (size == 0)
     size = 1;
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (size > 1)
+    setmode (fd, O_BINARY);
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
   buffer = (char *)xmalloc (size);
 
   return (make_buffered_stream (fd, buffer, size));
 }
 
@@ -559,19 +571,19 @@ sync_buffered_stream (bfd)
 int
 buffered_getchar ()
 {
   CHECK_TERMSIG;
 
-#if !defined (DJGPP)
+#if !defined (__DJGPP__)
   return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
-#else
+#else  /* __DJGPP__ */
   /* On DJGPP, ignore \r. */
   int ch;
   while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
     ;
   return ch;
-#endif
+#endif /* __DJGPP__ */
 }
 
 int
 buffered_ungetchar (c)
      int c;
diff -aprNU5 bash-4.4.orig/nojobs.c bash-4.4/nojobs.c
--- bash-4.4.orig/nojobs.c	2016-08-04 19:34:32 +0000
+++ bash-4.4/nojobs.c	2023-03-04 22:07:36 +0000
@@ -48,10 +48,14 @@
 #include "execute_cmd.h"
 #include "trap.h"
 
 #include "builtins/builtext.h"	/* for wait_builtin */
 
+#if !defined (HAVE_WORKING_FORK)
+#  include "nofork.h"
+#endif /* !HAVE_WORKING_FORK */
+
 #define DEFAULT_CHILD_MAX 32
 
 #if defined (_POSIX_VERSION) || !defined (HAVE_KILLPG)
 #  define killpg(pg, sig)		kill(-(pg),(sig))
 #endif /* USG || _POSIX_VERSION */
@@ -487,17 +491,21 @@ siginterrupt (sig, flag)
 
 /* Fork, handling errors.  Returns the pid of the newly made child, or 0.
    COMMAND is just for remembering the name of the command; we don't do
    anything else with it.  ASYNC_P says what to do with the tty.  If
    non-zero, then don't give it away. */
+#if defined (HAVE_WORKING_FORK)
 pid_t
 make_child (command, async_p)
      char *command;
      int async_p;
 {
   pid_t pid;
   int forksleep;
+#if defined (HAVE_WAITPID)
+  int retry = 1;
+#endif /* HAVE_WAITPID */
 
   /* Discard saved memory. */
   if (command)
     free (command);
 
@@ -578,10 +586,48 @@ make_child (command, async_p)
 
       add_pid (pid, async_p);
     }
   return (pid);
 }
+#else  /* !HAVE_WORKING_FORK */
+pid_t
+make_child (command, async_p)
+     char *command;
+     int async_p;
+{
+  pid_t pid;
+
+  /* Discard saved memory. */
+  if (command)
+    free (command);
+
+  start_pipeline ();
+
+#if defined (BUFFERED_INPUT)
+  /* If default_buffered_input is active, we are reading a script.  If
+     the command is asynchronous, we have already duplicated /dev/null
+     as fd 0, but have not changed the buffered stream corresponding to
+     the old fd 0.  We don't want to sync the stream in this case. */
+  if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0))
+    sync_buffered_stream (default_buffered_input);
+#endif /* BUFFERED_INPUT */
+
+  /* Create the child, handle severe errors. */
+  pid = nofork_make_child_pid ();
+
+  last_made_pid = pid;
+
+  if (async_p)
+    last_asynchronous_pid = pid;
+
+  add_pid (pid, async_p);
+
+  nofork_current_pid = pid;
+  
+  return (pid);
+}
+#endif /* !HAVE_WORKING_FORK */
 
 void
 ignore_tty_job_signals ()
 {
 #if defined (SIGTSTP)
@@ -821,10 +867,11 @@ wait_for (pid)
      a child to exit.  The loop below does some of this, but not all. */
   wait_sigint_received = 0;
   if (interactive_shell == 0)
     old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
 
+#if defined (HAVE_WORKING_FORK)
   while ((got_pid = WAITPID (-1, &status, 0)) != pid) /* XXX was pid now -1 */
     {
       CHECK_TERMSIG;
       CHECK_WAIT_INTR;
       if (got_pid < 0 && errno == ECHILD)
@@ -842,10 +889,21 @@ wait_for (pid)
 	set_pid_status (got_pid, status);
     }
 
   if (got_pid > 0)
     set_pid_status (got_pid, status);
+#else  /* !HAVE_WORKING_FORK */
+  {
+    status = nofork_wait_status;
+    if ((status & 0x0000ff00) == 0x0000ff00)
+      status &= 0x000000ff;
+    errno = 0;
+    got_pid = pid;
+
+    last_made_pid = NO_PID;
+  }
+#endif /* !HAVE_WORKING_FORK */
 
 #if defined (HAVE_WAITPID)
   if (got_pid >= 0)
     reap_zombie_children ();
 #endif /* HAVE_WAITPID */
diff -aprNU5 bash-4.4.orig/parse.y bash-4.4/parse.y
--- bash-4.4.orig/parse.y	2016-09-11 15:31:46 +0000
+++ bash-4.4/parse.y	2023-03-04 22:07:36 +0000
@@ -67,13 +67,14 @@
 #  include <readline/history.h>
 #endif /* HISTORY */
 
 #if defined (JOB_CONTROL)
 #  include "jobs.h"
-#else
+#else  /* !JOB_CONTROL */
 extern int cleanup_dead_jobs __P((void));
-#endif /* JOB_CONTROL */
+extern int count_all_jobs __P((void));
+#endif /* !JOB_CONTROL */
 
 #if defined (ALIAS)
 #  include "alias.h"
 #else
 typedef void *alias_t;
@@ -89,10 +90,14 @@ typedef void *alias_t;
 #    include <sys/time.h>
 #  endif /* TM_IN_SYS_TIME */
 #  include "maxpath.h"
 #endif /* PROMPT_STRING_DECODE */
 
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#include "general.h"
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
 #define RE_READ_TOKEN	-99
 #define NO_EXPANSION	-100
 
 #ifdef DEBUG
 #  define YYDEBUG 1
@@ -5613,10 +5618,17 @@ decode_prompt_string (string)
 	      /* Try to quote anything the user can set in the file system */
 	      if (promptvars || posixly_correct)
 		temp = sh_backslash_quote_for_double_quotes (temp);
 	      else
 		temp = savestring (temp);
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+	      {
+	        char *dot = strchr (temp, '.');
+	        if (dot)
+	          *dot = '\0';
+	      }
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
 	      goto add_string;
 
 	    case 'v':
 	    case 'V':
 	      temp = (char *)xmalloc (16);
@@ -5662,11 +5674,11 @@ decode_prompt_string (string)
 #define ROOT_PATH(x)	((x)[0] == '/' && (x)[1] == 0)
 #define DOUBLE_SLASH_ROOT(x)	((x)[0] == '/' && (x)[1] == '/' && (x)[2] == 0)
 		/* Abbreviate \W as ~ if $PWD == $HOME */
 		if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, t_string) == 0))
 		  {
-		    if (ROOT_PATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0)
+		    if (ROOTEDPATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0)
 		      {
 			t = strrchr (t_string, '/');
 			if (t)
 			  memmove (t_string, t + 1, strlen (t));	/* strlen(t) to copy NULL */
 		      }
diff -aprNU5 bash-4.4.orig/print_cmd.c bash-4.4/print_cmd.c
--- bash-4.4.orig/print_cmd.c	2016-08-20 18:14:30 +0000
+++ bash-4.4/print_cmd.c	2023-03-04 22:07:36 +0000
@@ -38,11 +38,15 @@
 #include "bashansi.h"
 #include "bashintl.h"
 
 #include "shell.h"
 #include "flags.h"
+#if defined (__MSDOS__) && !defined (__DJGPP__)
+#include <y_tab.h>	/* use <...> so we pick it up from the build directory */
+#else  /* !__MSDOS__ */
 #include <y.tab.h>	/* use <...> so we pick it up from the build directory */
+#endif /* !__MSDOS__ */
 #include "input.h"
 
 #include "shmbutil.h"
 
 #include "builtins/common.h"
diff -aprNU5 bash-4.4.orig/redir.c bash-4.4/redir.c
--- bash-4.4.orig/redir.c	2023-03-04 21:19:30 +0000
+++ bash-4.4/redir.c	2023-03-04 22:07:36 +0000
@@ -58,10 +58,26 @@ extern int errno;
 #  include "input.h"
 #endif
 
 #define SHELL_FD_BASE	10
 
+#if !defined (__MSDOS__)
+#  define SHELL_FD_BASE	10
+#else  /* __MSDOS__ */
+#  define SHELL_FD_BASE   20
+#endif /* __MSDOS__ */
+
+#if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
+#  define HAS_LFN_SUPPORT(name)  (pathconf ((name), _PC_NAME_MAX) > 12)
+#else
+#  if defined (__MSDOS__)
+#    define HAS_LFN_SUPPORT(name)  (0)
+#  else  /* !__MSDOS__ */
+#    define HAS_LFN_SUPPORT(name)  (1)
+#  endif /* !__MSDOS__ */
+#endif
+
 int expanding_redir;
 
 extern int posixly_correct;
 extern int last_command_exit_value;
 extern int executing_builtin;
@@ -94,10 +110,17 @@ static REDIRECTEE rd;
 
 /* Set to errno when a here document cannot be created for some reason.
    Used to print a reasonable error message. */
 static int heredoc_errno;
 
+#ifdef O_TEMPORARY
+   /* File will be unlinked automatically,
+      else file must be unlinked explicitly.  */
+#  undef unlink
+#  define unlink(x) (0)
+#endif /* O_TEMPORARY */
+
 #define REDIRECTION_ERROR(r, e, fd) \
 do { \
   if ((r) < 0) \
     { \
       if (fd >= 0) \
@@ -458,11 +481,11 @@ here_document_to_fd (redirectee, ri)
      enum r_instruction ri;
 {
   char *filename;
   int r, fd, fd2;
 
-  fd = sh_mktmpfd ("sh-thd", MT_USERANDOM|MT_USETMPDIR, &filename);
+  fd = sh_mktmpfd (HAS_LFN_SUPPORT(".") ? "sh-thd" : "hd", MT_USERANDOM|MT_USETMPDIR, &filename);
 
   /* If we failed for some reason other than the file existing, abort */
   if (fd < 0)
     {
       FREE (filename);
@@ -475,19 +498,29 @@ here_document_to_fd (redirectee, ri)
   /* write_here_document returns 0 on success, errno on failure. */
   if (redirectee->word)
     r = (ri != r_reading_string) ? write_here_document (fd, redirectee)
 				 : write_here_string (fd, redirectee);
 
+#if defined (__MSDOS__)
+  if (r == ENOTTY)
+      errno = r = 0;
+#endif /* __MSDOS__ */
+
   if (r)
     {
       close (fd);
       unlink (filename);
       free (filename);
       errno = r;
       return (-1);
     }
 
+#if defined (__MSDOS__)
+  /* Commit here document to disk before opening again.  */
+  fsync (fd);
+#endif /* __MSDOS__ */
+
   /* In an attempt to avoid races, we close the first fd only after opening
      the second. */
   /* Make the document really temporary.  Also make it the input. */
   fd2 = open (filename, O_RDONLY|O_BINARY, 0600);
 
diff -aprNU5 bash-4.4.orig/shell.c bash-4.4/shell.c
--- bash-4.4.orig/shell.c	2016-05-06 15:23:42 +0000
+++ bash-4.4/shell.c	2023-03-04 22:07:36 +0000
@@ -39,10 +39,11 @@
 #include <errno.h>
 #include "filecntl.h"
 #if defined (HAVE_PWD_H)
 #  include <pwd.h>
 #endif
+#include <ctype.h>
 
 #if defined (HAVE_UNISTD_H)
 #  include <unistd.h>
 #endif
 
@@ -57,14 +58,14 @@
 #include "builtins.h"
 #include "builtins/common.h"
 
 #if defined (JOB_CONTROL)
 #include "jobs.h"
-#else
+#else  /* !JOB_CONTROL */
 extern int initialize_job_control __P((int));
 extern int get_tty_state __P((void));
-#endif /* JOB_CONTROL */
+#endif /* !JOB_CONTROL */
 
 #include "input.h"
 #include "execute_cmd.h"
 #include "findcmd.h"
 
@@ -87,10 +88,27 @@ extern int get_tty_state __P((void));
 
 #if defined (__OPENNT)
 #  include <opennt/opennt.h>
 #endif
 
+#if defined (__DJGPP__)
+/* DJGPP always uses its own pipe implementation.
+   Required to store the script name.  */
+#include "dospipe.h"
+#include "dospath.h"
+#include <termios.h>
+#include <sys/system.h>
+#endif /* __DJGPP__ */
+
+#if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
+#  define HAS_LFN_SUPPORT(name)  (pathconf ((name), _PC_NAME_MAX) > 12)
+#else
+#  if defined (__MSDOS__)
+#    define HAS_LFN_SUPPORT(name)  (0)
+#  endif /* __MSDOS__ */
+#endif
+
 #if !defined (HAVE_GETPW_DECLS)
 extern struct passwd *getpwuid ();
 #endif /* !HAVE_GETPW_DECLS */
 
 #if !defined (errno)
@@ -198,10 +216,15 @@ int have_devfd = HAVE_DEV_FD;
 int have_devfd = 0;
 #endif
 
 /* The name of the .(shell)rc file. */
 static char *bashrc_file = DEFAULT_BASHRC;
+#if defined (__MSDOS__)
+/* DOS filenames cannot begin with a '.' in a short filename environment.  */
+const char *def_bashrc_file = "~/.bashrc";
+char *dos_bashrc_file = "~/_bashrc";
+#endif /* __MSDOS__ */
 
 /* Non-zero means to act more like the Bourne shell on startup. */
 static int act_like_sh;
 
 /* Non-zero if this shell is being run by `su'. */
@@ -403,10 +426,17 @@ main (argc, argv, env)
 
 #ifdef __CYGWIN__
   _cygwin32_check_tmp ();
 #endif /* __CYGWIN__ */
 
+#if defined (__DJGPP__)
+  /* Save stat some effort.  */
+  _djstat_flags |= _STAT_INODE | _STAT_DIRSIZE;
+  save_cwd();
+  init_path_separator();
+#endif /* __DJGPP__ */
+
   /* Wait forever if we are debugging a login shell. */
   while (debugging_login_shell) sleep (3);
 
   set_default_locale ();
 
@@ -463,11 +493,11 @@ main (argc, argv, env)
 
   /* Parse argument flags from the input line. */
 
   /* Find full word arguments first. */
   arg_index = parse_long_options (argv, arg_index, argc);
-  
+
   if (want_initial_help)
     {
       show_shell_usage (stdout, 1);
       exit (EXECUTION_SUCCESS);
     }
@@ -536,10 +566,14 @@ main (argc, argv, env)
        isatty (fileno (stderr))))	/* error output is a terminal. */
     init_interactive ();
   else
     init_noninteractive ();
 
+#if !defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#define CLOSE_FDS_AT_LOGIN
+#endif /* !HAVE_DOS_BASED_FILE_SYSTEM */
+#if defined (CLOSE_FDS_AT_LOGIN)
   /*
    * Some systems have the bad habit of starting login shells with lots of open
    * file descriptors.  For instance, most systems that have picked up the
    * pre-4.0 Sun YP code leave a file descriptor open each time you call one
    * of the getpw* functions, and it's set to be open across execs.  That
@@ -550,10 +584,11 @@ main (argc, argv, env)
   if (login_shell && interactive_shell)
     {
       for (i = 3; i < 20; i++)
 	SET_CLOSE_ON_EXEC (i);
     }
+#endif /* CLOSE_FDS_AT_LOGIN */
 
   /* If we're in a strict Posix.2 mode, turn on interactive comments,
      alias expansion in non-interactive shells, and other Posix.2 things. */
   if (posixly_correct)
     {
@@ -1095,10 +1130,20 @@ run_startup_files ()
 	  maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
 #  else
 	  maybe_execute_file (SYS_BASHRC, 1);
 #  endif
 #endif
+#if defined (__MSDOS__)
+          /* Try _bashrc first.  */
+          if (strcmp (def_bashrc_file, bashrc_file) == 0)
+            if (maybe_execute_file (dos_bashrc_file, 1))
+              return;
+          /* Don't bother trying to read .bashrc in an SFN environment.  */
+          if (!HAS_LFN_SUPPORT("."))
+            return;
+          /* Now try .bashrc.  */
+#endif /* __MSDOS__ */
 	  maybe_execute_file (bashrc_file, 1);
 	  return;
 	}
     }
 
@@ -1126,15 +1171,29 @@ run_startup_files ()
 	 initialization files. */
       if (no_profile == 0)
 	{
 	  maybe_execute_file (SYS_PROFILE, 1);
 
+#if defined (__MSDOS__)
+          if (act_like_sh)
+            {
+              if (maybe_execute_file ("~/.profile", 1) == 0)
+                maybe_execute_file ("~/_profile", 1);
+            }
+	  else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) &&
+		   (maybe_execute_file ("~/_bprof", 1) == 0) &&
+		   (maybe_execute_file ("~/.bash_login", 1) == 0) &&
+		   (maybe_execute_file ("~/_blogin", 1) == 0) &&
+		   (maybe_execute_file ("~/.profile", 1) == 0))
+	    maybe_execute_file ("~/_profile", 1);
+#else  /* !__MSDOS__ */
 	  if (act_like_sh)	/* sh */
 	    maybe_execute_file ("~/.profile", 1);
 	  else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) &&
 		   (maybe_execute_file ("~/.bash_login", 1) == 0))	/* bash */
 	    maybe_execute_file ("~/.profile", 1);
+#endif /* !__MSDOS__ */
 	}
 
       sourced_login = 1;
     }
 
@@ -1162,15 +1221,29 @@ run_startup_files ()
 	     initialization files. */
 	  if (no_profile == 0)
 	    {
 	      maybe_execute_file (SYS_PROFILE, 1);
 
+#if defined (__MSDOS__)
+              if (act_like_sh)
+                {
+                  if (maybe_execute_file ("~/.profile", 1) == 0)
+                    maybe_execute_file ("~/_profile", 1);
+                }
+              else if ((maybe_execute_file ("~/.bash_profile", 1) == 0)
+                       && (maybe_execute_file ("~/_bprof", 1) == 0)
+                       && (maybe_execute_file ("~/.bash_login", 1) == 0)
+                       && (maybe_execute_file ("~/_blogin", 1) == 0)
+                       && (maybe_execute_file ("~/.profile", 1) == 0))
+                maybe_execute_file ("~/_profile", 1);
+#else  /* !__MSDOS__ */
 	      if (act_like_sh)	/* sh */
 		maybe_execute_file ("~/.profile", 1);
 	      else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) &&
 		       (maybe_execute_file ("~/.bash_login", 1) == 0))	/* bash */
 		maybe_execute_file ("~/.profile", 1);
+#endif /* !__MSDOS__ */
 	    }
 	}
 
       /* bash */
       if (act_like_sh == 0 && no_rc == 0)
@@ -1180,11 +1253,17 @@ run_startup_files ()
 	  maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
 #  else
 	  maybe_execute_file (SYS_BASHRC, 1);
 #  endif
 #endif
+#if defined (__MSDOS__)
+	  if ( (maybe_execute_file (bashrc_file, 1) == 0)
+	       && (strcmp (def_bashrc_file, bashrc_file) == 0))
+            maybe_execute_file (dos_bashrc_file, 1);
+#else  /* !__MSDOS__ */
 	  maybe_execute_file (bashrc_file, 1);
+#endif /* !__MSDOS__ */
 	}
       /* sh */
       else if (act_like_sh && privileged_mode == 0 && sourced_env++ == 0)
 	execute_env_file (get_string_value ("ENV"));
     }
@@ -1505,10 +1584,17 @@ open_shell_script (script_name)
       e = errno;
       file_error (filename);
       sh_exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT);
     }
 
+#if defined (__DJGPP__)
+  /*  For debugging purposes, store the script name executed.  */
+#if (DOS_PIPE_DEBUG - 1) == 0
+  bash_script_name = savestring (filename);
+#endif /* DOS_PIPE_DEBUG */
+#endif /* __DJGPP__ */
+
   free (dollar_vars[0]);
   dollar_vars[0] = exec_argv0 ? savestring (exec_argv0) : savestring (script_name);
   if (exec_argv0)
     {
       free (exec_argv0);
@@ -1697,14 +1783,23 @@ set_shell_name (argv0)
       if (*shell_name == '-')
 	shell_name++;
       login_shell = 1;
     }
 
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (islower (shell_name[0]) == 's' && islower (shell_name[1]) == 'h'
+      && (shell_name[2] == '.' || shell_name[2] == '\0'))
+    act_like_sh++;
+  if (islower (shell_name[0]) == 's' && islower (shell_name[1]) == 'u'
+      && (shell_name[2] == '.' || shell_name[2] == '\0'))
+    su_shell++;
+#else  /* !HAVE_DOS_BASED_FILE_SYSTEM */
   if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0')
     act_like_sh++;
   if (shell_name[0] == 's' && shell_name[1] == 'u' && shell_name[2] == '\0')
     su_shell++;
+#endif /* !HAVE_DOS_BASED_FILE_SYSTEM */
 
   shell_name = argv0 ? argv0 : PROGRAM;
   FREE (dollar_vars[0]);
   dollar_vars[0] = savestring (shell_name);
 
@@ -1765,10 +1860,16 @@ get_current_user_info ()
       entry = getpwuid (current_user.uid);
 #endif
       if (entry)
 	{
 	  current_user.user_name = savestring (entry->pw_name);
+#if defined (__DJGPP__)
+          /* Don't use a DOS shell for Unix work.  */
+          if (entry->pw_shell && _is_dos_shell(entry->pw_shell))
+            current_user.shell = make_posix_path_from_filename (get_real_path(shell_name));
+          else
+#endif /* __DJGPP__ */
 	  current_user.shell = (entry->pw_shell && entry->pw_shell[0])
 				? savestring (entry->pw_shell)
 				: savestring ("/bin/sh");
 	  current_user.home_dir = savestring (entry->pw_dir);
 	}
@@ -1842,11 +1943,13 @@ shell_initialize ()
 #else
   initialize_shell_variables (shell_environment, privileged_mode||running_setuid);
 #endif
 
   /* Initialize the data structures for storing and running jobs. */
+#if defined (JOB_CONTROL)
   initialize_job_control (jobs_m_flag);
+#endif /* JOB_CONTROL */
 
   /* Initialize input streams to null. */
   initialize_bash_input ();
 
   initialize_flags ();
diff -aprNU5 bash-4.4.orig/sig.c bash-4.4/sig.c
--- bash-4.4.orig/sig.c	2023-03-04 21:19:30 +0000
+++ bash-4.4/sig.c	2023-03-04 22:07:36 +0000
@@ -33,11 +33,11 @@
 #include <signal.h>
 
 #include "bashintl.h"
 
 #include "shell.h"
-#if defined (JOB_CONTROL)
+#if defined (JOB_CONTROL) || !defined (HAVE_WORKING_FORK)
 #include "jobs.h"
 #endif /* JOB_CONTROL */
 #include "siglist.h"
 #include "sig.h"
 #include "trap.h"
@@ -390,11 +390,15 @@ top_level_cleanup ()
 
 #if defined (PROCESS_SUBSTITUTION)
   unlink_fifo_list ();
 #endif /* PROCESS_SUBSTITUTION */
 
+#if defined (HAVE_WORKING_FORK)
   run_unwind_protects ();
+#else  /* !HAVE_WORKING_FORK */
+  run_unwind_frame ("subshell-execute-command");
+#endif /* !HAVE_WORKING_FORK */
   loop_level = continuing = breaking = funcnest = 0;
   executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
 }
 
 /* What to do when we've been interrupted, and it is safe to handle it. */
@@ -597,10 +601,17 @@ termsig_handler (sig)
   loop_level = continuing = breaking = funcnest = 0;
   executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
 
   run_exit_trap ();	/* XXX - run exit trap possibly in signal context? */
   set_signal_handler (sig, SIG_DFL);
+#if defined (__DJGPP__)
+  /* Fake a hardware exception. A software exception would just print a
+     long traceback.  */
+  if (sig == SIGINT)
+    __asm__ __volatile__ ("movb $0x79,%al;call ___djgpp_hw_exception");
+  else
+#endif /* __DJGPP__ */
   kill (getpid (), sig);
 }
 
 /* What we really do when SIGINT occurs. */
 sighandler
diff -aprNU5 bash-4.4.orig/subst.c bash-4.4/subst.c
--- bash-4.4.orig/subst.c	2023-03-04 21:19:30 +0000
+++ bash-4.4/subst.c	2023-03-04 22:07:36 +0000
@@ -65,10 +65,21 @@
 #include "builtins/builtext.h"
 
 #include <tilde/tilde.h>
 #include <glob/strmatch.h>
 
+#if !defined (HAVE_WORKING_FORK)
+#  include "nofork.h"
+#endif /* !HAVE_WORKING_FORK */
+
+#if defined (__DJGPP__)
+/* DJGPP always uses its own pipe implementation.
+   Required for close and pipe.  */
+
+#  include "dospipe.h"
+#endif /* __DJGPP__ */
+
 #if !defined (errno)
 extern int errno;
 #endif /* !errno */
 
 /* The size that strings change by. */
@@ -5734,10 +5745,13 @@ process_substitute (string, open_for_rea
   int fildes[2];
 #endif /* HAVE_DEV_FD */
 #if defined (JOB_CONTROL)
   pid_t old_pipeline_pgrp;
 #endif
+#if !defined (HAVE_WORKING_FORK)
+  OLDENVBUF oldenvbuf;
+#endif /* !HAVE_WORKING_FORK */
 
   if (!string || !*string || wordexp_only)
     return ((char *)NULL);
 
 #if !defined (HAVE_DEV_FD)
@@ -5772,11 +5786,15 @@ process_substitute (string, open_for_rea
   if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0)
     pipeline_pgrp = shell_pgrp;
   save_pipeline (1);
 #endif /* JOB_CONTROL */
 
+#if !defined (HAVE_WORKING_FORK)
+  nofork_save_all_environment (&oldenvbuf);
+#endif /* !HAVE_WORKING_FORK */
   pid = make_child ((char *)NULL, 1);
+#if defined (HAVE_WORKING_FORK)
   if (pid == 0)
     {
       reset_terminating_signals ();	/* XXX */
       free_pushed_string_input ();
       /* Cancel traps, in trap.c. */
@@ -5789,10 +5807,11 @@ process_substitute (string, open_for_rea
 	 temporary environment, but commands in the subshell should have
 	 access to their own temporary environment. */
       if (expanding_redir)
         flush_temporary_env ();
     }
+#endif /* HAVE_WORKING_FORK */
 
 #if defined (JOB_CONTROL)
   set_sigchld_handler ();
   stop_making_children ();
   /* XXX - should we only do this in the parent? (as in command subst) */
@@ -5807,15 +5826,25 @@ process_substitute (string, open_for_rea
       free (pathname);
 #if defined (HAVE_DEV_FD)
       close (parent_pipe_fd);
       close (child_pipe_fd);
 #endif /* HAVE_DEV_FD */
+#if !defined (HAVE_WORKING_FORK)
+      nofork_restore_all_environment (&oldenvbuf);
+#endif /* !HAVE_WORKING_FORK */
       return ((char *)NULL);
     }
 
+#if defined (HAVE_WORKING_FORK)
   if (pid > 0)
-    {
+#else  /* !HAVE_WORKING_FORK */
+  if (0)
+#endif /* !HAVE_WORKING_FORK */
+    {
+#if !defined (HAVE_WORKING_FORK)
+      process_substitute_parent:
+#endif /* !HAVE_WORKING_FORK */
 #if defined (JOB_CONTROL)
       if (last_procsub_child)
 	discard_last_procsub_child ();
       last_procsub_child = restore_pipeline (0);
 #endif
@@ -5852,11 +5881,17 @@ process_substitute (string, open_for_rea
       if (open_for_read_in_child)
 	sys_error (_("cannot open named pipe %s for reading"), pathname);
       else
 	sys_error (_("cannot open named pipe %s for writing"), pathname);
 
+#if defined (HAVE_WORKING_FORK)
       exit (127);
+#else  /* !HAVE_WORKING_FORK */
+      nofork_restore_all_environment (&oldenvbuf);
+      nofork_wait_status = 127;
+      goto process_substitute_exit;
+#endif /* !HAVE_WORKING_FORK */
     }
   if (open_for_read_in_child)
     {
       if (sh_unset_nodelay_mode (fd) < 0)
 	{
@@ -5875,11 +5910,17 @@ process_substitute (string, open_for_rea
 
   if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
     {
       sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
 	open_for_read_in_child ? 0 : 1);
+#if defined (HAVE_WORKING_FORK)
       exit (127);
+#else  /* !HAVE_WORKING_FORK */
+      nofork_restore_all_environment (&oldenvbuf);
+      nofork_wait_status = 127;
+      goto process_substitute_exit;
+#endif /* !HAVE_WORKING_FORK */
     }
 
   if (fd != (open_for_read_in_child ? 0 : 1))
     close (fd);
 
@@ -5917,11 +5958,21 @@ process_substitute (string, open_for_rea
   close (open_for_read_in_child ? 0 : 1);
 #endif /* !HAVE_DEV_FD */
 
   last_command_exit_value = result;
   result = run_exit_trap ();
+#if defined (HAVE_WORKING_FORK)
   exit (result);
+#else  /* !HAVE_WORKING_FORK */
+  nofork_wait_status = result;
+
+process_substitute_exit:
+  nofork_restore_all_environment (&oldenvbuf);
+
+  /* run parent side */
+  goto process_substitute_parent;
+#endif /* !HAVE_WORKING_FORK */
   /*NOTREACHED*/
 }
 #endif /* PROCESS_SUBSTITUTION */
 
 /***********************************/
@@ -6053,10 +6104,13 @@ command_substitute (string, quoted)
 {
   pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
   char *istring, *s;
   int result, fildes[2], function_value, pflags, rc, tflag;
   WORD_DESC *ret;
+#if !defined (HAVE_WORKING_FORK)
+  OLDENVBUF oldenvbuf;
+#endif /* !HAVE_WORKING_FORK */
 
   istring = (char *)NULL;
 
   /* Don't fork () if there is no need to.  In the case of no command to
      run, just return NULL. */
@@ -6106,13 +6160,17 @@ command_substitute (string, quoted)
     pipeline_pgrp = shell_pgrp;
   cleanup_the_pipeline ();
 #endif /* JOB_CONTROL */
 
   old_async_pid = last_asynchronous_pid;
+#if !defined (HAVE_WORKING_FORK)
+  nofork_save_all_environment (&oldenvbuf);
+#endif /* !HAVE_WORKING_FORK */
   pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
   last_asynchronous_pid = old_async_pid;
 
+#if defined (HAVE_WORKING_FORK)
   if (pid == 0)
     {
       /* Reset the signal handlers in the child, but don't free the
 	 trap strings.  Set a flag noting that we have to free the
 	 trap strings if we run trap to change a signal disposition. */
@@ -6123,10 +6181,11 @@ command_substitute (string, quoted)
 	  CLRINTERRUPT;		/* if we're ignoring SIGINT somehow */
 	}	
       QUIT;	/* catch any interrupts we got post-fork */
       subshell_environment |= SUBSHELL_RESETTRAP;
     }
+#endif /* HAVE_WORKING_FORK */
 
 #if defined (JOB_CONTROL)
   /* XXX DO THIS ONLY IN PARENT ? XXX */
   set_sigchld_handler ();
   stop_making_children ();
@@ -6137,21 +6196,28 @@ command_substitute (string, quoted)
 #endif /* JOB_CONTROL */
 
   if (pid < 0)
     {
       sys_error (_("cannot make child for command substitution"));
+#if !defined (HAVE_WORKING_FORK)
+      nofork_restore_all_environment (&oldenvbuf);
+#endif /* !HAVE_WORKING_FORK */
     error_exit:
 
       last_made_pid = old_pid;
 
       FREE (istring);
       close (fildes[0]);
       close (fildes[1]);
       return ((WORD_DESC *)NULL);
     }
 
+#if defined (HAVE_WORKING_FORK)
   if (pid == 0)
+#else  /* !HAVE_WORKING_FORK */
+  if (1)
+#endif /* !HAVE_WORKING_FORK */
     {
       /* The currently executing shell is not interactive. */
       interactive = 0;
 
       set_sigint_handler ();	/* XXX */
@@ -6163,13 +6229,20 @@ command_substitute (string, quoted)
       fpurge (stdout);
 
       if (dup2 (fildes[1], 1) < 0)
 	{
 	  sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
+#if defined (HAVE_WORKING_FORK)
 	  exit (EXECUTION_FAILURE);
+#else  /* !HAVE_WORKING_FORK */
+	  nofork_restore_all_environment (&oldenvbuf);
+	  nofork_wait_status = (EXECUTION_FAILURE);
+	  goto error_exit;
+#endif /* !HAVE_WORKING_FORK */
 	}
 
+#if defined (HAVE_WORKING_FORK)
       /* If standard output is closed in the parent shell
 	 (such as after `exec >&-'), file descriptor 1 will be
 	 the lowest available file descriptor, and end up in
 	 fildes[0].  This can happen for stdin and stderr as well,
 	 but stdout is more important -- it will cause no output
@@ -6181,10 +6254,11 @@ command_substitute (string, quoted)
 
       if ((fildes[0] != fileno (stdin)) &&
 	  (fildes[0] != fileno (stdout)) &&
 	  (fildes[0] != fileno (stderr)))
 	close (fildes[0]);
+#endif /* HAVE_WORKING_FORK */
 
 #ifdef __CYGWIN__
       /* Let stdio know the fd may have changed from text to binary mode, and
 	 make sure to preserve stdout line buffering. */
       freopen (NULL, "w", stdout);
@@ -6223,18 +6297,29 @@ command_substitute (string, quoted)
       startup_state = 2;	/* see if we can avoid a fork */
       /* Give command substitution a place to jump back to on failure,
 	 so we don't go back up to main (). */
       result = setjmp_nosigs (top_level);
 
+#if !defined (HAVE_WORKING_FORK)
+      /* return_catch and return_catch_flag will be restored
+         after call to nofork_restore_all_environment(). */
+      if (result == 0)
+        return_catch_flag = 0;
+#endif /* !HAVE_WORKING_FORK */
+
       /* If we're running a command substitution inside a shell function,
 	 trap `return' so we don't return from the function in the subshell
 	 and go off to never-never land. */
       if (result == 0 && return_catch_flag)
 	function_value = setjmp_nosigs (return_catch);
       else
 	function_value = 0;
 
+#if !defined (HAVE_WORKING_FORK)
+#undef exit
+#define exit(x) (nofork_wait_status = (x))
+#endif /* !HAVE_WORKING_FORK */
       if (result == ERREXIT)
 	rc = last_command_exit_value;
       else if (result == EXITPROG)
 	rc = last_command_exit_value;
       else if (result)
@@ -6247,28 +6332,44 @@ command_substitute (string, quoted)
 	  rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
 	  subshell_level--;
 	}
 
       last_command_exit_value = rc;
+#if !defined (HAVE_WORKING_FORK) && 0
+      /* The call of run_exit_trap has been disabled to avoid
+         that trap code is executed every time when a . (dot)
+         command is started.
+         May be there is a better way to solve this!!! */
       rc = run_exit_trap ();
+#endif /* !HAVE_WORKING_FORK */
 #if defined (PROCESS_SUBSTITUTION)
       unlink_fifo_list ();
 #endif
       exit (rc);
+#if !defined (HAVE_WORKING_FORK)
+#undef exit
+      nofork_restore_all_environment (&oldenvbuf);
+#endif /* !HAVE_WORKING_FORK */
+#if defined (HAVE_WORKING_FORK)
     }
   else
     {
+#endif /* HAVE_WORKING_FORK */
 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
       close_pgrp_pipe ();
 #endif /* JOB_CONTROL && PGRP_PIPE */
 
       close (fildes[1]);
 
       tflag = 0;
       istring = read_comsub (fildes[0], quoted, &tflag);
 
       close (fildes[0]);
+#if defined (__DJGPP__)
+      /* Required to trigger pipe file removal.  */
+      remove_pipe (fildes[0]);
+#endif /*__DJGPP__ */
 
       current_command_subst_pid = pid;
       last_command_exit_value = wait_for (pid);
       last_command_subst_pid = pid;
       last_made_pid = old_pid;
@@ -8853,11 +8954,14 @@ comsub:
 	  tdesc = command_substitute (temp, quoted);
 	  temp1 = tdesc ? tdesc->word : (char *)NULL;
 	  if (tdesc)
 	    dispose_word_desc (tdesc);
 	}
+#if defined (HAVE_WORKING_FORK)
+/* Already freed by parse_and_execute() when fork isn't available.  */
       FREE (temp);
+#endif /* HAVE_WORKING_FORK */
       temp = temp1;
       break;
 
     /* Do POSIX.2d9-style arithmetic substitution.  This will probably go
        away in a future bash release. */
diff -aprNU5 bash-4.4.orig/test.c bash-4.4/test.c
--- bash-4.4.orig/test.c	2016-06-14 14:33:00 +0000
+++ bash-4.4/test.c	2023-03-04 22:07:36 +0000
@@ -59,10 +59,14 @@ extern int errno;
 #include "test.h"
 #include "builtins/common.h"
 
 #include <glob/strmatch.h>
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#endif
+
 #if !defined (STRLEN)
 #  define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
 #endif
 
 #if !defined (STREQ)
@@ -531,11 +535,23 @@ unary_test (op, arg)
 
     case 'w':			/* File is writeable? */
       return (sh_eaccess (arg, W_OK) == 0);
 
     case 'x':			/* File is executable? */
+#if !defined (__DJGPP__)
       return (sh_eaccess (arg, X_OK) == 0);
+#else  /* __DJGPP__ */
+      {
+        int ret = access (arg, X_OK);
+        const char *path;
+        
+        if (ret == 0)
+          return (ret == 0);
+        path = find_extension (arg);
+        return (path != 0);
+      }
+#endif /* __DJGPP__ */
 
     case 'O':			/* File is owned by you? */
       return (sh_stat (arg, &stat_buf) == 0 &&
 	      (uid_t) current_user.euid == (uid_t) stat_buf.st_uid);
 
@@ -546,12 +562,24 @@ unary_test (op, arg)
     case 'N':
       return (sh_stat (arg, &stat_buf) == 0 &&
 	      stat_buf.st_atime <= stat_buf.st_mtime);
 
     case 'f':			/* File is a file? */
+#if !defined (__DJGPP__)
       if (sh_stat (arg, &stat_buf) < 0)
 	return (FALSE);
+#else  /* __DJGPP__ */
+      if (sh_stat (arg, &stat_buf) < 0)
+      {
+        if (test_finds_exe)
+          {
+            const char *path = find_one_extension (arg, "exe");
+            return (path != NULL);
+          }
+        return (FALSE);
+      }
+#endif /* __DJGPP__ */
 
       /* -f is true if the given file exists and is a regular file. */
 #if defined (S_IFMT)
       return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0);
 #else
diff -aprNU5 bash-4.4.orig/trap.c bash-4.4/trap.c
--- bash-4.4.orig/trap.c	2016-07-21 18:43:34 +0000
+++ bash-4.4/trap.c	2023-03-04 22:07:36 +0000
@@ -812,11 +812,15 @@ restore_default_signal (sig)
   /* If we aren't trapping this signal, don't bother doing anything else. */
   /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
      sentinel to determine whether or not disposition is reset to the default
      while the trap handler is executing. */
   if (((sigmodes[sig] & SIG_TRAPPED) == 0) &&
-      (sig != SIGCHLD || (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
+      (
+#if defined (SIGCHLD)
+       sig != SIGCHLD ||
+#endif /* SIGCHLD */
+         (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
     return;
 
   /* Only change the signal handler for SIG if it allows it. */
   if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
     set_signal_handler (sig, original_signals[sig]);
@@ -948,10 +952,14 @@ _run_trap_internal (sig, tag)
   HASH_TABLE *save_tempenv;
   sh_parser_state_t pstate;
 #if defined (ARRAY_VARS)
   ARRAY *ps;
 #endif
+#if !defined (HAVE_WORKING_FORK)
+  int old_subshell_exit_builtin;
+  extern int subshell_exit_builtin;
+#endif /* !HAVE_WORKING_FORK */
 
   trap_exit_value = function_code = 0;
   trap_saved_exit_value = last_command_exit_value;
   /* Run the trap only if SIG is trapped and not ignored, and we are not
      currently executing in the trap handler. */
@@ -976,10 +984,14 @@ _run_trap_internal (sig, tag)
       CLRINTERRUPT;
 
 #if defined (ARRAY_VARS)
       ps = save_pipestatus_array ();
 #endif
+#if !defined (HAVE_WORKING_FORK)
+      old_subshell_exit_builtin = subshell_exit_builtin; 
+      subshell_exit_builtin = 0;
+#endif /* !HAVE_WORKING_FORK */
 
       save_parser_state (&pstate);
       save_subst_varlist = subst_assign_varlist;
       subst_assign_varlist = 0;
       save_tempenv = temporary_env;
@@ -1020,10 +1032,13 @@ _run_trap_internal (sig, tag)
 #if defined (ARRAY_VARS)
       restore_pipestatus_array (ps);
 #endif
 
       temporary_env = save_tempenv;
+#if !defined (HAVE_WORKING_FORK)
+      subshell_exit_builtin = old_subshell_exit_builtin;
+#endif /* !HAVE_WORKING_FORK */
 
       sigmodes[sig] &= ~SIG_INPROGRESS;
       running_trap = 0;
       interrupt_state = old_int;
 
@@ -1350,5 +1365,27 @@ int
 signal_in_progress (sig)
      int sig;
 {
   return (sigmodes[sig] & SIG_INPROGRESS);
 }
+
+#if !defined (HAVE_WORKING_FORK)
+/* Static variables wrapper. */
+int
+get_signal_modes (int sig)
+{
+  if (sig < 0 || sig >= NSIG)
+    return -1;
+  return sigmodes[sig];
+}
+
+int
+set_signal_modes (int sig, int modes)
+{
+  int oldmodes;
+  if (sig < 0 || sig >= NSIG)
+    return -1;
+  oldmodes = sigmodes[sig];
+  sigmodes[sig] = modes;
+  return oldmodes;
+}
+#endif /* !HAVE_WORKING_FORK */
diff -aprNU5 bash-4.4.orig/unwind_prot.c bash-4.4/unwind_prot.c
--- bash-4.4.orig/unwind_prot.c	2015-04-27 18:43:06 +0000
+++ bash-4.4/unwind_prot.c	2023-03-04 22:07:36 +0000
@@ -37,10 +37,14 @@
 
 #if STDC_HEADERS
 #  include <stddef.h>
 #endif
 
+#if defined (__DJGPP__)
+#  include <stdio.h>
+#endif /* __DJGPP__ */
+
 #ifndef offsetof
 #  define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 #endif
 
 #include "command.h"
@@ -83,10 +87,18 @@ static void add_unwind_protect_internal
 static void remove_unwind_protect_internal __P((char *, char *));
 static void run_unwind_protects_internal __P((char *, char *));
 static void clear_unwind_protects_internal __P((char *, char *));
 static inline void restore_variable __P((SAVED_VAR *));
 static void unwind_protect_mem_internal __P((char *, char *));
+#if !defined (HAVE_WORKING_FORK)
+#  include "shell.h"
+#  include "execute_cmd.h"
+static void clear_unwind_protect_list_entry_internal __P((char *, char *));
+#endif /* !HAVE_WORKING_FORK */
+#if defined (__DJGPP__)
+static void dump_unwind_protect_list_internal __P((char *));
+#endif /* __DJGPP__ */
 
 static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
 
 /* Allocating from a cache of unwind-protect elements */
 #define UWCACHESIZE	128
@@ -213,10 +225,32 @@ unwind_protect_tag_on_stack (tag)
       elt = elt->head.next;
     }
   return 0;
 }
 
+#if !defined (HAVE_WORKING_FORK)
+void
+clear_unwind_protect_list_entry (entry)
+     void *entry;
+{
+  if (unwind_protect_list && entry)
+    without_interrupts
+      (clear_unwind_protect_list_entry_internal, entry, (char *)NULL);
+}
+#endif /* !HAVE_WORKING_FORK */
+
+#if defined (__DJGPP__)
+void
+dump_unwind_protect_list (file_name)
+     char *file_name;
+{
+  if (unwind_protect_list && file_name)
+    without_interrupts
+      (dump_unwind_protect_list_internal, file_name, (char *)NULL);
+}
+#endif /* __DJGPP__ */
+
 /* **************************************************************** */
 /*								    */
 /*			The Actual Functions		 	    */
 /*								    */
 /* **************************************************************** */
@@ -367,10 +401,36 @@ unwind_protect_mem (var, size)
      int size;
 {
   without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
 }
 
+#if !defined (HAVE_WORKING_FORK)
+void
+clear_unwind_protect_list_entry_internal (entry, ignore)
+     char *entry, *ignore;
+{
+  UNWIND_ELT *elt;
+
+  for (elt = unwind_protect_list; elt; elt = elt->head.next)
+    {
+      if (elt->head.cleanup == (Function *) dispose_words && (WORD_LIST *) elt->arg.v == (WORD_LIST *) entry
+          && ((WORD_LIST *) elt->arg.v)->next == 0xCFCFCFCF && ((WORD_LIST *) elt->arg.v)->word == 0xCFCFCFCF)
+        {
+          elt->arg.v = (WORD_LIST *)NULL;
+          break;
+        }
+      else
+      if (elt->head.cleanup == (Function *) dispose_fd_bitmap && (struct fd_bitmap *) elt->arg.v == (struct fd_bitmap *) entry
+          && ((struct fd_bitmap *) elt->arg.v)->size < 0 && ((struct fd_bitmap *) elt->arg.v)->bitmap == 0xCFCFCFCF)
+        {
+          elt->arg.v = (struct fd_bitmap *)NULL;
+          break;
+        }
+    }
+}
+#endif /* !HAVE_WORKING_FORK */
+
 #if defined (DEBUG)
 #include <stdio.h>
 
 void
 print_unwind_protect_tags ()
@@ -384,5 +444,62 @@ print_unwind_protect_tags ()
         fprintf(stderr, "tag: %s\n", elt->arg.v);
       elt = elt->head.next;
     }
 }
 #endif
+#if defined (__DJGPP__)
+void
+dump_unwind_protect_list_internal (file_name)
+     char *file_name;
+{
+  int i;
+  UNWIND_ELT *elt;
+  FILE *dump_file = fopen(file_name, "a");
+  if (!dump_file)
+    return;
+
+  for (i = 1, elt = unwind_protect_list; elt; elt = elt->head.next, i++)
+    {
+      fprintf(dump_file, "elt(%03i)                  = 0x%p\n"
+                         "elt->head.next            = 0x%p\n"
+                         "elt->head.cleanup         = 0x%p\n",
+                         i,
+                         (void *)elt,
+                         (void *)(elt->head).next,
+                         (void *)(elt->head).cleanup);
+      if (!elt->head.cleanup)
+        fprintf(dump_file, "--- stop here ---\n"
+                           "elt->arg.v (tag)          = %s\n"
+                           "elt->arg.uwp_head.next    = 0x%p (no function)\n"
+                           "elt->arg.uwp_head.cleanup = 0x%p (no function)\n",
+                           elt->arg.v,
+                           (void *)(elt->arg.uwp_head).next,
+                           (void *)(elt->arg.uwp_head).cleanup);
+      else if (elt->head.cleanup == (Function *) restore_variable)
+        fprintf(dump_file, "--- restore variable ---\n"
+                           "(Function *)elt->sv.uwp_head.cleanup(&elt->sv.v)\n"
+                           "elt->sv.v                 = 0x%p\n"
+                           "elt->sv.v.variable        = %s\n"
+                           "elt->sv.v.size            = %d\n"
+                           "elt->sv.uwp_head.next     = 0x%p\n"
+                           "elt->sv.uwp_head.cleanup  = 0x%p\n",
+                           &elt->sv,
+                           elt->sv.v.variable,
+                           elt->sv.v.size,
+                           (void *)elt->sv.uwp_head.next,
+                           (void *)elt->sv.uwp_head.cleanup);
+      else
+        fprintf(dump_file, "--- clean up ---\n"
+                           "(*(elt->arg.uwp_head.cleanup))(elt->arg.v)\n"
+                           "elt->arg.v                = 0x%p\n"
+                           "elt->arg.uwp_head.next    = 0x%p\n"
+                           "elt->arg.uwp_head.cleanup = 0x%p\n",
+                           (void *)elt->arg.v,
+                           (void *)elt->arg.uwp_head.next,
+                           (void *)elt->arg.uwp_head.cleanup);
+      fprintf(dump_file, "\n");
+    }
+  fprintf(dump_file, "\n################################################################################\n\n\n");
+
+  fclose(dump_file);
+}
+#endif /* __DJGPP__ */
diff -aprNU5 bash-4.4.orig/variables.c bash-4.4/variables.c
--- bash-4.4.orig/variables.c	2016-06-15 20:05:52 +0000
+++ bash-4.4/variables.c	2023-03-04 22:07:36 +0000
@@ -77,10 +77,18 @@
 
 #if defined (PROGRAMMABLE_COMPLETION)
 #  include "pcomplete.h"
 #endif
 
+#if defined (__DJGPP__)
+#  include "dospath.h"
+#endif /* __DJGPP__ */
+
+#if !defined (HAVE_WORKING_FORK)
+#  include "nofork.h"
+#endif /* !HAVE_WORKING_FORK */
+
 #define VARIABLES_HASH_BUCKETS	1024	/* must be power of two */
 #define FUNCTIONS_HASH_BUCKETS	512
 #define TEMPENV_HASH_BUCKETS	4	/* must be power of two */
 
 #define BASHFUNC_PREFIX		"BASH_FUNC_"
@@ -428,10 +436,14 @@ initialize_shell_variables (env, privmod
 	}
       else
 #  endif /* ARRAY_EXPORT */
 #endif
 	{
+#ifdef att_pathconv
+	  char *orig_string = string;
+	  int is_converted_path = try_init_path_var (name, &string);
+#endif
 	  ro = 0;
 	  if (posixly_correct && STREQ (name, "SHELLOPTS"))
 	    {
 	      temp_var = find_variable ("SHELLOPTS");
 	      ro = temp_var && readonly_p (temp_var);
@@ -445,10 +457,18 @@ initialize_shell_variables (env, privmod
 		VSETATTR (temp_var, (att_exported | att_imported));
 	      else
 		VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
 	      if (ro)
 		VSETATTR (temp_var, att_readonly);
+#ifdef att_pathconv
+          if (is_converted_path)
+	    {
+              VSETATTR (temp_var, att_pathconv);
+              if (orig_string != string)
+                free(string);
+	    }
+#endif
 	      array_needs_making = 1;
 	    }
 	}
 
       name[char_index] = '=';
@@ -578,11 +598,19 @@ initialize_shell_variables (env, privmod
   /* Set history variables to defaults, and then do whatever we would
      do if the variable had just been set.  Do this only in the case
      that we are remembering commands on the history list. */
   if (remember_on_history)
     {
-      name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
+#if !defined (__MSDOS__)
+#define SHHIST "~/_shhist"
+#define BHIST "~/_bhist"
+#else  /* !__MSDOS__ */
+#define SHHIST "~/.sh_history"
+#define BHIST "~/.bash_history"
+#endif /* !__MSDOS__ */
+
+      name = bash_tilde_expand (posixly_correct ? SHHIST : BHIST, 0);
 
       set_if_not ("HISTFILE", name);
       free (name);
     }
 #endif /* HISTORY */
@@ -695,10 +723,13 @@ set_home_var ()
   SHELL_VAR *temp_var;
 
   temp_var = find_variable ("HOME");
   if (temp_var == 0)
     temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
+#ifdef att_pathconv
+  VSETATTR (temp_var, att_pathconv);
+#endif
 #if 0
   VSETATTR (temp_var, att_exported);
 #endif
 }
 
@@ -888,10 +919,13 @@ set_pwd ()
       temp_string = get_working_directory ("shell-init");
       if (temp_string)
 	{
 	  temp_var = bind_variable ("PWD", temp_string, 0);
 	  set_auto_export (temp_var);
+#ifdef att_pathconv
+	  VSETATTR (temp_var, att_pathconv);
+#endif
 	  free (temp_string);
 	}
     }
 
   /* According to the Single Unix Specification, v2, $OLDPWD is an
@@ -901,10 +935,13 @@ set_pwd ()
   temp_var = find_variable ("OLDPWD");
   if (temp_var == 0 || value_cell (temp_var) == 0 || file_isdir (value_cell (temp_var)) == 0)
     {
       temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
       VSETATTR (temp_var, (att_exported | att_invisible));
+#ifdef att_pathconv
+      VSETATTR (temp_var, att_pathconv);
+#endif
     }
 }
 
 /* Make a variable $PPID, which holds the pid of the shell's parent.  */
 void
@@ -2690,10 +2727,16 @@ bind_variable_internal (name, value, tab
      int hflags, aflags;
 {
   char *newval, *tname;
   SHELL_VAR *entry, *tentry;
 
+#if !defined (HAVE_WORKING_FORK)
+#if NOFORK_COPY_ON_CHANGE
+  if (vc_copyonchange(global_variables) && !(name[0] == '_' && name[1] == '\0'))
+    copy_var_contexts_on_change();
+#endif
+#endif /* !HAVE_WORKING_FORK */
   entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
   /* Follow the nameref chain here if this is the global variables table */
   if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
     {
       entry = find_global_variable (entry->name);
@@ -3247,11 +3290,11 @@ assign_in_env (word, flags)
 /*								    */
 /*			Copying variables			    */
 /*								    */
 /* **************************************************************** */
 
-#ifdef INCLUDE_UNUSED
+#if defined (INCLUDE_UNUSED) || !defined (HAVE_WORKING_FORK)
 /* Copy VAR to a new data structure and return that structure. */
 SHELL_VAR *
 copy_variable (var)
      SHELL_VAR *var;
 {
@@ -3286,11 +3329,11 @@ copy_variable (var)
 
       copy->context = var->context;
     }
   return (copy);
 }
-#endif
+#endif /* !HAVE_WORKING_FORK */
 
 /* **************************************************************** */
 /*								    */
 /*		  Deleting and unsetting variables		    */
 /*								    */
@@ -4283,12 +4326,24 @@ make_env_array_from_var_list (vars)
 
       if (value)
 	{
 	  /* Gee, I'd like to get away with not using savestring() if we're
 	     using the cached exportstr... */
+#ifndef att_pathconv
 	  list[list_index] = USE_EXPORTSTR ? savestring (value)
 					   : mk_env_string (var->name, value, function_p (var));
+#else
+          if (USE_EXPORTSTR)
+            list[list_index] = savestring (value);
+          else
+            {
+              if (pathconv_p (var))
+                list[list_index] = export_path_var (var->name, value);
+              else
+                list[list_index] = mk_env_string (var->name, value, function_p (var));
+            }
+#endif
 
 	  if (USE_EXPORTSTR == 0)
 	    SAVE_EXPORTSTR (var, list[list_index]);
 
 	  list_index++;
@@ -5022,10 +5077,16 @@ static struct name_and_function special_
   { "histchars", sv_histchars },
 #endif /* HISTORY && BANG_HISTORY */
 
   { "ignoreeof", sv_ignoreeof },
 
+#if defined (__DJGPP__)
+  { "PATH_SEPARATOR", sv_path_separator },
+  { "TEST_FINDS_EXE", sv_test_finds_exe },
+  { "PATH_EXPAND", sv_path_expand },
+#endif
+
   { (char *)0, (sh_sv_func_t *)0 }
 };
 
 #define N_SPECIAL_VARS	(sizeof (special_vars) / sizeof (special_vars[0]) - 1)
 
@@ -5690,5 +5751,58 @@ sv_childmax (name)
   tt = get_string_value (name);
   s = (tt && *tt) ? atoi (tt) : 0;
   set_maxchild (s);
 }
 #endif
+
+#if defined (__DJGPP__)
+void
+sv_path_separator (char *name)
+{
+  char *p;
+  char old_path_separator = path_separator;
+  
+  p = get_string_value (name);
+  path_separator = ';';
+  if (p && *p)
+    {
+      if (*p == ':' || *p == ';')
+	path_separator = *p;
+    }
+
+  if (old_path_separator != path_separator)
+    {
+      if (path_separator == ':')
+        make_path_vars_bash();
+      else
+        make_path_vars_dos();
+    }
+}
+
+void
+sv_test_finds_exe (char *name)
+{
+  char *p;
+
+  p = get_string_value (name);
+  test_finds_exe = 0;
+  if (p && *p)
+    {
+      if (*p == 'y' || *p == 'Y')
+        test_finds_exe = 1;
+    }
+}
+
+void
+sv_path_expand (char *name)
+{
+  char *p;
+
+  path_expand = 0;
+  p = get_string_value (name);
+  if (p && *p)
+    {
+      if (*p == 'y' || *p == 'Y')
+        path_expand = 1;
+    }
+}
+#endif /* __DJGPP__ */

