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