Mail Archives: djgpp-workers/1999/09/08/21:19:52
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 -