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