*/
#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.
**/
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
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;
-}