Message-Id: <199909050447.EAA74932@out5.ibm.net> From: "Mark E." To: djgpp-workers AT delorie DOT com Date: Sun, 5 Sep 1999 00:47:00 -0400 MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Subject: Win 9X style long command lines X-mailer: Pegasus Mail for Win32 (v3.12a) Reply-To: djgpp-workers AT delorie DOT com Hi folks, Today I decided to try and see if I could get DJGPP to understand and generate Win 9X style long command lines. I didn't take too much work to get things working with my sample Win32 console programs. I know even if the changes are accepted they won't make DJGPP 2.03, so I list a first draft of the patch below in case anyone has any comments and to see if I should bother cleaning them up. *** dosexec.c.orig Tue Jun 29 11:50:10 1999 --- dosexec.c Sat Sep 4 21:06:22 1999 *************** extern size_t __PROXY_LEN; *** 148,154 **** transfer buffer will be overrun! */ static int direct_exec_tail(const char *program, const char *args, ! char * const envp[], const char *proxy, int lfn) { __dpmi_regs r; unsigned long program_la; --- 148,155 ---- transfer buffer will be overrun! */ static int direct_exec_tail(const char *program, const char *args, ! char * const envp[], const char *proxy, ! int lfn, int using_cmdline_var) { __dpmi_regs r; unsigned long program_la; *************** direct_exec_tail(const char *program, co *** 206,213 **** 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)); --- 207,215 ---- dosmemput(progname, proglen, program_la); /* The command-line tail. */ ! arg_header[0] = (!using_cmdline_var) ? strlen(args) : 127; 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)); *************** _dos_exec(const char *program, const cha *** 369,375 **** 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 char GO32_V2_STRING[] = "go32-v2.exe"; --- 371,377 ---- 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, 0); } static char GO32_V2_STRING[] = "go32-v2.exe"; *************** static int direct_exec(const char *progr *** 436,441 **** --- 438,444 ---- char *args, *argp; int need_quote = !__dosexec_in_system; int unescape_quote = __dosexec_in_system; + int using_cmdline_var = 0; /* PROGRAM can be a shell which expects a single argument (beyond the /c or -c switch) that is the entire command *************** static int direct_exec(const char *progr *** 458,464 **** 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++) { --- 461,471 ---- 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 + 1)); ! #endif argp = args; for (i=1; argv[i]; i++) { *************** static int direct_exec(const char *progr *** 503,514 **** *argp = 0; if (argp - args > CMDLEN_LIMIT) errno = E2BIG; 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) --- 510,570 ---- *argp = 0; if (argp - args > CMDLEN_LIMIT) + #if 0 errno = E2BIG; + #else + { + /* 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 in direct_exec_tail. + This method is understood by 32-bit Windows and 4DOS. + Others will just get the truncated command line. */ + + const char cmdline_str[] = "CMDLINE="; + const int cmdline_str_size = sizeof(cmdline_str) - 1; + + char *cmdline = alloca(arglen + 1); + + argp = cmdline; + strcpy(cmdline, cmdline_str); + argp += cmdline_str_size; + strcpy(argp, program); + argp += strlen(program); + + /* Build up a command line in a manner very similiar to + the method above. */ + for (i = 1; argv[i]; i++) + { + int quoted = 0; + const char *p = argv[i]; + + *argp++ = ' '; + if (need_quote && strpbrk(p, " \t") != 0) + { + *argp++ = '"'; + quoted = 1; + } + while (*p) + { + if (*p == '"' && (quoted || need_quote)) + *argp++ = '\\'; + else if (*p == '\\' && p[1] == '\'' && unescape_quote) + p++; + *argp++ = *p++; + } + if (quoted) + *argp++ = '"'; + } + *argp = 0; + putenv(cmdline); + using_cmdline_var = 1; + } + #endif 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, using_cmdline_var); } static int go32_exec(const char *program, char **argv, char **envp) *************** static int go32_exec(const char *program *** 695,701 **** else argv[0] = save_argv0; ! retval = direct_exec_tail(rpath, pcmd, envp, pproxy, lfn); if (proxy_cmdline) free(proxy_cmdline); return retval; --- 751,757 ---- else argv[0] = save_argv0; ! retval = direct_exec_tail(rpath, pcmd, envp, pproxy, lfn, 0); if (proxy_cmdline) free(proxy_cmdline); return retval; *************** __dosexec_command_exec(const char *progr *** 804,810 **** tbuf_beg = tbuf_ptr = __tb; tbuf_len = _go32_info_block.size_of_transfer_buffer; tbuf_end = tbuf_ptr + tbuf_len - 1; ! i = direct_exec_tail(comspec, cmdline, envp, 0, 2); return i; } --- 860,866 ---- tbuf_beg = tbuf_ptr = __tb; tbuf_len = _go32_info_block.size_of_transfer_buffer; tbuf_end = tbuf_ptr + tbuf_len - 1; ! i = direct_exec_tail(comspec, cmdline, envp, 0, 2, 0); return i; } *** c1args.c.orig Tue Jun 29 11:49:58 1999 --- c1args.c Sun Sep 5 00:34:38 1999 *************** __crt0_setup_arguments(void) *** 399,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. ** --- 399,436 ---- { char doscmd[128]; movedata(_stubinfo->psp_selector, 128, ds, (int)doscmd, 128); ! if ((doscmd[0] & 0x7f) != 127) ! 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 *cmdline = getenv("CMDLINE"); ! if (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); ! } ! else ! { ! abort(); ! } ! } } ! /* ** Check for !proxy. ** --- Mark Elbrecht, snowball3 AT bigfoot DOT com http://snowball.frogspace.net/