* configure.in,
[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 #else
410   return "UNIX";
411 #endif
412 }
413
414 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
415 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
416 {
417   va_list args;
418   int len;
419
420   va_start(args, fmt);
421
422 # if defined(HAVE_VSNPRINTF)
423   len = vsnprintf(dst, n, fmt, args);
424 # else
425   vsprintf(dst, fmt, args);
426   len = strlen(dst) + 1;
427 # endif
428
429   va_end(args);
430
431   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
432    * In the C99 spec, vsnprintf returns the number of characters that 
433    * would have been written, were space available.
434    */
435   if ((len < 0) || (size_t) len >= n) {
436     fprintf(stderr, "internal error: sprintf truncated.\n");
437   }
438
439   return len;
440 }
441 #endif
442
443 /** Pragma tokenizer
444  */
445 void
446 init_pragma_token(struct pragma_token_s *token)
447 {
448   dbuf_init(&token->dbuf, 16);
449   token->type = TOKEN_UNKNOWN;
450 }
451
452 char *
453 get_pragma_token(const char *s, struct pragma_token_s *token)
454 {
455   dbuf_set_length(&token->dbuf, 0);
456
457   /* skip leading spaces */
458   while ('\n' != *s && isspace(*s))
459     ++s;
460
461   if ('\0' == *s || '\n' == *s)
462     {
463       token->type = TOKEN_EOL;
464     }
465   else
466     {
467       char *end;
468
469       long val = strtol(s, &end, 0);
470
471       if (end != s && ('\0' == *end || isspace(*end)))
472         {
473           token->val.int_val = val;
474           token->type = TOKEN_INT;
475           dbuf_append(&token->dbuf, s, end - s);
476           s = end;
477         }
478       else
479         {
480           while ('\0' != *s && !isspace(*s))
481             {
482               dbuf_append_char(&token->dbuf, *s);
483               ++s;
484             }
485
486           token->type = TOKEN_STR;
487         }
488     }
489
490   return (char *)s;
491 }
492
493 const char *
494 get_pragma_string(struct pragma_token_s *token)
495 {
496   return dbuf_c_str(&token->dbuf);
497 }
498
499 void
500 free_pragma_token(struct pragma_token_s *token)
501 {
502   dbuf_destroy(&token->dbuf);
503 }
504
505 /*! /fn char hexEscape(char **src)
506
507     /param src Pointer to 'x' from start of hex character value
508 */
509
510 unsigned char
511 hexEscape (const char **src)
512 {
513   char *s ;
514   unsigned long value ;
515
516   (*src)++ ;    /* Skip over the 'x' */
517
518   value = strtol (*src, &s, 16);
519
520   if (s == *src)
521     {
522       // no valid hex found
523       werror(E_INVALID_HEX);
524     }
525   else
526     {
527       if (value > 255)
528         {
529           werror(W_ESC_SEQ_OOR_FOR_CHAR);
530         }
531     }
532   *src = s;
533
534   return (char) value;
535 }
536
537 /*------------------------------------------------------------------*/
538 /* octalEscape - process an octal constant of max three digits      */
539 /* return the octal value, throw a warning for illegal octal        */
540 /* adjust src to point at the last proccesed char                   */
541 /*------------------------------------------------------------------*/
542
543 unsigned char
544 octalEscape (const char **str)
545 {
546   int digits;
547   unsigned value=0;
548
549   for (digits = 0; digits < 3; digits++)
550     {
551       if (**str >='0' && **str <= '7')
552         {
553           value = value*8 + (**str - '0');
554           (*str)++;
555         }
556       else
557         {
558           break;
559         }
560     }
561   if (digits)
562     {
563       if (value > 255 /* || (**str>='0' && **str<='7') */ )
564         {
565           werror (W_ESC_SEQ_OOR_FOR_CHAR);
566         }
567     }
568   return value;
569 }
570
571 /*!
572   /fn int copyStr (char *dest, char *src)
573
574   Copies a source string to a dest buffer interpreting escape sequences
575   and special characters
576
577   /param dest Buffer to receive the resultant string
578   /param src  Buffer containing the source string with escape sequecnes
579   /return Number of characters in output string
580
581 */
582
583 int
584 copyStr (char *dest, const char *src)
585 {
586   char *OriginalDest = dest ;
587
588   while (*src)
589     {
590       if (*src == '\"')
591         src++;
592       else if (*src == '\\')
593         {
594           src++;
595           switch (*src)
596             {
597             case 'n':
598               *dest++ = '\n';
599               break;
600             case 't':
601               *dest++ = '\t';
602               break;
603             case 'v':
604               *dest++ = '\v';
605               break;
606             case 'b':
607               *dest++ = '\b';
608               break;
609             case 'r':
610               *dest++ = '\r';
611               break;
612             case 'f':
613               *dest++ = '\f';
614               break;
615             case 'a':
616               *dest++ = '\a';
617               break;
618
619             case '0':
620             case '1':
621             case '2':
622             case '3':
623             case '4':
624             case '5':
625             case '6':
626             case '7':
627               *dest++ = octalEscape(&src);
628               src-- ;
629               break;
630
631             case 'x':
632               *dest++ = hexEscape(&src) ;
633               src-- ;
634               break ;
635
636             case '\\':
637               *dest++ = '\\';
638               break;
639             case '\?':
640               *dest++ = '\?';
641               break;
642             case '\'':
643               *dest++ = '\'';
644               break;
645             case '\"':
646               *dest++ = '\"';
647               break;
648             default:
649               *dest++ = *src;
650             }
651           src++;
652         }
653       else
654         *dest++ = *src++;
655     }
656
657   *dest++ = '\0';
658
659   return dest - OriginalDest ;
660 }