Update svn merge history.
[sdcc.git] / sdcc / src / SDCCsystem.c
blobb9eefb26cd167632ccef1463842328bf44e50818
1 /*-------------------------------------------------------------------------
2 SDCCsystem - SDCC system & pipe functions
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
9 later version.
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 -------------------------------------------------------------------------*/
25 #ifdef _WIN32
26 /* avoid DATADIR definition clash :-( */
27 #undef DATADIR
28 #include <windows.h>
29 #undef TRUE
30 #undef FALSE
31 #include <stdio.h>
32 #include <io.h>
33 #include <fcntl.h>
34 #else
35 #include <unistd.h>
36 #endif
37 #include <string.h>
38 #include <ctype.h>
39 #include "SDCCglobl.h"
40 #include "SDCCutil.h"
41 #include "dbuf_string.h"
42 #include "SDCCsystem.h"
43 #include "newalloc.h"
46 set *binPathSet = NULL; /* set of binary paths */
49 /*!
50 * get command and arguments from command line
53 static void
54 split_command (const char *cmd_line, char **command, char **params)
56 const char *p, *cmd_start;
57 char delim;
58 char *str;
59 unsigned len;
61 /* skip leading spaces */
62 for (p = cmd_line; isspace (*p); p++)
65 /* get command */
66 switch (*p)
68 case '\'':
69 case '"':
70 delim = *p;
71 cmd_start = ++p;
72 break;
74 default:
75 delim = ' ';
76 cmd_start = p;
79 if (delim == ' ')
81 while (*p != '\0' && !isspace (*p))
82 p++;
84 else
86 while (*p != '\0' && *p != delim)
87 p++;
90 if (command != NULL)
92 len = p - cmd_start;
93 str = Safe_alloc (len + 1);
94 strncpy (str, cmd_start, len);
95 str[len] = '\0';
96 *command = str;
99 p++;
101 /* skip spaces before parameters */
102 while (isspace (*p))
103 p++;
105 /* get parameters */
106 if (params != NULL)
107 *params = Safe_strdup (p);
112 * find the command:
113 * 1) if the command is specified by path, try it
114 * 2) try to find the command in predefined path's
115 * 3) trust on $PATH
118 #ifdef _WIN32
119 /* WIN32 version */
121 static bool
122 file_exists (const char* path)
124 DWORD attr = GetFileAttributes (path);
125 return attr != INVALID_FILE_ATTRIBUTES
126 && 0 == (attr & FILE_ATTRIBUTE_DIRECTORY);
130 * cmd.exe via _popen doesn't accept something like this:
131 * "program" "argument"
132 * It has to be:
133 * ""program with possible spaces" "argument with spaces""
134 * or
135 * ""program with possible spaces" argument_without_spaces"
136 * (note: the first and last " are also needed).
137 * The arguments at this point already contain double quotes,
138 * if necessary, so the following code formats the line as:
139 * ""program" arguments".
142 #define EXE_EXT ".exe"
145 * merge command and parameters to command line
148 static const char *
149 merge_command (const char *command, const char *params)
151 struct dbuf_s dbuf;
153 /* allocate extra space for '""', '"' ' and ""\0" */
154 dbuf_init (&dbuf, strlen (command) + strlen (params) + 6);
156 dbuf_append_str (&dbuf, "\"\"");
157 dbuf_append_str (&dbuf, command);
158 dbuf_append_str (&dbuf, "\" ");
159 dbuf_append_str (&dbuf, params);
160 dbuf_append_str (&dbuf, "\"");
162 return dbuf_detach_c_str (&dbuf);
167 * check if path/command exist by converting it to short file name
168 * if it exists, compose with args and return it
171 static const char *
172 compose_command_line (const char *path, const char *command, const char *args)
174 bool cmd_exists;
175 struct dbuf_s cmdPath;
177 dbuf_init (&cmdPath, PATH_MAX);
179 if (path != NULL)
180 dbuf_makePath (&cmdPath, path, command);
181 else
182 dbuf_append_str (&cmdPath, command);
184 /* Does cmdPath or cmdPath.exe exist? */
185 cmd_exists = file_exists (dbuf_c_str (&cmdPath));
186 if (!cmd_exists)
188 dbuf_append_str (&cmdPath, EXE_EXT);
189 cmd_exists = file_exists (dbuf_c_str (&cmdPath));
191 if (cmd_exists)
193 /* compose the command line */
194 return merge_command (dbuf_c_str (&cmdPath), args);
196 else
198 /* path/command not found */
199 return NULL;
204 static const char *
205 get_path (const char *cmd)
207 const char *cmdLine;
208 char *command;
209 char *args;
210 char *path;
212 /* get the command */
213 split_command (cmd, &command, &args);
215 if (NULL == (cmdLine = compose_command_line(NULL, command, args)))
217 /* not an absolute path: try to find the command in predefined binary paths */
218 if (NULL != (path = (char *)setFirstItem (binPathSet)))
220 while (NULL == (cmdLine = compose_command_line (path, command, args)) &&
221 NULL != (path = (char *)setNextItem (binPathSet)))
225 if (NULL == cmdLine)
227 /* didn't found the command in predefined binary paths: try with PATH */
228 char *envPath;
230 if (NULL != (envPath = getenv("PATH")))
232 /* make a local copy; strtok() will modify it */
233 envPath = Safe_strdup (envPath);
235 if (NULL != (path = strtok (envPath, ";")))
237 while (NULL == (cmdLine = compose_command_line (path, command, args)) &&
238 NULL != (path = strtok (NULL, ";")))
242 Safe_free (envPath);
246 /* didn't found it; probably this won't help neither :-( */
247 if (NULL == cmdLine)
248 cmdLine = merge_command (command, args);
251 Safe_free(command);
252 Safe_free(args);
254 return cmdLine;
257 #else
258 /* *nix version */
261 * merge command and parameters to command line
264 static const char *
265 merge_command (const char *command, const char *params)
267 struct dbuf_s dbuf;
268 char *s = shell_escape (command);
270 /* allocate extra space for ' ' and '\0' */
271 dbuf_init (&dbuf, strlen (command) + strlen (params) + 2);
273 dbuf_append_str (&dbuf, s);
274 dbuf_append (&dbuf, " ", 1);
275 dbuf_append_str (&dbuf, params);
277 return dbuf_detach_c_str (&dbuf);
282 * check if the path is relative or absolute (if contains the dir separator)
285 static int
286 has_path (const char *path)
288 return dbuf_splitPath (path, NULL, NULL);
292 static const char *
293 get_path (const char *cmd)
295 const char *cmdLine = NULL;
296 char *command;
297 char *args;
298 char *path;
300 /* get the command */
301 split_command (cmd, &command, &args);
303 if (!has_path (command))
305 /* try to find the command in predefined binary paths */
306 if (NULL != (path = (char *)setFirstItem (binPathSet)))
310 struct dbuf_s dbuf;
311 const char *cmdPath;
313 dbuf_init (&dbuf, PATH_MAX);
314 dbuf_makePath (&dbuf, path, command);
315 cmdPath = dbuf_detach (&dbuf);
317 /* Try if cmdPath */
318 if (0 == access (cmdPath, X_OK))
320 /* compose the command line */
321 cmdLine = merge_command (cmdPath, args);
322 break;
324 } while (NULL != (path = (char *)setNextItem (binPathSet)));
326 if (NULL == cmdLine)
327 cmdLine = merge_command (command, args);
329 Safe_free (command);
330 Safe_free (args);
332 return cmdLine;
334 else
337 * the command is defined with absolute path:
338 * just return it
340 Safe_free (command);
341 Safe_free (args);
343 return Safe_strdup (cmd);
346 #endif
350 * call an external program with arguments
354 sdcc_system (const char *cmd)
356 int e;
357 const char *cmdLine = get_path (cmd);
359 assert (NULL != cmdLine);
361 if (options.verboseExec)
362 printf ("+ %s\n", cmdLine);
364 e = system (cmdLine);
366 if (options.verboseExec && e)
367 printf ("+ %s returned errorcode %d\n", cmdLine, e);
369 dbuf_free (cmdLine);
371 return e;
376 * pipe an external program with arguments
379 #ifdef _WIN32
380 #define sdcc_popen_read(cmd) _popen ((cmd), "rt")
382 sdcc_pclose (FILE *fp)
384 return _pclose (fp);
386 #else
387 #define sdcc_popen_read(cmd) popen ((cmd), "r")
389 sdcc_pclose (FILE *fp)
391 return pclose (fp);
393 #endif
395 FILE *
396 sdcc_popen (const char *cmd)
398 FILE *fp;
399 const char *cmdLine = get_path (cmd);
401 assert (NULL != cmdLine);
403 if (options.verboseExec)
405 printf ("+ %s\n", cmdLine);
408 fp = sdcc_popen_read (cmdLine);
409 dbuf_free (cmdLine);
411 return fp;