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>
39 #include <kpathsea/concatn.h>
43 look_for_cmd(const char *cmd, char **app, char **new)
47 char pname[MAXPATHLEN], *fp;
48 char *suffixes[] = { ".bat", ".cmd", ".com", ".exe", NULL };
50 char *app_name, *new_cmd;
55 new_cmd = app_name = NULL;
57 /* We should look for the application name along the PATH,
58 and decide to prepend "%COMSPEC% /c " or not to the command line.
59 Do nothing for the moment. */
61 /* Another way to do that would be to try CreateProcess first without
62 invoking cmd, and look at the error code. If it fails because of
63 command not found, try to prepend "cmd /c" to the cmd line.
66 /* Look for the application name */
67 for (p = (char *)cmd; *p && isspace(*p); p++);
70 while(*p && *p != '"') p++;
72 fprintf(stderr, "Look_for_cmd: malformed command (\" not terminated)\n");
77 for (q = p; *p && !isspace(*p); p++);
78 /* q points to the beginning of appname, p to the last + 1 char */
79 if ((app_name = malloc(p - q + 1)) == NULL) {
80 fprintf(stderr, "Look_for_cmd: malloc(app_name) failed.\n");
83 strncpy(app_name, q, p - q );
84 app_name[p - q] = '\0';
87 fprintf(stderr, "popen: app_name = %s\n", app_name);
91 char *tmp = getenv("PATH");
92 env_path = xmalloc(strlen(tmp) + 3);
93 strcpy(env_path, ".;");
94 strcat(env_path, tmp);
97 /* Looking for appname on the path */
98 for (s = suffixes, go_on = TRUE; go_on; *s++) {
99 if (SearchPath(env_path, /* Address of search path */
100 app_name, /* Address of filename */
101 *s, /* Address of extension */
102 MAXPATHLEN, /* Size of destination buffer */
103 pname, /* Address of destination buffer */
104 &fp) /* File part of app_name */
107 fprintf(stderr, "%s found with suffix %s\nin %s\n", app_name, *s, pname);
109 new_cmd = xstrdup(cmd);
111 app_name = xstrdup(pname);
114 go_on = (*s != NULL);
116 if (go_on == FALSE) {
117 /* the app_name was not found */
119 fprintf(stderr, "%s not found, concatenating comspec\n", app_name);
121 new_cmd = concatn(getenv("COMSPEC"), " /c ", cmd, NULL);
127 if (env_path) free(env_path);
137 Command parser. Borrowed from DJGPP.
140 static BOOL __system_allow_multiple_cmds = FALSE;
154 /* Return a copy of a word between BEG and (excluding) END with all
155 quoting characters removed from it. */
158 __unquote (char *to, const char *beg, const char *end)
172 else if (quote == *s)
177 if (s[1] == '"' || s[1] == '\''
179 && (__system_allow_multiple_cmds)))
192 /* A poor-man's lexical analyzer for simplified command processing.
194 It only knows about these:
196 redirection and pipe symbols
197 semi-colon `;' (that possibly ends a command)
198 argument quoting rules with quotes and `\'
199 whitespace delimiters of words (except in quoted args)
201 Returns the type of next symbol and pointers to its first and (one
202 after) the last characters.
204 Only `get_sym' and `unquote' should know about quoting rules. */
207 get_sym (char *s, char **beg, char **end)
220 && (!*s || strchr ("<>| \t\n", *s)
221 || ((__system_allow_multiple_cmds) && *s == ';')))
241 if (__system_allow_multiple_cmds)
250 if (s[1] == '"' || s[1] == '\''
251 || (s[1] == ';' && (__system_allow_multiple_cmds)))
260 while (*s && *s != quote)
262 if (*s++ == '\\' && (*s == '"' || *s == '\''))
267 return UNMATCHED_QUOTE;
283 [cmd] [arg1] ... [argn] < [redinput] | [cmd2] | ... | [cmdn] > [redoutput]
285 void *parse_cmdline(char *line, char **input, char **output)
287 BOOL again, needcmd = TRUE, bSuccess = TRUE, append_out = FALSE;
288 char *beg = line, *end, *new_end;
289 cmd_sym_t token = EMPTY, prev_token = EMPTY;
290 int ncmd = 0, narg = 1;
293 char *dummy_input; /* So that we could pass NULL */
294 char *dummy_output; /* instead of a real ??put */
296 if (input == NULL) input = &dummy_input;
297 if (output == NULL) output = &dummy_output;
301 cmd = xmalloc(MAX_PIPES*sizeof(char **));
304 fprintf(stderr, "line = %s\n", line);
309 token = get_sym (beg, &beg, &end); /* get next symbol */
311 fprintf(stderr, "token = %s\n", beg);
315 if (prev_token == REDIR_INPUT
316 || prev_token == REDIR_OUTPUT) {
317 fprintf(stderr, "Ambigous input/output redirect.");
321 /* First word we see is the program to run. */
324 cmd[ncmd] = xmalloc(narg * sizeof(char *));
325 cmd[ncmd][narg - 1] = xmalloc(end - beg + 1);
326 __unquote (cmd[ncmd][narg - 1], beg, end); /* unquote and copy to prog */
327 if (cmd[ncmd][narg - 1][0] == '(') {
328 fprintf(stderr, "parse_cmdline(%s): Parenthesized groups not allowed.\n", line);
336 cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
337 cmd[ncmd][narg - 1] = xmalloc(end - beg + 1);
338 __unquote (cmd[ncmd][narg - 1], beg, end); /* unquote and copy to prog */
340 beg = end; /* go forward */
347 if (token == REDIR_INPUT) {
349 fprintf(stderr, "Ambiguous input redirect.");
356 else if (token == REDIR_OUTPUT || token == REDIR_APPEND) {
358 fprintf(stderr, "Ambiguous output redirect.");
364 if (token == REDIR_APPEND)
367 if (get_sym (end, &end, &new_end) != WORDARG) {
368 fprintf(stderr, "Target of redirect is not a filename.");
373 *fp = (char *)xmalloc (new_end - end + 1);
374 memcpy (*fp, end, new_end - end);
375 (*fp)[new_end - end] = '\0';
381 fprintf(stderr, "Ambiguous output redirect.");
387 cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
388 cmd[ncmd][narg - 1] = NULL;
397 fprintf(stderr, "No command name seen.");
403 cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
404 cmd[ncmd][narg - 1] = NULL;
410 case UNMATCHED_QUOTE:
411 fprintf(stderr, "Unmatched quote character.");
416 fprintf(stderr, "I cannot grok this.");
429 /* Need to free everything that was allocated */
430 for (i = 0; i < ncmd; i++) {
431 for (p = cmd[i]; *p; p++)
436 for (i = 0; i < narg; i++)
450 for (p = elt; *p; p++)
452 return concat3("\"", elt, "\"");
457 /* static (commented out for mingw; SK) */ char *
458 quote_args(char **argv)
461 char *line = NULL, *new_line;
467 line = quote_elt(argv[0]);
468 for (i = 1; argv[i]; i++) {
469 new_argv = quote_elt(argv[i]);
470 new_line = concat3(line, " ", new_argv);
480 build_cmdline(char ***cmd, char *input, char *output)
483 char *line = NULL, *new_line;
488 line = quote_args(cmd[0]);
490 new_line = concat3(line, " < ", quote_elt(input));
494 for(ncmd = 1; cmd[ncmd]; ncmd++) {
495 new_line = concat3(line, " | ", quote_args(cmd[ncmd]));
501 new_line = concat3(line, " > ", quote_elt(output));
511 display_cmd(char ***cmd, char *input, char *output, char *errput)
516 for (ncmd = 0; cmd[ncmd]; ncmd++) {
517 printf("cmd[%d] = %s ", ncmd, cmd[ncmd][0]);
518 for(narg = 1; cmd[ncmd][narg] != NULL; narg++)
519 printf("%s ", cmd[ncmd][narg]);
523 printf("input = %s\n", (input ? input : "<stdin>"));
524 printf("output = %s\n", (output ? output : "<stdout>"));
525 printf("errput = %s\n", (errput ? errput : "<stderr>"));
528 main(int argc, char *argv[])
535 printf("%s\n", line = "foo a b");
536 if (cmd = parse_cmdline(line, &input, &output)) {
537 display_cmd(cmd, input, output, NULL);
539 printf("%s\n", line = "foo < a > b");
540 if (cmd = parse_cmdline(line, &input, &output)) {
541 display_cmd(cmd, input, output, NULL);
543 printf("%s\n", line = "foo > a < b");
544 if (cmd = parse_cmdline(line, &input, &output)) {
545 display_cmd(cmd, input, output, NULL);
547 printf("%s\n", line = "foo | a b");
548 if (cmd = parse_cmdline(line, &input, &output)) {
549 display_cmd(cmd, input, output, NULL);
551 printf("%s\n", line = "foo a | b");
552 if (cmd = parse_cmdline(line, &input, &output)) {
553 display_cmd(cmd, input, output, NULL);
555 printf("%s\n", line = "foo | a > b");
556 if (cmd = parse_cmdline(line, &input, &output)) {
557 display_cmd(cmd, input, output, NULL);
559 printf("%s\n", line = "foo < a | b");
560 if (cmd = parse_cmdline(line, &input, &output)) {
561 display_cmd(cmd, input, output, NULL);
563 printf("%s\n", line = "foo < a | b");
564 if (cmd = parse_cmdline(line, &input, &output)) {
565 display_cmd(cmd, input, output, NULL);
567 printf("%s\n", line = "foo < a | b | c > d");
568 if (cmd = parse_cmdline(line, &input, &output)) {
569 display_cmd(cmd, input, output, NULL);
571 printf("%s\n", line = "foo > a | b < c");
572 if (cmd = parse_cmdline(line, &input, &output)) {
573 display_cmd(cmd, input, output, NULL);
576 printf("%s\n", line = "\"C:\\Program Files\\WinEdt\\WinEdt.exe\" -F \"[Open('%f');SelLine(%l,8)]\"");
577 if (cmd = parse_cmdline(line, &input, &output)) {
578 display_cmd(cmd, input, output, NULL);