1 /*-------------------------------------------------------------------------
2 MySystem - SDCC Support function
4 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 In other words, you are welcome to use, share and improve this program.
21 You are forbidden to forbid anyone else to use, share and improve
22 what you give them. Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
28 /* avoid DATADIR definition clash :-( */
34 #include "SDCCglobl.h"
40 set *binPathSet = NULL; /* set of binary paths */
44 * get command and arguments from command line
48 split_command(const char *cmd_line, char **command, char **params)
50 const char *p, *cmd_start;
55 /* skip leading spaces */
56 for (p = cmd_line; isspace(*p); p++)
73 while (*p != '\0' && !isspace(*p))
77 while (*p != '\0' && *p != delim)
81 if (command != NULL) {
83 str = Safe_alloc(len + 1);
84 strncpy(str, cmd_start, len);
91 /* skip spaces before parameters */
97 *params = Safe_strdup(p);
103 * 1) if the command is specified by path, try it
104 * 2) try to find the command in predefined path's
112 * I don't like this solution, but unfortunately cmd.exe and command.com
113 * don't accept something like this:
114 * "program" "argument"
115 * Cmd.exe accepts the following:
116 * ""program" "argument""
117 * but command.com doesn't.
118 * The following is accepted by both:
121 * So the most portable WIN32 solution is to use GetShortPathName() for
122 * program to get rid of spaces, so that quotes are not needed :-(
123 * Using spawnvp() instead of system() is more portable cross platform approach,
124 * but then also a substitute for _popen() should be developed...
127 #define EXE_EXT ".exe"
130 * merge command and parameters to command line
134 merge_command(const char *command, const char *params)
136 /* allocate extra space for ' ' and '\0' */
137 char *cmd_line = (char *)Safe_alloc(strlen(command) + strlen(params) + 2);
138 sprintf(cmd_line, "%s %s", command, params);
145 * check if path/command exist by converting it to short file name
146 * if it exists, compose with args and return it
150 compose_command_line(const char *path, const char *command, const char *args)
153 char cmdPath[PATH_MAX];
154 char shortPath[PATH_MAX];
157 SNPRINTF(cmdPath, sizeof cmdPath,
158 "%s" DIR_SEPARATOR_STRING "%s", path, command);
160 strncpyz(cmdPath, command, sizeof cmdPath);
162 /* Try if cmdPath or cmdPath.exe exist by converting it to the short path name */
163 len = GetShortPathName(cmdPath, shortPath, sizeof shortPath);
164 assert(len < sizeof shortPath);
166 len = GetShortPathName(strncatz(cmdPath, EXE_EXT, sizeof cmdPath), shortPath, sizeof shortPath);
167 assert(len < sizeof shortPath);
170 /* compose the command line */
171 return merge_command(shortPath, args);
174 /* path/command not found */
181 get_path(const char *cmd)
188 /* get the command */
189 split_command(cmd, &command, &args);
191 if (NULL == (cmdLine = compose_command_line(NULL, command, args))) {
192 /* not an absolute path: try to find the command in predefined binary paths */
193 if (NULL != (path = (char *)setFirstItem(binPathSet))) {
194 while (NULL == (cmdLine = compose_command_line(path, command, args)) &&
195 NULL != (path = (char *)setNextItem(binPathSet)))
199 if (NULL == cmdLine) {
200 /* didn't found the command in predefined binary paths: try with PATH */
203 if (NULL != (envPath = getenv("PATH"))) {
204 /* make a local copy; strtok() will modify it */
205 envPath = Safe_strdup(envPath);
207 if (NULL != (path = strtok(envPath, ";"))) {
208 while (NULL == (cmdLine = compose_command_line(path, command, args)) &&
209 NULL != (path = strtok(NULL, ";")))
217 /* didn't found it; probably this won't help neither :-( */
219 cmdLine = merge_command(command, args);
232 * merge command and parameters to command line
236 merge_command(const char *command, const char *params)
238 /* allocate extra space for 2x'"', ' ' and '\0' */
239 char *cmd_line = (char *)Safe_alloc(strlen(command) + strlen(params) + 4);
240 sprintf(cmd_line, "\"%s\" %s", command, params);
246 * check if the path is relative or absolute (if contains the dir separator)
250 has_path(const char *path)
252 return dbuf_splitPath(path, NULL, NULL);
257 get_path(const char *cmd)
259 char *cmdLine = NULL;
263 char cmdPath[PATH_MAX];
266 /* get the command */
267 split_command(cmd, &command, &args);
269 if (!has_path(command)) {
270 /* try to find the command in predefined binary paths */
271 if (NULL != (path = (char *)setFirstItem(binPathSet))) {
274 SNPRINTF(cmdPath, sizeof cmdPath,
275 "%s" DIR_SEPARATOR_STRING "%s", path, command);
278 if (0 == access(cmdPath, X_OK)) {
279 /* compose the command line */
280 cmdLine = merge_command(cmdPath, args);
283 } while (NULL != (path = (char *)setNextItem(binPathSet)));
286 cmdLine = merge_command(command, args);
295 * the command is defined with absolute path:
301 return Safe_strdup(cmd);
308 * call an external program with arguements
312 my_system(const char *cmd)
315 char *cmdLine = get_path(cmd);
317 assert(NULL != cmdLine);
319 if (options.verboseExec) {
320 printf("+ %s\n", cmdLine);
325 if (options.verboseExec && e) {
326 printf("+ %s returned errorcode %d\n", cmdLine, e);
336 * pipe an external program with arguements
340 #define popen_read(cmd) _popen((cmd), "rt")
342 #define popen_read(cmd) popen((cmd), "r")
346 my_popen(const char *cmd)
349 char *cmdLine = get_path(cmd);
351 assert(NULL != cmdLine);
353 if (options.verboseExec) {
354 printf("+ %s\n", cmdLine);
357 fp = popen_read(cmdLine);