X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=support%2FUtil%2FMySystem.c;h=30e657c571e9757900a1e807947563c691ba8049;hb=3062f96ccb55d1d05caf9c8782f4961f87b341ce;hp=46d29f9d5a42d5825b486062f48a5f2791aa0747;hpb=a52a555ba56bc5167e594206b229e2c626e0a2dd;p=fw%2Fsdcc diff --git a/support/Util/MySystem.c b/support/Util/MySystem.c index 46d29f9d..30e657c5 100644 --- a/support/Util/MySystem.c +++ b/support/Util/MySystem.c @@ -22,78 +22,335 @@ what you give them. Help stamp out software-hoarding! -------------------------------------------------------------------------*/ -#include "common.h" -#include "newalloc.h" -#if defined(_MSC_VER) +#ifdef _WIN32 +#undef DATADIR +#include +/* avoid DATADIR definition clash :-( */ #include #else -#include +#include #endif +#include +#include "SDCCglobl.h" +#include "SDCCutil.h" +#include "MySystem.h" +#include "newalloc.h" -#if !defined(__BORLANDC__) && !defined(_MSC_VER) -#include -#else -// No unistd.h in Borland C++ -extern int access (const char *, int); -#define X_OK 1 -#endif +set *binPathSet = NULL; /* set of binary paths */ + /*! -Call an external program with arguements -*/ + * get command and arguments from command line + */ -//char *ExePathList[]= {SRCDIR "/bin",PREFIX "/bin", NULL}; -char *ExePathList[] = {NULL, NULL}; /* First entry may be overwritten, so use two. */ +static void +split_command(const char *cmd_line, char **command, char **params) +{ + const char *p, *cmd_start; + char delim; + char *str; + unsigned len; -int -my_system (const char *cmd) + /* 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 */ + +/* + * 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 * +merge_command(const char *command, const char *params) { - int argsStart, e, 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); - argsStart = strstr (cmd, " ") - cmd; + return cmd_line; +} - // try to find the command in predefined path's - while (ExePathList[i]) - { - cmdLine = (char *) Safe_malloc (strlen (ExePathList[i]) + strlen (cmd) + 10); - strcpy (cmdLine, ExePathList[i]); // the path - strcat (cmdLine, DIR_SEPARATOR_STRING); - strncat (cmdLine, cmd, argsStart); // the command +/*! + * check if path/command exist by converting it to short file name + * if it exists, compose with args and return it + */ -#if NATIVE_WIN32 - strcat (cmdLine, ".exe"); -#endif +static char * +compose_command_line(const char *path, const char *command, const char *args) +{ + unsigned len; + char cmdPath[PATH_MAX]; + char shortPath[PATH_MAX]; + + 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; + } +} - if (access (cmdLine, X_OK) == 0) - { - // the arguments - strcat (cmdLine, cmd + argsStart); - break; - } - free (cmdLine); - cmdLine = NULL; - i++; - } - if (verboseExec) - { - printf ("+ %s\n", cmdLine ? cmdLine : cmd); +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 (cmdLine) - { - // command found in predefined path - e = system (cmdLine); - free (cmdLine); + 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); + } } - else - { - // trust on $PATH - e = system (cmd); + + /* 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 */ + +/*! + * 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) +{ + return splitPath(path, NULL, 0, NULL, 0); +} + + +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) +{ + int e; + char *cmdLine = get_path(cmd); + + assert(NULL != cmdLine); + + if (options.verboseExec) { + printf("+ %s\n", cmdLine); + } + + e = system(cmdLine); + Safe_free(cmdLine); + return e; } + +/*! + * pipe an external program with arguements + */ + +#ifdef _WIN32 +#define popen_read(cmd) _popen((cmd), "rt") +#else +#define popen_read(cmd) popen((cmd), "r") +#endif + +FILE * +my_popen(const char *cmd) +{ + FILE *fp; + char *cmdLine = get_path(cmd); + + assert(NULL != cmdLine); + + if (options.verboseExec) { + printf("+ %s\n", cmdLine); + } + + fp = popen_read(cmdLine); + Safe_free(cmdLine); + + return fp; +}