fixed *nix build
[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 /** Split the path string to the directory and file name (including extension) components.
124     The directory component doesn't contain trailing directory separator.
125     Returns true if the path contains the directory separator. */
126 int
127 dbuf_splitPath(const char *path, struct dbuf_s *dir, struct dbuf_s *file)
128 {
129   const char *p;
130   int ret;
131   const char *end = &path[strlen(path)];
132
133   for (p = end - 1; p >= path && !IS_DIR_SEPARATOR(*p); --p)
134     ;
135
136   ret = p >= path;
137
138   if (NULL != dir)
139     {
140       int len = p - path;
141
142       if (0 < len)
143         dbuf_append(dir, path, len);
144     }
145
146   if (NULL != file)
147     {
148       int len;
149
150       ++p;
151       len = end - p;
152
153       if (0 < len)
154         dbuf_append(file, p, len);
155     }
156
157   return ret;
158 }
159
160 /** Split the path string to the file name (including directory) and file extension components.
161     The file name component doesn't contain trailing extension separator.
162     Returns true if the path contains the extension separator. */
163 int
164 dbuf_splitFile(const char *path, struct dbuf_s *file, struct dbuf_s *ext)
165 {
166   const char *p;
167   const char *end = &path[strlen(path)];
168
169   for (p = end - 1; p >= path && !IS_DIR_SEPARATOR(*p) && '.' != *p; --p)
170     ;
171
172   if (p < path || '.' != *p)
173     {
174       dbuf_append_str(file, path);
175
176       return 0;
177     }
178   else
179     {
180       if (NULL != file)
181         {
182           int len = p - path;
183
184           if (0 < len)
185             dbuf_append(file, path, len);
186         }
187
188       if (NULL != ext)
189         {
190           int len;
191
192           ++p;
193           len = end - p;
194
195           if (0 < len)
196             dbuf_append(ext, p, len);
197         }
198
199       return 1;
200     }
201 }
202
203 /** Combile directory and the file name to a path string using the DIR_SEPARATOR_CHAR.
204  */
205 void
206 dbuf_makePath(struct dbuf_s *path,const char *dir, const char *file)
207 {
208   if (dir != NULL)
209     dbuf_append_str(path, dir);
210   
211   dbuf_append_char(path, DIR_SEPARATOR_CHAR);
212
213   if (file != NULL)
214     dbuf_append_str(path, file);
215 }
216
217 /** Given a file with path information in the binary files directory,
218     returns the directory component. Used for discovery of bin
219     directory of SDCC installation. Returns NULL if the path is
220     impossible.
221 */
222 #ifdef _WIN32
223 const char *
224 getBinPath(const char *prel)
225 {
226   struct dbuf_s path;
227   const char *p;
228
229   dbuf_init(&path, 128);
230   dbuf_splitPath(prel, &path, NULL);
231
232   p = dbuf_c_str(&path);
233   if ('\0' != *p)
234     return p;
235   else
236     {
237       char module[PATH_MAX];
238
239       dbuf_destroy(&path);
240
241       /* not enough info in prel; do it with module name */
242       if (0 != GetModuleFileName(NULL, module, sizeof (module)))
243         {
244           dbuf_init(&path, 128);
245
246           dbuf_splitPath(module, &path, NULL);
247           dbuf_c_str(&path);
248           return dbuf_detach(&path);
249         }
250       else
251         return NULL;
252     }
253 }
254 #else
255 const char *
256 getBinPath(const char *prel)
257 {
258   const char *ret_path;
259
260   if (NULL != (ret_path = findProgramPath(prel)))
261     {
262       struct dbuf_s path;
263
264       dbuf_init(&path, 128);
265
266       dbuf_splitPath(ret_path, &path, NULL);
267       free((void *)ret_path);
268       dbuf_c_str(&path);
269       return dbuf_detach(&path);
270     }
271   else
272     return NULL;
273 }
274 #endif
275
276 /** Returns true if the given path exists.
277  */
278 bool
279 pathExists (const char *ppath)
280 {
281   struct stat s;
282
283   return stat (ppath, &s) == 0;
284 }
285
286 static hTab *_mainValues;
287
288 void
289 setMainValue (const char *pname, const char *pvalue)
290 {
291   assert(pname);
292
293   shash_add (&_mainValues, pname, pvalue);
294 }
295
296 void
297 buildCmdLine2 (char *pbuffer, size_t len, const char *pcmd, ...)
298 {
299   va_list ap;
300   char *poutcmd;
301
302   assert(pbuffer && pcmd);
303   assert(_mainValues);
304
305   va_start(ap, pcmd);
306
307   poutcmd = mvsprintf(_mainValues, pcmd, ap);
308
309   va_end(ap);
310
311   strncpyz(pbuffer, poutcmd, len);
312   Safe_free(poutcmd);
313 }
314
315 void
316 populateMainValues (const char **ppin)
317 {
318   _mainValues = populateStringHash(ppin);
319 }
320
321 /** Returns true if sz starts with the string given in key.
322  */
323 bool
324 startsWith (const char *sz, const char *key)
325 {
326   return !strncmp (sz, key, strlen (key));
327 }
328
329 /** Removes any newline characters from the string.  Not strictly the
330     same as perl's chomp.
331 */
332 void
333 chomp (char *sz)
334 {
335   char *nl;
336   while ((nl = strrchr (sz, '\n')))
337     *nl = '\0';
338 }
339
340 hTab *
341 getRuntimeVariables(void)
342 {
343   return _mainValues;
344 }
345
346
347 /* strncpy() with guaranteed NULL termination. */
348 char *strncpyz(char *dest, const char *src, size_t n)
349 {
350     assert(n > 0);
351
352     --n;
353     /* paranoia... */
354     if (strlen(src) > n)
355     {
356         fprintf(stderr, "strncpyz prevented buffer overrun!\n");
357     }
358     
359     strncpy(dest, src, n);
360     dest[n] = 0;
361     return dest;
362 }
363
364 /* like strncat() with guaranteed NULL termination
365  * The passed size should be the size of the dest buffer, not the number of 
366  * bytes to copy.
367  */
368 char *strncatz(char *dest, const char *src, size_t n)
369 {
370     size_t maxToCopy;
371     size_t destLen = strlen(dest);
372     
373     assert(n > 0);
374     assert(n > destLen);
375     
376     maxToCopy = n - destLen - 1;
377     
378     /* paranoia... */
379     if (strlen(src) + destLen >= n)
380     {
381         fprintf(stderr, "strncatz prevented buffer overrun!\n");
382     }
383     
384     strncat(dest, src, maxToCopy);
385     dest[n - 1] = 0;
386     return dest;
387 }
388
389
390 /*-----------------------------------------------------------------*/
391 /* getBuildNumber - return build number                            */
392 /*-----------------------------------------------------------------*/
393 const char *getBuildNumber(void)
394 {
395   return (SDCC_BUILD_NUMBER);
396 }
397
398 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
399 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
400 {
401   va_list args;
402   int len;
403
404   va_start(args, fmt);
405
406 # if defined(HAVE_VSNPRINTF)
407   len = vsnprintf(dst, n, fmt, args);
408 # else
409   vsprintf(dst, fmt, args);
410   len = strlen(dst) + 1;
411 # endif
412
413   va_end(args);
414
415   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
416    * In the C99 spec, vsnprintf returns the number of characters that 
417    * would have been written, were space available.
418    */
419   if ((len < 0) || (size_t) len >= n) {
420     fprintf(stderr, "internal error: sprintf truncated.\n");
421   }
422
423   return len;
424 }
425 #endif
426
427 /** Pragma tokenizer
428  */
429 void
430 init_pragma_token(struct pragma_token_s *token)
431 {
432   dbuf_init(&token->dbuf, 16);
433   token->type = TOKEN_UNKNOWN;
434 }
435
436 char *
437 get_pragma_token(const char *s, struct pragma_token_s *token)
438 {
439   dbuf_set_length(&token->dbuf, 0);
440
441   /* skip leading spaces */
442   while ('\n' != *s && isspace(*s))
443     ++s;
444
445   if ('\0' == *s || '\n' == *s)
446     {
447       token->type = TOKEN_EOL;
448     }
449   else
450     {
451       char *end;
452
453       long val = strtol(s, &end, 0);
454
455       if (end != s && ('\0' == *end || isspace(*end)))
456         {
457           token->val.int_val = val;
458           token->type = TOKEN_INT;
459           dbuf_append(&token->dbuf, s, end - s);
460           s = end;
461         }
462       else
463         {
464           while ('\0' != *s && !isspace(*s))
465             {
466               dbuf_append_char(&token->dbuf, *s);
467               ++s;
468             }
469
470           token->type = TOKEN_STR;
471         }
472     }
473
474   return (char *)s;
475 }
476
477 const char *
478 get_pragma_string(struct pragma_token_s *token)
479 {
480   return dbuf_c_str(&token->dbuf);
481 }
482
483 void
484 free_pragma_token(struct pragma_token_s *token)
485 {
486   dbuf_destroy(&token->dbuf);
487 }