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