rewrite, char *ExePathList[] replaced with set *binPathSet
[fw/sdcc] / support / Util / MySystem.c
1 /*-------------------------------------------------------------------------
2   MySystem - SDCC Support function
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
5
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.
10
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.
15
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.
19
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 -------------------------------------------------------------------------*/
24
25 #include "common.h"
26 #include "MySystem.h"
27 #include "newalloc.h"
28 #ifdef _WIN32
29 #include <io.h>
30 #else
31 #include <unistd.h>
32 #endif
33
34 #ifdef _WIN32
35 #define EXE_EXT ".exe"
36 #else
37 #define EXE_EXT ""
38 #endif
39
40
41 set *binPathSet = NULL; /* set of binary paths */
42
43
44 /*!
45  * get command and arguments from command line
46  */
47
48 static void
49 split_command(const char *cmd_line, char **command, char **params)
50 {
51   const char *p, *cmd_start;
52   char delim;
53   char *str;
54   unsigned len;
55
56   /* skip leading spaces */
57   for (p = cmd_line; isspace(*p); p++)
58     ;
59
60   /* get command */
61   switch (*p) {
62   case '\'':
63   case '"':
64     delim = *p;
65     cmd_start = ++p;
66     break;
67
68   default:
69     delim = ' ';
70     cmd_start = p;
71   }
72
73   if (delim == ' ') {
74     while (*p != '\0' && !isspace(*p))
75       p++;
76   }
77   else {
78     while (*p != '\0' && *p != delim)
79       p++;
80   }
81
82   if (command != NULL) {
83     len = p - cmd_start;
84     str = Safe_alloc(len + 1);
85     strncpy(str, cmd_start, len);
86     str[len] = '\0';
87     *command = str;
88   }
89
90   p++;
91
92   /* skip spaces before parameters */
93   while (isspace(*p))
94     p++;
95
96   /* get parameters */
97   if (params != NULL)
98     *params = Safe_strdup(p);
99 }
100
101
102 /*!
103  * merge command and parameters to command line
104  */
105
106 static char *
107 merge_command(const char *command, const char *params)
108 {
109   char *cmd_line;
110   size_t len;
111
112   /* allocate extra space for ' ' and '\0' */
113   len = strlen(command) + strlen(params) + 2;
114   cmd_line = (char *)Safe_alloc(len);
115   SNPRINTF(cmd_line, len, "%s %s", command, params);
116
117   return cmd_line;
118 }
119
120
121 /*!
122  * check if the path is absolute
123  */
124
125 static int
126 has_path(const char *path)
127 {
128   if (strrchr(path, DIR_SEPARATOR_CHAR) == NULL)
129 #ifdef _WIN32
130     /* try *nix deir separator on WIN32 */
131     if (strrchr(path, UNIX_DIR_SEPARATOR_CHAR) == NULL)
132 #endif
133       return 0;
134
135   return 1;
136 }
137
138
139 /*!
140  * find the command:
141  * 1) if the command is specified by absolute or relative path, try it
142  * 2) try to find the command in predefined path's
143  * 3) trust on $PATH
144  */
145
146 static char *
147 get_path(const char *cmd)
148 {
149   char *cmdLine = NULL;
150   char *command;
151   char *args;
152   char *path;
153   char cmdPath[PATH_MAX];
154
155
156   /* get the command */
157   split_command(cmd, &command, &args);
158
159   if (!has_path(command)) {
160     /* try to find the command in predefined binary paths */
161     if ((path = (char *)setFirstItem(binPathSet)) != NULL) {
162       do
163       {
164         SNPRINTF(cmdPath, sizeof cmdPath,
165           "%s" DIR_SEPARATOR_STRING "%s", path, command);
166
167 #ifdef _WIN32
168         /* Try if cmdPath or cmdPath.exe exist */
169         if (0 == access(cmdPath, 0) ||
170           0 == access(strncatz(cmdPath, EXE_EXT, sizeof cmdPath), 0)) {
171 #else
172         /* Try if cmdPath */
173         if (0 == access(cmdPath, X_OK)) {
174 #endif
175           /* compose the command line */
176           cmdLine = merge_command(cmdPath, args);
177           break;
178         }
179       } while ((path = (char *)setNextItem(binPathSet)) != NULL);
180     }
181     if (cmdLine == NULL)
182       cmdLine = merge_command(command, args);
183   }
184   else {
185     /*
186      * the command is defined with absolute path:
187      * just return it
188      */
189     return Safe_strdup(cmd);
190   }
191
192   Safe_free(command);
193   Safe_free(args);
194
195   return cmdLine;
196 }
197
198
199 /*!
200  * call an external program with arguements
201  */
202
203 int
204 my_system(const char *cmd)
205 {
206   int e;
207   char *cmdLine = get_path(cmd);
208
209   assert(cmdLine != NULL);
210
211   if (options.verboseExec) {
212       printf("+ %s\n", cmdLine);
213   }
214
215   e = system(cmdLine);
216   Safe_free(cmdLine);
217
218   return e;
219 }
220
221
222 /*!
223  * pipe an external program with arguements
224  */
225
226 #ifdef _WIN32
227 #define popen_read(cmd) _popen((cmd), "rt")
228 #else
229 #define popen_read(cmd) popen((cmd), "r")
230 #endif
231
232 FILE *
233 my_popen(const char *cmd)
234 {
235   FILE *fp;
236   char *cmdLine = get_path(cmd);
237
238   assert(cmdLine != NULL);
239
240   if (options.verboseExec) {
241       printf("+ %s\n", cmdLine);
242   }
243
244   fp = popen_read(cmdLine);
245   Safe_free(cmdLine);
246
247   return fp;
248 }