* src/SDCCsymt.c (computeType): fixed bug, thanks Fan Weiguang
[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     File extension component contains the 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 = end - p;
191
192           if (0 < len)
193             dbuf_append(ext, p, len);
194         }
195
196       return 1;
197     }
198 }
199
200 /** Combine directory and the file name to a path string using the DIR_SEPARATOR_CHAR.
201  */
202 void
203 dbuf_makePath(struct dbuf_s *path,const char *dir, const char *file)
204 {
205   if (dir != NULL)
206     dbuf_append_str(path, dir);
207   
208   dbuf_append_char(path, DIR_SEPARATOR_CHAR);
209
210   if (file != NULL)
211     dbuf_append_str(path, file);
212 }
213
214 /** Given a file with path information in the binary files directory,
215     returns the directory component. Used for discovery of bin
216     directory of SDCC installation. Returns NULL if the path is
217     impossible.
218 */
219 #ifdef _WIN32
220 const char *
221 getBinPath(const char *prel)
222 {
223   struct dbuf_s path;
224   const char *p;
225
226   dbuf_init(&path, 128);
227   dbuf_splitPath(prel, &path, NULL);
228
229   p = dbuf_c_str(&path);
230   if ('\0' != *p)
231     return p;
232   else
233     {
234       char module[PATH_MAX];
235
236       dbuf_destroy(&path);
237
238       /* not enough info in prel; do it with module name */
239       if (0 != GetModuleFileName(NULL, module, sizeof (module)))
240         {
241           dbuf_init(&path, 128);
242
243           dbuf_splitPath(module, &path, NULL);
244           dbuf_c_str(&path);
245           return dbuf_detach(&path);
246         }
247       else
248         return NULL;
249     }
250 }
251 #else
252 const char *
253 getBinPath(const char *prel)
254 {
255   const char *ret_path;
256
257   if (NULL != (ret_path = findProgramPath(prel)))
258     {
259       struct dbuf_s path;
260
261       dbuf_init(&path, 128);
262
263       dbuf_splitPath(ret_path, &path, NULL);
264       free((void *)ret_path);
265       dbuf_c_str(&path);
266       return dbuf_detach(&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 /* getBuildNumber - return build number                            */
388 /*-----------------------------------------------------------------*/
389 const char *getBuildNumber(void)
390 {
391   return (SDCC_BUILD_NUMBER);
392 }
393
394 /*-----------------------------------------------------------------*/
395 /* getBuildEnvironment - return environment used to build SDCC     */
396 /*-----------------------------------------------------------------*/
397 const char *getBuildEnvironment(void)
398 {
399 #ifdef __CYGWIN__
400   return "CYGWIN";
401 #elif defined __MINGW32__
402   return "MINGW32";
403 #elif defined __DJGPP__
404   return "DJGPP";
405 #elif defined(_MSC_VER)
406   return "MSVC";
407 #elif defined(__BORLANDC__)
408   return "BORLANDC";
409 #elif defined(__APPLE__)
410 # if defined(__i386__)
411   return "Mac OS X i386";
412 # else
413   return "Mac OS X ppc";
414 #endif
415 #else
416   return "UNIX";
417 #endif
418 }
419
420 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
421 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
422 {
423   va_list args;
424   int len;
425
426   va_start(args, fmt);
427
428 # if defined(HAVE_VSNPRINTF)
429   len = vsnprintf(dst, n, fmt, args);
430 # else
431   vsprintf(dst, fmt, args);
432   len = strlen(dst) + 1;
433 # endif
434
435   va_end(args);
436
437   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
438    * In the C99 spec, vsnprintf returns the number of characters that 
439    * would have been written, were space available.
440    */
441   if ((len < 0) || (size_t) len >= n) {
442     fprintf(stderr, "internal error: sprintf truncated.\n");
443   }
444
445   return len;
446 }
447 #endif
448
449 /** Pragma tokenizer
450  */
451 void
452 init_pragma_token(struct pragma_token_s *token)
453 {
454   dbuf_init(&token->dbuf, 16);
455   token->type = TOKEN_UNKNOWN;
456 }
457
458 char *
459 get_pragma_token(const char *s, struct pragma_token_s *token)
460 {
461   dbuf_set_length(&token->dbuf, 0);
462
463   /* skip leading spaces */
464   while ('\n' != *s && isspace(*s))
465     ++s;
466
467   if ('\0' == *s || '\n' == *s)
468     {
469       token->type = TOKEN_EOL;
470     }
471   else
472     {
473       char *end;
474
475       long val = strtol(s, &end, 0);
476
477       if (end != s && ('\0' == *end || isspace(*end)))
478         {
479           token->val.int_val = val;
480           token->type = TOKEN_INT;
481           dbuf_append(&token->dbuf, s, end - s);
482           s = end;
483         }
484       else
485         {
486           while ('\0' != *s && !isspace(*s))
487             {
488               dbuf_append_char(&token->dbuf, *s);
489               ++s;
490             }
491
492           token->type = TOKEN_STR;
493         }
494     }
495
496   return (char *)s;
497 }
498
499 const char *
500 get_pragma_string(struct pragma_token_s *token)
501 {
502   return dbuf_c_str(&token->dbuf);
503 }
504
505 void
506 free_pragma_token(struct pragma_token_s *token)
507 {
508   dbuf_destroy(&token->dbuf);
509 }
510
511 /*! /fn char hexEscape(char **src)
512
513     /param src Pointer to 'x' from start of hex character value
514 */
515
516 unsigned char
517 hexEscape (const char **src)
518 {
519   char *s ;
520   unsigned long value ;
521
522   (*src)++ ;    /* Skip over the 'x' */
523
524   value = strtol (*src, &s, 16);
525
526   if (s == *src)
527     {
528       // no valid hex found
529       werror(E_INVALID_HEX);
530     }
531   else
532     {
533       if (value > 255)
534         {
535           werror(W_ESC_SEQ_OOR_FOR_CHAR);
536         }
537     }
538   *src = s;
539
540   return (char) value;
541 }
542
543 /*------------------------------------------------------------------*/
544 /* octalEscape - process an octal constant of max three digits      */
545 /* return the octal value, throw a warning for illegal octal        */
546 /* adjust src to point at the last proccesed char                   */
547 /*------------------------------------------------------------------*/
548
549 unsigned char
550 octalEscape (const char **str)
551 {
552   int digits;
553   unsigned value=0;
554
555   for (digits = 0; digits < 3; digits++)
556     {
557       if (**str >='0' && **str <= '7')
558         {
559           value = value*8 + (**str - '0');
560           (*str)++;
561         }
562       else
563         {
564           break;
565         }
566     }
567   if (digits)
568     {
569       if (value > 255 /* || (**str>='0' && **str<='7') */ )
570         {
571           werror (W_ESC_SEQ_OOR_FOR_CHAR);
572         }
573     }
574   return value;
575 }
576
577 /*!
578   /fn int copyStr (char *dest, char *src)
579
580   Copies a source string to a dest buffer interpreting escape sequences
581   and special characters
582
583   /param dest Buffer to receive the resultant string
584   /param src  Buffer containing the source string with escape sequecnes
585   /return Number of characters in output string
586
587 */
588
589 int
590 copyStr (char *dest, const char *src)
591 {
592   char *OriginalDest = dest ;
593
594   while (*src)
595     {
596       if (*src == '\"')
597         src++;
598       else if (*src == '\\')
599         {
600           src++;
601           switch (*src)
602             {
603             case 'n':
604               *dest++ = '\n';
605               break;
606             case 't':
607               *dest++ = '\t';
608               break;
609             case 'v':
610               *dest++ = '\v';
611               break;
612             case 'b':
613               *dest++ = '\b';
614               break;
615             case 'r':
616               *dest++ = '\r';
617               break;
618             case 'f':
619               *dest++ = '\f';
620               break;
621             case 'a':
622               *dest++ = '\a';
623               break;
624
625             case '0':
626             case '1':
627             case '2':
628             case '3':
629             case '4':
630             case '5':
631             case '6':
632             case '7':
633               *dest++ = octalEscape(&src);
634               src-- ;
635               break;
636
637             case 'x':
638               *dest++ = hexEscape(&src) ;
639               src-- ;
640               break ;
641
642             case '\\':
643               *dest++ = '\\';
644               break;
645             case '\?':
646               *dest++ = '\?';
647               break;
648             case '\'':
649               *dest++ = '\'';
650               break;
651             case '\"':
652               *dest++ = '\"';
653               break;
654             default:
655               *dest++ = *src;
656             }
657           src++;
658         }
659       else
660         *dest++ = *src++;
661     }
662
663   *dest++ = '\0';
664
665   return dest - OriginalDest ;
666 }