summaryrefslogtreecommitdiff
path: root/Build/source/libs/libgnuw32/lookcmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/libgnuw32/lookcmd.c')
-rw-r--r--Build/source/libs/libgnuw32/lookcmd.c778
1 files changed, 778 insertions, 0 deletions
diff --git a/Build/source/libs/libgnuw32/lookcmd.c b/Build/source/libs/libgnuw32/lookcmd.c
new file mode 100644
index 00000000000..bd4f2d8a4b1
--- /dev/null
+++ b/Build/source/libs/libgnuw32/lookcmd.c
@@ -0,0 +1,778 @@
+/* libc replacement functions for win32.
+
+Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/*
+ This does make sense only under WIN32.
+ Functions:
+ - look_for_cmd() : locates an executable file
+ - parse_cmd_line() : splits a command with pipes and redirections
+ - build_cmd_line() : builds a command with pipes and redirections (useful ?)
+ */
+
+/*
+ This part looks for the real location of the program invoked
+ by cmd. If it can find the program, that's good. Else
+ command processor is invoked.
+*/
+
+#include <win32lib.h>
+#include <errno.h>
+
+#undef _DEBUG
+
+#ifdef _DEBUG
+#define TRACE(x) x
+#else
+#define TRACE(x)
+#endif
+
+#define DIR_SEP '/'
+#define DIR_SEP_STRING "/"
+#define IS_DEVICE_SEP(ch) ((ch) == ':')
+#define NAME_BEGINS_WITH_DEVICE(name) (*(name) && IS_DEVICE_SEP((name)[1]))
+/* On DOS, it's good to allow both \ and / between directories. */
+#define IS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\')
+/* On win32, UNC names are authorized */
+#define IS_UNC_NAME(name) (strlen(name)>=3 && IS_DIR_SEP(*name) \
+ && IS_DIR_SEP(*(name+1)) && isalnum(*(name+2)))
+
+#if (defined(_DEBUG) || defined(TEST))
+void display_cmd(char ***cmd, char *input, char *output, char *errput);
+#endif
+
+void
+free_cmd_pipe(char ***cmd_pipe, int n)
+{
+ int i,j;
+ if (cmd_pipe) {
+ for (i = 0; i < n; i++) {
+ for (j = 0; cmd_pipe[i][j]; j++) {
+ TRACE(fprintf(stderr, "freeing %x\n", cmd_pipe[i][j]));
+ free(cmd_pipe[i][j]);
+ }
+ TRACE(fprintf(stderr, "freeing %x\n", cmd_pipe[i]));
+ free(cmd_pipe[i]);
+ }
+ TRACE(fprintf(stderr, "freeing %x\n", cmd_pipe));
+ free(cmd_pipe);
+ }
+}
+
+/*
+ Return a quoted string if space is found
+ New string is allocated
+*/
+static char *
+quote_elt(char *elt)
+{
+ int len = 2*strlen(elt)*sizeof(char) + 2;
+ char *to = xmalloc(len);
+ char *p = to;
+ BOOL need_quote = FALSE;
+
+ if (strchr(elt, ' ')) {
+ *to++ = '"';
+ need_quote = TRUE;
+ }
+
+ while (*elt) {
+ switch (*elt) {
+ case '"':
+ case '\'':
+ /* case '\\': */
+ *to++ = '\\';
+ default:
+ *to++ = *elt++;
+ }
+ }
+ if (need_quote) {
+ *to++ = '"';
+ }
+
+ *to = *elt;
+ to = xstrdup(p);
+ free(p);
+
+ return to;
+}
+
+/*
+ Process an array of strings, quote them
+ an return their catenation
+*/
+char *
+quote_args(char **argv)
+{
+ int i;
+ char *line = NULL, *new_line;
+ char *new_argv_i;
+
+ if (!argv)
+ return line;
+
+ line = quote_elt(argv[0]);
+ for (i = 1; argv[i]; i++) {
+ new_argv_i = quote_elt(argv[i]);
+ new_line = concat3(line, " ", new_argv_i);
+ TRACE(fprintf(stderr, "quote_args: new_line = %s\n", new_line));
+ free(line);
+ free(new_argv_i);
+ line = new_line;
+ }
+
+ return line;
+}
+
+static BOOL
+is_absolute(const char *filename)
+{
+ BOOL absolute = IS_DIR_SEP (*filename)
+ /* Novell allows non-alphanumeric drive letters. */
+ || (*filename && IS_DEVICE_SEP (filename[1]))
+ /* UNC names */
+ || IS_UNC_NAME(filename)
+ ;
+ BOOL explicit_relative = (*filename == '.' && (IS_DIR_SEP (filename[1])
+ || (filename[1] == '.' && IS_DIR_SEP (filename[2]))));
+ /* FIXME: On UNIX an IS_DIR_SEP of any but the last character in the name
+ implies relative. */
+ return absolute || explicit_relative;
+}
+
+BOOL
+look_for_cmd(const char *cmd, char **app)
+{
+ char *env_path = NULL;
+ char *p, *q;
+ char pname[MAXPATHLEN];
+ char *suffixes[] = {".com", ".exe", ".bat", ".cmd", NULL };
+ char **s;
+ char *app_name = NULL, *bare_name = NULL;
+ int i;
+ BOOL bIsWindowsNT = (GetVersion() < 0x80000000);
+ BOOL found, has_suffix = FALSE;
+
+ *app = app_name = bare_name = NULL;
+
+ /* We should look for the application name along the PATH,
+ and decide to prepend "%COMSPEC% /c " or not to the command line.
+ Do nothing for the moment. */
+
+ /* Another way to do that would be to try CreateProcess first without
+ invoking cmd, and look at the error code. If it fails because of
+ command not found, try to prepend "cmd /c" to the cmd line.
+ */
+
+ /* Look for the application name */
+ for (p = (char *)cmd; *p && isspace(*p); p++); /* Trim spaces on the left */
+ if (*p == '"') { /* If quoted string */
+ q = ++p;
+ while(*p && *p != '"') p++; /* stop at next quote */
+ if (*p == '\0') {
+ fprintf(stderr, "Look_for_cmd: malformed command (\" not terminated)\n");
+ return FALSE;
+ }
+ }
+ else {
+ for (q = p; *p && !isspace(*p); p++); /* stop at next space */
+ }
+
+ /* q points to the beginning of appname, p to the last + 1 char */
+ if ((app_name = xmalloc(p - q + 1)) == NULL) {
+ fprintf(stderr, "Look_for_cmd: malloc(app_name) failed.\n");
+ return FALSE;
+ }
+ /* the app name has been found */
+ for (i = 0; i < p - q; i++)
+ app_name[i] = (q[i] == '/' ? '\\' : q[i]);
+ // strncpy(app_name, q, p - q );
+ app_name[p - q] = '\0';
+
+ /* First of all : if it is an absolute path ... */
+ if (is_absolute(app_name)) {
+ if (_access(app_name, 0) == 0) { /* and it exists */
+ *app = app_name;
+ found = TRUE;
+ }
+ else { /* not found */
+ found = FALSE;
+ }
+ goto exit_1;
+ }
+
+ /* pname[] will serve as full path name */
+ pname[0] = '\0';
+ /* app_name without potential extension */
+ bare_name = xstrdup(app_name);
+ has_suffix = ((p = strrchr(bare_name, '.')) != NULL);
+
+ TRACE(fprintf(stderr, "look for command: app_name = %s\n", app_name));
+
+ /* Add the current directory */
+ {
+ char *tmp = getenv("PATH");
+ env_path = xmalloc(strlen(tmp) + 3);
+ strcpy(env_path, ".;");
+ strcat(env_path, tmp);
+ }
+
+ /* Looping over directories in env_path */
+ p = strtok(env_path, ";");
+ found = FALSE;
+ while (p != NULL && ! found) {
+ /* If the file has an extension ... */
+ if (has_suffix) {
+ strcpy(pname, p);
+ strcat(pname, "\\");
+ strcat(pname, app_name);
+ TRACE(fprintf(stderr, "look for command: trying %s\n", pname));
+ if (_access(pname, 0) == 0) {
+ free(app_name);
+ app_name = xstrdup(pname);
+ found = TRUE;
+ break;
+ }
+ }
+ else {
+ /* For each suffix in the list */
+ for (s = suffixes; *s != NULL; *s++) {
+ strcpy(pname, p);
+ strcat(pname, "\\");
+ strcat(pname, bare_name);
+ strcat(pname, *s);
+ TRACE(fprintf(stderr, "look for command: trying %s\n", pname));
+ if (_access(pname, 0) == 0) {
+ free(app_name);
+ app_name = xstrdup(pname);
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ p = strtok(NULL, ";");
+ }
+
+ exit_1:
+
+ if (found == TRUE) {
+ TRACE(fprintf(stderr, "look for command: app_name = %s\n", app_name));
+ if (! bIsWindowsNT) {
+ // Fix against short pathnames vs long pathnames
+ char lpShortPathName[_MAX_PATH];
+ if (GetShortPathName((LPCTSTR)app_name, lpShortPathName, sizeof(lpShortPathName)) != 0) {
+ free(app_name);
+ app_name = xstrdup(lpShortPathName);
+ }
+ }
+ for (p = app_name; p && *p; p++) {
+ *p = (*p == '/' ? '\\' : *p);
+ }
+ TRACE(fprintf(stderr, "\n!!! Absolute path = %s\n", app_name));
+ *app = app_name;
+ }
+ else {
+ /* the app_name was not found */
+ TRACE(fprintf(stderr, "look for command: %s not found\n", app_name));
+ if (app_name) free(app_name);
+ *app = app_name = NULL;
+ }
+
+ if (env_path) free(env_path);
+ if (bare_name) free(bare_name);
+
+ return found;
+}
+
+/*
+ Command parser. Borrowed from DJGPP.
+ */
+
+static BOOL __system_allow_multiple_cmds = FALSE;
+
+typedef enum {
+ EMPTY,
+ WORDARG,
+ REDIR_INPUT,
+ REDIR_APPEND,
+ REDIR_OUTPUT,
+ PIPE,
+ SEMICOLON,
+ UNMATCHED_QUOTE,
+ EOL
+} cmd_sym_t;
+
+/* Return a copy of a word between BEG and (excluding) END with all
+ quoting characters removed from it. */
+
+static char *
+__unquote (char *to, const char *beg, const char *end)
+{
+ const char *s = beg;
+ char *d = to;
+ int quote = 0;
+
+ while (s < end)
+ {
+ switch (*s)
+ {
+ case '"':
+ case '\'':
+ if (!quote)
+ quote = *s;
+ else if (quote == *s)
+ quote = 0;
+ s++;
+ break;
+ case '\\':
+ if (s[1] == '"' || s[1] == '\''
+ || (s[1] == '&'
+ && (__system_allow_multiple_cmds)))
+ s++;
+ /* Fall-through. */
+ default:
+ *d++ = *s++;
+ break;
+ }
+ }
+
+ *d = 0;
+ TRACE(fprintf(stderr, "unquote returns `%s' (%x)\n", to, to));
+ return to;
+}
+
+/* A poor-man's lexical analyzer for simplified command processing.
+
+ It only knows about these:
+
+ redirection and pipe symbols
+ semi-colon `;' (that possibly ends a command)
+ argument quoting rules with quotes and `\'
+ whitespace delimiters of words (except in quoted args)
+
+ Returns the type of next symbol and pointers to its first and (one
+ after) the last characters.
+
+ Only `get_sym' and `unquote' should know about quoting rules. */
+
+static cmd_sym_t
+get_sym (char *s, char **beg, char **end)
+{
+ int in_a_word = 0;
+
+ while (isspace (*s))
+ s++;
+
+ *beg = s;
+
+ do {
+ *end = s + 1;
+
+ if (in_a_word
+ && (!*s || strchr ("<>| \t\n", *s)
+ || ((__system_allow_multiple_cmds) && *s == '&')))
+ {
+ --*end;
+ return WORDARG;
+ }
+
+ switch (*s)
+ {
+ case '<':
+ return REDIR_INPUT;
+ case '>':
+ if (**end == '>')
+ {
+ ++*end;
+ return REDIR_APPEND;
+ }
+ return REDIR_OUTPUT;
+ case '|':
+ return PIPE;
+ case '&':
+ if (__system_allow_multiple_cmds)
+ return SEMICOLON;
+ else
+ in_a_word = 1;
+ break;
+ case '\0':
+ --*end;
+ return EOL;
+ case '\\':
+ if (s[1] == '"' || s[1] == '\''
+ || (s[1] == '&' && (__system_allow_multiple_cmds)))
+ s++;
+ in_a_word = 1;
+ break;
+ case '\'':
+ case '"':
+ {
+ char quote = *s++;
+
+ while (*s && *s != quote)
+ {
+ if (*s++ == '\\' && (*s == '"' || *s == '\''))
+ s++;
+ }
+ *end = s;
+ if (!*s)
+ return UNMATCHED_QUOTE;
+ in_a_word = 1;
+ break;
+ }
+ default:
+ in_a_word = 1;
+ break;
+ }
+
+ s++;
+
+ } while (1);
+}
+
+/*
+ What we allow :
+ [cmd] [arg1] ... [argn] < [redinput] | [cmd2] | ... | [cmdn] > [redoutput]
+*/
+void *parse_cmdline(char *line, char **input, char **output, int *nb_cmds)
+{
+ BOOL again, needcmd = TRUE, bSuccess = TRUE, append_out = FALSE;
+ char *beg = line, *end, *new_end;
+ cmd_sym_t token = EMPTY, prev_token = EMPTY;
+ int ncmd = 0, narg = 0;
+ char **fp;
+ char ***cmd;
+ char *dummy_input; /* So that we could pass NULL */
+ char *dummy_output; /* instead of a real ??put */
+
+#if 0
+ /* if _DEBUG is not defined, these macros will result in nothing. */
+ SETUP_CRTDBG;
+ /* Set the debug-heap flag so that freed blocks are kept on the
+ linked list, to catch any inadvertent use of freed memory */
+ SET_CRT_DEBUG_FIELD( _CRTDBG_CHECK_ALWAYS_DF );
+ SET_CRT_DEBUG_FIELD( _CRTDBG_ALLOC_MEM_DF );
+#endif
+ if (input == NULL) input = &dummy_input;
+ if (output == NULL) output = &dummy_output;
+
+ *input = NULL;
+ *output = NULL;
+ cmd = xmalloc(MAX_PIPES*sizeof(char **));
+ TRACE(fprintf(stderr, "cmd = %x, size = %d\n", cmd, MAX_PIPES*sizeof(char **)));
+ cmd[ncmd] = NULL;
+
+ TRACE(fprintf(stderr, "line = %s\n", line));
+
+ do {
+ again = FALSE;
+ prev_token = token;
+ token = get_sym (beg, &beg, &end); /* get next symbol */
+
+ TRACE(fprintf(stderr, "token = %s\n", beg));
+
+ switch (token) {
+ case WORDARG:
+ TRACE(fprintf(stderr, "WORDARG: "));
+ if (prev_token == REDIR_INPUT
+ || prev_token == REDIR_OUTPUT) {
+ fprintf(stderr, "Ambigous input/output redirect.");
+ bSuccess = FALSE;
+ goto leave;
+ }
+ /* Incrementing number of arguments */
+ narg++;
+ /* First word we see is the program to run. */
+ if (needcmd) {
+ cmd[ncmd] = xmalloc(narg * sizeof(char *));
+ TRACE(fprintf(stderr, "cmd[%d] = %x, size = %d\n", ncmd, cmd[ncmd], narg*sizeof(char *)));
+ if (cmd[ncmd] == NULL) {
+ fprintf(stderr, "parse_cmdline: xmalloc(%d) failed.\n", narg * sizeof(char *));
+ }
+ needcmd = FALSE;
+ }
+ else {
+ TRACE(fprintf(stderr, "cmd[%d] = %x -> ", ncmd, cmd[ncmd]));
+ cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
+ TRACE(fprintf(stderr, "%x, size = %d\n", cmd[ncmd], narg*sizeof(char *)));
+ if (cmd[ncmd] == NULL) {
+ fprintf(stderr, "parse_cmdline: xrealloc(%d) failed.\n", narg * sizeof(char *));
+ }
+ }
+ cmd[ncmd][narg - 1] = xmalloc(end - beg + 10);
+ TRACE(fprintf(stderr, "cmd[%d][%d] = %x, size = %d\n", ncmd, narg-1, cmd[ncmd][narg-1], end-beg+1));
+ if (cmd[ncmd] == NULL) {
+ fprintf(stderr, "parse_cmdline: xmalloc(%d) failed.\n", end - beg + 1);
+ }
+ __unquote (cmd[ncmd][narg - 1], beg, end); /* unquote and copy to prog */
+ TRACE(fprintf(stderr, "parse_cmd_line: cmd[%d][%d] = %s\n", ncmd, narg - 1, cmd[ncmd][narg - 1]));
+ if (cmd[ncmd][narg - 1][0] == '(') {
+ fprintf(stderr, "parse_cmdline(%s): Parenthesized groups not allowed.\n", line);
+ bSuccess = FALSE;
+ goto leave;
+ }
+ beg = end; /* go forward */
+ again = TRUE;
+ break;
+
+ case REDIR_INPUT:
+ case REDIR_OUTPUT:
+ case REDIR_APPEND:
+ TRACE(fprintf(stderr, "REDIR: "));
+ if (token == REDIR_INPUT) {
+ if (*input) {
+ fprintf(stderr, "Ambiguous input redirect.");
+ errno = EINVAL;
+ bSuccess = FALSE;
+ goto leave;
+ }
+ fp = input;
+ }
+ else if (token == REDIR_OUTPUT || token == REDIR_APPEND) {
+ if (*output) {
+ fprintf(stderr, "Ambiguous output redirect.");
+ errno = EINVAL;
+ bSuccess = FALSE;
+ goto leave;
+ }
+ fp = output;
+ if (token == REDIR_APPEND)
+ append_out = TRUE;
+ }
+ if (get_sym (end, &end, &new_end) != WORDARG) {
+ fprintf(stderr, "Target of redirect is not a filename.");
+ errno = EINVAL;
+ bSuccess = FALSE;
+ goto leave;
+ }
+ *fp = (char *)xmalloc (new_end - end + 1);
+ if (*fp == NULL) {
+ fprintf(stderr, "parse_cmdline: xmalloc(%d) failed.\n", new_end - end + 1);
+ }
+ __unquote (*fp, end, new_end);
+ /* (*fp)[new_end - end] = '\0'; */
+ beg = new_end;
+ again = TRUE;
+ break;
+ case PIPE:
+ TRACE(fprintf(stderr, "PIPE: "));
+ if (*output) {
+ fprintf(stderr, "Ambiguous output redirect.");
+ errno = EINVAL;
+ bSuccess = FALSE;
+ goto leave;
+ }
+ narg++;
+ TRACE(fprintf(stderr, "cmd[%d] = %x -> ", ncmd, cmd[ncmd]));
+ cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
+ TRACE(fprintf(stderr, "%x, size = %d\n", cmd[ncmd], narg*sizeof(char *)));
+ cmd[ncmd][narg - 1] = NULL;
+ ncmd++;
+ needcmd = TRUE;
+ cmd[ncmd] = NULL;
+ beg = end;
+ again = TRUE;
+ break;
+ case SEMICOLON:
+ case EOL:
+ TRACE(fprintf(stderr, "SEMICOLON|EOL: "));
+ if (needcmd) {
+ fprintf(stderr, "No command name seen.");
+ errno = EINVAL;
+ bSuccess = FALSE;
+ goto leave;
+ }
+ narg++;
+ TRACE(fprintf(stderr, "cmd[%d] = %x -> ", ncmd, cmd[ncmd]));
+ cmd[ncmd] = xrealloc(cmd[ncmd], narg * sizeof(char *));
+ TRACE(fprintf(stderr, "%x, size = %d\n", cmd[ncmd], narg*sizeof(char *)));
+ cmd[ncmd][narg - 1] = NULL;
+ ncmd++;
+ cmd[ncmd] = NULL;
+ again = FALSE;
+ break;
+
+ case UNMATCHED_QUOTE:
+ fprintf(stderr, "Unmatched quote character.");
+ errno = EINVAL;
+ bSuccess = FALSE;
+ goto leave;
+ default:
+ fprintf(stderr, "I cannot grok this.");
+ errno = EINVAL;
+ bSuccess = FALSE;
+ goto leave;
+
+ }
+
+ } while (again);
+
+ leave:
+ if (!bSuccess) {
+ int i;
+ char **p;
+ /* Need to free everything that was allocated */
+ for (i = 0; i < ncmd; i++) {
+ for (p = cmd[i]; *p; p++)
+ free(*p);
+ free(cmd[i]);
+ }
+ if (cmd[ncmd]) {
+ for (i = 0; i < narg; i++)
+ free(cmd[ncmd][i]);
+ free(cmd[ncmd]);
+ }
+ free(cmd);
+ *cmd = NULL;
+ ncmd = 0;
+ }
+
+ if (nb_cmds != NULL) *nb_cmds = ncmd;
+
+#if (defined(_DEBUG) || defined(TEST))
+ display_cmd(cmd, *input, *output, NULL);
+#endif
+ return cmd;
+}
+
+char *
+build_cmdline(char ***cmd, char *input, char *output)
+{
+ int ncmd;
+ char *line = NULL, *new_line;
+
+ if (!cmd)
+ return line;
+
+ line = quote_args(cmd[0]);
+ if (input) {
+ new_line = concat3(line, " < ", quote_elt(input));
+ free(line);
+ line = new_line;
+ }
+ for(ncmd = 1; cmd[ncmd]; ncmd++) {
+ new_line = concat3(line, " | ", quote_args(cmd[ncmd]));
+ free(line);
+ line = new_line;
+ }
+
+ if (output) {
+ new_line = concat3(line, " > ", quote_elt(output));
+ free(line);
+ line = new_line;
+ }
+
+ return line;
+}
+
+#if (defined(_DEBUG) || defined(TEST))
+void
+display_cmd(char ***cmd, char *input, char *output, char *errput)
+{
+ int ncmd = 0, narg;
+
+ if (cmd) {
+ for (ncmd = 0; cmd[ncmd]; ncmd++) {
+ printf("cmd[%d] = %s ", ncmd, cmd[ncmd][0]);
+ for(narg = 1; cmd[ncmd][narg] != NULL; narg++)
+ printf("%s ", cmd[ncmd][narg]);
+ printf("\n");
+ }
+ }
+ printf("input = %s\n", (input ? input : "<stdin>"));
+ printf("output = %s\n", (output ? output : "<stdout>"));
+ printf("errput = %s\n", (errput ? errput : "<stderr>"));
+}
+#endif
+
+#ifdef TEST
+main(int argc, char *argv[])
+{
+ char *input;
+ char *output;
+ char ***cmd;
+ char *line;
+
+ /* SETUP_CRTDBG; */
+
+ printf("%s\n", line = "foo a b");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "foo < a > b");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "filter 1 | filter 2");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "foo > a < b");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "foo | a b");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "foo a | b");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "foo | a > b");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "foo < a | b");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "foo < a | b");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "foo < a | b b1 b2 | c > d");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+
+ printf("%s\n", line = "foo > a | b < c");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+ printf("%s\n", line = "\"C:\\Program Files\\WinEdt\\WinEdt.exe\" -F \"[Open('%f');SelLine(%l,8)]\"");
+ if (cmd = parse_cmdline(line, &input, &output, 0)) {
+ display_cmd(cmd, input, output, NULL);
+ }
+
+ {
+ char buf[256];
+ char *app, *cmd;
+ while (gets(buf)) {
+ look_for_cmd(buf, &app, &cmd);
+ if (app) {
+ printf("app: %s, cmd: %s\n", app, cmd);
+ }
+ else {
+ printf("app not found, cmd: %s\n", cmd);
+ }
+ if (app) free(app);
+ if (cmd) free(cmd);
+ }
+ }
+}
+#endif