aboutsummaryrefslogtreecommitdiffhomepage
path: root/libslang/src/slmisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libslang/src/slmisc.c')
-rw-r--r--libslang/src/slmisc.c605
1 files changed, 605 insertions, 0 deletions
diff --git a/libslang/src/slmisc.c b/libslang/src/slmisc.c
new file mode 100644
index 0000000..84d15f4
--- /dev/null
+++ b/libslang/src/slmisc.c
@@ -0,0 +1,605 @@
+/* Copyright (c) 1992, 1999, 2001, 2002, 2003 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#define _GNU_SOURCE
+#include "slinclud.h"
+
+#include <ctype.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#define DEBUG_MALLOC 0
+
+#if DEBUG_MALLOC
+# define SLREALLOC_FUN SLdebug_realloc
+# define SLMALLOC_FUN SLdebug_malloc
+# define SLFREE_FUN SLdebug_free
+#else
+# define SLREALLOC_FUN SLREALLOC
+# define SLMALLOC_FUN SLMALLOC
+# define SLFREE_FUN SLFREE
+#endif
+
+/* Version information goes here since this file is always needed. */
+int SLang_Version = SLANG_VERSION;
+char *SLang_Version_String = SLANG_VERSION_STRING;
+
+char *SLmake_string(char *str)
+{
+ return SLmake_nstring(str, strlen (str));
+}
+
+char *SLmake_nstring (char *str, unsigned int n)
+{
+ char *ptr;
+
+ if (NULL == (ptr = SLmalloc(n + 1)))
+ {
+ return NULL;
+ }
+ SLMEMCPY (ptr, str, n);
+ ptr[n] = 0;
+ return(ptr);
+}
+
+void SLmake_lut (unsigned char *lut, unsigned char *range, unsigned char reverse)
+{
+ /* register unsigned char *l = lut, *lmax = lut + 256; */
+ int i, r1, r2;
+
+ memset ((char *)lut, reverse, 256);
+ /* while (l < lmax) *l++ = reverse; */
+ reverse = !reverse;
+
+ r1 = *range++;
+ while (r1)
+ {
+ r2 = *range++;
+ if ((r2 == '-') && (*range != 0))
+ {
+ r2 = *range++;
+ for (i = r1; i <= r2; i++) lut[i] = reverse;
+ r1 = *range++;
+ continue;
+ }
+ lut[r1] = reverse;
+ r1 = r2;
+ }
+}
+
+char *SLmalloc (unsigned int len)
+{
+ char *p;
+
+ p = (char *) SLMALLOC_FUN (len);
+ if (p == NULL)
+ SLang_Error = SL_MALLOC_ERROR;
+
+ return p;
+}
+
+void SLfree (char *p)
+{
+ if (p != NULL) SLFREE_FUN (p);
+}
+
+char *SLrealloc (char *p, unsigned int len)
+{
+ if (len == 0)
+ {
+ SLfree (p);
+ return NULL;
+ }
+
+ if (p == NULL) p = SLmalloc (len);
+ else
+ {
+ p = (char *)SLREALLOC_FUN (p, len);
+ if (p == NULL)
+ SLang_Error = SL_MALLOC_ERROR;
+ }
+ return p;
+}
+
+char *SLcalloc (unsigned int nelems, unsigned int len)
+{
+ char *p;
+
+ len = nelems * len;
+ p = SLmalloc (len);
+ if (p != NULL) SLMEMSET (p, 0, len);
+ return p;
+}
+
+
+char *_SLskip_whitespace (char *s)
+{
+ while (isspace (*s))
+ s++;
+
+ return s;
+}
+
+
+/* p and ch may point to the same buffer */
+char *_SLexpand_escaped_char(char *p, char *ch)
+{
+ int i = 0;
+ int max = 0, num, base = 0;
+ char ch1;
+
+ ch1 = *p++;
+
+ switch (ch1)
+ {
+ default: num = ch1; break;
+ case 'n': num = '\n'; break;
+ case 't': num = '\t'; break;
+ case 'v': num = '\v'; break;
+ case 'b': num = '\b'; break;
+ case 'r': num = '\r'; break;
+ case 'f': num = '\f'; break;
+ case 'E': case 'e': num = 27; break;
+ case 'a': num = 7;
+ break;
+
+ /* octal */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ max = '7';
+ base = 8; i = 2; num = ch1 - '0';
+ break;
+
+ case 'd': /* decimal -- S-Lang extension */
+ base = 10;
+ i = 3;
+ max = '9';
+ num = 0;
+ break;
+
+ case 'x': /* hex */
+ base = 16;
+ max = '9';
+ i = 2;
+ num = 0;
+ break;
+ }
+
+ while (i--)
+ {
+ ch1 = *p;
+
+ if ((ch1 <= max) && (ch1 >= '0'))
+ {
+ num = base * num + (ch1 - '0');
+ }
+ else if (base == 16)
+ {
+ ch1 |= 0x20;
+ if ((ch1 < 'a') || ((ch1 > 'f'))) break;
+ num = base * num + 10 + (ch1 - 'a');
+ }
+ else break;
+ p++;
+ }
+
+ *ch = (char) num;
+ return p;
+}
+
+/* s and t could represent the same space */
+void SLexpand_escaped_string (register char *s, register char *t,
+ register char *tmax)
+{
+ char ch;
+
+ while (t < tmax)
+ {
+ ch = *t++;
+ if (ch == '\\')
+ {
+ t = _SLexpand_escaped_char (t, &ch);
+ }
+ *s++ = ch;
+ }
+ *s = 0;
+}
+
+int SLextract_list_element (char *list, unsigned int nth, char delim,
+ char *elem, unsigned int buflen)
+{
+ char *el, *elmax;
+ char ch;
+
+ while (nth > 0)
+ {
+ while ((0 != (ch = *list)) && (ch != delim))
+ list++;
+
+ if (ch == 0) return -1;
+
+ list++;
+ nth--;
+ }
+
+ el = elem;
+ elmax = el + (buflen - 1);
+
+ while ((0 != (ch = *list)) && (ch != delim) && (el < elmax))
+ *el++ = *list++;
+ *el = 0;
+
+ return 0;
+}
+
+#ifndef HAVE_VSNPRINTF
+int _SLvsnprintf (char *buf, unsigned int buflen, char *fmt, va_list ap)
+{
+#if 1
+ unsigned int len;
+
+ /* On some systems vsprintf returns useless information. So, punt */
+ vsprintf (buf, fmt, ap);
+ len = strlen (buf);
+ if (len >= buflen)
+ {
+ SLang_exit_error ("\
+Your system lacks the vsnprintf system call and vsprintf overflowed a buffer.\n\
+The integrity of this program has been violated.\n");
+ return EOF; /* NOT reached */
+ }
+ return (int)len;
+#else
+ int status;
+
+ status = vsprintf (buf, fmt, ap);
+ if (status >= (int) buflen)
+ {
+ /* If we are lucky, we will get this far. The real solution is to
+ * provide a working version of vsnprintf
+ */
+ SLang_exit_error ("\
+Your system lacks the vsnprintf system call and vsprintf overflowed a buffer.\n\
+The integrity of this program has been violated.\n");
+ return EOF; /* NOT reached */
+ }
+ return status;
+#endif
+}
+#endif
+
+#ifndef HAVE_SNPRINTF
+int _SLsnprintf (char *buf, unsigned int buflen, char *fmt, ...)
+{
+ int status;
+
+ va_list ap;
+
+ va_start (ap, fmt);
+ status = _SLvsnprintf (buf, buflen, fmt, ap);
+ va_end (ap);
+
+ return status;
+}
+#endif
+
+typedef struct _Cleanup_Function_Type
+{
+ struct _Cleanup_Function_Type *next;
+ void (*f)(void);
+}
+Cleanup_Function_Type;
+
+static Cleanup_Function_Type *Cleanup_Function_List;
+
+static void cleanup_slang (void)
+{
+ while (Cleanup_Function_List != NULL)
+ {
+ Cleanup_Function_Type *next = Cleanup_Function_List->next;
+ (*Cleanup_Function_List->f)();
+ SLFREE_FUN ((char *) Cleanup_Function_List);
+ Cleanup_Function_List = next;
+ }
+}
+
+#ifndef HAVE_ATEXIT
+# ifdef HAVE_ON_EXIT
+static void on_exit_cleanup_slang (int arg_unused)
+{
+ (void) arg_unused;
+ cleanup_slang ();
+}
+# endif
+#endif
+
+int SLang_add_cleanup_function (void (*f)(void))
+{
+ Cleanup_Function_Type *l;
+
+ l = (Cleanup_Function_Type *) SLMALLOC_FUN (sizeof (Cleanup_Function_Type));
+ if (l == NULL)
+ return -1;
+
+ l->f = f;
+ l->next = Cleanup_Function_List;
+
+ if (Cleanup_Function_List == NULL)
+ {
+#ifdef HAVE_ATEXIT
+ (void) atexit (cleanup_slang);
+#else
+# ifdef HAVE_ON_EXIT
+ (void) on_exit (on_exit_cleanup_slang, 0);
+# endif
+#endif
+ }
+ Cleanup_Function_List = l;
+ return 0;
+}
+
+
+int SLang_guess_type (char *t)
+{
+ char *p;
+ register char ch;
+ int modifier;
+
+ if (*t == '-') t++;
+ p = t;
+
+#if SLANG_HAS_FLOAT
+ if (*p != '.')
+ {
+#endif
+ modifier = 0;
+ while ((*p >= '0') && (*p <= '9')) p++;
+ if (t == p) return (SLANG_STRING_TYPE);
+ if ((*p == 'x') && (p == t + 1)) /* 0x?? */
+ {
+ modifier |= 8;
+ p++;
+ while (ch = *p,
+ ((ch >= '0') && (ch <= '9'))
+ || (((ch | 0x20) >= 'a') && ((ch | 0x20) <= 'f'))) p++;
+ }
+
+ /* Now look for UL, LU, UH, HU, L, H modifiers */
+ while ((ch = *p) != 0)
+ {
+ ch |= 0x20;
+ if (ch == 'h') modifier |= 1;
+ else if (ch == 'l') modifier |= 2;
+ else if (ch == 'u') modifier |= 4;
+ else break;
+ p++;
+ }
+ if ((1|2) == (modifier & (1|2))) /* hl present */
+ return SLANG_STRING_TYPE;
+
+ if (ch == 0)
+ {
+ if ((modifier & 0x7) == 0) return SLANG_INT_TYPE;
+ if (modifier & 4)
+ {
+ if (modifier & 1) return SLANG_USHORT_TYPE;
+ if (modifier & 2) return SLANG_ULONG_TYPE;
+ return SLANG_UINT_TYPE;
+ }
+ if (modifier & 1) return SLANG_SHORT_TYPE;
+ if (modifier & 2) return SLANG_LONG_TYPE;
+ return SLANG_INT_TYPE;
+ }
+
+ if (modifier) return SLANG_STRING_TYPE;
+#if SLANG_HAS_FLOAT
+ }
+
+ /* now down to double case */
+ if (*p == '.')
+ {
+ p++;
+ while ((*p >= '0') && (*p <= '9')) p++;
+ }
+ if (*p == 0) return(SLANG_DOUBLE_TYPE);
+ if ((*p != 'e') && (*p != 'E'))
+ {
+# if SLANG_HAS_COMPLEX
+ if (((*p == 'i') || (*p == 'j'))
+ && (p[1] == 0))
+ return SLANG_COMPLEX_TYPE;
+# endif
+ if (((*p | 0x20) == 'f') && (p[1] == 0))
+ return SLANG_FLOAT_TYPE;
+
+ return SLANG_STRING_TYPE;
+ }
+
+ p++;
+ if ((*p == '-') || (*p == '+')) p++;
+ while ((*p >= '0') && (*p <= '9')) p++;
+ if (*p != 0)
+ {
+# if SLANG_HAS_COMPLEX
+ if (((*p == 'i') || (*p == 'j'))
+ && (p[1] == 0))
+ return SLANG_COMPLEX_TYPE;
+# endif
+ if (((*p | 0x20) == 'f') && (p[1] == 0))
+ return SLANG_FLOAT_TYPE;
+
+ return SLANG_STRING_TYPE;
+ }
+ return SLANG_DOUBLE_TYPE;
+#else
+ return SLANG_STRING_TYPE;
+#endif /* SLANG_HAS_FLOAT */
+}
+
+static int hex_atoul (unsigned char *s, unsigned long *ul)
+{
+ register unsigned char ch;
+ register unsigned long value;
+ register int base;
+
+ s++; /* skip the leading 0 */
+
+ /* look for 'x' which indicates hex */
+ if ((*s | 0x20) == 'x')
+ {
+ base = 16;
+ s++;
+ if (*s == 0)
+ {
+ SLang_Error = SL_SYNTAX_ERROR;
+ return -1;
+ }
+ }
+ else base = 8;
+
+ value = 0;
+ while ((ch = *s++) != 0)
+ {
+ char ch1 = ch | 0x20;
+ switch (ch1)
+ {
+ default:
+ SLang_Error = SL_SYNTAX_ERROR;
+ break;
+
+ case 'u':
+ case 'l':
+ case 'h':
+ *ul = value;
+ return 0;
+
+ case '8':
+ case '9':
+ if (base != 16) SLang_Error = SL_SYNTAX_ERROR;
+ /* drop */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ ch1 -= '0';
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ if (base != 16) SLang_Error = SL_SYNTAX_ERROR;
+ ch1 = (ch1 - 'a') + 10;
+ break;
+ }
+ value = value * base + ch1;
+ }
+ *ul = value;
+ return 0;
+}
+
+/* Note: These routines do not check integer overflow. I would use the C
+ * library functions atol and atoul but some implementations check overflow
+ * and some do not. The following implementations provide a consistent
+ * behavior.
+ */
+unsigned long SLatoul (unsigned char *s)
+{
+ int sign;
+ unsigned long value;
+
+ if (*s == '-') sign = -1;
+ else
+ {
+ sign = 1;
+ if (*s == '+') s++;
+ }
+
+ if (*s == '0')
+ {
+ if (-1 == hex_atoul (s, &value))
+ return (unsigned long) -1;
+ }
+ else
+ {
+ s = (unsigned char *) _SLskip_whitespace ((char *)s);
+
+ value = 0;
+ while (isdigit (*s))
+ {
+ value = value * 10 + (unsigned long) (*s - '0');
+ s++;
+ }
+ }
+
+ if (sign == -1)
+ value = (unsigned long)-1L * value;
+
+ return value;
+}
+
+long SLatol (unsigned char *s)
+{
+ s = (unsigned char *) _SLskip_whitespace ((char *)s);
+
+ if (*s == '-')
+ {
+ long value = (long) SLatoul (s+1);
+ return -value;
+ }
+ return (long) SLatoul (s);
+}
+
+int SLatoi (unsigned char *s)
+{
+ return (int) SLatol (s);
+}
+
+#if !defined(HAVE_ISSETUGID) && defined(__GLIBC__) && (__GLIBC__ >= 2)
+extern int __libc_enable_secure;
+# define HAVE___LIBC_ENABLE_SECURE 1
+#endif
+
+int _SLsecure_issetugid (void)
+{
+#ifdef HAVE_ISSETUGID
+ return (1 == issetugid ());
+#else
+# ifdef HAVE___LIBC_ENABLE_SECURE
+ return __libc_enable_secure;
+# else
+# if defined(HAVE_GETUID) && defined(HAVE_GETEUID) && defined(HAVE_GETGID) && defined(HAVE_GETEUID)
+ static int enable_secure;
+ if (enable_secure == 0)
+ {
+ if ((getuid () != geteuid ())
+ || (getgid () != getegid ()))
+ enable_secure = 1;
+ else
+ enable_secure = -1;
+ }
+ return (enable_secure == 1);
+# else
+ return 0;
+# endif
+# endif
+#endif
+}
+
+/* Like getenv, except if running as setuid or setgid, returns NULL */
+char *_SLsecure_getenv (char *s)
+{
+ if (_SLsecure_issetugid ())
+ return NULL;
+ return getenv (s);
+}