* sim/ucsim/cmd.src/cmdutil.cc: NUL device is detected as CG_FILE type
[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           return dbuf_c_str(&path);
248         }
249       else
250         return NULL;
251     }
252 }
253 #else
254 const char *
255 getBinPath(const char *prel)
256 {
257   struct dbuf_s path;
258   const char *ret_path;
259
260   if (NULL != (ret_path = findProgramPath(prel)))
261     {
262       dbuf_splitPath(prel, path, NULL);
263
264       free((void *)ret_path);
265
266       return dbuf_c_str(path);
267     }
268   else
269     return NULL;
270 }
271 #endif
272
273 /** Returns true if the given path exists.
274  */
275 bool
276 pathExists (const char *ppath)
277 {
278   struct stat s;
279
280   return stat (ppath, &s) == 0;
281 }
282
283 static hTab *_mainValues;
284
285 void
286 setMainValue (const char *pname, const char *pvalue)
287 {
288   assert(pname);
289
290   shash_add (&_mainValues, pname, pvalue);
291 }
292
293 void
294 buildCmdLine2 (char *pbuffer, size_t len, const char *pcmd, ...)
295 {
296   va_list ap;
297   char *poutcmd;
298
299   assert(pbuffer && pcmd);
300   assert(_mainValues);
301
302   va_start(ap, pcmd);
303
304   poutcmd = mvsprintf(_mainValues, pcmd, ap);
305
306   va_end(ap);
307
308   strncpyz(pbuffer, poutcmd, len);
309   Safe_free(poutcmd);
310 }
311
312 void
313 populateMainValues (const char **ppin)
314 {
315   _mainValues = populateStringHash(ppin);
316 }
317
318 /** Returns true if sz starts with the string given in key.
319  */
320 bool
321 startsWith (const char *sz, const char *key)
322 {
323   return !strncmp (sz, key, strlen (key));
324 }
325
326 /** Removes any newline characters from the string.  Not strictly the
327     same as perl's chomp.
328 */
329 void
330 chomp (char *sz)
331 {
332   char *nl;
333   while ((nl = strrchr (sz, '\n')))
334     *nl = '\0';
335 }
336
337 hTab *
338 getRuntimeVariables(void)
339 {
340   return _mainValues;
341 }
342
343
344 /* strncpy() with guaranteed NULL termination. */
345 char *strncpyz(char *dest, const char *src, size_t n)
346 {
347     assert(n > 0);
348
349     --n;
350     /* paranoia... */
351     if (strlen(src) > n)
352     {
353         fprintf(stderr, "strncpyz prevented buffer overrun!\n");
354     }
355     
356     strncpy(dest, src, n);
357     dest[n] = 0;
358     return dest;
359 }
360
361 /* like strncat() with guaranteed NULL termination
362  * The passed size should be the size of the dest buffer, not the number of 
363  * bytes to copy.
364  */
365 char *strncatz(char *dest, const char *src, size_t n)
366 {
367     size_t maxToCopy;
368     size_t destLen = strlen(dest);
369     
370     assert(n > 0);
371     assert(n > destLen);
372     
373     maxToCopy = n - destLen - 1;
374     
375     /* paranoia... */
376     if (strlen(src) + destLen >= n)
377     {
378         fprintf(stderr, "strncatz prevented buffer overrun!\n");
379     }
380     
381     strncat(dest, src, maxToCopy);
382     dest[n - 1] = 0;
383     return dest;
384 }
385
386
387 /*-----------------------------------------------------------------*/
388 /* getBuildNumber - return build number                            */
389 /*-----------------------------------------------------------------*/
390 const char *getBuildNumber(void)
391 {
392   return (SDCC_BUILD_NUMBER);
393 }
394
395 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
396 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
397 {
398   va_list args;
399   int len;
400
401   va_start(args, fmt);
402
403 # if defined(HAVE_VSNPRINTF)
404   len = vsnprintf(dst, n, fmt, args);
405 # else
406   vsprintf(dst, fmt, args);
407   len = strlen(dst) + 1;
408 # endif
409
410   va_end(args);
411
412   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
413    * In the C99 spec, vsnprintf returns the number of characters that 
414    * would have been written, were space available.
415    */
416   if ((len < 0) || (size_t) len >= n) {
417     fprintf(stderr, "internal error: sprintf truncated.\n");
418   }
419
420   return len;
421 }
422 #endif
423
424 /** Pragma tokenizer
425  */
426 void
427 init_pragma_token(struct pragma_token_s *token)
428 {
429   dbuf_init(&token->dbuf, 16);
430   token->type = TOKEN_UNKNOWN;
431 }
432
433 char *
434 get_pragma_token(const char *s, struct pragma_token_s *token)
435 {
436   dbuf_set_length(&token->dbuf, 0);
437
438   /* skip leading spaces */
439   while ('\n' != *s && isspace(*s))
440     ++s;
441
442   if ('\0' == *s || '\n' == *s)
443     {
444       token->type = TOKEN_EOL;
445     }
446   else
447     {
448       char *end;
449
450       long val = strtol(s, &end, 0);
451
452       if (end != s && ('\0' == *end || isspace(*end)))
453         {
454           token->val.int_val = val;
455           token->type = TOKEN_INT;
456           dbuf_append(&token->dbuf, s, end - s);
457           s = end;
458         }
459       else
460         {
461           while ('\0' != *s && !isspace(*s))
462             {
463               dbuf_append_char(&token->dbuf, *s);
464               ++s;
465             }
466
467           token->type = TOKEN_STR;
468         }
469     }
470
471   return (char *)s;
472 }
473
474 const char *
475 get_pragma_string(struct pragma_token_s *token)
476 {
477   return dbuf_c_str(&token->dbuf);
478 }
479
480 void
481 free_pragma_token(struct pragma_token_s *token)
482 {
483   dbuf_destroy(&token->dbuf);
484 }