3cd6a0c8b8c7b9c515444c6f23b1ad794bd33f92
[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 char
137 pathCharTransform(char c)
138 {
139 #if NATIVE_WIN32
140   if (c == '/')
141     {
142       return DIR_SEPARATOR_CHAR;
143     }
144   else
145     {
146       return c;
147     }
148 #else
149   return c;
150 #endif
151 }
152
153 /** Fixes up a potentially mixed path to the proper representation for
154     the host.  Fixes up in place.
155 */
156 static char *
157 fixupPath(char *pin)
158 {
159   char *p = pin;
160
161   while (*p)
162     {
163       *p = pathCharTransform(*p);
164       p++;
165     }
166   *p = '\0';
167
168   return pin;
169 }
170
171 /** Returns the characters in p2 past the last matching characters in
172     p1.  
173 */
174 char *
175 getPathDifference (char *pinto, const char *p1, const char *p2)
176 {
177   char *p = pinto;
178
179 #if NATIVE_WIN32
180   /* win32 can have a path at the start. */
181   if (strchr(p2, ':'))
182     {
183       p2 = strchr(p2, ':')+1;
184     }
185 #endif  
186
187   while (*p1 != '\0' && *p2 != '\0')
188     {
189       if (pathCharsEquivalent(*p1, *p2) == FALSE)
190         {
191           break;
192         }
193       p1++;
194       p2++;
195     }
196   while (*p2)
197     {
198       *p++ = *p2++;
199     }
200   *p = '\0';
201
202   return fixupPath(pinto);
203 }
204
205
206 /** Given a file with path information in the binary files directory,
207     returns the directory component. Used for discovery of bin
208     directory of SDCC installation. Returns NULL if the path is
209     impossible.
210 */
211 char *
212 getBinPath(const char *prel)
213 {
214   char *p;
215   size_t len;
216   static char path[PATH_MAX];
217     
218   if ((p = strrchr(prel, DIR_SEPARATOR_CHAR)) == NULL)
219 #ifdef _WIN32
220     /* try *nix dir separator on WIN32 */
221     if ((p = strrchr(prel, UNIX_DIR_SEPARATOR_CHAR)) == NULL)
222 #endif
223       return NULL;
224
225   len = min((sizeof path) - 1, p - prel);
226   strncpy(path, prel, len);
227   path[len] = '\0';
228
229   return path;
230 }
231
232
233 /** Returns true if the given path exists.
234  */
235 bool
236 pathExists (const char *ppath)
237 {
238   struct stat s;
239
240   return stat (ppath, &s) == 0;
241 }
242
243 static hTab *_mainValues;
244
245 void
246 setMainValue (const char *pname, const char *pvalue)
247 {
248   assert(pname);
249
250   shash_add (&_mainValues, pname, pvalue);
251 }
252
253 void
254 buildCmdLine2 (char *pbuffer, const char *pcmd, size_t len)
255 {
256   char *poutcmd;
257   assert(pbuffer && pcmd);
258   assert(_mainValues);
259
260   poutcmd = msprintf(_mainValues, pcmd);
261   strncpyz(pbuffer, poutcmd, len);
262 }
263
264 void
265 populateMainValues (const char **ppin)
266 {
267   _mainValues = populateStringHash(ppin);
268 }
269
270 /** Returns true if sz starts with the string given in key.
271  */
272 bool
273 startsWith (const char *sz, const char *key)
274 {
275   return !strncmp (sz, key, strlen (key));
276 }
277
278 /** Removes any newline characters from the string.  Not strictly the
279     same as perl's chomp.
280 */
281 void
282 chomp (char *sz)
283 {
284   char *nl;
285   while ((nl = strrchr (sz, '\n')))
286     *nl = '\0';
287 }
288
289 hTab *
290 getRuntimeVariables(void)
291 {
292   return _mainValues;
293 }
294
295
296 /* strncpy() with guaranteed NULL termination. */
297 char *strncpyz(char *dest, const char *src, size_t n)
298 {
299     assert(n > 0);
300
301     --n;
302     // paranoia...
303     if (strlen(src) > n)
304     {
305         fprintf(stderr, "strncpyz prevented buffer overrun!\n");
306     }
307     
308     strncpy(dest, src, n);
309     dest[n] = 0;
310     return dest;
311 }
312
313 /* like strncat() with guaranteed NULL termination
314  * The passed size should be the size of the dest buffer, not the number of 
315  * bytes to copy.
316  */
317 char *strncatz(char *dest, const char *src, size_t n)
318 {
319     size_t maxToCopy;
320     size_t destLen = strlen(dest);
321     
322     assert(n > 0);
323     assert(n > destLen);
324     
325     maxToCopy = n - destLen - 1;
326     
327     // paranoia...
328     if (strlen(src) + destLen >= n)
329     {
330         fprintf(stderr, "strncatz prevented buffer overrun!\n");
331     }
332     
333     strncat(dest, src, maxToCopy);
334     dest[n - 1] = 0;
335     return dest;
336 }
337
338
339 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
340 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
341 {
342   va_list args;
343   int len;
344
345   va_start(args, fmt);
346
347 # if defined(HAVE_VSNPRINTF)
348   len = vsnprintf(dst, n, fmt, args);
349 # else
350   vsprintf(dst, fmt, args);
351   len = strlen(dst) + 1;
352 # endif
353
354   va_end(args);
355
356   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
357    * In the C99 spec, vsnprintf returns the number of characters that 
358    * would have been written, were space available.
359    */
360   if ((len < 0) || (size_t) len >= n) {
361     fprintf(stderr, "internal error: sprintf truncated.\n");
362   }
363
364   return len;
365 }
366
367 #endif