X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=support%2FUtil%2FMySystem.c;h=b78d99aac17b20736a6e3eda39af189a3cfd3fe8;hb=90bdb43b342189fcb94a398855d43f3f47f96738;hp=475e97e8c259097ecd19b87809e4fbde4241357a;hpb=7269a6502093b7fa21b62f7894e5c01a4d21f811;p=fw%2Fsdcc diff --git a/support/Util/MySystem.c b/support/Util/MySystem.c index 475e97e8..b78d99aa 100644 --- a/support/Util/MySystem.c +++ b/support/Util/MySystem.c @@ -22,99 +22,317 @@ what you give them. Help stamp out software-hoarding! -------------------------------------------------------------------------*/ -#include "common.h" -#include "MySystem.h" -#include "newalloc.h" #ifdef _WIN32 +#undef DATADIR +#include +/* avoid DATADIR definition clash :-( */ #include #else #include #endif +#include +#include "SDCCglobl.h" +#include "SDCCutil.h" +#include "MySystem.h" +#include "newalloc.h" -//char *ExePathList[]= {SRCDIR "/bin",PREFIX "/bin", NULL}; -char *ExePathList[] = {NULL, NULL}; /* First entry may be overwritten, so use two. */ +set *binPathSet = NULL; /* set of binary paths */ + /*! -Find the comamnd in one of predefined paths + * get command and arguments from command line + */ + +static void +split_command(const char *cmd_line, char **command, char **params) +{ + const char *p, *cmd_start; + char delim; + char *str; + unsigned len; -NOTE: this function does't do it's job if: -- the program name also contains the path - (and it seems thet this is always true :-(() -- there are no spaces in cmd -- the program name contains space characters + /* skip leading spaces */ + for (p = cmd_line; isspace(*p); p++) + ; + + /* get command */ + switch (*p) { + case '\'': + case '"': + delim = *p; + cmd_start = ++p; + break; + + default: + delim = ' '; + cmd_start = p; + } + + if (delim == ' ') { + while (*p != '\0' && !isspace(*p)) + p++; + } + else { + while (*p != '\0' && *p != delim) + p++; + } + + if (command != NULL) { + len = p - cmd_start; + str = Safe_alloc(len + 1); + strncpy(str, cmd_start, len); + str[len] = '\0'; + *command = str; + } + + p++; + + /* skip spaces before parameters */ + while (isspace(*p)) + p++; + + /* get parameters */ + if (params != NULL) + *params = Safe_strdup(p); +} + + +/*! + * find the command: + * 1) if the command is specified by path, try it + * 2) try to find the command in predefined path's + * 3) trust on $PATH + */ + +#ifdef _WIN32 +/* WIN32 version */ -It has to be rewritten. -*/ +/* + * I don't like this solution, but unfortunately cmd.exe and command.com + * don't accept something like this: + * "program" "argument" + * Cmd.exe accepts the following: + * ""program" "argument"" + * but command.com doesn't. + * The following is accepted by both: + * program "argument" + * + * So the most portable WIN32 solution is to use GetShortPathName() for + * program to get rid of spaces, so that quotes are not needed :-( + * Using spawnvp() instead of system() is more portable cross platform approach, + * but then also a substitute for _popen() should be developed... + */ + +#define EXE_EXT ".exe" + +/*! + * merge command and parameters to command line + */ static char * -get_path (const char *cmd) +merge_command(const char *command, const char *params) { - int argsStart, i = 0; - char *cmdLine = NULL; + /* allocate extra space for ' ' and '\0' */ + char *cmd_line = (char *)Safe_alloc(strlen(command) + strlen(params) + 2); + sprintf(cmd_line, "%s %s", command, params); + + return cmd_line; +} - argsStart = strstr (cmd, " ") - cmd; - // try to find the command in predefined path's - while (ExePathList[i]) - { - cmdLine = (char *) Safe_alloc (strlen (ExePathList[i]) + strlen (cmd) + 10); - strcpy (cmdLine, ExePathList[i]); // the path +/*! + * check if path/command exist by converting it to short file name + * if it exists, compose with args and return it + */ - strcat (cmdLine, DIR_SEPARATOR_STRING); - strncat (cmdLine, cmd, argsStart); // the command +static char * +compose_command_line(const char *path, const char *command, const char *args) +{ + unsigned len; + char cmdPath[PATH_MAX]; + char shortPath[PATH_MAX]; -#ifdef _WIN32 - strcat (cmdLine, ".exe"); - if (access(cmdLine, 0) == 0) -#else - if (access(cmdLine, X_OK) == 0) -#endif - { - // the arguments - strcat (cmdLine, cmd + argsStart); - break; - } - Safe_free (cmdLine); - cmdLine = NULL; - i++; + if (path != NULL) + SNPRINTF(cmdPath, sizeof cmdPath, + "%s" DIR_SEPARATOR_STRING "%s", path, command); + else + strncpyz(cmdPath, command, sizeof cmdPath); + + /* Try if cmdPath or cmdPath.exe exist by converting it to the short path name */ + len = GetShortPathName(cmdPath, shortPath, sizeof shortPath); + assert(len < sizeof shortPath); + if (0 == len) { + len = GetShortPathName(strncatz(cmdPath, EXE_EXT, sizeof cmdPath), shortPath, sizeof shortPath); + assert(len < sizeof shortPath); + } + if (0 != len) { + /* compose the command line */ + return merge_command(shortPath, args); + } + else { + /* path/command not found */ + return NULL; + } +} + + +static char * +get_path(const char *cmd) +{ + char *cmdLine; + char *command; + char *args; + char *path; + + /* get the command */ + split_command(cmd, &command, &args); + + if (NULL == (cmdLine = compose_command_line(NULL, command, args))) { + /* not an absolute path: try to find the command in predefined binary paths */ + if (NULL != (path = (char *)setFirstItem(binPathSet))) { + while (NULL == (cmdLine = compose_command_line(path, command, args)) && + NULL != (path = (char *)setNextItem(binPathSet))) + ; } + if (NULL == cmdLine) { + /* didn't found the command in predefined binary paths: try with PATH */ + char *envPath; + + if (NULL != (envPath = getenv("PATH"))) { + /* make a local copy; strtok() will modify it */ + envPath = Safe_strdup(envPath); + + if (NULL != (path = strtok(envPath, ";"))) { + while (NULL == (cmdLine = compose_command_line(path, command, args)) && + NULL != (path = strtok(NULL, ";"))) + ; + } + + Safe_free(envPath); + } + } + + /* didn't found it; probably this won't help neither :-( */ + if (NULL == cmdLine) + cmdLine = merge_command(command, args); + } + + Safe_free(command); + Safe_free(args); + return cmdLine; } +#else +/* *nix version */ /*! -Call an external program with arguements -*/ + * merge command and parameters to command line + */ + +static char * +merge_command(const char *command, const char *params) +{ + /* allocate extra space for 2x'"', ' ' and '\0' */ + char *cmd_line = (char *)Safe_alloc(strlen(command) + strlen(params) + 4); + sprintf(cmd_line, "\"%s\" %s", command, params); + return cmd_line; +} + + +/*! + * check if the path is relative or absolute (if contains the dir separator) + */ + +static int +has_path(const char *path) +{ + if (strrchr(path, DIR_SEPARATOR_CHAR) == NULL) + return 0; + + return 1; +} + + +static char * +get_path(const char *cmd) +{ + char *cmdLine = NULL; + char *command; + char *args; + char *path; + char cmdPath[PATH_MAX]; + + + /* get the command */ + split_command(cmd, &command, &args); + + if (!has_path(command)) { + /* try to find the command in predefined binary paths */ + if (NULL != (path = (char *)setFirstItem(binPathSet))) { + do + { + SNPRINTF(cmdPath, sizeof cmdPath, + "%s" DIR_SEPARATOR_STRING "%s", path, command); + + /* Try if cmdPath */ + if (0 == access(cmdPath, X_OK)) { + /* compose the command line */ + cmdLine = merge_command(cmdPath, args); + break; + } + } while (NULL != (path = (char *)setNextItem(binPathSet))); + } + if (NULL == cmdLine) + cmdLine = merge_command(command, args); + + Safe_free(command); + Safe_free(args); + + return cmdLine; + } + else { + /* + * the command is defined with absolute path: + * just return it + */ + Safe_free(command); + Safe_free(args); + + return Safe_strdup(cmd); + } +} +#endif + + +/*! + * call an external program with arguements + */ int -my_system (const char *cmd) +my_system(const char *cmd) { int e; - char *cmdLine = get_path (cmd); + char *cmdLine = get_path(cmd); + + assert(NULL != cmdLine); if (options.verboseExec) { - printf ("+ %s\n", cmdLine ? cmdLine : cmd); + printf("+ %s\n", cmdLine); } - if (cmdLine) { - // command found in predefined path - e = system (cmdLine); - Safe_free (cmdLine); - } - else { - // trust on $PATH - e = system (cmd); - } + e = system(cmdLine); + Safe_free(cmdLine); return e; } /*! -Pipe an external program with arguements -*/ + * pipe an external program with arguements + */ #ifdef _WIN32 #define popen_read(cmd) _popen((cmd), "rt") @@ -123,24 +341,19 @@ Pipe an external program with arguements #endif FILE * -my_popen (const char *cmd) +my_popen(const char *cmd) { FILE *fp; - char *cmdLine = get_path (cmd); + char *cmdLine = get_path(cmd); + + assert(NULL != cmdLine); if (options.verboseExec) { - printf ("+ %s\n", cmdLine ? cmdLine : cmd); + printf("+ %s\n", cmdLine); } - if (cmdLine) { - // command found in predefined path - fp = popen_read (cmdLine); - Safe_free (cmdLine); - } - else { - // trust on $PATH - fp = popen_read (cmd); - } + fp = popen_read(cmdLine); + Safe_free(cmdLine); return fp; }