/* Unix SMB/CIFS implementation. Samba utility functions Copyright (C) Andrew Tridgell 1992-2001 Copyright (C) Simo Sorce 2001-2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" /**************************************************************************** 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 ****************************************************************************/ BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize) { char *s; BOOL quoted; size_t len=1; if (!ptr) return(False); s = *ptr; /* default to simple separators */ if (!sep) sep = " \t\n\r"; /* find the first non sep char */ while (*s && strchr_m(sep,*s)) s++; /* nothing left? */ if (! *s) return(False); /* copy over the token */ for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) { if (*s == '\"') { quoted = !quoted; } else { len++; *buff++ = *s; } } *ptr = (*s) ? s+1 : s; *buff = 0; return(True); } /**************************************************************************** This is like next_token but is not re-entrant and "remembers" the first parameter so you can pass NULL. This is useful for user interface code but beware the fact that it is not re-entrant! ****************************************************************************/ static char *last_ptr=NULL; BOOL next_token_nr(char **ptr,char *buff,char *sep, size_t bufsize) { BOOL ret; if (!ptr) ptr = &last_ptr; ret = next_token(ptr, buff, sep, bufsize); last_ptr = *ptr; return ret; } static uint16 tmpbuf[sizeof(pstring)]; void set_first_token(char *ptr) { last_ptr = ptr; } /**************************************************************************** Convert list of tokens to array; dependent on above routine. Uses last_ptr from above - bit of a hack. ****************************************************************************/ char **toktocliplist(int *ctok, char *sep) { char *s=last_ptr; int ictok=0; char **ret, **iret; if (!sep) sep = " \t\n\r"; while(*s && strchr_m(sep,*s)) s++; /* nothing left? */ if (!*s) return(NULL); do { ictok++; while(*s && (!strchr_m(sep,*s))) s++; while(*s && strchr_m(sep,*s)) *s++=0; } while(*s); *ctok=ictok; s=last_ptr; if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL; while(ictok--) { *iret++=s; while(*s++); while(!*s) s++; } return ret; } /******************************************************************* case insensitive string compararison ********************************************************************/ int StrCaseCmp(const char *s, const char *t) { pstring buf1, buf2; unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1)); unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2)); return strcmp(buf1,buf2); } /******************************************************************* case insensitive string compararison, length limited ********************************************************************/ int StrnCaseCmp(const char *s, const char *t, size_t n) { pstring buf1, buf2; unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1)); unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2)); return strncmp(buf1,buf2,n); } /******************************************************************* compare 2 strings ********************************************************************/ BOOL strequal(const char *s1, const char *s2) { if (s1 == s2) return(True); if (!s1 || !s2) return(False); return(StrCaseCmp(s1,s2)==0); } /******************************************************************* compare 2 strings up to and including the nth char. ******************************************************************/ BOOL strnequal(const char *s1,const char *s2,size_t n) { if (s1 == s2) return(True); if (!s1 || !s2 || !n) return(False); return(StrnCaseCmp(s1,s2,n)==0); } /******************************************************************* compare 2 strings (case sensitive) ********************************************************************/ BOOL strcsequal(const char *s1,const char *s2) { if (s1 == s2) return(True); if (!s1 || !s2) return(False); return(strcmp(s1,s2)==0); } /*************************************************************************** Do a case-insensitive, whitespace-ignoring string compare. ***************************************************************************/ 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(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0') break; psz1++; psz2++; } return (*psz1 - *psz2); } /* Convert a string to upper case, but don't modify it */ char *strupper_static(const char *s) { static pstring str; pstrcpy(str, s); strupper(str); return str; } /******************************************************************* convert a string to "normal" form ********************************************************************/ void strnorm(char *s) { extern int case_default; if (case_default == CASE_UPPER) strupper(s); else strlower(s); } /******************************************************************* check if a string is in "normal" case ********************************************************************/ BOOL strisnormal(char *s) { extern int case_default; if (case_default == CASE_UPPER) return(!strhaslower(s)); return(!strhasupper(s)); } /**************************************************************************** string replace NOTE: oldc and newc must be 7 bit characters ****************************************************************************/ void string_replace(char *s,char oldc,char newc) { push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE); string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc)); pull_ucs2(NULL, s, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE); } /******************************************************************* skip past some strings in a buffer ********************************************************************/ char *skip_string(char *buf,size_t n) { while (n--) buf += strlen(buf) + 1; return(buf); } /******************************************************************* Count the number of characters in a string. Normally this will be the same as the number of bytes in a string for single byte strings, but will be different for multibyte. ********************************************************************/ size_t str_charnum(const char *s) { push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE); return strlen_w(tmpbuf); } /******************************************************************* trim the specified elements off the front and back of a string ********************************************************************/ BOOL trim_string(char *s,const char *front,const char *back) { BOOL ret = False; size_t front_len; size_t back_len; size_t len; /* Ignore null or empty strings. */ if (!s || (s[0] == '\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) { memcpy(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; } /**************************************************************************** does a string have any uppercase chars in it? ****************************************************************************/ BOOL strhasupper(const char *s) { smb_ucs2_t *ptr; push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE); for(ptr=tmpbuf;*ptr;ptr++) if(isupper_w(*ptr)) return True; return(False); } /**************************************************************************** does a string have any lowercase chars in it? ****************************************************************************/ BOOL strhaslower(const char *s) { smb_ucs2_t *ptr; push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE); for(ptr=tmpbuf;*ptr;ptr++) if(islower_w(*ptr)) return True; return(False); } /**************************************************************************** find the number of 'c' chars in a string ****************************************************************************/ 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++) if(*ptr==UCS2_CHAR(c)) count++; return(count); } /******************************************************************* Return True if a string consists only of one particular character. ********************************************************************/ BOOL str_is_all(const char *s,char c) { smb_ucs2_t *ptr; if(s == NULL) return False; if(!*s) return False; push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE); for(ptr=tmpbuf;*ptr;ptr++) if(*ptr!=UCS2_CHAR(c)) return False; return True; } /******************************************************************* safe string copy into a known length string. maxlength does not include the terminating zero. ********************************************************************/ 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; } if (!src) { *dest = 0; return dest; } len = strlen(src); if (len > maxlength) { DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n", (int)(len-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. ********************************************************************/ char *safe_strcat(char *dest, const char *src, size_t maxlength) { size_t src_len, dest_len; if (!dest) { DEBUG(0,("ERROR: NULL dest in safe_strcat\n")); return NULL; } if (!src) { return dest; } 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)); src_len = maxlength - dest_len; } memcpy(&dest[dest_len], src, src_len); dest[dest_len + src_len] = 0; return dest; } /******************************************************************* Paranoid strcpy into a buffer of given length (includes terminating zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars and replaces with '_'. Deliberately does *NOT* check for multibyte characters. Don't change it ! ********************************************************************/ char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength) { size_t len, i; if (!dest) { DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n")); return NULL; } if (!src) { *dest = 0; return dest; } len = strlen(src); if (len >= maxlength) len = maxlength - 1; if (!other_safe_chars) other_safe_chars = ""; for(i = 0; i < len; i++) { int val = (src[i] & 0xff); if(isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val)) dest[i] = src[i]; else dest[i] = '_'; } dest[i] = '\0'; return dest; } /**************************************************************************** Like strncpy but always null terminates. Make sure there is room! The variable n should always be one less than the available size. ****************************************************************************/ char *StrnCpy(char *dest,const char *src,size_t n) { char *d = dest; if (!dest) return(NULL); if (!src) { *dest = 0; return(dest); } while (n-- && (*d++ = *src++)) ; *d = 0; return(dest); } /**************************************************************************** like strncpy but copies up to the character marker. always null terminates. returns a pointer to the character marker in the source string (src). ****************************************************************************/ char *strncpyn(char *dest, const char *src,size_t n, char c) { char *p; size_t str_len; p = strchr_m(src, c); if (p == NULL) { DEBUG(5, ("strncpyn: separator character (%c) not found\n", c)); return NULL; } str_len = PTR_DIFF(p, src); strncpy(dest, src, MIN(n, str_len)); dest[str_len] = '\0'; return p; } /************************************************************* 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" **************************************************************/ size_t strhex_to_str(char *p, size_t len, const char *strhex) { size_t i; size_t num_chars = 0; unsigned char lonybble, hinybble; char *hexchars = "0123456789ABCDEF"; char *p1 = NULL, *p2 = NULL; for (i = 0; i < len && strhex[i] != 0; i++) { if (strnequal(hexchars, "0x", 2)) { i++; /* skip two chars */ continue; } if (!(p1 = strchr_m(hexchars, toupper(strhex[i])))) { break; } i++; /* next hex digit */ if (!(p2 = strchr_m(hexchars, toupper(strhex[i])))) { break; } /* get the two nybbles */ hinybble = PTR_DIFF(p1, hexchars); lonybble = PTR_DIFF(p2, hexchars); p[num_chars] = (hinybble << 4) | lonybble; num_chars++; p1 = NULL; p2 = NULL; } return num_chars; } /**************************************************************************** check if a string is part of a list ****************************************************************************/ BOOL in_list(char *s,char *list,BOOL casesensitive) { pstring tok; char *p=list; if (!list) return(False); while (next_token(&p,tok,LIST_SEP,sizeof(tok))) { if (casesensitive) { if (strcmp(tok,s) == 0) return(True); } else { if (StrCaseCmp(tok,s) == 0) return(True); } } return(False); } /* this is used to prevent lots of mallocs of size 1 */ static char *null_string = NULL; /**************************************************************************** set a string value, allocing the space for the string ****************************************************************************/ static BOOL string_init(char **dest,const char *src) { size_t l; if (!src) src = ""; l = strlen(src); if (l == 0) { if (!null_string) { if((null_string = (char *)malloc(1)) == NULL) { DEBUG(0,("string_init: malloc fail for null_string.\n")); return False; } *null_string = 0; } *dest = null_string; } else { (*dest) = (char *)malloc(l+1); if ((*dest) == NULL) { DEBUG(0,("Out of memory in string_init\n")); return False; } pstrcpy(*dest,src); } return(True); } /**************************************************************************** free a string value ****************************************************************************/ void string_free(char **s) { if (!s || !(*s)) return; if (*s == null_string) *s = NULL; SAFE_FREE(*s); } /**************************************************************************** set a string value, allocing the space for the string, and deallocating any existing space ****************************************************************************/ BOOL string_set(char **dest,const char *src) { string_free(dest); return(string_init(dest,src)); } /**************************************************************************** substitute a string for a pattern in another string. Make sure there is enough room! This routine looks for pattern in s and replaces it with insert. It may do multiple replacements. any of " ; ' $ or ` in the insert string are replaced with _ if len==0 then the string cannot be extended. This is different from the old use of len==0 which was for no length checks to be done. ****************************************************************************/ void string_sub(char *s,const char *pattern, const char *insert, size_t len) { char *p; ssize_t ls,lp,li, i; if (!insert || !pattern || !*pattern || !s) return; ls = (ssize_t)strlen(s); lp = (ssize_t)strlen(pattern); li = (ssize_t)strlen(insert); if (len == 0) len = ls + 1; /* len is number of *bytes* */ while (lp <= ls && (p = strstr(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), pattern, (int)len)); break; } if (li != lp) { memmove(p+li,p+lp,strlen(p+lp)+1); } for (i=0;i<li;i++) { switch (insert[i]) { case '`': case '"': case '\'': case ';': case '$': case '%': case '\r': case '\n': p[i] = '_'; break; default: p[i] = insert[i]; } } s = p + li; ls += (li-lp); } } void fstring_sub(char *s,const char *pattern,const char *insert) { string_sub(s, pattern, insert, sizeof(fstring)); } void pstring_sub(char *s,const char *pattern,const char *insert) { string_sub(s, pattern, insert, sizeof(pstring)); } /* similar to string_sub, but it will accept only allocated strings * and may realloc them so pay attention at what you pass on no * pointers inside strings, no pstrings or const must be passed * as string. */ char *realloc_string_sub(char *string, const char *pattern, const char *insert) { char *p, *in; char *s; ssize_t ls,lp,li,ld, i; if (!insert || !pattern || !*pattern || !string || !*string) return NULL; s = string; in = strdup(insert); if (!in) { DEBUG(0, ("realloc_string_sub: out of memory!\n")); return NULL; } ls = (ssize_t)strlen(s); lp = (ssize_t)strlen(pattern); li = (ssize_t)strlen(insert); ld = li - lp; for (i=0;i<li;i++) { switch (in[i]) { case '`': case '"': case '\'': case ';': case '$': case '%': case '\r': case '\n': in[i] = '_'; default: /* ok */ break; } } while ((p = strstr(s,pattern))) { if (ld > 0) { char *t = Realloc(string, ls + ld + 1); if (!t) { DEBUG(0, ("realloc_string_sub: out of memory!\n")); SAFE_FREE(in); return NULL; } string = t; p = t + (p - s); } if (li != lp) { memmove(p+li,p+lp,strlen(p+lp)+1); } memcpy(p, in, li); s = p + li; ls += ld; } SAFE_FREE(in); return string; } /**************************************************************************** similar to string_sub() but allows for any character to be substituted. Use with caution! if len==0 then the string cannot be extended. This is different from the old use of len==0 which was for no length checks to be done. ****************************************************************************/ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len) { char *p; ssize_t ls,lp,li; if (!insert || !pattern || !s) return; ls = (ssize_t)strlen(s); lp = (ssize_t)strlen(pattern); li = (ssize_t)strlen(insert); if (!*pattern) return; if (len == 0) len = ls + 1; /* len is number of *bytes* */ while (lp <= ls && (p = strstr(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), pattern, (int)len)); break; } if (li != lp) { memmove(p+li,p+lp,strlen(p+lp)+1); } memcpy(p, insert, li); s = p + li; ls += (li-lp); } } /**************************************************************************** similar to all_string_sub but for unicode strings. return a new allocate unicode string. similar to string_sub() but allows for any character to be substituted. Use with caution! ****************************************************************************/ smb_ucs2_t *all_string_sub_w(const smb_ucs2_t *s, const smb_ucs2_t *pattern, const smb_ucs2_t *insert) { smb_ucs2_t *r, *rp; const smb_ucs2_t *sp; size_t lr, lp, li, lt; if (!insert || !pattern || !*pattern || !s) return NULL; lt = (size_t)strlen_w(s); lp = (size_t)strlen_w(pattern); li = (size_t)strlen_w(insert); if (li > lp) { const smb_ucs2_t *st = s; int ld = li - lp; while ((sp = strstr_w(st, pattern))) { st = sp + lp; lt += ld; } } r = rp = (smb_ucs2_t *)malloc((lt + 1)*(sizeof(smb_ucs2_t))); if (!r) { DEBUG(0, ("all_string_sub_w: out of memory!\n")); return NULL; } while ((sp = strstr_w(s, pattern))) { memcpy(rp, s, (sp - s)); rp += ((sp - s) / sizeof(smb_ucs2_t)); memcpy(rp, insert, (li * sizeof(smb_ucs2_t))); s = sp + lp; rp += li; } lr = ((rp - r) / sizeof(smb_ucs2_t)); if (lr < lt) { memcpy(rp, s, ((lt - lr) * sizeof(smb_ucs2_t))); rp += (lt - lr); } *rp = 0; return r; } smb_ucs2_t *all_string_sub_wa(smb_ucs2_t *s, const char *pattern, const char *insert) { wpstring p, i; if (!insert || !pattern || !s) return NULL; push_ucs2(NULL, p, pattern, sizeof(wpstring) - 1, STR_TERMINATE); push_ucs2(NULL, i, insert, sizeof(wpstring) - 1, STR_TERMINATE); return all_string_sub_w(s, p, i); } /**************************************************************************** Splits out the front and back at a separator. ****************************************************************************/ void split_at_last_component(char *path, char *front, char sep, char *back) { char *p = strrchr_m(path, sep); if (p != NULL) *p = 0; if (front != NULL) pstrcpy(front, path); if (p != NULL) { if (back != NULL) pstrcpy(back, p+1); *p = '\\'; } else { if (back != NULL) back[0] = 0; } } /**************************************************************************** Write an octal as a string. ****************************************************************************/ char *octal_string(int i) { static char ret[64]; if (i == -1) return "-1"; slprintf(ret, sizeof(ret)-1, "0%o", i); return ret; } /**************************************************************************** Truncate a string at a specified length. ****************************************************************************/ char *string_truncate(char *s, int length) { if (s && strlen(s) > length) s[length] = 0; return s; } /**************************************************************************** Strchr and strrchr_m are very hard to do on general multi-byte strings. We convert via ucs2 for now. ****************************************************************************/ char *strchr_m(const char *s, char c) { wpstring ws; pstring s2; smb_ucs2_t *p; push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE); p = strchr_w(ws, UCS2_CHAR(c)); if (!p) return NULL; *p = 0; pull_ucs2_pstring(s2, ws); return (char *)(s+strlen(s2)); } char *strrchr_m(const char *s, char c) { wpstring ws; pstring s2; smb_ucs2_t *p; push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE); p = strrchr_w(ws, UCS2_CHAR(c)); if (!p) return NULL; *p = 0; pull_ucs2_pstring(s2, ws); return (char *)(s+strlen(s2)); } /******************************************************************* Convert a string to lower case. ********************************************************************/ void strlower_m(char *s) { /* 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) */ while (*s && !(((unsigned char)s[0]) & 0x7F)) *s++ = tolower((unsigned char)*s); if (!*s) return; /* 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); } /******************************************************************* Duplicate convert a string to lower case. ********************************************************************/ char *strdup_lower(const char *s) { char *t = strdup(s); if (t == NULL) { DEBUG(0, ("strdup_lower: Out of memory!\n")); return NULL; } strlower_m(t); return t; } /******************************************************************* Convert a string to upper case. ********************************************************************/ void strupper_m(char *s) { /* 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) */ while (*s && !(((unsigned char)s[0]) & 0x7F)) *s++ = toupper((unsigned char)*s); if (!*s) return; /* 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); } /******************************************************************* Convert a string to upper case. ********************************************************************/ char *strdup_upper(const char *s) { char *t = strdup(s); if (t == NULL) { DEBUG(0, ("strdup_upper: Out of memory!\n")); return NULL; } strupper_m(t); return t; } /* return a RFC2254 binary string representation of a buffer used in LDAP filters caller must free */ char *binary_string(char *buf, int len) { char *s; int i, j; const char *hex = "0123456789ABCDEF"; s = malloc(len * 3 + 1); if (!s) return NULL; for (j=i=0;i<len;i++) { s[j] = '\\'; s[j+1] = hex[((unsigned char)buf[i]) >> 4]; s[j+2] = hex[((unsigned char)buf[i]) & 0xF]; j += 3; } s[j] = 0; return s; } /* Just a typesafety wrapper for snprintf into a pstring */ int pstr_sprintf(pstring s, const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = vsnprintf(s, PSTRING_LEN, fmt, ap); va_end(ap); return ret; } /* Just a typesafety wrapper for snprintf into a fstring */ int fstr_sprintf(fstring s, const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = vsnprintf(s, FSTRING_LEN, fmt, ap); va_end(ap); return ret; } #ifndef HAVE_STRNDUP /******************************************************************* Some platforms don't have strndup. ********************************************************************/ char *strndup(const char *s, size_t n) { char *ret; n = strnlen(s, n); ret = malloc(n+1); if (!ret) return NULL; memcpy(ret, s, n); ret[n] = 0; return ret; } #endif #ifndef HAVE_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++) /* noop */ ; return i; } #endif /*********************************************************** List of Strings manipulation functions ***********************************************************/ #define S_LIST_ABS 16 /* List Allocation Block Size */ char **str_list_make(const char *string, const char *sep) { char **list, **rlist; char *str, *s; int num, lsize; pstring tok; if (!string || !*string) return NULL; s = strdup(string); if (!s) { DEBUG(0,("str_list_make: Unable to allocate memory")); return NULL; } if (!sep) sep = LIST_SEP; num = lsize = 0; list = NULL; str = s; while (next_token(&str, tok, sep, sizeof(tok))) { if (num == lsize) { lsize += S_LIST_ABS; rlist = (char **)Realloc(list, ((sizeof(char **)) * (lsize +1))); if (!rlist) { DEBUG(0,("str_list_make: Unable to allocate memory")); str_list_free(&list); SAFE_FREE(s); return NULL; } else list = rlist; memset (&list[num], 0, ((sizeof(char**)) * (S_LIST_ABS +1))); } list[num] = strdup(tok); if (!list[num]) { DEBUG(0,("str_list_make: Unable to allocate memory")); str_list_free(&list); SAFE_FREE(s); return NULL; } num++; } SAFE_FREE(s); return list; } BOOL str_list_copy(char ***dest, char **src) { char **list, **rlist; int num, lsize; *dest = NULL; if (!src) return False; num = lsize = 0; list = NULL; while (src[num]) { if (num == lsize) { lsize += S_LIST_ABS; rlist = (char **)Realloc(list, ((sizeof(char **)) * (lsize +1))); if (!rlist) { DEBUG(0,("str_list_copy: Unable to allocate memory")); str_list_free(&list); return False; } else list = rlist; memset (&list[num], 0, ((sizeof(char **)) * (S_LIST_ABS +1))); } list[num] = strdup(src[num]); if (!list[num]) { DEBUG(0,("str_list_copy: Unable to allocate memory")); str_list_free(&list); return False; } num++; } *dest = list; return True; } /* return true if all the elemnts of the list matches exactly */ BOOL str_list_compare(char **list1, char **list2) { int num; if (!list1 || !list2) return (list1 == list2); for (num = 0; list1[num]; num++) { if (!list2[num]) return False; if (!strcsequal(list1[num], list2[num])) return False; } if (list2[num]) return False; /* if list2 has more elements than list1 fail */ return True; } void str_list_free(char ***list) { char **tlist; if (!list || !*list) return; tlist = *list; for(; *tlist; tlist++) SAFE_FREE(*tlist); SAFE_FREE(*list); } BOOL str_list_substitute(char **list, const char *pattern, const char *insert) { char *p, *s, *t; ssize_t ls, lp, li, ld, i, d; if (!list) return False; if (!pattern) return False; if (!insert) return False; lp = (ssize_t)strlen(pattern); li = (ssize_t)strlen(insert); ld = li -lp; while (*list) { s = *list; ls = (ssize_t)strlen(s); while ((p = strstr(s, pattern))) { t = *list; d = p -t; if (ld) { t = (char *) malloc(ls +ld +1); if (!t) { DEBUG(0,("str_list_substitute: Unable to allocate memory")); return False; } memcpy(t, *list, d); memcpy(t +d +li, p +lp, ls -d -lp +1); SAFE_FREE(*list); *list = t; ls += ld; s = t +d +li; } for (i = 0; i < li; i++) { switch (insert[i]) { case '`': case '"': case '\'': case ';': case '$': case '%': case '\r': case '\n': t[d +i] = '_'; break; default: t[d +i] = insert[i]; } } } list++; } return True; }