delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/09/08/21:19:52

Message-Id: <199909090114.BAA150418@out2.ibm.net>
From: "Mark E." <snowball3 AT bigfoot DOT com>
To: djgpp-workers AT delorie DOT com
Date: Wed, 8 Sep 1999 21:14:55 -0400
MIME-Version: 1.0
Subject: long command line patch v2
X-mailer: Pegasus Mail for Win32 (v3.12a)
Reply-To: djgpp-workers AT delorie DOT com

This is the second version of the patch that enables use of long command 
lines with Win32 and 4DOS. This version detects PE-COFF Win32 executables, 
and the 4DOS shell and it tries to detect a long cmdline capable of 
command.com.

*** src/libc/crt0/c1args.c.orig	Tue Jun 29 11:49:58 1999
--- src/libc/crt0/c1args.c	Sun Sep  5 16:16:44 1999
*************** __crt0_setup_arguments(void)
*** 398,408 ****
    */
    {
      char doscmd[128];
      movedata(_stubinfo->psp_selector, 128, ds, (int)doscmd, 128);
!     arglist = parse_bytes(doscmd+1, doscmd[0] & 0x7f,
! 			  (_crt0_startup_flags & _CRT0_FLAG_KEEP_QUOTES) == 0);
    }
!   
    /*
    ** Check for !proxy.
    **
--- 398,430 ----
    */
    {
      char doscmd[128];
+     char *cmdline;
+ 
      movedata(_stubinfo->psp_selector, 128, ds, (int)doscmd, 128);
!     if ((doscmd[0] & 0x7f) != 127 || ((cmdline = getenv("CMDLINE)) == NULL))
!       arglist = parse_bytes(doscmd + 1, doscmd[0] & 0x7f,
!                             (_crt0_startup_flags & _CRT0_FLAG_KEEP_QUOTES) == 0);
!     else
!     {
!       /* Command line is in the environment variable CMDLINE.  */
!       char stop_token;
! 
!       /* Skip over the name of the program.  */
!       if ((*cmdline == '\"') || (*cmdline == '\''))
!         stop_token = *cmdline;
!       else
!         stop_token = ' ';
! 
!       while (*cmdline != stop_token)
!         ++cmdline;
! 
!       ++cmdline; /* Skip over the stop token.  */
! 
!       arglist = parse_bytes(cmdline, strlen(cmdline),
!                             (_crt0_startup_flags & _CRT0_FLAG_KEEP_QUOTES) == 0);
!     }
    }
! 
    /*
    ** Check for !proxy.
    **
*** src/libc/dos/process/chkv2prg.c.orig	Thu Jul 22 12:59:50 1999
--- src/libc/dos/process/chkv2prg.c	Wed Sep  8 13:55:54 1999
*************** const _v2_prog_type *_check_v2_prog_inte
*** 77,83 ****
--- 77,107 ----
      char go32stub[9];
      unsigned long coff_start = (unsigned long)header[2]*512L;
      unsigned long exe_start;
+     unsigned long real_exe_start;
      type.exec_format = _V2_EXEC_FORMAT_EXE;
+ 
+     if (lseek(pf, 0x3c, SEEK_SET) != 0x3c)
+       return NULL;
+     if (read(pf, &real_exe_start, 4) != 4)
+       return NULL;
+ 
+     /* Detect if EXE is really a PE-COFF EXE.  */
+     if (real_exe_start != 0)
+     {
+       unsigned long magic;
+ 
+       if (lseek(pf, real_exe_start, SEEK_SET) != real_exe_start)
+         return NULL;
+       if (read(pf, &magic, 4) != 4)
+         return NULL;
+ 
+       if (magic == 0x00004550) /* PE */
+       {
+         type.object_format = _V2_OBJECT_FORMAT_PE_COFF;
+         return &type;
+       }
+     }
+ 
      if (header[1])
        coff_start += (long)header[1] - 512L;
      exe_start = (unsigned long)header[4]*16L;
*** src/libc/dos/process/dosexec.c.orig	Tue Jun 29 11:50:10 1999
--- src/libc/dos/process/dosexec.c	Wed Sep  8 19:34:42 1999
***************
*** 15,20 ****
--- 15,21 ----
  #include <go32.h>
  #include <dpmi.h>
  #include <ctype.h>
+ #include <dos.h>
  #include <sys/system.h>
  #include <sys/movedata.h>
  #include <libc/dosexec.h>
*************** direct_exec_tail(const char *program, co
*** 163,168 ****
--- 164,170 ----
    unsigned proglen;
    int i;
    unsigned long fcb1_la, fcb2_la, fname_la;
+   int arg_len;
  
    /* This used to just call sync().  But `sync' flushes the disk
       cache nowadays, and that can slow down the child tremendously,
*************** direct_exec_tail(const char *program, co
*** 206,215 ****
    dosmemput(progname, proglen, program_la);
  
    /* The command-line tail.  */
!   arg_header[0] = strlen(args);
    arg_header[1] = '\r';
    dosmemput(arg_header, 1, arg_la);
!   dosmemput(args, strlen(args), arg_la+1);
    dosmemput(arg_header+1, 1, arg_la+1+strlen(args));
  
    /* The 2 FCBs.  Some programs (like XCOPY from DOS 6.x) need them.  */
--- 208,222 ----
    dosmemput(progname, proglen, program_la);
  
    /* The command-line tail.  */
!   arg_len = strlen(args);
!   arg_header[0] = arg_len;
    arg_header[1] = '\r';
+ 
+   if (arg_len > 126)
+     arg_len = 126;
+ 
    dosmemput(arg_header, 1, arg_la);
!   dosmemput(args, arg_len, arg_la+1);
    dosmemput(arg_header+1, 1, arg_la+1+strlen(args));
  
    /* The 2 FCBs.  Some programs (like XCOPY from DOS 6.x) need them.  */
*************** static int direct_exec(const char *progr
*** 458,466 ****
    for (i=1; argv[i]; i++)
      arglen += 2*strlen(argv[i]) + 1 + 2;
  
!   args = (char *)alloca(arglen+1);
    argp = args;
!   for (i=1; argv[i]; i++)
    {
      int quoted = 0;
      const char *p = argv[i];
--- 465,477 ----
    for (i=1; argv[i]; i++)
      arglen += 2*strlen(argv[i]) + 1 + 2;
  
! #if 0
!   args = (char *)alloca(arglen + 1);
! #else
!   args = (char *)alloca((arglen <= CMDLEN_LIMIT) ? (arglen + 1) : (CMDLEN_LIMIT + 2));
! #endif
    argp = args;
!   for (i = 1; argv[i]; i++)
    {
      int quoted = 0;
      const char *p = argv[i];
*************** static int direct_exec(const char *progr
*** 511,516 ****
--- 522,617 ----
    return direct_exec_tail(program, args, envp, 0, 2);
  }
  
+ static int direct_pe_exec(const char *program, char **argv, char **envp)
+ {
+   int i, arglen;
+   char *args, *argp, *varp;
+   int need_quote = !__dosexec_in_system;
+   int unescape_quote = __dosexec_in_system;
+   const char cmdline_str[] = "CMDLINE=";
+   const unsigned int cmdline_str_len = sizeof(cmdline_str) - 1;
+ 
+   /* PROGRAM can be a shell which expects a single argument
+      (beyond the /c or -c switch) that is the entire command
+      line.  With some shells, we must NOT quote that command
+      line, because that will confuse the shell.
+ 
+      The hard problem is to know when PROGRAM names a shell
+      that doesn't like its command line quoted...  */
+ 
+   if (need_quote
+       && argv[1] && !strcmp (argv[1], "/c")
+       && argv[2] && !argv[3]
+       && _is_dos_shell (program))
+     need_quote = 0;
+ 
+   if (unescape_quote && _is_unixy_shell (program))
+     unescape_quote = 0;
+ 
+   arglen = 0;
+   for (i=1; argv[i]; i++)
+     arglen += 2*strlen(argv[i]) + 1 + 2;
+ 
+   varp = (char *)alloca(cmdline_str_len + arglen + 1);
+   strcpy(varp, cmdline_str);
+   args = varp + cmdline_str_len;
+ 
+   argp = args;
+   for (i = 1; argv[i]; i++)
+   {
+     int quoted = 0;
+     const char *p = argv[i];
+ 
+     *argp++ = ' ';
+     /* If invoked by `spawnXX' or `execXX' functions, we need to
+        quote arguments which include whitespace, so they end up
+        as a single argument on the child side.
+        We will invoke PROGRAM directly by DOS Exec function (not
+        through COMMAND.COM), therefore no need to quote characters
+        special only to COMMAND.COM.
+        We also assume that DJGPP programs aren't invoked through
+        here, so a single quote `\'' is also not special.  The only
+        programs other than DJGPP that treat a single quote specially
+        are Unix-like shells, but whoever uses them should know to
+        escape the quotes himself.  */
+     if (need_quote && strpbrk(p, " \t") != 0)
+     {
+       *argp++ = '"';
+       quoted = 1;
+     }
+     while (*p)
+     {
+       if (*p == '"' && (quoted || need_quote))
+ 	*argp++ = '\\';
+       /* Most non-DJGPP programs don't treat `\'' specially,
+ 	 but our `system' requires we always escape it, so
+ 	 we should undo the quoting here.  */
+       else if (*p == '\\' && p[1] == '\'' && unescape_quote)
+ 	p++;
+       *argp++ = *p++;
+     }
+     if (quoted)
+       *argp++ = '"';
+   }
+   *argp = 0;
+ 
+   if (argp - args > CMDLEN_LIMIT)
+   {
+     /* The command line is too long to pass directly. Put the entire
+        contents of the command line into the CMDLINE variable and
+        set the command line length to 127. direct_exec_tail will
+        take care of the final details. */
+ 
+     putenv(varp);
+     args[127] = 0;
+   }
+   
+   tbuf_beg = tbuf_ptr = __tb;
+   tbuf_len = _go32_info_block.size_of_transfer_buffer;
+   tbuf_end = tbuf_beg + tbuf_len - 1;
+   return direct_exec_tail(program, args, envp, 0, 2);
+ }
+ 
  static int go32_exec(const char *program, char **argv, char **envp)
  {
    const _v2_prog_type * type;
*************** static int go32_exec(const char *program
*** 545,552 ****
--- 646,658 ----
    if (!is_coff)
    {
      if (type->exec_format == _V2_EXEC_FORMAT_EXE)
+     {
+       if (type->object_format != _V2_OBJECT_FORMAT_PE_COFF)
          return direct_exec(program, argv, envp);
        else
+         return direct_pe_exec(program, argv, envp);
+     }
+     else
        return __dosexec_command_exec (program, argv, envp);
    }
  
*************** __dosexec_command_exec(const char *progr
*** 709,714 ****
--- 815,821 ----
    int cmdlen;
    int i;
    int was_quoted = 0;	/* was the program name quoted? */
+   int cmdline_len;
  
    /* Add spare space for possible quote characters.  */
    cmdlen = strlen(program) + 4 + 2;
*************** __dosexec_command_exec(const char *progr
*** 795,804 ****
      comspec = "c:\\command.com";
  
    /* FIXME: 126-char limit below isn't LFN-clean.  */
!   if (strlen(cmdline) > CMDLEN_LIMIT + 1)
    {
!     cmdline[CMDLEN_LIMIT+1] = '\0';
      errno = E2BIG;
    }
  
    tbuf_beg = tbuf_ptr = __tb;
--- 902,957 ----
      comspec = "c:\\command.com";
  
    /* FIXME: 126-char limit below isn't LFN-clean.  */
!   if ((cmdline_len = strlen(cmdline)) > CMDLEN_LIMIT + 1)
    {
!     static const char *comspec_cache = NULL;
!     static unsigned int cmdline_limit = 126;
! 
!     if (comspec != comspec_cache)
!     {
!       char *base;
!       comspec_cache = comspec;
! 
!       base = basename(comspec_cache);
! 
!       if ((stricmp (base, "command.com") == 0) && (_osmajor >= 7))
!         cmdline_limit = (unsigned int)(-1); /* No limit for MS-DOS 7.  */
!       else if ((stricmp (base, "4dos.com") == 0)
!                || (stricmp (base, "ndos.com") == 0))
!         cmdline_limit = 255; /* 255 char limit for [4N]DOS.  */
!       else
!         cmdline_limit = 126; /* 126 char limit otherwise.  */
!     }
! 
!     if (cmdline_len > cmdline_limit)
!     {
!       cmdline[CMDLEN_LIMIT + 1] = '\0';
        errno = E2BIG;
+     }
+     else
+     {
+       int comspec_len = strlen(comspec); 
+       char *cmdline_var = (char *)alloca(comspec_len + 1 + cmdline_len + 1);
+       char *ptr = cmdline_var;
+ 
+       /* Dump into CMDLINE the name of the shell to execute and the
+          entire command line.  */
+       strcpy(cmdline_var, "CMDLINE=");
+       ptr += sizeof("CMDLINE=") - 1;
+ 
+       strcpy(ptr, comspec);
+       ptr += comspec_len;
+ 
+       *ptr = ' ';
+       ++ptr;
+ 
+       strcpy (ptr, cmdline);
+ 
+       putenv (cmdline_var);
+       /* Set the command line to 127 characters long to signal
+          direct_exec_tail that it has a long command line.  */
+       cmdline[CMDLEN_LIMIT + 2] = '\0';
+     }
    }
  
    tbuf_beg = tbuf_ptr = __tb;
*** src/libc/ansi/stdlib/system.c.orig	Tue Jun 29 11:49:46 1999
--- src/libc/ansi/stdlib/system.c	Wed Sep  8 14:23:46 1999
***************
*** 15,20 ****
--- 15,21 ----
  #include <ctype.h>
  #include <errno.h>
  #include <process.h>
+ #include <dos.h>
  #include <libc/dosexec.h>
  #include <libc/unconst.h>
  #include <libc/file.h> /* for fileno() */
*************** _shell_command (const char *prog, const 
*** 92,101 ****
    }
    else if (_is_dos_shell (shell))
    {
!     char *cmd_tail = (char *)alloca (3 + strlen (prog) + 1
! 				     + strlen (cmdline) + 1);
      const char *s = prog;
      char *d = cmd_tail + 3;
  
      strcpy (cmd_tail, "/c ");
      while ((*d = *s++) != 0)
--- 93,103 ----
    }
    else if (_is_dos_shell (shell))
    {
!     int cmd_tail_alloc = 3 + strlen(prog) + 1 + strlen (cmdline) + 1;
!     char *cmd_tail = (char *)alloca(cmd_tail_alloc);
      const char *s = prog;
      char *d = cmd_tail + 3;
+     int cmd_tail_len;
  
      strcpy (cmd_tail, "/c ");
      while ((*d = *s++) != 0)
*************** _shell_command (const char *prog, const 
*** 113,126 ****
        strcpy (d, cmdline);
      }
  
!     /* [4N]DOS.COM can support upto 255 chars per command line.
!        They lose that feature here, because there's no simple
!        way to pass long command lines to DOS function 4Bh (Exec)
!        which `_dos_exec' summons.  */
!     if (strlen (cmd_tail) > 126)
      {
!       errno = E2BIG;
!       return emiterror ("Command line too long.", 0);
      }
      else
        return _dos_exec (shell, cmd_tail, environ);
--- 115,174 ----
        strcpy (d, cmdline);
      }
  
!     /* [4N]DOS.COM can support up to 255 chars per command line.
!        Win32 supports a much longer command line.  */
!     if ((cmd_tail_len = strlen (cmd_tail)) > 126)
      {
!       static unsigned int cmd_tail_limit = 0;
!       static char *shell_ptr = NULL;
! 
!       if (shell != shell_ptr)
!       {
!         char *base;
! 
!         shell_ptr = shell;
!         base = basename(shell_ptr);
! 
!         if ((stricmp(base, "command.com") == 0) && (_osmajor >= 7)
!             && (stricmp(_os_flavor, "ms-dos") == 0))
!           cmd_tail_limit = (unsigned int)(-1); /* No limit for MSDOS 7.  */
!         else if ((stricmp(base, "4dos.com") == 0)
!                  || (stricmp(base, "ndos.com") == 0))
!           cmd_tail_limit = 255; /* 255 char limit for [4N]DOS.  */
!         else
!           cmd_tail_limit = 126; /* 126 char limit otherwise.  */
!       }
! 
!       if (cmd_tail_len > cmd_tail_limit)
!       {
!         errno = E2BIG;
!         return emiterror ("Command line too long.", 0);
!       }
!       else
!       {
!         int shell_len = strlen (shell);
!         char *cmdline_var = (char *)alloca (shell_len + 1 + cmd_tail_len + 8);
!         char *ptr = cmdline_var;
! 
!         /* Dump into CMDLINE the shell to execute and the
!            entire command line.  */
!         strcpy(cmdline_var, "CMDLINE=");
!         ptr += sizeof("CMDLINE=") - 1;
! 
!         strcpy(ptr, shell);
!         ptr += shell_len;
! 
!         *ptr = ' ';
!         ++ptr;
! 
!         strcpy (ptr, cmd_tail);
! 
!         putenv (cmdline_var);
!         /* Set the command line to 127 characters long to signal
!            direct_exec_tail that it has a long command line.  */
!         cmd_tail[127] = '\0';
!         return _dos_exec (shell, cmd_tail, environ);
!       }
      }
      else
        return _dos_exec (shell, cmd_tail, environ);

--- 
Mark Elbrecht, snowball3 AT bigfoot DOT com
http://snowball.frogspace.net/

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019