lib/util/debug.h uses va_list, needs stdarg.h
[sfrench/samba-autobuild/.git] / lib / util / util_str.c
index 231f7f2c6f3367a8d8753dbfcaeed90f4b0bba53..673fbc7c6b5ebac23a88020eb0510afb77b1e0cd 100644 (file)
 */
 
 #include "includes.h"
-#include "libcli/raw/smb.h"
 #include "system/locale.h"
+#undef strncasecmp
+#undef strcasemp
 
 /**
  * @file
  * @brief String utilities.
  **/
 
-
 /**
- Trim the specified elements off the front and back of a string.
-**/
-_PUBLIC_ bool trim_string(char *s, const char *front, const char *back)
+ * Parse a string containing a boolean value.
+ *
+ * val will be set to the read value.
+ *
+ * @retval true if a boolean value was parsed, false otherwise.
+ */
+_PUBLIC_ bool conv_str_bool(const char * str, bool * val)
 {
-       bool ret = false;
-       size_t front_len;
-       size_t back_len;
-       size_t len;
+       char *  end = NULL;
+       long    lval;
 
-       /* Ignore null or empty strings. */
-       if (!s || (s[0] == '\0'))
+       if (str == NULL || *str == '\0') {
                return false;
-
-       front_len       = front? strlen(front) : 0;
-       back_len        = back? strlen(back) : 0;
-
-       len = strlen(s);
-
-       if (front_len) {
-               while (len && strncmp(s, front, front_len)==0) {
-                       /* Must use memmove here as src & dest can
-                        * easily overlap. Found by valgrind. JRA. */
-                       memmove(s, s+front_len, (len-front_len)+1);
-                       len -= front_len;
-                       ret=true;
-               }
-       }
-       
-       if (back_len) {
-               while ((len >= back_len) && strncmp(s+len-back_len,back,back_len)==0) {
-                       s[len-back_len]='\0';
-                       len -= back_len;
-                       ret=true;
-               }
        }
-       return ret;
-}
-
-/**
- Find the number of 'c' chars in a string
-**/
-_PUBLIC_ _PURE_ size_t count_chars(const char *s, char c)
-{
-       size_t count = 0;
 
-       while (*s) {
-               if (*s == c) count++;
-               s ++;
+       lval = strtol(str, &end, 10 /* base */);
+       if (end == NULL || *end != '\0' || end == str) {
+               return set_boolean(str, val);
        }
 
-       return count;
+       *val = (lval) ? true : false;
+       return true;
 }
 
-
-
-/**
- Safe string copy into a known length string. maxlength does not
- include the terminating zero.
-**/
-_PUBLIC_ char *safe_strcpy(char *dest,const char *src, size_t maxlength)
-{
-       size_t len;
-
-       if (!dest) {
-               DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
-               return NULL;
-       }
-
-#ifdef DEVELOPER
-       /* We intentionally write out at the extremity of the destination
-        * string.  If the destination is too short (e.g. pstrcpy into mallocd
-        * or fstring) then this should cause an error under a memory
-        * checker. */
-       dest[maxlength] = '\0';
-       if (PTR_DIFF(&len, dest) > 0) {  /* check if destination is on the stack, ok if so */
-               log_suspicious_usage("safe_strcpy", src);
-       }
-#endif
-
-       if (!src) {
-               *dest = 0;
-               return dest;
-       }  
-
-       len = strlen(src);
-
-       if (len > maxlength) {
-               DEBUG(0,("ERROR: string overflow by %u (%u - %u) in safe_strcpy [%.50s]\n",
-                        (uint_t)(len-maxlength), (unsigned)len, (unsigned)maxlength, src));
-               len = maxlength;
-       }
-      
-       memmove(dest, src, len);
-       dest[len] = 0;
-       return dest;
-}  
-
 /**
- Safe string cat into a string. maxlength does not
- include the terminating zero.
-**/
-_PUBLIC_ char *safe_strcat(char *dest, const char *src, size_t maxlength)
+ * Convert a size specification like 16K into an integral number of bytes. 
+ **/
+_PUBLIC_ bool conv_str_size_error(const char * str, uint64_t * val)
 {
-       size_t src_len, dest_len;
+       char *              end = NULL;
+       unsigned long long  lval;
 
-       if (!dest) {
-               DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
-               return NULL;
+       if (str == NULL || *str == '\0') {
+               return false;
        }
 
-       if (!src)
-               return dest;
-       
-#ifdef DEVELOPER
-       if (PTR_DIFF(&src_len, dest) > 0) {  /* check if destination is on the stack, ok if so */
-               log_suspicious_usage("safe_strcat", src);
-       }
-#endif
-       src_len = strlen(src);
-       dest_len = strlen(dest);
-
-       if (src_len + dest_len > maxlength) {
-               DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
-                        (int)(src_len + dest_len - maxlength), src));
-               if (maxlength > dest_len) {
-                       memcpy(&dest[dest_len], src, maxlength - dest_len);
-               }
-               dest[maxlength] = 0;
-               return NULL;
+       lval = strtoull(str, &end, 10 /* base */);
+       if (end == NULL || end == str) {
+               return false;
        }
-       
-       memcpy(&dest[dest_len], src, src_len);
-       dest[dest_len + src_len] = 0;
-       return dest;
-}
-
-/**
- Routine to get hex characters and turn them into a 16 byte array.
- the array can be variable length, and any non-hex-numeric
- characters are skipped.  "0xnn" or "0Xnn" is specially catered
- for.
-
- valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
-
-
-**/
-_PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len)
-{
-       size_t i;
-       size_t num_chars = 0;
-       uint8_t   lonybble, hinybble;
-       const char     *hexchars = "0123456789ABCDEF";
-       char           *p1 = NULL, *p2 = NULL;
-
-       for (i = 0; i < strhex_len && strhex[i] != 0; i++) {
-               if (strncasecmp(hexchars, "0x", 2) == 0) {
-                       i++; /* skip two chars */
-                       continue;
-               }
 
-               if (!(p1 = strchr(hexchars, toupper((unsigned char)strhex[i]))))
-                       break;
-
-               i++; /* next hex digit */
-
-               if (!(p2 = strchr(hexchars, toupper((unsigned char)strhex[i]))))
-                       break;
-
-               /* get the two nybbles */
-               hinybble = PTR_DIFF(p1, hexchars);
-               lonybble = PTR_DIFF(p2, hexchars);
-
-               if (num_chars >= p_len) {
-                       break;
+       if (*end) {
+               if (strwicmp(end, "K") == 0) {
+                       lval *= 1024ULL;
+               } else if (strwicmp(end, "M") == 0) {
+                       lval *= (1024ULL * 1024ULL);
+               } else if (strwicmp(end, "G") == 0) {
+                       lval *= (1024ULL * 1024ULL * 1024ULL);
+               } else if (strwicmp(end, "T") == 0) {
+                       lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
+               } else if (strwicmp(end, "P") == 0) {
+                       lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL);
+               } else {
+                       return false;
                }
-
-               p[num_chars] = (hinybble << 4) | lonybble;
-               num_chars++;
-
-               p1 = NULL;
-               p2 = NULL;
        }
-       return num_chars;
-}
-
-/** 
- * Parse a hex string and return a data blob. 
- */
-_PUBLIC_ _PURE_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) 
-{
-       DATA_BLOB ret_blob = data_blob_talloc(mem_ctx, NULL, strlen(strhex)/2+1);
-
-       ret_blob.length = strhex_to_str((char *)ret_blob.data, ret_blob.length,
-                                       strhex,
-                                       strlen(strhex));
 
-       return ret_blob;
+       *val = (uint64_t)lval;
+       return true;
 }
 
-
 /**
- * Routine to print a buffer as HEX digits, into an allocated string.
+ * Parse a uint64_t value from a string
+ *
+ * val will be set to the value read.
+ *
+ * @retval true if parsing was successful, false otherwise
  */
-_PUBLIC_ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
+_PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val)
 {
-       int i;
-       char *hex_buffer;
+       char *              end = NULL;
+       unsigned long long  lval;
+
+       if (str == NULL || *str == '\0') {
+               return false;
+       }
 
-       *out_hex_buffer = malloc_array_p(char, (len*2)+1);
-       hex_buffer = *out_hex_buffer;
+       lval = strtoull(str, &end, 10 /* base */);
+       if (end == NULL || *end != '\0' || end == str) {
+               return false;
+       }
 
-       for (i = 0; i < len; i++)
-               slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
+       *val = (uint64_t)lval;
+       return true;
 }
 
 /**
- * talloc version of hex_encode()
- */
-_PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len)
+ * Compare 2 strings.
+ *
+ * @note The comparison is case-insensitive.
+ **/
+_PUBLIC_ bool strequal(const char *s1, const char *s2)
 {
-       int i;
-       char *hex_buffer;
-
-       hex_buffer = talloc_array(mem_ctx, char, (len*2)+1);
-
-       for (i = 0; i < len; i++)
-               slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
-
-       return hex_buffer;
+       if (s1 == s2)
+               return true;
+       if (!s1 || !s2)
+               return false;
+  
+       return strcasecmp_m(s1,s2) == 0;
 }
 
 /**
- Unescape a URL encoded string, in place.
-**/
+ * @file
+ * @brief String utilities.
+ **/
 
-_PUBLIC_ void rfc1738_unescape(char *buf)
+static bool next_token_internal_talloc(TALLOC_CTX *ctx,
+                               const char **ptr,
+                                char **pp_buff,
+                                const char *sep,
+                                bool ltrim)
 {
-       char *p=buf;
-
-       while ((p=strchr(p,'+')))
-               *p = ' ';
-
-       p = buf;
-
-       while (p && *p && (p=strchr(p,'%'))) {
-               int c1 = p[1];
-               int c2 = p[2];
-
-               if (c1 >= '0' && c1 <= '9')
-                       c1 = c1 - '0';
-               else if (c1 >= 'A' && c1 <= 'F')
-                       c1 = 10 + c1 - 'A';
-               else if (c1 >= 'a' && c1 <= 'f')
-                       c1 = 10 + c1 - 'a';
-               else {p++; continue;}
-
-               if (c2 >= '0' && c2 <= '9')
-                       c2 = c2 - '0';
-               else if (c2 >= 'A' && c2 <= 'F')
-                       c2 = 10 + c2 - 'A';
-               else if (c2 >= 'a' && c2 <= 'f')
-                       c2 = 10 + c2 - 'a';
-               else {p++; continue;}
-                       
-               *p = (c1<<4) | c2;
-
-               memmove(p+1, p+3, strlen(p+3)+1);
-               p++;
+       const char *s;
+       const char *saved_s;
+       char *pbuf;
+       bool quoted;
+       size_t len=1;
+
+       *pp_buff = NULL;
+       if (!ptr) {
+               return(false);
        }
-}
-
-#ifdef VALGRIND
-size_t valgrind_strlen(const char *s)
-{
-       size_t count;
-       for(count = 0; *s++; count++)
-               ;
-       return count;
-}
-#endif
 
+       s = *ptr;
 
-/**
-  format a string into length-prefixed dotted domain format, as used in NBT
-  and in some ADS structures
-**/
-_PUBLIC_ const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s)
-{
-       char *ret;
-       int i;
-       if (!s || !*s) {
-               return talloc_strdup(mem_ctx, "");
+       /* default to simple separators */
+       if (!sep) {
+               sep = " \t\n\r";
        }
-       ret = talloc_array(mem_ctx, char, strlen(s)+2);
-       if (!ret) {
-               return ret;
-       }
-       
-       memcpy(ret+1, s, strlen(s)+1);
-       ret[0] = '.';
-
-       for (i=0;ret[i];i++) {
-               if (ret[i] == '.') {
-                       char *p = strchr(ret+i+1, '.');
-                       if (p) {
-                               ret[i] = p-(ret+i+1);
-                       } else {
-                               ret[i] = strlen(ret+i+1);
-                       }
+
+       /* find the first non sep char, if left-trimming is requested */
+       if (ltrim) {
+               while (*s && strchr_m(sep,*s)) {
+                       s++;
                }
        }
 
-       return ret;
-}
+       /* nothing left? */
+       if (!*s) {
+               return false;
+       }
 
-/**
- * Add a string to an array of strings.
- *
- * num should be a pointer to an integer that holds the current 
- * number of elements in strings. It will be updated by this function.
- */
-_PUBLIC_ 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);
+       /* When restarting we need to go from here. */
+       saved_s = s;
 
-       *strings = talloc_realloc(mem_ctx,
-                                   *strings,
-                                   const char *, ((*num)+1));
+       /* Work out the length needed. */
+       for (quoted = false; *s &&
+                       (quoted || !strchr_m(sep,*s)); s++) {
+               if (*s == '\"') {
+                       quoted = !quoted;
+               } else {
+                       len++;
+               }
+       }
 
-       if ((*strings == NULL) || (dup_str == NULL))
+       /* We started with len = 1 so we have space for the nul. */
+       *pp_buff = talloc_array(ctx, char, len);
+       if (!*pp_buff) {
                return false;
+       }
 
-       (*strings)[*num] = dup_str;
-       *num += 1;
+       /* copy over the token */
+       pbuf = *pp_buff;
+       s = saved_s;
+       for (quoted = false; *s &&
+                       (quoted || !strchr_m(sep,*s)); s++) {
+               if ( *s == '\"' ) {
+                       quoted = !quoted;
+               } else {
+                       *pbuf++ = *s;
+               }
+       }
+
+       *ptr = (*s) ? s+1 : s;
+       *pbuf = 0;
 
        return true;
 }
 
+bool next_token_talloc(TALLOC_CTX *ctx,
+                       const char **ptr,
+                       char **pp_buff,
+                       const char *sep)
+{
+       return next_token_internal_talloc(ctx, ptr, pp_buff, sep, true);
+}
 
+/*
+ * Get the next token from a string, return false if none found.  Handles
+ * double-quotes.  This version does not trim leading separator characters
+ * before looking for a token.
+ */
 
-/**
-  varient of strcmp() that handles NULL ptrs
-**/
-_PUBLIC_ int strcmp_safe(const char *s1, const char *s2)
+bool next_token_no_ltrim_talloc(TALLOC_CTX *ctx,
+                       const char **ptr,
+                       char **pp_buff,
+                       const char *sep)
 {
-       if (s1 == s2) {
-               return 0;
-       }
-       if (s1 == NULL || s2 == NULL) {
-               return s1?-1:1;
-       }
-       return strcmp(s1, s2);
+       return next_token_internal_talloc(ctx, ptr, pp_buff, sep, false);
 }
 
-
 /**
-return the number of bytes occupied by a buffer in ASCII format
-the result includes the null termination
-limited by 'n' bytes
-**/
-_PUBLIC_ size_t ascii_len_n(const char *src, size_t n)
+ * Get the next token from a string, return False if none found.
+ * Handles double-quotes.
+ *
+ * Based on a routine by GJC@VILLAGE.COM.
+ * Extensively modified by Andrew.Tridgell@anu.edu.au
+ **/
+_PUBLIC_ bool next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
 {
-       size_t len;
+       const char *s;
+       bool quoted;
+       size_t len=1;
 
-       len = strnlen(src, n);
-       if (len+1 <= n) {
-               len += 1;
-       }
+       if (!ptr)
+               return false;
 
-       return len;
-}
+       s = *ptr;
 
+       /* default to simple separators */
+       if (!sep)
+               sep = " \t\n\r";
 
-/**
- Return a string representing a CIFS attribute for a file.
-**/
-_PUBLIC_ char *attrib_string(TALLOC_CTX *mem_ctx, uint32_t attrib)
-{
-       int i, len;
-       const struct {
-               char c;
-               uint16_t attr;
-       } attr_strs[] = {
-               {'V', FILE_ATTRIBUTE_VOLUME},
-               {'D', FILE_ATTRIBUTE_DIRECTORY},
-               {'A', FILE_ATTRIBUTE_ARCHIVE},
-               {'H', FILE_ATTRIBUTE_HIDDEN},
-               {'S', FILE_ATTRIBUTE_SYSTEM},
-               {'N', FILE_ATTRIBUTE_NORMAL},
-               {'R', FILE_ATTRIBUTE_READONLY},
-               {'d', FILE_ATTRIBUTE_DEVICE},
-               {'t', FILE_ATTRIBUTE_TEMPORARY},
-               {'s', FILE_ATTRIBUTE_SPARSE},
-               {'r', FILE_ATTRIBUTE_REPARSE_POINT},
-               {'c', FILE_ATTRIBUTE_COMPRESSED},
-               {'o', FILE_ATTRIBUTE_OFFLINE},
-               {'n', FILE_ATTRIBUTE_NONINDEXED},
-               {'e', FILE_ATTRIBUTE_ENCRYPTED}
-       };
-       char *ret;
-
-       ret = talloc_array(mem_ctx, char, ARRAY_SIZE(attr_strs)+1);
-       if (!ret) {
-               return NULL;
-       }
+       /* find the first non sep char */
+       while (*s && strchr_m(sep,*s))
+               s++;
+
+       /* nothing left? */
+       if (!*s)
+               return false;
 
-       for (len=i=0; i<ARRAY_SIZE(attr_strs); i++) {
-               if (attrib & attr_strs[i].attr) {
-                       ret[len++] = attr_strs[i].c;
+       /* copy over the token */
+       for (quoted = false; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
+               if (*s == '\"') {
+                       quoted = !quoted;
+               } else {
+                       len++;
+                       *buff++ = *s;
                }
        }
 
-       ret[len] = 0;
+       *ptr = (*s) ? s+1 : s;
+       *buff = 0;
 
-       return ret;
+       return true;
 }
 
 /**
  Set a boolean variable from the text value stored in the passed string.
- Returns true in success, false if the passed string does not correctly 
+ Returns true in success, false if the passed string does not correctly
  represent a boolean.
 **/
 
@@ -474,93 +303,6 @@ _PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean)
        return false;
 }
 
-/**
- * Parse a string containing a boolean value.
- *
- * val will be set to the read value.
- *
- * @retval true if a boolean value was parsed, false otherwise.
- */
-_PUBLIC_ bool conv_str_bool(const char * str, bool * val)
-{
-       char *  end = NULL;
-       long    lval;
-
-       if (str == NULL || *str == '\0') {
-               return false;
-       }
-
-       lval = strtol(str, &end, 10 /* base */);
-       if (end == NULL || *end != '\0' || end == str) {
-               return set_boolean(str, val);
-       }
-
-       *val = (lval) ? true : false;
-       return true;
-}
-
-/**
- * Convert a size specification like 16K into an integral number of bytes. 
- **/
-_PUBLIC_ bool conv_str_size(const char * str, uint64_t * val)
-{
-       char *              end = NULL;
-       unsigned long long  lval;
-
-       if (str == NULL || *str == '\0') {
-               return false;
-       }
-
-       lval = strtoull(str, &end, 10 /* base */);
-       if (end == NULL || end == str) {
-               return false;
-       }
-
-       if (*end) {
-               if (strwicmp(end, "K") == 0) {
-                       lval *= 1024ULL;
-               } else if (strwicmp(end, "M") == 0) {
-                       lval *= (1024ULL * 1024ULL);
-               } else if (strwicmp(end, "G") == 0) {
-                       lval *= (1024ULL * 1024ULL * 1024ULL);
-               } else if (strwicmp(end, "T") == 0) {
-                       lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
-               } else if (strwicmp(end, "P") == 0) {
-                       lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL);
-               } else {
-                       return false;
-               }
-       }
-
-       *val = (uint64_t)lval;
-       return true;
-}
-
-/**
- * Parse a uint64_t value from a string
- *
- * val will be set to the value read.
- *
- * @retval true if parsing was successful, false otherwise
- */
-_PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val)
-{
-       char *              end = NULL;
-       unsigned long long  lval;
-
-       if (str == NULL || *str == '\0') {
-               return false;
-       }
-
-       lval = strtoull(str, &end, 10 /* base */);
-       if (end == NULL || *end != '\0' || end == str) {
-               return false;
-       }
-
-       *val = (uint64_t)lval;
-       return true;
-}
-
 /**
 return the number of bytes occupied by a buffer in CH_UTF16 format
 the result includes the null termination
@@ -591,66 +333,3 @@ _PUBLIC_ size_t utf16_len_n(const void *src, size_t n)
 
        return len;
 }
-
-_PUBLIC_ size_t ucs2_align(const void *base_ptr, const void *p, int flags)
-{
-       if (flags & (STR_NOALIGN|STR_ASCII))
-               return 0;
-       return PTR_DIFF(p, base_ptr) & 1;
-}
-
-/**
-Do a case-insensitive, whitespace-ignoring string compare.
-**/
-_PUBLIC_ int strwicmp(const char *psz1, const char *psz2)
-{
-       /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
-       /* appropriate value. */
-       if (psz1 == psz2)
-               return (0);
-       else if (psz1 == NULL)
-               return (-1);
-       else if (psz2 == NULL)
-               return (1);
-
-       /* sync the strings on first non-whitespace */
-       while (1) {
-               while (isspace((int)*psz1))
-                       psz1++;
-               while (isspace((int)*psz2))
-                       psz2++;
-               if (toupper((unsigned char)*psz1) != toupper((unsigned char)*psz2) 
-                   || *psz1 == '\0'
-                   || *psz2 == '\0')
-                       break;
-               psz1++;
-               psz2++;
-       }
-       return (*psz1 - *psz2);
-}
-
-/**
- String replace.
-**/
-_PUBLIC_ void string_replace(char *s, char oldc, char newc)
-{
-       while (*s) {
-               if (*s == oldc) *s = newc;
-               s++;
-       }
-}
-
-/**
- * Compare 2 strings.
- *
- * @note The comparison is case-insensitive.
- **/
-_PUBLIC_ bool strequal(const char *s1, const char *s2)
-{
-       if (s1 == s2)
-               return true;
-       if (!s1 || !s2)
-               return false;
-  
-       return strcasecmp(s1,s2) == 0;
-}