048f5f54ce5e5a0a4fce4dbbb7fc16ba87b7ab5e
[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 <math.h>
26 #include <ctype.h>
27
28 #ifdef _WIN32
29 #include <windows.h>
30 #endif
31 #include <sys/stat.h>
32 #include "dbuf.h"
33 #include "SDCCglobl.h"
34 #include "SDCCmacro.h"
35 #include "SDCCutil.h"
36 #include "newalloc.h"
37 #include "dbuf_string.h"
38 #ifndef _WIN32
39 #include "findme.h"
40 #endif
41
42 #include "version.h"
43
44 /** Given an array of name, value string pairs creates a new hash
45     containing all of the pairs.
46 */
47 hTab *
48 populateStringHash(const char **pin)
49 {
50   hTab *pret = NULL;
51
52   while (*pin)
53     {
54       shash_add (&pret, pin[0], pin[1]);
55       pin += 2;
56     }
57
58   return pret;
59 }
60
61 /** Prints elements of the set to the file, each element on new line
62 */
63 void
64 fputStrSet(FILE *fp, set *list)
65 {
66   const char *s;
67
68   for (s = setFirstItem(list); s != NULL; s = setNextItem(list)) {
69     fputs(s, fp);
70     fputc('\n', fp);
71   }
72 }
73
74 /** Prepend / append given strings to each item of string set. The result is in a
75     new string set.
76 */
77 set *
78 appendStrSet(set *list, const char *pre, const char *post)
79 {
80   set *new_list = NULL;
81   const char *item;
82   struct dbuf_s dbuf;
83
84   for (item = setFirstItem(list); item != NULL; item = setNextItem(list)) {
85     dbuf_init(&dbuf, PATH_MAX);
86
87     if (pre != NULL)
88       dbuf_append_str(&dbuf, pre);
89     dbuf_append_str(&dbuf, item);
90     if (post != NULL)
91       dbuf_append_str(&dbuf, post);
92
93     /* null terminate the buffer */
94     dbuf_c_str(&dbuf);
95     addSet(&new_list, dbuf_detach(&dbuf));
96   }
97
98   return new_list;
99 }
100
101 /** Given a set returns a string containing all of the strings seperated
102     by spaces. The returned string is on the heap.
103 */
104 const char *
105 joinStrSet(set *list)
106 {
107   const char *s;
108   struct dbuf_s dbuf;
109
110   dbuf_init(&dbuf, PATH_MAX);
111
112   for (s = setFirstItem(list); s != NULL; s = setNextItem(list))
113     {
114       dbuf_append_str(&dbuf, s);
115       dbuf_append_char(&dbuf, ' ');
116     }
117
118   s = dbuf_c_str(&dbuf);
119   dbuf_detach(&dbuf);
120   return s;
121 }
122
123 /** Given a file with path information in the binary files directory,
124     returns the directory component. Used for discovery of bin
125     directory of SDCC installation. Returns NULL if the path is
126     impossible.
127 */
128 #ifdef _WIN32
129 char *
130 getBinPath(const char *prel)
131 {
132   char *p;
133   size_t len;
134   static char path[PATH_MAX];
135     
136   /* try DOS and *nix dir separator on WIN32 */
137   if (NULL != (p = strrchr(prel, DIR_SEPARATOR_CHAR)) ||
138     NULL != (p = strrchr(prel, UNIX_DIR_SEPARATOR_CHAR))) {
139     len = min((sizeof path) - 1, p - prel);
140     strncpy(path, prel, len);
141     path[len] = '\0';
142     return path;
143   }
144   /* not enough info in prel; do it with module name */
145   else if (0 != GetModuleFileName(NULL, path, sizeof path) &&
146     NULL != (p = strrchr(path, DIR_SEPARATOR_CHAR))) {
147     *p = '\0';
148     return path;
149   }
150   else
151     return NULL;
152 }
153 #else
154 char *
155 getBinPath(const char *prel)
156 {
157   static char path[PATH_MAX];
158   const char *ret_path;
159
160   if (NULL != (ret_path = findProgramPath(prel))) {
161     char *p;
162     size_t len;
163
164     if (NULL != (p = strrchr(ret_path, DIR_SEPARATOR_CHAR)) &&
165       PATH_MAX > (len = p - ret_path)) {
166       memcpy(path, ret_path, len);
167       path[len] = '\0';
168       free((void *)ret_path);
169
170       return path;
171     }
172     else {
173       free((void *)ret_path);
174
175       return NULL;
176     }
177   }
178   else
179     return NULL;
180 }
181 #endif
182
183 /** Returns true if the given path exists.
184  */
185 bool
186 pathExists (const char *ppath)
187 {
188   struct stat s;
189
190   return stat (ppath, &s) == 0;
191 }
192
193 static hTab *_mainValues;
194
195 void
196 setMainValue (const char *pname, const char *pvalue)
197 {
198   assert(pname);
199
200   shash_add (&_mainValues, pname, pvalue);
201 }
202
203 void
204 buildCmdLine2 (char *pbuffer, size_t len, const char *pcmd, ...)
205 {
206   va_list ap;
207   char *poutcmd;
208
209   assert(pbuffer && pcmd);
210   assert(_mainValues);
211
212   va_start(ap, pcmd);
213
214   poutcmd = mvsprintf(_mainValues, pcmd, ap);
215
216   va_end(ap);
217
218   strncpyz(pbuffer, poutcmd, len);
219   Safe_free(poutcmd);
220 }
221
222 void
223 populateMainValues (const char **ppin)
224 {
225   _mainValues = populateStringHash(ppin);
226 }
227
228 /** Returns true if sz starts with the string given in key.
229  */
230 bool
231 startsWith (const char *sz, const char *key)
232 {
233   return !strncmp (sz, key, strlen (key));
234 }
235
236 /** Removes any newline characters from the string.  Not strictly the
237     same as perl's chomp.
238 */
239 void
240 chomp (char *sz)
241 {
242   char *nl;
243   while ((nl = strrchr (sz, '\n')))
244     *nl = '\0';
245 }
246
247 hTab *
248 getRuntimeVariables(void)
249 {
250   return _mainValues;
251 }
252
253
254 /* strncpy() with guaranteed NULL termination. */
255 char *strncpyz(char *dest, const char *src, size_t n)
256 {
257     assert(n > 0);
258
259     --n;
260     /* paranoia... */
261     if (strlen(src) > n)
262     {
263         fprintf(stderr, "strncpyz prevented buffer overrun!\n");
264     }
265     
266     strncpy(dest, src, n);
267     dest[n] = 0;
268     return dest;
269 }
270
271 /* like strncat() with guaranteed NULL termination
272  * The passed size should be the size of the dest buffer, not the number of 
273  * bytes to copy.
274  */
275 char *strncatz(char *dest, const char *src, size_t n)
276 {
277     size_t maxToCopy;
278     size_t destLen = strlen(dest);
279     
280     assert(n > 0);
281     assert(n > destLen);
282     
283     maxToCopy = n - destLen - 1;
284     
285     /* paranoia... */
286     if (strlen(src) + destLen >= n)
287     {
288         fprintf(stderr, "strncatz prevented buffer overrun!\n");
289     }
290     
291     strncat(dest, src, maxToCopy);
292     dest[n - 1] = 0;
293     return dest;
294 }
295
296
297 /*-----------------------------------------------------------------*/
298 /* getBuildNumber - return build number                            */
299 /*-----------------------------------------------------------------*/
300 const char *getBuildNumber(void)
301 {
302   return (SDCC_BUILD_NUMBER);
303 }
304
305 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
306 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
307 {
308   va_list args;
309   int len;
310
311   va_start(args, fmt);
312
313 # if defined(HAVE_VSNPRINTF)
314   len = vsnprintf(dst, n, fmt, args);
315 # else
316   vsprintf(dst, fmt, args);
317   len = strlen(dst) + 1;
318 # endif
319
320   va_end(args);
321
322   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
323    * In the C99 spec, vsnprintf returns the number of characters that 
324    * would have been written, were space available.
325    */
326   if ((len < 0) || (size_t) len >= n) {
327     fprintf(stderr, "internal error: sprintf truncated.\n");
328   }
329
330   return len;
331 }
332 #endif
333
334 /** Pragma tokenizer
335  */
336 void
337 init_pragma_token(struct pragma_token_s *token)
338 {
339   dbuf_init(&token->dbuf, 16);
340   token->type = TOKEN_UNKNOWN;
341 }
342
343 char *
344 get_pragma_token(const char *s, struct pragma_token_s *token)
345 {
346   dbuf_set_length(&token->dbuf, 0);
347
348   /* skip leading spaces */
349   while ('\n' != *s && isspace(*s))
350     ++s;
351
352   if ('\0' == *s || '\n' == *s)
353     {
354       token->type = TOKEN_EOL;
355     }
356   else
357     {
358       char *end;
359
360       long val = strtol(s, &end, 0);
361
362       if (end != s && ('\0' == *end || isspace(*end)))
363         {
364           token->val.int_val = val;
365           token->type = TOKEN_INT;
366           dbuf_append(&token->dbuf, s, end - s);
367           s = end;
368         }
369       else
370         {
371           while ('\0' != *s && !isspace(*s))
372             {
373               dbuf_append_char(&token->dbuf, *s);
374               ++s;
375             }
376
377           token->type = TOKEN_STR;
378         }
379     }
380
381   return (char *)s;
382 }
383
384 const char *
385 get_pragma_string(struct pragma_token_s *token)
386 {
387   return dbuf_c_str(&token->dbuf);
388 }
389
390 void
391 free_pragma_token(struct pragma_token_s *token)
392 {
393   dbuf_destroy(&token->dbuf);
394 }