r7415: * big change -- volker's new async winbindd from trunk
[samba.git] / source / lib / util_str.c
index d93f39696f4862234b1ff9a4313f40cf83310a56..f600d1704e06ccf328a22cdc074343254790c6f4 100644 (file)
@@ -62,7 +62,7 @@ BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
        /* copy over the token */
        pbuf = buff;
        for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
-               if (*s == '\"' || *s == '\'') {
+               if ( *s == '\"' ) {
                        quoted = !quoted;
                } else {
                        len++;
@@ -134,17 +134,20 @@ char **toktocliplist(int *ctok, const char *sep)
        *ctok=ictok;
        s=(char *)last_ptr;
        
-       if (!(ret=iret=malloc(ictok*sizeof(char *))))
+       if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
                return NULL;
        
        while(ictok--) {    
                *iret++=s;
-               while(*s++)
-                       ;
-               while(!*s)
-                       s++;
+               if (ictok > 0) {
+                       while(*s++)
+                               ;
+                       while(!*s)
+                               s++;
+               }
        }
 
+       ret[*ctok] = NULL;
        return ret;
 }
 
@@ -334,9 +337,8 @@ char *strupper_static(const char *s)
  Convert a string to "normal" form.
 **/
 
-void strnorm(char *s)
+void strnorm(char *s, int case_default)
 {
-       extern int case_default;
        if (case_default == CASE_UPPER)
                strupper_m(s);
        else
@@ -347,9 +349,8 @@ void strnorm(char *s)
  Check if a string is in "normal" case.
 **/
 
-BOOL strisnormal(const char *s)
+BOOL strisnormal(const char *s, int case_default)
 {
-       extern int case_default;
        if (case_default == CASE_UPPER)
                return(!strhaslower(s));
        
@@ -362,16 +363,16 @@ BOOL strisnormal(const char *s)
  NOTE: oldc and newc must be 7 bit characters
 **/
 
-void string_replace(pstring s,char oldc,char newc)
+void string_replace( pstring s, char oldc, char newc )
 {
-       unsigned char *p;
+       char *p;
 
        /* this is quite a common operation, so we want it to be
           fast. We optimise for the ascii case, knowing that all our
           supported multi-byte character sets are ascii-compatible
           (ie. they match for the first 128 chars) */
 
-       for (p = (unsigned char *)s; *p; p++) {
+       for (p = s; *p; p++) {
                if (*p & 0x80) /* mb string - slow path. */
                        break;
                if (*p == oldc)
@@ -557,10 +558,17 @@ size_t count_chars(const char *s,char c)
 {
        smb_ucs2_t *ptr;
        int count;
-       push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
-       for(count=0,ptr=tmpbuf;*ptr;ptr++)
+       smb_ucs2_t *alloc_tmpbuf = NULL;
+
+       if (push_ucs2_allocate(&alloc_tmpbuf, s) == (size_t)-1) {
+               return 0;
+       }
+
+       for(count=0,ptr=alloc_tmpbuf;*ptr;ptr++)
                if(*ptr==UCS2_CHAR(c))
                        count++;
+
+       SAFE_FREE(alloc_tmpbuf);
        return(count);
 }
 
@@ -787,6 +795,17 @@ size_t strhex_to_str(char *p, size_t len, const char *strhex)
        return num_chars;
 }
 
+DATA_BLOB strhex_to_data_blob(const char *strhex) 
+{
+       DATA_BLOB ret_blob = data_blob(NULL, strlen(strhex)/2+1);
+
+       ret_blob.length = strhex_to_str((char*)ret_blob.data,   
+                                       strlen(strhex), 
+                                       strhex);
+
+       return ret_blob;
+}
+
 /**
  * Routine to print a buffer as HEX digits, into an allocated string.
  */
@@ -796,7 +815,7 @@ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
        int i;
        char *hex_buffer;
 
-       *out_hex_buffer = smb_xmalloc((len*2)+1);
+       *out_hex_buffer = SMB_XMALLOC_ARRAY(char, (len*2)+1);
        hex_buffer = *out_hex_buffer;
 
        for (i = 0; i < len; i++)
@@ -807,7 +826,7 @@ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
  Check if a string is part of a list.
 **/
 
-BOOL in_list(char *s,char *list,BOOL casesensitive)
+BOOL in_list(const char *s, const char *list, BOOL casesensitive)
 {
        pstring tok;
        const char *p=list;
@@ -844,7 +863,7 @@ static BOOL string_init(char **dest,const char *src)
 
        if (l == 0) {
                if (!null_string) {
-                       if((null_string = (char *)malloc(1)) == NULL) {
+                       if((null_string = (char *)SMB_MALLOC(1)) == NULL) {
                                DEBUG(0,("string_init: malloc fail for null_string.\n"));
                                return False;
                        }
@@ -852,7 +871,7 @@ static BOOL string_init(char **dest,const char *src)
                }
                *dest = null_string;
        } else {
-               (*dest) = strdup(src);
+               (*dest) = SMB_STRDUP(src);
                if ((*dest) == NULL) {
                        DEBUG(0,("Out of memory in string_init\n"));
                        return False;
@@ -912,7 +931,7 @@ void string_sub(char *s,const char *pattern, const char *insert, size_t len)
        if (len == 0)
                len = ls + 1; /* len is number of *bytes* */
 
-       while (lp <= ls && (p = strstr(s,pattern))) {
+       while (lp <= ls && (p = strstr_m(s,pattern))) {
                if (ls + (li-lp) >= len) {
                        DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n", 
                                 (int)(ls + (li-lp) - len),
@@ -971,7 +990,7 @@ char *realloc_string_sub(char *string, const char *pattern, const char *insert)
 
        s = string;
 
-       in = strdup(insert);
+       in = SMB_STRDUP(insert);
        if (!in) {
                DEBUG(0, ("realloc_string_sub: out of memory!\n"));
                return NULL;
@@ -997,10 +1016,10 @@ char *realloc_string_sub(char *string, const char *pattern, const char *insert)
                }
        }
        
-       while ((p = strstr(s,pattern))) {
+       while ((p = strstr_m(s,pattern))) {
                if (ld > 0) {
                        int offset = PTR_DIFF(s,string);
-                       char *t = Realloc(string, ls + ld + 1);
+                       char *t = SMB_REALLOC(string, ls + ld + 1);
                        if (!t) {
                                DEBUG(0, ("realloc_string_sub: out of memory!\n"));
                                SAFE_FREE(in);
@@ -1045,7 +1064,7 @@ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
        if (len == 0)
                len = ls + 1; /* len is number of *bytes* */
        
-       while (lp <= ls && (p = strstr(s,pattern))) {
+       while (lp <= ls && (p = strstr_m(s,pattern))) {
                if (ls + (li-lp) >= len) {
                        DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n", 
                                 (int)(ls + (li-lp) - len),
@@ -1091,7 +1110,7 @@ static smb_ucs2_t *all_string_sub_w(const smb_ucs2_t *s, const smb_ucs2_t *patte
                }
        }
 
-       r = rp = (smb_ucs2_t *)malloc((lt + 1)*(sizeof(smb_ucs2_t)));
+       r = rp = SMB_MALLOC_ARRAY(smb_ucs2_t, lt + 1);
        if (!r) {
                DEBUG(0, ("all_string_sub_w: out of memory!\n"));
                return NULL;
@@ -1189,6 +1208,12 @@ char *strchr_m(const char *src, char c)
        smb_ucs2_t *p;
        const char *s;
 
+       /* characters below 0x3F are guaranteed to not appear in
+          non-initial position in multi-byte charsets */
+       if ((c & 0xC0) == 0) {
+               return strchr(src, c);
+       }
+
        /* this is quite a common operation, so we want it to be
           fast. We optimise for the ascii case, knowing that all our
           supported multi-byte character sets are ascii-compatible
@@ -1218,6 +1243,12 @@ char *strchr_m(const char *src, char c)
 
 char *strrchr_m(const char *s, char c)
 {
+       /* characters below 0x3F are guaranteed to not appear in
+          non-initial position in multi-byte charsets */
+       if ((c & 0xC0) == 0) {
+               return strrchr(s, c);
+       }
+
        /* this is quite a common operation, so we want it to be
           fast. We optimise for the ascii case, knowing that all our
           supported multi-byte character sets are ascii-compatible
@@ -1287,12 +1318,96 @@ char *strnrchr_m(const char *s, char c, unsigned int n)
        return (char *)(s+strlen(s2));
 }
 
+/***********************************************************************
+ strstr_m - We convert via ucs2 for now.
+***********************************************************************/
+
+char *strstr_m(const char *src, const char *findstr)
+{
+       smb_ucs2_t *p;
+       smb_ucs2_t *src_w, *find_w;
+       const char *s;
+       char *s2;
+       char *retp;
+
+       size_t findstr_len = 0;
+
+       /* for correctness */
+       if (!findstr[0]) {
+               return (char*)src;
+       }
+
+       /* Samba does single character findstr calls a *lot*. */
+       if (findstr[1] == '\0')
+               return strchr_m(src, *findstr);
+
+       /* We optimise for the ascii case, knowing that all our
+          supported multi-byte character sets are ascii-compatible
+          (ie. they match for the first 128 chars) */
+
+       for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
+               if (*s == *findstr) {
+                       if (!findstr_len) 
+                               findstr_len = strlen(findstr);
+
+                       if (strncmp(s, findstr, findstr_len) == 0) {
+                               return (char *)s;
+                       }
+               }
+       }
+
+       if (!*s)
+               return NULL;
+
+#if 1 /* def BROKEN_UNICODE_COMPOSE_CHARACTERS */
+       /* 'make check' fails unless we do this */
+
+       /* With compose characters we must restart from the beginning. JRA. */
+       s = src;
+#endif
+
+       if (push_ucs2_allocate(&src_w, src) == (size_t)-1) {
+               DEBUG(0,("strstr_m: src malloc fail\n"));
+               return NULL;
+       }
+       
+       if (push_ucs2_allocate(&find_w, findstr) == (size_t)-1) {
+               SAFE_FREE(src_w);
+               DEBUG(0,("strstr_m: find malloc fail\n"));
+               return NULL;
+       }
+
+       p = strstr_w(src_w, find_w);
+
+       if (!p) {
+               SAFE_FREE(src_w);
+               SAFE_FREE(find_w);
+               return NULL;
+       }
+       
+       *p = 0;
+       if (pull_ucs2_allocate(&s2, src_w) == (size_t)-1) {
+               SAFE_FREE(src_w);
+               SAFE_FREE(find_w);
+               DEBUG(0,("strstr_m: dest malloc fail\n"));
+               return NULL;
+       }
+       retp = (char *)(s+strlen(s2));
+       SAFE_FREE(src_w);
+       SAFE_FREE(find_w);
+       SAFE_FREE(s2);
+       return retp;
+}
+
 /**
  Convert a string to lower case.
 **/
 
 void strlower_m(char *s)
 {
+       size_t len;
+       int errno_save;
+
        /* this is quite a common operation, so we want it to be
           fast. We optimise for the ascii case, knowing that all our
           supported multi-byte character sets are ascii-compatible
@@ -1308,7 +1423,14 @@ void strlower_m(char *s)
 
        /* I assume that lowercased string takes the same number of bytes
         * as source string even in UTF-8 encoding. (VIV) */
-       unix_strlower(s,strlen(s)+1,s,strlen(s)+1);     
+       len = strlen(s) + 1;
+       errno_save = errno;
+       errno = 0;
+       unix_strlower(s,len,s,len);     
+       /* Catch mb conversion errors that may not terminate. */
+       if (errno)
+               s[len-1] = '\0';
+       errno = errno_save;
 }
 
 /**
@@ -1317,6 +1439,9 @@ void strlower_m(char *s)
 
 void strupper_m(char *s)
 {
+       size_t len;
+       int errno_save;
+
        /* this is quite a common operation, so we want it to be
           fast. We optimise for the ascii case, knowing that all our
           supported multi-byte character sets are ascii-compatible
@@ -1332,7 +1457,14 @@ void strupper_m(char *s)
 
        /* I assume that lowercased string takes the same number of bytes
         * as source string even in multibyte encoding. (VIV) */
-       unix_strupper(s,strlen(s)+1,s,strlen(s)+1);     
+       len = strlen(s) + 1;
+       errno_save = errno;
+       errno = 0;
+       unix_strupper(s,len,s,len);     
+       /* Catch mb conversion errors that may not terminate. */
+       if (errno)
+               s[len-1] = '\0';
+       errno = errno_save;
 }
 
 /**
@@ -1346,7 +1478,7 @@ char *binary_string(char *buf, int len)
        char *s;
        int i, j;
        const char *hex = "0123456789ABCDEF";
-       s = malloc(len * 3 + 1);
+       s = SMB_MALLOC(len * 3 + 1);
        if (!s)
                return NULL;
        for (j=i=0;i<len;i++) {
@@ -1391,17 +1523,20 @@ int fstr_sprintf(fstring s, const char *fmt, ...)
 }
 
 
-#ifndef HAVE_STRNDUP
+#if !defined(HAVE_STRNDUP) || defined(BROKEN_STRNDUP)
 /**
  Some platforms don't have strndup.
 **/
+#if defined(PARANOID_MALLOC_CHECKER)
+#undef strndup
+#endif
 
  char *strndup(const char *s, size_t n)
 {
        char *ret;
        
        n = strnlen(s, n);
-       ret = malloc(n+1);
+       ret = SMB_MALLOC(n+1);
        if (!ret)
                return NULL;
        memcpy(ret, s, n);
@@ -1409,17 +1544,22 @@ int fstr_sprintf(fstring s, const char *fmt, ...)
 
        return ret;
 }
+
+#if defined(PARANOID_MALLOC_CHECKER)
+#define strndup(s,n) __ERROR_DONT_USE_STRNDUP_DIRECTLY
+#endif
+
 #endif
 
-#ifndef HAVE_STRNLEN
+#if !defined(HAVE_STRNLEN) || defined(BROKEN_STRNLEN)
 /**
  Some platforms don't have strnlen
 **/
 
  size_t strnlen(const char *s, size_t n)
 {
-       int i;
-       for (i=0; s[i] && i<n; i++)
+       size_t i;
+       for (i=0; i<n && s[i] != '\0'; i++)
                /* noop */ ;
        return i;
 }
@@ -1441,7 +1581,7 @@ char **str_list_make(const char *string, const char *sep)
        
        if (!string || !*string)
                return NULL;
-       s = strdup(string);
+       s = SMB_STRDUP(string);
        if (!s) {
                DEBUG(0,("str_list_make: Unable to allocate memory"));
                return NULL;
@@ -1455,7 +1595,7 @@ char **str_list_make(const char *string, const char *sep)
        while (next_token(&str, tok, sep, sizeof(tok))) {               
                if (num == lsize) {
                        lsize += S_LIST_ABS;
-                       rlist = (char **)Realloc(list, ((sizeof(char **)) * (lsize +1)));
+                       rlist = SMB_REALLOC_ARRAY(list, char *, lsize +1);
                        if (!rlist) {
                                DEBUG(0,("str_list_make: Unable to allocate memory"));
                                str_list_free(&list);
@@ -1466,7 +1606,7 @@ char **str_list_make(const char *string, const char *sep)
                        memset (&list[num], 0, ((sizeof(char**)) * (S_LIST_ABS +1)));
                }
                
-               list[num] = strdup(tok);
+               list[num] = SMB_STRDUP(tok);
                if (!list[num]) {
                        DEBUG(0,("str_list_make: Unable to allocate memory"));
                        str_list_free(&list);
@@ -1496,7 +1636,7 @@ BOOL str_list_copy(char ***dest, const char **src)
        while (src[num]) {
                if (num == lsize) {
                        lsize += S_LIST_ABS;
-                       rlist = (char **)Realloc(list, ((sizeof(char **)) * (lsize +1)));
+                       rlist = SMB_REALLOC_ARRAY(list, char *, lsize +1);
                        if (!rlist) {
                                DEBUG(0,("str_list_copy: Unable to re-allocate memory"));
                                str_list_free(&list);
@@ -1506,7 +1646,7 @@ BOOL str_list_copy(char ***dest, const char **src)
                        memset (&list[num], 0, ((sizeof(char **)) * (S_LIST_ABS +1)));
                }
                
-               list[num] = strdup(src[num]);
+               list[num] = SMB_STRDUP(src[num]);
                if (!list[num]) {
                        DEBUG(0,("str_list_copy: Unable to allocate memory"));
                        str_list_free(&list);
@@ -1554,6 +1694,20 @@ void str_list_free(char ***list)
        SAFE_FREE(*list);
 }
 
+/******************************************************************************
+ *****************************************************************************/
+
+int str_list_count( const char **list )
+{
+       int i = 0;
+
+       /* count the number of list members */
+       
+       for ( i=0; *list; i++, list++ );
+       
+       return i;
+}
+
 /******************************************************************************
  version of standard_sub_basic() for string lists; uses alloc_sub_basic() 
  for the work
@@ -1571,6 +1725,7 @@ BOOL str_list_sub_basic( char **list, const char *smb_name )
                        return False;
                }
 
+               SAFE_FREE(*list);
                *list = tmpstr;
                        
                list++;
@@ -1603,11 +1758,11 @@ BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
                s = *list;
                ls = (ssize_t)strlen(s);
 
-               while ((p = strstr(s, pattern))) {
+               while ((p = strstr_m(s, pattern))) {
                        t = *list;
                        d = p -t;
                        if (ld) {
-                               t = (char *) malloc(ls +ld +1);
+                               t = (char *) SMB_MALLOC(ls +ld +1);
                                if (!t) {
                                        DEBUG(0,("str_list_substitute: Unable to allocate memory"));
                                        return False;
@@ -1730,7 +1885,7 @@ int ipstr_list_parse(const char* ipstr_list, struct ip_service **ip_list)
                return 0;
        
        count = count_chars(ipstr_list, IPSTR_LIST_CHAR) + 1;
-       if ( (*ip_list = (struct ip_service*)malloc(count * sizeof(struct ip_service))) == NULL ) {
+       if ( (*ip_list = SMB_MALLOC_ARRAY(struct ip_service, count)) == NULL ) {
                DEBUG(0,("ipstr_list_parse: malloc failed for %lu entries\n", (unsigned long)count));
                return 0;
        }
@@ -1838,6 +1993,10 @@ DATA_BLOB base64_decode_data_blob(const char *s)
                s++; i++;
        }
 
+       if ((n > 0) && (*s == '=')) {
+               n -= 1;
+       }
+
        /* fix up length */
        decoded.length = n;
        return decoded;
@@ -1849,9 +2008,15 @@ DATA_BLOB base64_decode_data_blob(const char *s)
 void base64_decode_inplace(char *s)
 {
        DATA_BLOB decoded = base64_decode_data_blob(s);
-       memcpy(s, decoded.data, decoded.length);
-       /* null terminate */
-       s[decoded.length] = '\0';
+
+       if ( decoded.length != 0 ) {
+               memcpy(s, decoded.data, decoded.length);
+
+               /* null terminate */
+               s[decoded.length] = '\0';
+       } else {
+               *s = '\0';
+       }
 
        data_blob_free(&decoded);
 }
@@ -1865,10 +2030,16 @@ char * base64_encode_data_blob(DATA_BLOB data)
 {
        int bits = 0;
        int char_count = 0;
-       size_t out_cnt = 0;
-       size_t len = data.length;
-       size_t output_len = data.length * 2;
-       char *result = malloc(output_len); /* get us plenty of space */
+       size_t out_cnt, len, output_len;
+       char *result;
+
+        if (!data.length || !data.data)
+               return NULL;
+
+       out_cnt = 0;
+       len = data.length;
+       output_len = data.length * 2;
+       result = SMB_MALLOC(output_len); /* get us plenty of space */
 
        while (len-- && out_cnt < (data.length * 2) - 5) {
                int c = (unsigned char) *(data.data++);
@@ -1923,3 +2094,103 @@ SMB_BIG_UINT STR_TO_SMB_BIG_UINT(const char *nptr, const char **entptr)
 
        return val;
 }
+
+void string_append(char **left, const char *right)
+{
+       int new_len = strlen(right) + 1;
+
+       if (*left == NULL) {
+               *left = SMB_MALLOC(new_len);
+               *left[0] = '\0';
+       } else {
+               new_len += strlen(*left);
+               *left = SMB_REALLOC(*left, new_len);
+       }
+
+       if (*left == NULL)
+               return;
+
+       safe_strcat(*left, right, new_len-1);
+}
+
+BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
+                        const char *str, const char ***strings,
+                        int *num)
+{
+       char *dup_str = talloc_strdup(mem_ctx, str);
+
+       *strings = TALLOC_REALLOC_ARRAY(mem_ctx, *strings, const char *, (*num)+1);
+
+       if ((*strings == NULL) || (dup_str == NULL))
+               return False;
+
+       (*strings)[*num] = dup_str;
+       *num += 1;
+       return True;
+}
+
+/* Append an sprintf'ed string. Double buffer size on demand. Usable without
+ * error checking in between. The indiation that something weird happened is
+ * string==NULL */
+
+void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len,
+                   size_t *bufsize, const char *fmt, ...)
+{
+       va_list ap;
+       char *newstr;
+       int ret;
+       BOOL increased;
+
+       /* len<0 is an internal marker that something failed */
+       if (*len < 0)
+               goto error;
+
+       if (*string == NULL) {
+               if (*bufsize == 0)
+                       *bufsize = 128;
+
+               if (mem_ctx != NULL)
+                       *string = TALLOC_ARRAY(mem_ctx, char, *bufsize);
+               else
+                       *string = SMB_MALLOC_ARRAY(char, *bufsize);
+
+               if (*string == NULL)
+                       goto error;
+       }
+
+       va_start(ap, fmt);
+       ret = vasprintf(&newstr, fmt, ap);
+       va_end(ap);
+
+       if (ret < 0)
+               goto error;
+
+       increased = False;
+
+       while ((*len)+ret >= *bufsize) {
+               increased = True;
+               *bufsize *= 2;
+               if (*bufsize >= (1024*1024*256))
+                       goto error;
+       }
+
+       if (increased) {
+               if (mem_ctx != NULL)
+                       *string = TALLOC_REALLOC_ARRAY(mem_ctx, *string, char,
+                                                      *bufsize);
+               else
+                       *string = SMB_REALLOC_ARRAY(*string, char, *bufsize);
+
+               if (*string == NULL)
+                       goto error;
+       }
+
+       StrnCpy((*string)+(*len), newstr, ret);
+       (*len) += ret;
+       free(newstr);
+       return;
+
+ error:
+       *len = -1;
+       *string = NULL;
+}