rewritten getPrefixFromBinPath()
[fw/sdcc] / src / SDCCutil.c
1 /*-------------------------------------------------------------------------
2   SDCCutil.c - Small utility functions.
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 "SDCCmacro.h"
27 #include "SDCCutil.h"
28 #include "newalloc.h"
29 #include <sys/stat.h>
30
31 /** Given an array of name, value string pairs creates a new hash
32     containing all of the pairs.
33 */
34 hTab *
35 populateStringHash(const char **pin)
36 {
37   hTab *pret = NULL;
38
39   while (*pin)
40     {
41       shash_add (&pret, pin[0], pin[1]);
42       pin += 2;
43     }
44
45   return pret;
46 }
47
48 /** Given an array of string pointers and another string, adds the
49     string to the end of the list.  The end of the list is assumed to
50     be the first NULL pointer.
51 */
52 void
53 addToList (const char **list, const char *str)
54 {
55   /* This is the bad way to do things :) */
56   while (*list)
57     list++;
58   *list = Safe_strdup (str);
59   if (!*list)
60     {
61       werror (E_OUT_OF_MEM, __FILE__, 0);
62       exit (1);
63     }
64   *(++list) = NULL;
65 }
66
67 /** Given an array of string pointers returns a string containing all
68     of the strings seperated by spaces.  The returned string is on the
69     heap.  The join stops when a NULL pointer is hit.
70 */
71 char *
72 join(const char **pplist)
73 {
74     buffer[0] = 0;  
75     
76     while (*pplist)
77     {
78         strncatz(buffer, *pplist, PATH_MAX);
79         strncatz(buffer, " ", PATH_MAX);
80         pplist++;
81     }
82
83     return buffer;
84 }
85
86 /** Given an array of string pointers, returns a string containing all
87     of the strings seperated by spaces.  The returned string is on the
88     heap.  n is the number of strings in the list.
89 */
90 char *
91 joinn(char **pplist, int n)
92 {
93     buffer[0] = 0;  
94     
95     while (n--)
96     {
97         strncatz(buffer, *pplist, PATH_MAX);
98         strncatz(buffer, " ", PATH_MAX);
99         pplist++;
100     }
101
102     return buffer;
103 }
104
105 /** Returns TRUE if for the host the two path characters are
106     equivalent.
107 */
108 static bool
109 pathCharsEquivalent(char c1, char c2)
110 {
111 #if NATIVE_WIN32
112   /* win32 is case insensitive */
113   if (tolower(c1) == tolower(c2))
114     {
115       return TRUE;
116     }
117   /* And / is equivalent to \ */
118   else if (c1 == '/' && c2 == '\\')
119     {
120       return TRUE;
121     }
122   else if (c1 == '\\' && c2 == '/')
123     {
124       return TRUE;
125     }
126   else
127     {
128       return FALSE;
129     }
130 #else
131   /* Assume a Unix host where they must match exactly. */
132   return c1 == c2;
133 #endif
134 }
135
136 static bool
137 pathEquivalent(const char *p1, const char *p2)
138 {
139   while (*p1 != '\0' && *p2 != '\0')
140     {
141       if (pathCharsEquivalent (*p1, *p2) == FALSE)
142         {
143           break;
144         }
145       p1++;
146       p2++;
147     }
148
149   return *p1 == *p2;
150 }
151
152 static char
153 pathCharTransform(char c)
154 {
155 #if NATIVE_WIN32
156   if (c == '/')
157     {
158       return DIR_SEPARATOR_CHAR;
159     }
160   else
161     {
162       return c;
163     }
164 #else
165   return c;
166 #endif
167 }
168
169 /** Fixes up a potentially mixed path to the proper representation for
170     the host.  Fixes up in place.
171 */
172 static char *
173 fixupPath(char *pin)
174 {
175   char *p = pin;
176
177   while (*p)
178     {
179       *p = pathCharTransform(*p);
180       p++;
181     }
182   *p = '\0';
183
184   return pin;
185 }
186
187 /** Returns the characters in p2 past the last matching characters in
188     p1.  
189 */
190 char *
191 getPathDifference (char *pinto, const char *p1, const char *p2)
192 {
193   char *p = pinto;
194
195 #if NATIVE_WIN32
196   /* win32 can have a path at the start. */
197   if (strchr(p2, ':'))
198     {
199       p2 = strchr(p2, ':')+1;
200     }
201 #endif  
202
203   while (*p1 != '\0' && *p2 != '\0')
204     {
205       if (pathCharsEquivalent(*p1, *p2) == FALSE)
206         {
207           break;
208         }
209       p1++;
210       p2++;
211     }
212   while (*p2)
213     {
214       *p++ = *p2++;
215     }
216   *p = '\0';
217
218   return fixupPath(pinto);
219 }
220
221
222 /** Given a file with path information in the binary files directory,
223     returns the directory component. Used for discovery of bin
224     directory of SDCC installation. Returns NULL if the path is
225     impossible.
226 */
227 char *
228 getBinPath(const char *prel)
229 {
230   char *p;
231   size_t len;
232   static char path[PATH_MAX];
233     
234   if ((p = strrchr(prel, DIR_SEPARATOR_CHAR)) == NULL)
235 #ifdef _WIN32
236     /* try *nix dir separator on WIN32 */
237     if ((p = strrchr(prel, UNIX_DIR_SEPARATOR_CHAR)) == NULL)
238 #endif
239       return NULL;
240
241   len = min((sizeof path) - 1, p - prel);
242   strncpy(path, prel, len);
243   path[len] = '\0';
244
245   return path;
246 }
247
248
249 /** Returns true if the given path exists.
250  */
251 bool
252 pathExists (const char *ppath)
253 {
254   struct stat s;
255
256   return stat (ppath, &s) == 0;
257 }
258
259 static hTab *_mainValues;
260
261 void
262 setMainValue (const char *pname, const char *pvalue)
263 {
264   assert(pname);
265
266   shash_add (&_mainValues, pname, pvalue);
267 }
268
269 void
270 buildCmdLine2 (char *pbuffer, const char *pcmd, size_t len)
271 {
272   char *poutcmd;
273   assert(pbuffer && pcmd);
274   assert(_mainValues);
275
276   poutcmd = msprintf(_mainValues, pcmd);
277   strncpyz(pbuffer, poutcmd, len);
278 }
279
280 void
281 populateMainValues (const char **ppin)
282 {
283   _mainValues = populateStringHash(ppin);
284 }
285
286 /** Returns true if sz starts with the string given in key.
287  */
288 bool
289 startsWith (const char *sz, const char *key)
290 {
291   return !strncmp (sz, key, strlen (key));
292 }
293
294 /** Removes any newline characters from the string.  Not strictly the
295     same as perl's chomp.
296 */
297 void
298 chomp (char *sz)
299 {
300   char *nl;
301   while ((nl = strrchr (sz, '\n')))
302     *nl = '\0';
303 }
304
305 hTab *
306 getRuntimeVariables(void)
307 {
308   return _mainValues;
309 }
310
311
312 /* strncpy() with guaranteed NULL termination. */
313 char *strncpyz(char *dest, const char *src, size_t n)
314 {
315     assert(n > 0);
316
317     --n;
318     // paranoia...
319     if (strlen(src) > n)
320     {
321         fprintf(stderr, "strncpyz prevented buffer overrun!\n");
322     }
323     
324     strncpy(dest, src, n);
325     dest[n] = 0;
326     return dest;
327 }
328
329 /* like strncat() with guaranteed NULL termination
330  * The passed size should be the size of the dest buffer, not the number of 
331  * bytes to copy.
332  */
333 char *strncatz(char *dest, const char *src, size_t n)
334 {
335     size_t maxToCopy;
336     size_t destLen = strlen(dest);
337     
338     assert(n > 0);
339     assert(n > destLen);
340     
341     maxToCopy = n - destLen - 1;
342     
343     // paranoia...
344     if (strlen(src) + destLen >= n)
345     {
346         fprintf(stderr, "strncatz prevented buffer overrun!\n");
347     }
348     
349     strncat(dest, src, maxToCopy);
350     dest[n - 1] = 0;
351     return dest;
352 }
353
354
355 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
356 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
357 {
358   va_list args;
359   int len;
360
361   va_start(args, fmt);
362
363 # if defined(HAVE_VSNPRINTF)
364   len = vsnprintf(dst, n, fmt, args);
365 # else
366   vsprintf(dst, fmt, args);
367   len = strlen(dst) + 1;
368 # endif
369
370   va_end(args);
371
372   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
373    * In the C99 spec, vsnprintf returns the number of characters that 
374    * would have been written, were space available.
375    */
376   if ((len < 0) || (size_t) len >= n) {
377     fprintf(stderr, "internal error: sprintf truncated.\n");
378   }
379
380   return len;
381 }
382
383 #endif