1 /* libc replacement functions for win32.
3 Copyright (C) 1998, 99 Free Software Foundation, Inc.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 This does make sense only under WIN32.
22 - look_for_cmd() : locates an executable file
23 - parse_cmd_line() : splits a command with pipes and redirections
24 - build_cmd_line() : builds a command with pipes and redirections (useful ?)
28 This part looks for the real location of the program invoked
29 by cmd. If it can find the program, that's good. Else
30 command processor is invoked.
35 #include <kpathsea/config.h>
36 #include <kpathsea/c-proto.h>
37 #include <kpathsea/win32lib.h>
38 #include <kpathsea/lib.h>
42 look_for_cmd(const char *cmd, char **app, char **new)
46 char pname[MAXPATHLEN], *fp;
47 char *suffixes[] = { ".bat", ".cmd", ".com", ".exe", NULL };
49 char *app_name, *new_cmd;
54 new_cmd = app_name = NULL;
56 /* We should look for the application name along the PATH,
57 and decide to prepend "%COMSPEC% /c " or not to the command line.
58 Do nothing for the moment. */
60 /* Another way to do that would be to try CreateProcess first without
61 invoking cmd, and look at the error code. If it fails because of
62 command not found, try to prepend "cmd /c" to the cmd line.
65 /* Look for the application name */
66 for (p = (char *)cmd; *p && isspace(*p); p++);
69 while(*p && *p != '"') p++;
71 fprintf(stderr, "Look_for_cmd: malformed command (\" not terminated)\n");
76 for (q = p; *p && !isspace(*p); p++);
77 /* q points to the beginning of appname, p to the last + 1 char */
78 if ((app_name = malloc(p - q + 1)) == NULL) {
79 fprintf(stderr, "Look_for_cmd: malloc(app_name) failed.\n");
82 strncpy(app_name, q, p - q );
83 app_name[p - q] = '\0';
86 fprintf(stderr, "popen: app_name = %s\n", app_name);
90 char *tmp = getenv("PATH");
91 env_path = xmalloc(strlen(tmp) + 3);
92 strcpy(env_path, ".;");
93 strcat(env_path, tmp);
96 /* Looking for appname on the path */
97 for (s = suffixes, go_on = TRUE; go_on; *s++) {
98 if (SearchPath(env_path, /* Address of search path */
99 app_name, /* Address of filename */
100 *s, /* Address of extension */
101 MAXPATHLEN, /* Size of destination buffer */
102 pname, /* Address of destination buffer */
103 &fp) /* File part of app_name */
106 fprintf(stderr, "%s found with suffix %s\nin %s\n", app_name, *s, pname);
108 new_cmd = xstrdup(cmd);
110 app_name = xstrdup(pname);
113 go_on = (*s != NULL);
115 if (go_on == FALSE) {
116 /* the app_name was not found */
118 fprintf(stderr, "%s not found, concatenating comspec\n", app_name);
120 new_cmd = concatn(getenv("COMSPEC"), " /c ", cmd, NULL);
126 if (env_path) free(env_path);
136 Command parser. Borrowed from DJGPP.
139 static BOOL __system_allow_multiple_cmds = FALSE;
153 /* Return a copy of a word between BEG and (excluding) END with all
154 quoting characters removed from it. */
157 __unquote (char *to, const char *beg, const char *end)
171 else if (quote == *s)
176 if (s[1] == '"' || s[1] == '\''
178 && (__system_allow_multiple_cmds)))
191 /* A poor-man's lexical analyzer for simplified command processing.
193 It only knows about these:
195 redirection and pipe symbols
196 semi-colon `;' (that possibly ends a command)
197 argument quoting rules with quotes and `\'
198 whitespace delimiters of words (except in quoted args)
200 Returns the type of next symbol and pointers to its first and (one
201 after) the last characters.
203 Only `get_sym' and `unquote' should know about quoting rules. */
206 get_sym (char *s, char **beg, char **end)
219 && (!*s || strchr ("<>| \t\n", *s)
220 || ((__system_allow_multiple_cmds) && *s == ';')))
240 if (__system_allow_multiple_cmds)
249 if (s[1] == '"' || s[1] == '\''
250 || (s[1] == ';' && (__system_allow_multiple_cmds)))
259 while (*s && *s != quote)
261 if (*s++ == '\\' && (*s == '"' || *s == '\''))
266 return UNMATCHED_QUOTE;
282 [cmd] [arg1] ... [argn] < [redinput] | [cmd2] | ... | [cmdn] > [redoutput]
284 void *parse_cmdline(char *line, char **input, char **output)
286 BOOL again, needcmd = TRUE, bSuccess = TRUE, append_out = FALSE;
287 char *beg = line, *end, *new_end;
288 cmd_sym_t token = EMPTY, prev_token = EMPTY;
289 int ncmd = 0, narg = 1;
292 char *dummy_input; /* So that we could pass NULL */
293 char *dummy_output; /* instead of a real ??put */
295 if (input == NULL) input = &dummy_input;
296 if (output == NULL) output = &dummy_output;
300 cmd = xmalloc(MAX_PIPES*sizeof(char **));
303 fprintf(stderr, "line = %s\n", line);
308 token = get_sym (beg, &beg, &end); /* get next symbol */
310 fprintf(stderr, "token = %s\n", beg);
314 if (prev_token == REDIR_INPUT
315 || prev_token == REDIR_OUTPUT) {
316 fprintf(stderr, "Ambigous input/output redirect.");
320 /* First word we see is the program to run. */
323 cmd[ncmd] = xmalloc(narg * sizeof(char *));
324 cmd[ncmd][narg - 1] = xmalloc(end - beg + 1);
325 __unquote (cmd[ncmd][narg - 1], beg, end); /* unquote and copy to prog */
326 if (cmd[ncmd][narg - 1][0] == '(') {
327 fprintf(stderr, "parse_cmdline(%s): Parenthesized groups not allowed.\n", line);
335 cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
336 cmd[ncmd][narg - 1] = xmalloc(end - beg + 1);
337 __unquote (cmd[ncmd][narg - 1], beg, end); /* unquote and copy to prog */
339 beg = end; /* go forward */
346 if (token == REDIR_INPUT) {
348 fprintf(stderr, "Ambiguous input redirect.");
355 else if (token == REDIR_OUTPUT || token == REDIR_APPEND) {
357 fprintf(stderr, "Ambiguous output redirect.");
363 if (token == REDIR_APPEND)
366 if (get_sym (end, &end, &new_end) != WORDARG) {
367 fprintf(stderr, "Target of redirect is not a filename.");
372 *fp = (char *)xmalloc (new_end - end + 1);
373 memcpy (*fp, end, new_end - end);
374 (*fp)[new_end - end] = '\0';
380 fprintf(stderr, "Ambiguous output redirect.");
386 cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
387 cmd[ncmd][narg - 1] = NULL;
396 fprintf(stderr, "No command name seen.");
402 cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
403 cmd[ncmd][narg - 1] = NULL;
409 case UNMATCHED_QUOTE:
410 fprintf(stderr, "Unmatched quote character.");
415 fprintf(stderr, "I cannot grok this.");
428 /* Need to free everything that was allocated */
429 for (i = 0; i < ncmd; i++) {
430 for (p = cmd[i]; *p; p++)
435 for (i = 0; i < narg; i++)
449 for (p = elt; *p; p++)
451 return concat3("\"", elt, "\"");
456 /* static (commented out for mingw; SK) */ char *
457 quote_args(char **argv)
460 char *line = NULL, *new_line;
466 line = quote_elt(argv[0]);
467 for (i = 1; argv[i]; i++) {
468 new_argv = quote_elt(argv[i]);
469 new_line = concat3(line, " ", new_argv);
479 build_cmdline(char ***cmd, char *input, char *output)
482 char *line = NULL, *new_line;
487 line = quote_args(cmd[0]);
489 new_line = concat3(line, " < ", quote_elt(input));
493 for(ncmd = 1; cmd[ncmd]; ncmd++) {
494 new_line = concat3(line, " | ", quote_args(cmd[ncmd]));
500 new_line = concat3(line, " > ", quote_elt(output));
510 display_cmd(char ***cmd, char *input, char *output, char *errput)
515 for (ncmd = 0; cmd[ncmd]; ncmd++) {
516 printf("cmd[%d] = %s ", ncmd, cmd[ncmd][0]);
517 for(narg = 1; cmd[ncmd][narg] != NULL; narg++)
518 printf("%s ", cmd[ncmd][narg]);
522 printf("input = %s\n", (input ? input : "<stdin>"));
523 printf("output = %s\n", (output ? output : "<stdout>"));
524 printf("errput = %s\n", (errput ? errput : "<stderr>"));
527 main(int argc, char *argv[])
534 printf("%s\n", line = "foo a b");
535 if (cmd = parse_cmdline(line, &input, &output)) {
536 display_cmd(cmd, input, output, NULL);
538 printf("%s\n", line = "foo < a > b");
539 if (cmd = parse_cmdline(line, &input, &output)) {
540 display_cmd(cmd, input, output, NULL);
542 printf("%s\n", line = "foo > a < b");
543 if (cmd = parse_cmdline(line, &input, &output)) {
544 display_cmd(cmd, input, output, NULL);
546 printf("%s\n", line = "foo | a b");
547 if (cmd = parse_cmdline(line, &input, &output)) {
548 display_cmd(cmd, input, output, NULL);
550 printf("%s\n", line = "foo a | b");
551 if (cmd = parse_cmdline(line, &input, &output)) {
552 display_cmd(cmd, input, output, NULL);
554 printf("%s\n", line = "foo | a > b");
555 if (cmd = parse_cmdline(line, &input, &output)) {
556 display_cmd(cmd, input, output, NULL);
558 printf("%s\n", line = "foo < a | b");
559 if (cmd = parse_cmdline(line, &input, &output)) {
560 display_cmd(cmd, input, output, NULL);
562 printf("%s\n", line = "foo < a | b");
563 if (cmd = parse_cmdline(line, &input, &output)) {
564 display_cmd(cmd, input, output, NULL);
566 printf("%s\n", line = "foo < a | b | c > d");
567 if (cmd = parse_cmdline(line, &input, &output)) {
568 display_cmd(cmd, input, output, NULL);
570 printf("%s\n", line = "foo > a | b < c");
571 if (cmd = parse_cmdline(line, &input, &output)) {
572 display_cmd(cmd, input, output, NULL);
575 printf("%s\n", line = "\"C:\\Program Files\\WinEdt\\WinEdt.exe\" -F \"[Open('%f');SelLine(%l,8)]\"");
576 if (cmd = parse_cmdline(line, &input, &output)) {
577 display_cmd(cmd, input, output, NULL);