Date: Mon, 16 Sep 1996 11:49:42 +0200 (IST) From: Eli Zaretskii To: djgpp-workers AT delorie DOT com Subject: Changes for `system' and `dosexec' Message-Id: Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII The changes below take care of a few minor problems: - the test for unixy or dos shell is now done in one place, and the functions which do that are exported, so these tests are consistent; - invoking a v1.x program is always done through !proxy, to prevent go32 from printing its copyright line; - a couple of executable extensions were added; - if the first character if the command line (ater removing the redirection constructs) is a left paren `(', the shell is called immediately (for the sake of those who use this feature of [4N]DOS); - the semi-colon `;' escaping is handled better. Don't be scared by the size of the diff: most of it is whitespace changes (because a block of code was removed, causeing a change in the indentation). ------------------------------------------------------------------------ *** src/libc/ansi/stdlib/system.c~8 Sat Sep 7 16:54:38 1996 --- src/libc/ansi/stdlib/system.c Sun Sep 15 16:38:42 1996 *************** _shell_command (const char *prog, const *** 85,178 **** the command interpreter and let the user type ``exit''. */ return _dos_exec (shell, "", environ); } ! else { ! char *p, *shellbase = shell; ! ! for (p = shell; *p; p++) ! if (*p == ':' || *p == '/' || *p == '\\') ! shellbase = p + 1; ! if (!stricmp (shellbase, "command.com") ! || !stricmp (shellbase, "4dos.com") ! || !stricmp (shellbase, "ndos.com")) { ! 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) ! { ! if (*d == '/') ! *d = '\\'; ! d++; ! } ! if (*cmdline) ! { ! if (*prog) ! *d++ = ' '; ! 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); } else ! { ! /* Assume this is a `sh' work-alike. What's below should ! work with `ms_sh'; others should be fine if they support ! the response file method (but I didn't test anything ! except `ms_sh'). */ ! FILE *respf; ! int e = errno; ! char *atfile = (char *) alloca (L_tmpnam); ! char *cmd_tail = (char *)alloca (L_tmpnam + 5); ! errno = 0; ! respf = fopen (tmpnam (atfile), "wb"); ! /* Note that the command line is written to the response file ! as a single (possibly long) line. The docs of `ms_sh' tells ! that when invoking other programs, it writes each argument ! on a separate line, but the shell itself doesn't seem to ! care when it gets everything as a single line. */ ! if (respf) ! { ! int retval; ! errno = e; ! if (*prog) ! { ! fputs (prog, respf); ! fputc (' ', respf); ! } ! fputs (cmdline, respf); ! fputc ('\n', respf); ! fclose (respf); ! strcpy (cmd_tail, "-c @"); ! strcat (cmd_tail, atfile); ! retval = _dos_exec (shell, cmd_tail, environ); ! remove (atfile); ! return retval; } ! else ! return emiterror ("Cannot open response file for SH", errno); } } } --- 85,167 ---- the command interpreter and let the user type ``exit''. */ return _dos_exec (shell, "", environ); } ! 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) { ! if (*d == '/') ! *d = '\\'; ! d++; ! } ! if (*cmdline) ! { ! if (*prog) ! *d++ = ' '; ! 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); ! } ! else ! { ! /* Assume this is a `sh' work-alike. What's below should ! work with `ms_sh'; others should be fine if they support ! the response file method (but I didn't test anything ! except `ms_sh'). */ ! FILE *respf; ! int e = errno; ! char *atfile = (char *) alloca (L_tmpnam); ! char *cmd_tail = (char *)alloca (L_tmpnam + 5); ! errno = 0; ! respf = fopen (tmpnam (atfile), "wb"); ! /* Note that the command line is written to the response file ! as a single (possibly long) line. The docs of `ms_sh' tells ! that when invoking other programs, it writes each argument ! on a separate line, but the shell itself doesn't seem to ! care when it gets everything as a single line. */ ! if (respf) ! { ! int retval; ! errno = e; ! if (*prog) ! { ! fputs (prog, respf); ! fputc (' ', respf); } ! fputs (cmdline, respf); ! fputc ('\n', respf); ! fclose (respf); ! strcpy (cmd_tail, "-c @"); ! strcat (cmd_tail, atfile); ! retval = _dos_exec (shell, cmd_tail, environ); ! remove (atfile); ! return retval; } + else + return emiterror ("Cannot open response file for SH", errno); } } *************** __unquote (char *to, const char *beg, co *** 385,391 **** s++; break; case '\\': ! if (s[1] == '"' || s[1] == '\'') s++; /* Fall-through. */ default: --- 374,382 ---- s++; break; case '\\': ! if (s[1] == '"' || s[1] == '\'' ! || (s[1] == ';' ! && (__system_flags & __system_allow_multiple_cmds))) s++; /* Fall-through. */ default: *************** get_sym (char *s, char **beg, char **end *** 456,462 **** --*end; return EOL; case '\\': ! if (s[1] == '"' || s[1] == '\'') s++; in_a_word = 1; break; --- 447,454 ---- --*end; return EOL; case '\\': ! if (s[1] == '"' || s[1] == '\'' ! || (s[1] == ';' && (sys_flags & __system_allow_multiple_cmds))) s++; in_a_word = 1; break; *************** system (const char *cmdline) *** 579,584 **** --- 571,580 ---- if (needcmd) { __unquote (prog, t, u); /* unquote and copy to prog */ + /* We can't grok commands in parentheses, so assume they + use a shell that knows about these, like 4DOS or `sh'. */ + if (prog[0] == '(') + return _shell_command ("", cmdline); strcpy (s, u); /* remove program name from cmdline */ needcmd = 0; } *** src/libc/dos/process/dosexec.c~1 Wed Sep 4 18:54:28 1996 --- src/libc/dos/process/dosexec.c Sun Sep 15 11:53:34 1996 *************** direct_exec_tail(const char *program, co *** 188,194 **** } else progname = program; ! if (!check_talloc(proglen + strlen(args) + 3 + sizeof(Execp) + 32)) return -1; program_la = talloc(proglen); arg_la = talloc(strlen(args)+3); --- 188,194 ---- } else progname = program; ! if (!check_talloc(proglen + strlen(args) + 3 + sizeof(Execp) + 48)) return -1; program_la = talloc(proglen); arg_la = talloc(strlen(args)+3); *************** direct_exec_tail(const char *program, co *** 252,259 **** parm_la -= tbuf_beg; program_la -= tbuf_beg; #endif - if (!check_talloc(0)) - return -1; /* The environment. Replace the !proxy variable, if there is one (for nested programs) if we are called from `system', --- 252,257 ---- *************** static const char *unix_shells[] = { *** 388,412 **** 0 }; static int direct_exec(const char *program, char **argv, char **envp) { int i, arglen; char *args, *argp; int need_quote = !__dosexec_in_system; int unescape_quote = __dosexec_in_system; - const char *ptail = program; - - { - const char *p = ptail; - - while (*p) - { - if (*p == '/' || *p == ':' || *p == '\\') - ptail = p + 1; - p++; - } - } - /* PROGRAM can be a shell which expects a single argument (beyond the /c or -c switch) that is the entire command --- 386,429 ---- 0 }; + static int + list_member (const char *program, const char *program_list[]) + { + const char *p = program, *ptail = program; + int i; + + while (*p) + { + if (*p == '/' || *p == ':' || *p == '\\') + ptail = p + 1; + p++; + } + + for (i = 0; program_list[i]; i++) + if (!stricmp (ptail, program_list[i])) + return 1; + + return 0; + } + + int + _is_unixy_shell (const char *shellpath) + { + return list_member (shellpath, unix_shells); + } + + int + _is_dos_shell (const char *shellpath) + { + return list_member (shellpath, shell_brokets); + } + static int direct_exec(const char *program, char **argv, char **envp) { int i, arglen; char *args, *argp; int need_quote = !__dosexec_in_system; int unescape_quote = __dosexec_in_system; /* 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 *** 416,444 **** 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]) ! { ! for (i = 0; shell_brokets[i]; i++) ! { ! if (!stricmp (ptail, shell_brokets[i])) ! { ! need_quote = 0; ! break; ! } ! } ! } ! if (unescape_quote) ! { ! for (i = 0; unix_shells[i]; i++) ! { ! if (!stricmp (ptail, unix_shells[i])) ! { ! unescape_quote = 0; ! break; ! } ! } ! } arglen = 0; for (i=1; argv[i]; i++) --- 433,446 ---- 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++) *************** static int go32_exec(const char *program *** 631,640 **** /* Construct the DOS command tail */ for (argc=0; argv[argc]; argc++); ! if (__dosexec_in_system) { ! /* If PROGRAM is an un-stubbed COFF, it must be passed in the ! command tail as well, since we call GO32 to run it. */ for (i = (is_stubbed ? 1 : 0); i < argc; i++) { const char *p = argv[i]; --- 633,642 ---- /* Construct the DOS command tail */ for (argc=0; argv[argc]; argc++); ! if (__dosexec_in_system && v2_0) { ! /* If PROGRAM is an un-stubbed COFF, its name must be passed ! in the command tail as well, since we call GO32 to run it. */ for (i = (is_stubbed ? 1 : 0); i < argc; i++) { const char *p = argv[i]; *************** static int go32_exec(const char *program *** 660,667 **** tbuf_end = tbuf_ptr + tbuf_len - 1; /* If called from `system' and we have a command line shorter ! than the DOS limit, we don't need to use !proxy at all. */ ! if (!__dosexec_in_system || cmdp - cmdline > CMDLEN_LIMIT) { if (!check_talloc(found_si ? si.struct_length : 0 --- 662,671 ---- tbuf_end = tbuf_ptr + tbuf_len - 1; /* If called from `system' and we have a command line shorter ! than the DOS limit, we don't need to use !proxy at all. ! Note that v1.x programs are always run through !proxy, ! to prevent go32.exe from printing its copyright line. */ ! if (!__dosexec_in_system || !v2_0 || cmdp - cmdline > CMDLEN_LIMIT) { if (!check_talloc(found_si ? si.struct_length : 0 *************** static struct { *** 941,946 **** --- 945,952 ---- { ".btm", __dosexec_command_exec }, { ".sh", script_exec }, /* for compatibility with ms_sh */ { ".ksh", script_exec }, + { ".pl", script_exec }, /* Perl */ + { ".sed", script_exec }, { "", go32_exec }, { 0, script_exec }, /* every extension not mentioned above calls it */ { 0, 0 }, *************** __dosexec_find_on_path(const char *progr *** 1003,1009 **** } } ! if (haspath) return 0; *rp = 0; --- 1009,1015 ---- } } ! if (haspath || !envp) return 0; *rp = 0; *** include/stdlib.h~2 Fri Aug 30 19:57:42 1996 --- include/stdlib.h Fri Sep 13 18:27:24 1996 *************** void * xrealloc(void *ptr, size_t _size *** 108,114 **** extern int __system_flags; ! extern int _shell_command (const char *_prog, const char *_cmdline); #endif /* !_POSIX_SOURCE */ #endif /* !__STRICT_ANSI__ */ --- 108,116 ---- extern int __system_flags; ! extern int _shell_command (const char *_prog, const char *_cmdline); ! extern int _is_unixy_shell (const char *_prog); ! extern int _is_dos_shell (const char *_prog); #endif /* !_POSIX_SOURCE */ #endif /* !__STRICT_ANSI__ */