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 if (strrchr(path, DIR_SEPARATOR_CHAR) == NULL)
260 get_path(const char *cmd)
262 char *cmdLine = NULL;
266 char cmdPath[PATH_MAX];
269 /* get the command */
270 split_command(cmd, &command, &args);
272 if (!has_path(command)) {
273 /* try to find the command in predefined binary paths */
274 if (NULL != (path = (char *)setFirstItem(binPathSet))) {
277 SNPRINTF(cmdPath, sizeof cmdPath,
278 "%s" DIR_SEPARATOR_STRING "%s", path, command);
281 if (0 == access(cmdPath, X_OK)) {
282 /* compose the command line */
283 cmdLine = merge_command(cmdPath, args);
286 } while (NULL != (path = (char *)setNextItem(binPathSet)));
289 cmdLine = merge_command(command, args);
298 * the command is defined with absolute path:
304 return Safe_strdup(cmd);
311 * call an external program with arguements
315 my_system(const char *cmd)
318 char *cmdLine = get_path(cmd);
320 assert(NULL != cmdLine);
322 if (options.verboseExec) {
323 printf("+ %s\n", cmdLine);
334 * pipe an external program with arguements
338 #define popen_read(cmd) _popen((cmd), "rt")
340 #define popen_read(cmd) popen((cmd), "r")
344 my_popen(const char *cmd)
347 char *cmdLine = get_path(cmd);
349 assert(NULL != cmdLine);
351 if (options.verboseExec) {
352 printf("+ %s\n", cmdLine);
355 fp = popen_read(cmdLine);