* src/SDCCast.c (processParms): fixed bug #920866; decorateType() can return an optim...
[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 #ifdef _WIN32
26 #include <ctype.h>
27 #include <windows.h>
28 #endif
29 #include <sys/stat.h>
30 #include "dbuf.h"
31 #include "SDCCglobl.h"
32 #include "SDCCmacro.h"
33 #include "SDCCutil.h"
34 #include "newalloc.h"
35 #ifndef _WIN32
36 #include "findme.h"
37 #endif
38
39 /** Given an array of name, value string pairs creates a new hash
40     containing all of the pairs.
41 */
42 hTab *
43 populateStringHash(const char **pin)
44 {
45   hTab *pret = NULL;
46
47   while (*pin)
48     {
49       shash_add (&pret, pin[0], pin[1]);
50       pin += 2;
51     }
52
53   return pret;
54 }
55
56 /** Prints elements of the set to the file, each element on new line
57 */
58 void
59 fputStrSet(FILE *fp, set *list)
60 {
61   const char *s;
62
63   for (s = setFirstItem(list); s != NULL; s = setNextItem(list)) {
64     fputs(s, fp);
65     fputc('\n', fp);
66   }
67 }
68
69 /** Prepend / append given strings to each item of string set. The result is in a
70     new string set.
71 */
72 set *
73 appendStrSet(set *list, const char *pre, const char *post)
74 {
75   set *new_list = NULL;
76   const char *item;
77   struct dbuf_s dbuf;
78
79   for (item = setFirstItem(list); item != NULL; item = setNextItem(list)) {
80     dbuf_init(&dbuf, PATH_MAX);
81     if (pre != NULL)
82       dbuf_append(&dbuf, pre, strlen(pre));
83     dbuf_append(&dbuf, item, strlen(item));
84     if (post != NULL)
85       dbuf_append(&dbuf, post, strlen(post));
86     addSet(&new_list, (void *)dbuf_c_str(&dbuf));
87     dbuf_detach(&dbuf);
88   }
89
90   return new_list;
91 }
92
93 /** Given a set returns a string containing all of the strings seperated
94     by spaces. The returned string is on the heap.
95 */
96 const char *
97 joinStrSet(set *list)
98 {
99   const char *s;
100   struct dbuf_s dbuf;
101
102   dbuf_init(&dbuf, PATH_MAX);
103
104   for (s = setFirstItem(list); s != NULL; s = setNextItem(list))
105     {
106       dbuf_append(&dbuf, s, strlen(s));
107       dbuf_append(&dbuf, " ", 1);
108     }
109
110   s = dbuf_c_str(&dbuf);
111   dbuf_detach(&dbuf);
112   return s;
113 }
114
115 /** Given a file with path information in the binary files directory,
116     returns the directory component. Used for discovery of bin
117     directory of SDCC installation. Returns NULL if the path is
118     impossible.
119 */
120 #ifdef _WIN32
121 char *
122 getBinPath(const char *prel)
123 {
124   char *p;
125   size_t len;
126   static char path[PATH_MAX];
127     
128   /* try DOS and *nix dir separator on WIN32 */
129   if (NULL != (p = strrchr(prel, DIR_SEPARATOR_CHAR)) ||
130     NULL != (p = strrchr(prel, UNIX_DIR_SEPARATOR_CHAR))) {
131     len = min((sizeof path) - 1, p - prel);
132     strncpy(path, prel, len);
133     path[len] = '\0';
134     return path;
135   }
136   /* not enough info in prel; do it with module name */
137   else if (0 != GetModuleFileName(NULL, path, sizeof path) != 0 &&
138     NULL != (p = strrchr(path, DIR_SEPARATOR_CHAR))) {
139     *p = '\0';
140     return path;
141   }
142   else
143     return NULL;
144 }
145 #else
146 char *
147 getBinPath(const char *prel)
148 {
149   static char path[PATH_MAX];
150   const char *ret_path;
151
152   if (NULL != (ret_path = findProgramPath(prel))) {
153     char *p;
154     size_t len;
155
156     if (NULL != (p = strrchr(ret_path, DIR_SEPARATOR_CHAR)) &&
157       PATH_MAX > (len = p - ret_path)) {
158       memcpy(path, ret_path, len);
159       path[len] = '\0';
160       free((void *)ret_path);
161
162       return path;
163     }
164     else {
165       free((void *)ret_path);
166
167       return NULL;
168     }
169   }
170   else
171     return NULL;
172 }
173 #endif
174
175 /** Returns true if the given path exists.
176  */
177 bool
178 pathExists (const char *ppath)
179 {
180   struct stat s;
181
182   return stat (ppath, &s) == 0;
183 }
184
185 static hTab *_mainValues;
186
187 void
188 setMainValue (const char *pname, const char *pvalue)
189 {
190   assert(pname);
191
192   shash_add (&_mainValues, pname, pvalue);
193 }
194
195 void
196 buildCmdLine2 (char *pbuffer, size_t len, const char *pcmd, ...)
197 {
198   va_list ap;
199   char *poutcmd;
200
201   assert(pbuffer && pcmd);
202   assert(_mainValues);
203
204   va_start(ap, pcmd);
205
206   poutcmd = mvsprintf(_mainValues, pcmd, ap);
207
208   va_end(ap);
209
210   strncpyz(pbuffer, poutcmd, len);
211   Safe_free(poutcmd);
212 }
213
214 void
215 populateMainValues (const char **ppin)
216 {
217   _mainValues = populateStringHash(ppin);
218 }
219
220 /** Returns true if sz starts with the string given in key.
221  */
222 bool
223 startsWith (const char *sz, const char *key)
224 {
225   return !strncmp (sz, key, strlen (key));
226 }
227
228 /** Removes any newline characters from the string.  Not strictly the
229     same as perl's chomp.
230 */
231 void
232 chomp (char *sz)
233 {
234   char *nl;
235   while ((nl = strrchr (sz, '\n')))
236     *nl = '\0';
237 }
238
239 hTab *
240 getRuntimeVariables(void)
241 {
242   return _mainValues;
243 }
244
245
246 /* strncpy() with guaranteed NULL termination. */
247 char *strncpyz(char *dest, const char *src, size_t n)
248 {
249     assert(n > 0);
250
251     --n;
252     /* paranoia... */
253     if (strlen(src) > n)
254     {
255         fprintf(stderr, "strncpyz prevented buffer overrun!\n");
256     }
257     
258     strncpy(dest, src, n);
259     dest[n] = 0;
260     return dest;
261 }
262
263 /* like strncat() with guaranteed NULL termination
264  * The passed size should be the size of the dest buffer, not the number of 
265  * bytes to copy.
266  */
267 char *strncatz(char *dest, const char *src, size_t n)
268 {
269     size_t maxToCopy;
270     size_t destLen = strlen(dest);
271     
272     assert(n > 0);
273     assert(n > destLen);
274     
275     maxToCopy = n - destLen - 1;
276     
277     /* paranoia... */
278     if (strlen(src) + destLen >= n)
279     {
280         fprintf(stderr, "strncatz prevented buffer overrun!\n");
281     }
282     
283     strncat(dest, src, maxToCopy);
284     dest[n - 1] = 0;
285     return dest;
286 }
287
288
289 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
290 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
291 {
292   va_list args;
293   int len;
294
295   va_start(args, fmt);
296
297 # if defined(HAVE_VSNPRINTF)
298   len = vsnprintf(dst, n, fmt, args);
299 # else
300   vsprintf(dst, fmt, args);
301   len = strlen(dst) + 1;
302 # endif
303
304   va_end(args);
305
306   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
307    * In the C99 spec, vsnprintf returns the number of characters that 
308    * would have been written, were space available.
309    */
310   if ((len < 0) || (size_t) len >= n) {
311     fprintf(stderr, "internal error: sprintf truncated.\n");
312   }
313
314   return len;
315 }
316
317 #endif