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