fixed Z80 port - crt0.o: cannot open.
[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, size_t len, const char *pcmd, ...)
183 {
184   va_list ap;
185   char *poutcmd;
186
187   assert(pbuffer && pcmd);
188   assert(_mainValues);
189
190   va_start(ap, pcmd);
191
192   poutcmd = mvsprintf(_mainValues, pcmd, ap);
193
194   va_end(ap);
195
196   strncpyz(pbuffer, poutcmd, len);
197   Safe_free(poutcmd);
198 }
199
200 void
201 populateMainValues (const char **ppin)
202 {
203   _mainValues = populateStringHash(ppin);
204 }
205
206 /** Returns true if sz starts with the string given in key.
207  */
208 bool
209 startsWith (const char *sz, const char *key)
210 {
211   return !strncmp (sz, key, strlen (key));
212 }
213
214 /** Removes any newline characters from the string.  Not strictly the
215     same as perl's chomp.
216 */
217 void
218 chomp (char *sz)
219 {
220   char *nl;
221   while ((nl = strrchr (sz, '\n')))
222     *nl = '\0';
223 }
224
225 hTab *
226 getRuntimeVariables(void)
227 {
228   return _mainValues;
229 }
230
231
232 /* strncpy() with guaranteed NULL termination. */
233 char *strncpyz(char *dest, const char *src, size_t n)
234 {
235     assert(n > 0);
236
237     --n;
238     /* paranoia... */
239     if (strlen(src) > n)
240     {
241         fprintf(stderr, "strncpyz prevented buffer overrun!\n");
242     }
243     
244     strncpy(dest, src, n);
245     dest[n] = 0;
246     return dest;
247 }
248
249 /* like strncat() with guaranteed NULL termination
250  * The passed size should be the size of the dest buffer, not the number of 
251  * bytes to copy.
252  */
253 char *strncatz(char *dest, const char *src, size_t n)
254 {
255     size_t maxToCopy;
256     size_t destLen = strlen(dest);
257     
258     assert(n > 0);
259     assert(n > destLen);
260     
261     maxToCopy = n - destLen - 1;
262     
263     /* paranoia... */
264     if (strlen(src) + destLen >= n)
265     {
266         fprintf(stderr, "strncatz prevented buffer overrun!\n");
267     }
268     
269     strncat(dest, src, maxToCopy);
270     dest[n - 1] = 0;
271     return dest;
272 }
273
274
275 #if defined(HAVE_VSNPRINTF) || defined(HAVE_VSPRINTF)
276 size_t SDCCsnprintf(char *dst, size_t n, const char *fmt, ...)
277 {
278   va_list args;
279   int len;
280
281   va_start(args, fmt);
282
283 # if defined(HAVE_VSNPRINTF)
284   len = vsnprintf(dst, n, fmt, args);
285 # else
286   vsprintf(dst, fmt, args);
287   len = strlen(dst) + 1;
288 # endif
289
290   va_end(args);
291
292   /* on some gnu systems, vsnprintf returns -1 if output is truncated.
293    * In the C99 spec, vsnprintf returns the number of characters that 
294    * would have been written, were space available.
295    */
296   if ((len < 0) || (size_t) len >= n) {
297     fprintf(stderr, "internal error: sprintf truncated.\n");
298   }
299
300   return len;
301 }
302
303 #endif