Changes from APPLIANCE_HEAD:
[ira/wip.git] / source3 / lib / util_str.c
index 15eefb00013745677eb84a0aa8fbbe0978b6f0ed..e07e5ef6ada681263221cc51d1e0f64b6a6626a0 100644 (file)
@@ -36,11 +36,11 @@ void set_first_token(char *ptr)
 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, int bufsize)
+BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize)
 {
   char *s;
   BOOL quoted;
-  int len=1;
+  size_t len=1;
 
   if (!ptr) ptr = &last_ptr;
   if (!ptr) return(False);
@@ -115,7 +115,7 @@ char **toktocliplist(int *ctok, char *sep)
 /*******************************************************************
   case insensitive string compararison
 ********************************************************************/
-int StrCaseCmp(char *s, char *t)
+int StrCaseCmp(const char *s, const char *t)
 {
   /* compare until we run out of string, either t or s, or find a difference */
   /* We *must* use toupper rather than tolower here due to the
@@ -188,7 +188,7 @@ int StrCaseCmp(char *s, char *t)
 /*******************************************************************
   case insensitive string compararison, length limited
 ********************************************************************/
-int StrnCaseCmp(char *s, char *t, int n)
+int StrnCaseCmp(const char *s, const char *t, size_t n)
 {
   /* compare until we run out of string, either t or s, or chars */
   /* We *must* use toupper rather than tolower here due to the
@@ -272,7 +272,7 @@ int StrnCaseCmp(char *s, char *t, int n)
 /*******************************************************************
   compare 2 strings 
 ********************************************************************/
-BOOL strequal(char *s1, char *s2)
+BOOL strequal(const char *s1, const char *s2)
 {
   if (s1 == s2) return(True);
   if (!s1 || !s2) return(False);
@@ -283,7 +283,7 @@ BOOL strequal(char *s1, char *s2)
 /*******************************************************************
   compare 2 strings up to and including the nth char.
   ******************************************************************/
-BOOL strnequal(char *s1,char *s2,int n)
+BOOL strnequal(const char *s1,const char *s2,size_t n)
 {
   if (s1 == s2) return(True);
   if (!s1 || !s2 || !n) return(False);
@@ -294,7 +294,7 @@ BOOL strnequal(char *s1,char *s2,int n)
 /*******************************************************************
   compare 2 strings (case sensitive)
 ********************************************************************/
-BOOL strcsequal(char *s1,char *s2)
+BOOL strcsequal(const char *s1,const char *s2)
 {
   if (s1 == s2) return(True);
   if (!s1 || !s2) return(False);
@@ -302,6 +302,36 @@ BOOL strcsequal(char *s1,char *s2)
   return(strcmp(s1,s2)==0);
 }
 
+/***************************************************************************
+Do a case-insensitive, whitespace-ignoring string compare.
+***************************************************************************/
+int strwicmp(char *psz1, 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(*psz1))
+                       psz1++;
+               while (isspace(*psz2))
+                       psz2++;
+               if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0'
+                   || *psz2 == '\0')
+                       break;
+               psz1++;
+               psz2++;
+       }
+       return (*psz1 - *psz2);
+}
+
 
 /*******************************************************************
   convert a string to lower case
@@ -343,7 +373,7 @@ void strlower(char *s)
     else
 #endif /* KANJI_WIN95_COMPATIBILITY */
     {
-      int skip = skip_multibyte_char( *s );
+      size_t skip = get_character_len( *s );
       if( skip != 0 )
         s += skip;
       else
@@ -396,7 +426,7 @@ void strupper(char *s)
     else
 #endif /* KANJI_WIN95_COMPATIBILITY */
     {
-      int skip = skip_multibyte_char( *s );
+      size_t skip = get_character_len( *s );
       if( skip != 0 )
         s += skip;
       else
@@ -439,18 +469,30 @@ BOOL strisnormal(char *s)
 ****************************************************************************/
 void string_replace(char *s,char oldc,char newc)
 {
-  int skip;
-  while (*s)
-  {
-    skip = skip_multibyte_char( *s );
-    if( skip != 0 )
-      s += skip;
-    else
-    {
+  size_t skip;
+
+  /*
+   * sbcs optimization.
+   */
+  if(!global_is_multibyte_codepage) {
+    while (*s) {
       if (oldc == *s)
         *s = newc;
       s++;
     }
+  } else {
+    while (*s)
+    {
+      skip = get_character_len( *s );
+      if( skip != 0 )
+        s += skip;
+      else
+      {
+        if (oldc == *s)
+          *s = newc;
+        s++;
+      }
+    }
   }
 }
 
@@ -458,7 +500,7 @@ void string_replace(char *s,char oldc,char newc)
 /*******************************************************************
 skip past some strings in a buffer
 ********************************************************************/
-char *skip_string(char *buf,int n)
+char *skip_string(char *buf,size_t n)
 {
   while (n--)
     buf += strlen(buf) + 1;
@@ -472,14 +514,21 @@ char *skip_string(char *buf,int n)
  16.oct.98, jdblair@cobaltnet.com.
 ********************************************************************/
 
-size_t str_charnum(char *s)
+size_t str_charnum(const char *s)
 {
   size_t len = 0;
   
-  while (*s != '\0') {
-    int skip = skip_multibyte_char(*s);
-    s += (skip ? skip : 1);
-    len++;
+  /*
+   * sbcs optimization.
+   */
+  if(!global_is_multibyte_codepage) {
+    return strlen(s);
+  } else {
+    while (*s != '\0') {
+      int skip = get_character_len(*s);
+      s += (skip ? skip : 1);
+      len++;
+    }
   }
   return len;
 }
@@ -488,7 +537,7 @@ size_t str_charnum(char *s)
 trim the specified elements off the front and back of a string
 ********************************************************************/
 
-BOOL trim_string(char *s,char *front,char *back)
+BOOL trim_string(char *s,const char *front,const char *back)
 {
   BOOL ret = False;
   size_t front_len = (front && *front) ? strlen(front) : 0;
@@ -518,7 +567,7 @@ BOOL trim_string(char *s,char *front,char *back)
 
   if(back_len)
   {
-    if(!is_multibyte_codepage())
+    if(!global_is_multibyte_codepage)
     {
       s_len = strlen(s);
       while ((s_len >= back_len) && 
@@ -552,11 +601,20 @@ BOOL trim_string(char *s,char *front,char *back)
         size_t charcount = 0;
         char *mbp = s;
 
-        while(charcount < (mb_s_len - mb_back_len))
-        {
-          size_t skip = skip_multibyte_char(*mbp);
-          mbp += (skip ? skip : 1);
-          charcount++;
+        /*
+         * sbcs optimization.
+         */
+        if(!global_is_multibyte_codepage) {
+          while(charcount < (mb_s_len - mb_back_len)) {
+            mbp += 1;
+            charcount++;
+          }
+        } else {
+          while(charcount < (mb_s_len - mb_back_len)) {
+            size_t skip = skip_multibyte_char(*mbp);
+            mbp += (skip ? skip : 1);
+            charcount++;
+          }
         }
 
         /*
@@ -584,7 +642,7 @@ BOOL trim_string(char *s,char *front,char *back)
 /****************************************************************************
 does a string have any uppercase chars in it?
 ****************************************************************************/
-BOOL strhasupper(char *s)
+BOOL strhasupper(const char *s)
 {
   while (*s) 
   {
@@ -615,7 +673,7 @@ BOOL strhasupper(char *s)
     else
 #endif /* KANJI_WIN95_COMPATIBILITY */
     {
-      int skip = skip_multibyte_char( *s );
+      size_t skip = get_character_len( *s );
       if( skip != 0 )
         s += skip;
       else {
@@ -631,7 +689,7 @@ BOOL strhasupper(char *s)
 /****************************************************************************
 does a string have any lowercase chars in it?
 ****************************************************************************/
-BOOL strhaslower(char *s)
+BOOL strhaslower(const char *s)
 {
   while (*s) 
   {
@@ -670,7 +728,7 @@ BOOL strhaslower(char *s)
     else
 #endif /* KANJI_WIN95_COMPATIBILITY */
     {
-      int skip = skip_multibyte_char( *s );
+      size_t skip = get_character_len( *s );
       if( skip != 0 )
         s += skip;
       else {
@@ -686,9 +744,9 @@ BOOL strhaslower(char *s)
 /****************************************************************************
 find the number of chars in a string
 ****************************************************************************/
-int count_chars(char *s,char c)
+size_t count_chars(const char *s,char c)
 {
-  int count=0;
+  size_t count=0;
 
 #if !defined(KANJI_WIN95_COMPATIBILITY)
   /*
@@ -720,7 +778,7 @@ int count_chars(char *s,char c)
   {
     while (*s) 
     {
-      int skip = skip_multibyte_char( *s );
+      size_t skip = get_character_len( *s );
       if( skip != 0 )
         s += skip;
       else {
@@ -733,15 +791,68 @@ int count_chars(char *s,char c)
   return(count);
 }
 
+/*******************************************************************
+Return True if a string consists only of one particular character.
+********************************************************************/
+
+BOOL str_is_all(const char *s,char c)
+{
+  if(s == NULL)
+    return False;
+  if(!*s)
+    return False;
+
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+  /*
+   * For completeness we should put in equivalent code for code pages
+   * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+   * doubt anyone wants Samba to behave differently from Win95 and WinNT
+   * here. They both treat full width ascii characters as case senstive
+   * filenames (ie. they don't do the work we do here).
+   * JRA.
+   */
 
+  if(lp_client_code_page() == KANJI_CODEPAGE)
+  {
+    /* Win95 treats full width ascii characters as case sensitive. */
+    while (*s)
+    {
+      if (is_shift_jis (*s))
+        s += 2;
+      else
+      {
+        if (*s != c)
+          return False;
+        s++;
+      }
+    }
+  }
+  else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+  {
+    while (*s)
+    {
+      size_t skip = get_character_len( *s );
+      if( skip != 0 )
+        s += skip;
+      else {
+        if (*s != c)
+          return False;
+        s++;
+      }
+    }
+  }
+  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, int maxlength)
+
+char *safe_strcpy(char *dest,const char *src, size_t maxlength)
 {
-    int len;
+    size_t len;
 
     if (!dest) {
         DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
@@ -757,7 +868,7 @@ char *safe_strcpy(char *dest,const char *src, int maxlength)
 
     if (len > maxlength) {
            DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
-                    len-maxlength, src));
+                    (int)(len-maxlength), src));
            len = maxlength;
     }
       
@@ -770,9 +881,10 @@ char *safe_strcpy(char *dest,const char *src, int maxlength)
 safe string cat into a string. maxlength does not
 include the terminating zero.
 ********************************************************************/
-char *safe_strcat(char *dest, char *src, int maxlength)
+
+char *safe_strcat(char *dest, const char *src, size_t maxlength)
 {
-    int src_len, dest_len;
+    size_t src_len, dest_len;
 
     if (!dest) {
         DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
@@ -788,7 +900,7 @@ char *safe_strcat(char *dest, char *src, int maxlength)
 
     if (src_len + dest_len > maxlength) {
            DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
-                    src_len + dest_len - maxlength, src));
+                    (int)(src_len + dest_len - maxlength), src));
            src_len = maxlength - dest_len;
     }
       
@@ -797,29 +909,49 @@ char *safe_strcat(char *dest, char *src, int maxlength)
     return dest;
 }
 
-/****************************************************************************
-this is a safer strcpy(), meant to prevent core dumps when nasty things happen
-****************************************************************************/
-char *StrCpy(char *dest,char *src)
+/*******************************************************************
+ Paranoid strcpy into a buffer of given length (includes terminating
+ zero. Strips out all but 'a-Z0-9' and replaces with '_'. Deliberately
+ does *NOT* check for multibyte characters. Don't change it !
+********************************************************************/
+
+char *alpha_strcpy(char *dest, const char *src, size_t maxlength)
 {
-  char *d = dest;
+       size_t len, i;
 
-  /* I don't want to get lazy with these ... */
-  SMB_ASSERT(dest && src);
+       if (!dest) {
+               DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
+               return NULL;
+       }
 
-  if (!dest) return(NULL);
-  if (!src) {
-    *dest = 0;
-    return(dest);
-  }
-  while ((*d++ = *src++)) ;
-  return(dest);
+       if (!src) {
+               *dest = 0;
+               return dest;
+       }  
+
+       len = strlen(src);
+       if (len >= maxlength)
+               len = maxlength - 1;
+
+       for(i = 0; i < len; i++) {
+               int val = (src[i] & 0xff);
+               if(isupper(val) ||islower(val) || isdigit(val))
+                       dest[i] = src[i];
+               else
+                       dest[i] = '_';
+       }
+
+       dest[i] = '\0';
+
+       return dest;
 }
 
 /****************************************************************************
-like strncpy but always null terminates. Make sure there is room!
+ 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,char *src,int n)
+
+char *StrnCpy(char *dest,const char *src,size_t n)
 {
   char *d = dest;
   if (!dest) return(NULL);
@@ -832,15 +964,14 @@ char *StrnCpy(char *dest,char *src,int n)
   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, char *src,int n, char c)
+char *strncpyn(char *dest, const char *src,size_t n, char c)
 {
        char *p;
-       int str_len;
+       size_t str_len;
 
        p = strchr(src, c);
        if (p == NULL)
@@ -866,10 +997,10 @@ char *strncpyn(char *dest, char *src,int n, char c)
  valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
 
 **************************************************************/
-int strhex_to_str(char *p, int len, const char *strhex)
+size_t strhex_to_str(char *p, size_t len, const char *strhex)
 {
-       int i;
-       int num_chars = 0;
+       size_t i;
+       size_t num_chars = 0;
        unsigned char   lonybble, hinybble;
        char           *hexchars = "0123456789ABCDEF";
        char           *p1 = NULL, *p2 = NULL;
@@ -882,16 +1013,16 @@ int strhex_to_str(char *p, int len, const char *strhex)
                        continue;
                }
 
-               while (!(p1 = strchr(hexchars, toupper(strhex[i]))))
+               if (!(p1 = strchr(hexchars, toupper(strhex[i]))))
                {
-                       continue;
+                       break;
                }
 
                i++; /* next hex digit */
 
-               while (!(p2 = strchr(hexchars, toupper(strhex[i]))))
+               if (!(p2 = strchr(hexchars, toupper(strhex[i]))))
                {
-                       continue;
+                       break;
                }
 
                /* get the two nybbles */
@@ -935,9 +1066,9 @@ static char *null_string = NULL;
 /****************************************************************************
 set a string value, allocing the space for the string
 ****************************************************************************/
-BOOL string_init(char **dest,char *src)
+static BOOL string_init(char **dest,const char *src)
 {
-  int l;
+  size_t l;
   if (!src)     
     src = "";
 
@@ -983,13 +1114,14 @@ void string_free(char **s)
 set a string value, allocing the space for the string, and deallocating any 
 existing space
 ****************************************************************************/
-BOOL string_set(char **dest,char *src)
+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!
@@ -997,30 +1129,172 @@ enough room!
 This routine looks for pattern in s and replaces it with 
 insert. It may do multiple replacements.
 
-return True if a substitution was done.
+any of " ; ' $ or ` in the insert string are replaced with _
+if len==0 then no length check is performed
 ****************************************************************************/
-BOOL string_sub(char *s,char *pattern,char *insert)
+void string_sub(char *s,const char *pattern,const char *insert, size_t len)
 {
-  BOOL ret = False;
-  char *p;
-  int ls,lp,li;
+       char *p;
+       ssize_t ls,lp,li, i;
+
+       if (!insert || !pattern || !s) return;
+
+       ls = (ssize_t)strlen(s);
+       lp = (ssize_t)strlen(pattern);
+       li = (ssize_t)strlen(insert);
+
+       if (!*pattern) return;
+       
+       while (lp <= ls && (p = strstr(s,pattern))) {
+               if (len && (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);
+       }
+}
 
-  if (!insert || !pattern || !s) return(False);
+void fstring_sub(char *s,const char *pattern,const char *insert)
+{
+       string_sub(s, pattern, insert, sizeof(fstring));
+}
 
-  ls = strlen(s);
-  lp = strlen(pattern);
-  li = strlen(insert);
+void pstring_sub(char *s,const char *pattern,const char *insert)
+{
+       string_sub(s, pattern, insert, sizeof(pstring));
+}
 
-  if (!*pattern) return(False);
+/****************************************************************************
+similar to string_sub() but allows for any character to be substituted. 
+Use with caution!
+if len==0 then no length check is performed
+****************************************************************************/
+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;
+       
+       while (lp <= ls && (p = strstr(s,pattern))) {
+               if (len && (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);
+       }
+}
 
-  while (lp <= ls && (p = strstr(s,pattern)))
-    {
-      ret = True;
-      memmove(p+li,p+lp,ls + 1 - (PTR_DIFF(p,s) + lp));
-      memcpy(p,insert,li);
-      s = p + li;
-      ls = strlen(s);
-    }
-  return(ret);
+/****************************************************************************
+ 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(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), "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;
 }
 
+/* Parse a string of the form DOMAIN/user into a domain and a user */
+
+void parse_domain_user(char *domuser, fstring domain, fstring user)
+{
+       char *p;
+       char *sep = lp_winbind_separator();
+       if (!sep) sep = "\\";
+       p = strchr(domuser,*sep);
+       if (!p) p = strchr(domuser,'\\');
+       if (!p) {
+               fstrcpy(domain,"");
+               fstrcpy(user, domuser);
+               return;
+       }
+       
+       fstrcpy(user, p+1);
+       fstrcpy(domain, domuser);
+       domain[PTR_DIFF(p, domuser)] = 0;
+       strupper(domain);
+}