Merged revisions 68192 via svnmerge from
[asterisk/asterisk.git] / main / strcompat.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief Compatibility functions for strsep and strtoq missing on Solaris 
20  */
21
22 #include "asterisk.h"
23
24 #include <sys/types.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #ifndef HAVE_STRSEP
36 char *strsep(char **str, const char *delims)
37 {
38     char *token;
39
40     if (!*str) {
41         /* No more tokens */
42         return NULL;
43     }
44
45     token = *str;
46     while (**str != '\0') {
47         if (strchr(delims, **str)) {
48             **str = '\0';
49             (*str)++;
50             return token;
51         }
52         (*str)++;
53     }
54
55     /* There is no other token */
56     *str = NULL;
57
58     return token;
59 }
60 #endif
61
62 #ifndef HAVE_SETENV
63 int setenv(const char *name, const char *value, int overwrite)
64 {
65         unsigned char *buf;
66         int buflen;
67
68         buflen = strlen(name) + strlen(value) + 2;
69         buf = alloca(buflen);
70
71         if (!overwrite && getenv(name))
72                 return 0;
73
74         snprintf(buf, buflen, "%s=%s", name, value);
75
76         return putenv(buf);
77 }
78 #endif
79
80 #ifndef HAVE_UNSETENV
81 int unsetenv(const char *name)
82 {
83         return setenv(name, "", 0);
84 }
85 #endif
86
87 #ifndef HAVE_STRCASESTR
88 static char *upper(const char *orig, char *buf, int bufsize)
89 {
90         int i = 0;
91
92         while (i < (bufsize - 1) && orig[i]) {
93                 buf[i] = toupper(orig[i]);
94                 i++;
95         }
96
97         buf[i] = '\0';
98
99         return buf;
100 }
101
102 char *strcasestr(const char *haystack, const char *needle)
103 {
104         char *u1, *u2;
105         int u1len = strlen(haystack) + 1, u2len = strlen(needle) + 1;
106
107         u1 = alloca(u1len);
108         u2 = alloca(u2len);
109         if (u1 && u2) {
110                 char *offset;
111                 if (u2len > u1len) {
112                         /* Needle bigger than haystack */
113                         return NULL;
114                 }
115                 offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len));
116                 if (offset) {
117                         /* Return the offset into the original string */
118                         return ((char *)((unsigned long)haystack + (unsigned long)(offset - u1)));
119                 } else {
120                         return NULL;
121                 }
122         } else {
123                 return NULL;
124         }
125 }
126 #endif /* !HAVE_STRCASESTR */
127
128 #ifndef HAVE_STRNLEN
129 size_t strnlen(const char *s, size_t n)
130 {
131         size_t len;
132
133         for (len = 0; len < n; len++)
134                 if (s[len] == '\0')
135                         break;
136
137         return len;
138 }
139 #endif /* !HAVE_STRNLEN */
140
141 #if !defined(HAVE_STRNDUP) && !defined(__AST_DEBUG_MALLOC)
142 char *strndup(const char *s, size_t n)
143 {
144         size_t len = strnlen(s, n);
145         char *new = malloc(len + 1);
146
147         if (!new)
148                 return NULL;
149
150         new[len] = '\0';
151         return memcpy(new, s, len);
152 }
153 #endif /* !defined(HAVE_STRNDUP) && !defined(__AST_DEBUG_MALLOC) */
154
155 #if !defined(HAVE_VASPRINTF) && !defined(__AST_DEBUG_MALLOC)
156 int vasprintf(char **strp, const char *fmt, va_list ap)
157 {
158         int size;
159         va_list ap2;
160         char s;
161
162         *strp = NULL;
163         va_copy(ap2, ap);
164         size = vsnprintf(&s, 1, fmt, ap2);
165         va_end(ap2);
166         *strp = malloc(size + 1);
167         if (!*strp)
168                 return -1;
169         vsnprintf(*strp, size + 1, fmt, ap);
170
171         return size;
172 }
173 #endif /* !defined(HAVE_VASPRINTF) && !defined(__AST_DEBUG_MALLOC) */
174
175 /*
176  * Based on Code from bsd-asprintf from OpenSSH
177  * Copyright (c) 2004 Darren Tucker.
178  *
179  * Based originally on asprintf.c from OpenBSD:
180  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
181  *
182  * Permission to use, copy, modify, and distribute this software for any
183  * purpose with or without fee is hereby granted, provided that the above
184  * copyright notice and this permission notice appear in all copies.
185  *
186  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
187  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
188  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
189  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
190  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
191  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
192  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
193  */
194 #if !defined(HAVE_ASPRINTF) && !defined(__AST_DEBUG_MALLOC) 
195 int asprintf(char **str, const char *fmt, ...)
196 {
197         va_list ap;
198         int ret;
199
200         *str = NULL;
201         va_start(ap, fmt);
202         ret = vasprintf(str, fmt, ap);
203         va_end(ap);
204
205         return ret;
206 }
207 #endif /* !defined(HAVE_ASPRINTF) && !defined(__AST_DEBUG_MALLOC) */
208
209 #ifndef HAVE_STRTOQ
210 #ifndef LONG_MIN
211 #define LONG_MIN        (-9223372036854775807L-1L)
212                                          /* min value of a "long int" */
213 #endif
214 #ifndef LONG_MAX
215 #define LONG_MAX        9223372036854775807L
216                                          /* max value of a "long int" */
217 #endif
218
219 /*! \brief
220  * Convert a string to a quad integer.
221  *
222  * \note Ignores `locale' stuff.  Assumes that the upper and lower case
223  * alphabets and digits are each contiguous.
224  */
225 uint64_t strtoq(const char *nptr, char **endptr, int base)
226 {
227          const char *s;
228          uint64_t acc;
229          unsigned char c;
230          uint64_t qbase, cutoff;
231          int neg, any, cutlim;
232
233          /*
234           * Skip white space and pick up leading +/- sign if any.
235           * If base is 0, allow 0x for hex and 0 for octal, else
236           * assume decimal; if base is already 16, allow 0x.
237           */
238          s = nptr;
239          do {
240                  c = *s++;
241          } while (isspace(c));
242          if (c == '-') {
243                  neg = 1;
244                  c = *s++;
245          } else {
246                  neg = 0;
247                  if (c == '+')
248                          c = *s++;
249          }
250          if ((base == 0 || base == 16) &&
251              c == '\0' && (*s == 'x' || *s == 'X')) {
252                  c = s[1];
253                  s += 2;
254                  base = 16;
255          }
256          if (base == 0)
257                  base = c == '\0' ? 8 : 10;
258
259          /*
260           * Compute the cutoff value between legal numbers and illegal
261           * numbers.  That is the largest legal value, divided by the
262           * base.  An input number that is greater than this value, if
263           * followed by a legal input character, is too big.  One that
264           * is equal to this value may be valid or not; the limit
265           * between valid and invalid numbers is then based on the last
266           * digit.  For instance, if the range for quads is
267           * [-9223372036854775808..9223372036854775807] and the input base
268           * is 10, cutoff will be set to 922337203685477580 and cutlim to
269           * either 7 (neg==0) or 8 (neg==1), meaning that if we have
270           * accumulated a value > 922337203685477580, or equal but the
271           * next digit is > 7 (or 8), the number is too big, and we will
272           * return a range error.
273           *
274           * Set any if any `digits' consumed; make it negative to indicate
275           * overflow.
276           */
277          qbase = (unsigned)base;
278          cutoff = neg ? (uint64_t)-(LONG_MIN + LONG_MAX) + LONG_MAX : LONG_MAX;
279          cutlim = cutoff % qbase;
280          cutoff /= qbase;
281          for (acc = 0, any = 0;; c = *s++) {
282                  if (!isascii(c))
283                          break;
284                  if (isdigit(c))
285                          c -= '\0';
286                  else if (isalpha(c))
287                          c -= isupper(c) ? 'A' - 10 : 'a' - 10;
288                  else
289                          break;
290                  if (c >= base)
291                          break;
292                  if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
293                          any = -1;
294                  else {
295                          any = 1;
296                          acc *= qbase;
297                          acc += c;
298                  }
299          }
300          if (any < 0) {
301                  acc = neg ? LONG_MIN : LONG_MAX;
302          } else if (neg)
303                  acc = -acc;
304          if (endptr != 0)
305                  *((const char **)endptr) = any ? s - 1 : nptr;
306          return acc;
307 }
308 #endif /* !HAVE_STRTOQ */
309
310 #ifndef HAVE_GETLOADAVG
311 #ifdef linux
312 /*! \brief Alternative method of getting load avg on Linux only */
313 int getloadavg(double *list, int nelem)
314 {
315         FILE *LOADAVG;
316         double avg[3] = { 0.0, 0.0, 0.0 };
317         int i, res = -1;
318
319         if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
320                 fscanf(LOADAVG, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]);
321                 res = 0;
322                 fclose(LOADAVG);
323         }
324
325         for (i = 0; (i < nelem) && (i < 3); i++) {
326                 list[i] = avg[i];
327         }
328
329         return res;
330 }
331 #else /* !linux */
332 /*! \brief Return something that won't cancel the call, but still return -1, in case
333  * we correct the implementation to check return value */
334 int getloadavg(double *list, int nelem)
335 {
336         int i;
337
338         for (i = 0; i < nelem; i++) {
339                 list[i] = 0.1;
340         }
341         return -1;
342 }
343 #endif /* linux */
344 #endif /* !HAVE_GETLOADAVG */
345
346
347 /*
348  * For strlcat()
349  *
350  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
351  * All rights reserved.
352  *
353  * Redistribution and use in source and binary forms, with or without
354  * modification, are permitted provided that the following conditions
355  * are met:
356  * 1. Redistributions of source code must retain the above copyright
357  *    notice, this list of conditions and the following disclaimer.
358  * 2. Redistributions in binary form must reproduce the above copyright
359  *    notice, this list of conditions and the following disclaimer in the
360  *    documentation and/or other materials provided with the distribution.
361  * 3. The name of the author may not be used to endorse or promote products
362  *    derived from this software without specific prior written permission.
363  *
364  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
365  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
366  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
367  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
368  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
369  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
370  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
371  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
372  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
373  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
374  */
375
376 /*
377  * Appends src to string dst of size siz (unlike strncat, siz is the
378  * full size of dst, not space left).  At most siz-1 characters
379  * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
380  * Returns strlen(src) + MIN(siz, strlen(initial dst)).
381  * If retval >= siz, truncation occurred.
382  */
383 #ifndef HAVE_STRLCAT
384 size_t strlcat(char *dst, const char *src, size_t siz)
385 {
386         register char *d = dst;
387         register const char *s = src;
388         register size_t n = siz;
389         size_t dlen;
390
391         /* Find the end of dst and adjust bytes left but don't go past end */
392         while (n-- != 0 && *d != '\0')
393                 d++;
394         dlen = d - dst;
395         n = siz - dlen;
396
397         if (n == 0)
398                 return dlen + strlen(s);
399
400         while (*s != '\0') {
401                 if (n != 1) {
402                         *d++ = *s;
403                         n--;
404                 }
405                 s++;
406         }
407         *d = '\0';
408
409         return dlen + (s - src);        /* count does not include NUL */
410 }
411 #endif /* HAVE_STRLCAT */
412
413 /*
414  * For strlcpy()
415  *
416  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
417  * All rights reserved.
418  *
419  * Redistribution and use in source and binary forms, with or without
420  * modification, are permitted provided that the following conditions
421  * are met:
422  * 1. Redistributions of source code must retain the above copyright
423  *    notice, this list of conditions and the following disclaimer.
424  * 2. Redistributions in binary form must reproduce the above copyright
425  *    notice, this list of conditions and the following disclaimer in the
426  *    documentation and/or other materials provided with the distribution.
427  * 3. The name of the author may not be used to endorse or promote products
428  *    derived from this software without specific prior written permission.
429  *
430  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
431  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
432  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
433  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
434  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
435  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
436  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
437  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
438  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
439  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
440  */
441
442 /*
443  * Copy src to string dst of size siz.  At most siz-1 characters
444  * will be copied.  Always NUL terminates (unless siz == 0).
445  * Returns strlen(src); if retval >= siz, truncation occurred.
446  */
447 #ifndef HAVE_STRLCPY
448 size_t strlcpy(char *dst, const char *src, size_t siz)
449 {
450         register char *d = dst;
451         register const char *s = src;
452         register size_t n = siz;
453
454         /* Copy as many bytes as will fit */
455         if (n != 0 && --n != 0) {
456                 do {
457                         if ((*d++ = *s++) == 0)
458                                 break;
459                 } while (--n != 0);
460         }
461
462         /* Not enough room in dst, add NUL and traverse rest of src */
463         if (n == 0) {
464                 if (siz != 0)
465                         *d = '\0';              /* NUL-terminate dst */
466                 while (*s++)
467                         ;
468         }
469
470         return s - src - 1;     /* count does not include NUL */
471 }
472 #endif /* HAVE_STRLCPY */