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