The big character set handling changeover!
[samba.git] / source / lib / util_str.c
index 31dc9bfd62c3150fc80f94797116a825a98a1897..8ff3e23443afbe1576d31e99b9e14c55b604e92c 100644 (file)
@@ -1,8 +1,8 @@
 /* 
    Unix SMB/Netbios implementation.
-   Version 1.9.
+   Version 3.0
    Samba utility functions
-   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Andrew Tridgell 1992-2001
    
    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
 
 extern int DEBUGLEVEL;
 
-static char *last_ptr=NULL;
-
-void set_first_token(char *ptr)
-{
-       last_ptr = ptr;
-}
-
 /****************************************************************************
   Get the next token from a string, return False if none found
   handles double-quotes. 
@@ -38,151 +31,112 @@ 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;
+       char *s;
+       BOOL quoted;
+       size_t len=1;
 
-  if (!ptr) ptr = &last_ptr;
-  if (!ptr) return(False);
+       if (!ptr) return(False);
 
-  s = *ptr;
+       s = *ptr;
 
-  /* default to simple separators */
-  if (!sep) sep = " \t\n\r";
+       /* default to simple separators */
+       if (!sep) sep = " \t\n\r";
 
-  /* find the first non sep char */
-  while(*s && strchr(sep,*s)) s++;
+       /* find the first non sep char */
+       while (*s && strchr(sep,*s)) s++;
+       
+       /* nothing left? */
+       if (! *s) return(False);
+       
+       /* copy over the token */
+       for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) {
+               if (*s == '\"') {
+                       quoted = !quoted;
+               } else {
+                       len++;
+                       *buff++ = *s;
+               }
+       }
+       
+       *ptr = (*s) ? s+1 : s;  
+       *buff = 0;
+       
+       return(True);
+}
 
-  /* nothing left? */
-  if (! *s) return(False);
 
-  /* copy over the token */
-  for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++)
-    {
-           if (*s == '\"') {
-                   quoted = !quoted;
-           } else {
-                   len++;
-                   *buff++ = *s;
-           }
-    }
 
-  *ptr = (*s) ? s+1 : s;  
-  *buff = 0;
-  last_ptr = *ptr;
+/****************************************************************************
+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;
 
-  return(True);
+       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";
+       char *s=last_ptr;
+       int ictok=0;
+       char **ret, **iret;
 
-  while(*s && strchr(sep,*s)) s++;
+       if (!sep) sep = " \t\n\r";
 
-  /* nothing left? */
-  if (!*s) return(NULL);
+       while(*s && strchr(sep,*s)) s++;
 
-  do {
-    ictok++;
-    while(*s && (!strchr(sep,*s))) s++;
-    while(*s && strchr(sep,*s)) *s++=0;
-  } while(*s);
+       /* nothing left? */
+       if (!*s) return(NULL);
 
-  *ctok=ictok;
-  s=last_ptr;
-
-  if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL;
-  
-  while(ictok--) {    
-    *iret++=s;
-    while(*s++);
-    while(!*s) s++;
-  }
+       do {
+               ictok++;
+               while(*s && (!strchr(sep,*s))) s++;
+               while(*s && strchr(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;
+       return ret;
 }
 
-
 /*******************************************************************
   case insensitive string compararison
 ********************************************************************/
 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
-     asynchronous upper to lower mapping.
-   */
-#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. */
-    int diff;
-    for (;;)
-    {
-      if (!*s || !*t)
-           return toupper (*s) - toupper (*t);
-      else if (is_sj_alph (*s) && is_sj_alph (*t))
-      {
-        diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
-        if (diff)
-          return diff;
-        s += 2;
-        t += 2;
-      }
-      else if (is_shift_jis (*s) && is_shift_jis (*t))
-      {
-        diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
-        if (diff)
-          return diff;
-        diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
-        if (diff)
-          return diff;
-        s += 2;
-        t += 2;
-      }
-      else if (is_shift_jis (*s))
-        return 1;
-      else if (is_shift_jis (*t))
-        return -1;
-      else 
-      {
-        diff = toupper (*s) - toupper (*t);
-        if (diff)
-          return diff;
-        s++;
-        t++;
-      }
-    }
-  }
-  else
-#endif /* KANJI_WIN95_COMPATIBILITY */
-  {
-    while (*s && *t && toupper(*s) == toupper(*t))
-    {
-      s++;
-      t++;
-    }
-
-    return(toupper(*s) - toupper(*t));
-  }
+   pstring buf1, buf2;
+   unix_strlower(s, strlen(s)+1, buf1, sizeof(buf1));
+   unix_strlower(t, strlen(t)+1, buf2, sizeof(buf2));
+   return strcmp(buf1,buf2);
 }
 
 /*******************************************************************
@@ -190,83 +144,10 @@ int StrCaseCmp(const char *s, const char *t)
 ********************************************************************/
 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
-     asynchronous upper to lower mapping.
-   */
-#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. */
-    int diff;
-    for (;n > 0;)
-    {
-      if (!*s || !*t)
-        return toupper (*s) - toupper (*t);
-      else if (is_sj_alph (*s) && is_sj_alph (*t))
-      {
-        diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
-        if (diff)
-          return diff;
-        s += 2;
-        t += 2;
-        n -= 2;
-      }
-      else if (is_shift_jis (*s) && is_shift_jis (*t))
-      {
-        diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
-        if (diff)
-          return diff;
-        diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
-        if (diff)
-          return diff;
-        s += 2;
-        t += 2;
-        n -= 2;
-      }
-      else if (is_shift_jis (*s))
-        return 1;
-      else if (is_shift_jis (*t))
-        return -1;
-      else 
-      {
-        diff = toupper (*s) - toupper (*t);
-        if (diff)
-          return diff;
-        s++;
-        t++;
-        n--;
-      }
-    }
-    return 0;
-  }
-  else
-#endif /* KANJI_WIN95_COMPATIBILITY */
-  {
-    while (n && *s && *t && toupper(*s) == toupper(*t))
-    {
-      s++;
-      t++;
-      n--;
-    }
-
-    /* not run out of chars - strings are different lengths */
-    if (n) 
-      return(toupper(*s) - toupper(*t));
-
-    /* identical up to where we run out of chars, 
-       and strings are same length */
-    return(0);
-  }
+   pstring buf1, buf2;
+   unix_strlower(s, strlen(s)+1, buf1, sizeof(buf1));
+   unix_strlower(t, strlen(t)+1, buf2, sizeof(buf2));
+   return strncmp(buf1,buf2,n);
 }
 
 /*******************************************************************
@@ -302,113 +183,37 @@ BOOL strcsequal(const char *s1,const char *s2)
   return(strcmp(s1,s2)==0);
 }
 
-
-/*******************************************************************
-  convert a string to lower case
-********************************************************************/
-void strlower(char *s)
+/***************************************************************************
+Do a case-insensitive, whitespace-ignoring string compare.
+***************************************************************************/
+int strwicmp(char *psz1, char *psz2)
 {
-  while (*s)
-  {
-#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. */
-      if (is_shift_jis (*s))
-      {
-        if (is_sj_upper (s[0], s[1]))
-          s[1] = sj_tolower2 (s[1]);
-        s += 2;
-      }
-      else if (is_kana (*s))
-      {
-        s++;
-      }
-      else
-      {
-        if (isupper(*s))
-          *s = tolower(*s);
-        s++;
-      }
-    }
-    else
-#endif /* KANJI_WIN95_COMPATIBILITY */
-    {
-      size_t skip = skip_multibyte_char( *s );
-      if( skip != 0 )
-        s += skip;
-      else
-      {
-        if (isupper(*s))
-          *s = tolower(*s);
-        s++;
-      }
-    }
-  }
-}
+       /* 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);
 
-/*******************************************************************
-  convert a string to upper case
-********************************************************************/
-void strupper(char *s)
-{
-  while (*s)
-  {
-#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. */
-      if (is_shift_jis (*s))
-      {
-        if (is_sj_lower (s[0], s[1]))
-          s[1] = sj_toupper2 (s[1]);
-        s += 2;
-      }
-      else if (is_kana (*s))
-      {
-        s++;
-      }
-      else
-      {
-        if (islower(*s))
-          *s = toupper(*s);
-        s++;
-      }
-    }
-    else
-#endif /* KANJI_WIN95_COMPATIBILITY */
-    {
-      size_t skip = skip_multibyte_char( *s );
-      if( skip != 0 )
-        s += skip;
-      else
-      {
-        if (islower(*s))
-          *s = toupper(*s);
-        s++;
-      }
-    }
-  }
+       /* 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 "normal" form
 ********************************************************************/
@@ -426,32 +231,26 @@ 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));
+       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)
 {
-  size_t skip;
-  while (*s)
-  {
-    skip = skip_multibyte_char( *s );
-    if( skip != 0 )
-      s += skip;
-    else
-    {
-      if (oldc == *s)
-        *s = newc;
-      s++;
-    }
-  }
+       smb_ucs2_t *ptr;
+       push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+       for(ptr=tmpbuf;*ptr;ptr++) {
+               if(*ptr==UCS2_CHAR(oldc)) *ptr = UCS2_CHAR(newc);
+       }
+       pull_ucs2(NULL, s, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);
 }
 
 
@@ -460,28 +259,20 @@ skip past some strings in a buffer
 ********************************************************************/
 char *skip_string(char *buf,size_t n)
 {
-  while (n--)
-    buf += strlen(buf) + 1;
-  return(buf);
+       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.
- 16.oct.98, jdblair@cobaltnet.com.
 ********************************************************************/
-
 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++;
-  }
-  return len;
+       push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+       return strlen_w(tmpbuf);
 }
 
 /*******************************************************************
@@ -490,94 +281,36 @@ 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 = (front && *front) ? strlen(front) : 0;
-  size_t back_len = (back && *back) ? strlen(back) : 0;
-  size_t s_len;
-
-  while (front_len && strncmp(s, front, front_len) == 0)
-  {
-    char *p = s;
-    ret = True;
-    while (1)
-    {
-      if (!(*p = p[front_len]))
-        break;
-      p++;
-    }
-  }
+       BOOL ret = False;
+       size_t front_len;
+       size_t back_len;
+       size_t len;
 
-  /*
-   * We split out the multibyte code page
-   * case here for speed purposes. Under a
-   * multibyte code page we need to walk the
-   * string forwards only and multiple times.
-   * Thanks to John Blair for finding this
-   * one. JRA.
-   */
-
-  if(back_len)
-  {
-    if(!is_multibyte_codepage())
-    {
-      s_len = strlen(s);
-      while ((s_len >= back_len) && 
-             (strncmp(s + s_len - back_len, back, back_len)==0))  
-      {
-        ret = True;
-        s[s_len - back_len] = '\0';
-        s_len = strlen(s);
-      }
-    }
-    else
-    {
+       /* Ignore null or empty strings. */
+       if (!s || (s[0] == '\0'))
+               return False;
 
-      /*
-       * Multibyte code page case.
-       * Keep going through the string, trying
-       * to match the 'back' string with the end
-       * of the string. If we get a match, truncate
-       * 'back' off the end of the string and
-       * go through the string again from the
-       * start. Keep doing this until we have
-       * gone through the string with no match
-       * at the string end.
-       */
-
-      size_t mb_back_len = str_charnum(back);
-      size_t mb_s_len = str_charnum(s);
-
-      while(mb_s_len >= mb_back_len)
-      {
-        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++;
-        }
+       front_len       = front? strlen(front) : 0;
+       back_len        = back? strlen(back) : 0;
 
-        /*
-         * mbp now points at mb_back_len multibyte
-         * characters from the end of s.
-         */
-
-        if(strcmp(mbp, back) == 0)
-        {
-          ret = True;
-          *mbp = '\0';
-          mb_s_len = str_charnum(s);
-          mbp = s;
-        }
-        else
-          break;
-      } /* end while mb_s_len... */
-    } /* end else .. */
-  } /* end if back_len .. */
+       len = strlen(s);
 
-  return(ret);
+       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 (strncmp(s+len-back_len,back,back_len)==0) {
+                       s[len-back_len]='\0';
+                       len -= back_len;
+                       ret=True;
+               }
+       }
+       return ret;
 }
 
 
@@ -586,46 +319,11 @@ does a string have any uppercase chars in it?
 ****************************************************************************/
 BOOL strhasupper(const char *s)
 {
-  while (*s) 
-  {
-#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. */
-      if (is_shift_jis (*s))
-        s += 2;
-      else if (is_kana (*s))
-        s++;
-      else
-      {
-        if (isupper(*s))
-          return(True);
-        s++;
-      }
-    }
-    else
-#endif /* KANJI_WIN95_COMPATIBILITY */
-    {
-      size_t skip = skip_multibyte_char( *s );
-      if( skip != 0 )
-        s += skip;
-      else {
-        if (isupper(*s))
-          return(True);
-        s++;
-      }
-    }
-  }
-  return(False);
+       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);
 }
 
 /****************************************************************************
@@ -633,206 +331,165 @@ does a string have any lowercase chars in it?
 ****************************************************************************/
 BOOL strhaslower(const char *s)
 {
-  while (*s) 
-  {
-#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. */
-      if (is_shift_jis (*s))
-      {
-        if (is_sj_upper (s[0], s[1]))
-          return(True);
-        if (is_sj_lower (s[0], s[1]))
-          return (True);
-        s += 2;
-      }
-      else if (is_kana (*s))
-      {
-        s++;
-      }
-      else
-      {
-        if (islower(*s))
-          return(True);
-        s++;
-      }
-    }
-    else
-#endif /* KANJI_WIN95_COMPATIBILITY */
-    {
-      size_t skip = skip_multibyte_char( *s );
-      if( skip != 0 )
-        s += skip;
-      else {
-        if (islower(*s))
-          return(True);
-        s++;
-      }
-    }
-  }
-  return(False);
+       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 chars in a string
+find the number of 'c' chars in a string
 ****************************************************************************/
 size_t count_chars(const char *s,char c)
 {
-  size_t count=0;
-
-#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)
-          count++;
-        s++;
-      }
-    }
-  }
-  else
-#endif /* KANJI_WIN95_COMPATIBILITY */
-  {
-    while (*s) 
-    {
-      size_t skip = skip_multibyte_char( *s );
-      if( skip != 0 )
-        s += skip;
-      else {
-        if (*s == c)
-          count++;
-        s++;
-      }
-    }
-  }
-  return(count);
+       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;
+       size_t len;
 
-    if (!dest) {
-        DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
-        return NULL;
-    }
+       if (!dest) {
+               DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
+               return NULL;
+       }
 
-    if (!src) {
-        *dest = 0;
-        return dest;
-    }  
+       if (!src) {
+               *dest = 0;
+               return dest;
+       }  
 
-    len = strlen(src);
+       len = strlen(src);
 
-    if (len > maxlength) {
-           DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
-                    len-maxlength, src));
-           len = maxlength;
-    }
+       if (len > maxlength) {
+               DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
+                        (int)(len-maxlength), src));
+               len = maxlength;
+       }
       
-    memcpy(dest, src, len);
-    dest[len] = 0;
-    return dest;
+       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;
+       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 (!dest) {
+               DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
+               return NULL;
+       }
 
-    if (src_len + dest_len > maxlength) {
-           DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
-                    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;
+       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;
 }
 
-/****************************************************************************
-this is a safer strcpy(), meant to prevent core dumps when nasty things happen
-****************************************************************************/
-char *StrCpy(char *dest,const char *src)
+/*******************************************************************
+ 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)
 {
-  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;
+
+       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(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!
+ 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);
+       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).
@@ -882,16 +539,16 @@ size_t strhex_to_str(char *p, size_t 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,7 +592,7 @@ static char *null_string = NULL;
 /****************************************************************************
 set a string value, allocing the space for the string
 ****************************************************************************/
-BOOL string_init(char **dest,const char *src)
+static BOOL string_init(char **dest,const char *src)
 {
   size_t l;
   if (!src)     
@@ -998,29 +655,42 @@ 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 _
+any of " ; ' $ or ` in the insert string are replaced with _
+if len==0 then no length check is performed
 ****************************************************************************/
-void string_sub(char *s,const char *pattern,const char *insert)
+void string_sub(char *s,const char *pattern,const char *insert, size_t len)
 {
        char *p;
-       size_t ls,lp,li, i;
+       ssize_t ls,lp,li, i;
 
        if (!insert || !pattern || !s) return;
 
-       ls = strlen(s);
-       lp = strlen(pattern);
-       li = strlen(insert);
+       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))) {
-               memmove(p+li,p+lp,ls + 1 - (PTR_DIFF(p,s) + lp));
+               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:
@@ -1032,26 +702,44 @@ void string_sub(char *s,const char *pattern,const char *insert)
        }
 }
 
+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 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)
+void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
 {
        char *p;
-       size_t ls,lp,li;
+       ssize_t ls,lp,li;
 
        if (!insert || !pattern || !s) return;
 
-       ls = strlen(s);
-       lp = strlen(pattern);
-       li = strlen(insert);
+       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))) {
-               memmove(p+li,p+lp,ls + 1 - (PTR_DIFF(p,s) + lp));
+               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);
@@ -1090,72 +778,82 @@ void split_at_last_component(char *path, char *front, char sep, char *back)
        }
 }
 
-/****************************************************************************
-convert a bit field to a string.  if you want multiple bits to be detected
-set them first, e.g SV_TYPE_ALL to be "All" or "Full Control" for ACB_INFOs.
-
-strings are expected to contain their own separators, although the code
-below only assumes that separators are spaces.
 
+/****************************************************************************
+write an octal as a string
 ****************************************************************************/
-char *bit_field_to_str(uint32 type, struct field_info *bs)
+char *octal_string(int i)
 {
-       static fstring typestr;
-       int i = 0;
-
-       typestr[0] = 0;
-
-       if (type == 0 || bs == NULL)
-       {
-               return NULL;
+       static char ret[64];
+       if (i == -1) {
+               return "-1";
        }
+       slprintf(ret, sizeof(ret)-1, "0%o", i);
+       return ret;
+}
 
-       while (bs[i].str != NULL && type != 0)
-       {
-               if (IS_BITS_SET_ALL(bs[i].bits, type))
-               {
-                       fstrcat(typestr, bs[i].str);
-                       type &= ~bs[i].bits;
-               }
-               i++;
-       }
-       
-       i = strlen(typestr)-1;
-       if (i > 0 && typestr[i] == ' ')
-       {
-               typestr[i] = 0;
-       }
 
-       return typestr;
+/****************************************************************************
+truncate a string at a specified length
+****************************************************************************/
+char *string_truncate(char *s, int length)
+{
+       if (s && strlen(s) > length) {
+               s[length] = 0;
+       }
+       return s;
 }
 
+
 /****************************************************************************
-convert an enumeration to a string.  first item is the default.
+strchr and strrchr are very hard to do on general multi-byte strings. 
+we convert via ucs2 for now
 ****************************************************************************/
-char *enum_field_to_str(uint32 type, struct field_info *bs, BOOL first_default)
+char *strchr_m(const char *s, char c)
 {
-       int i = 0;
+       wpstring ws;
+       pstring s2;
+       smb_ucs2_t *p;
 
-       if (bs == NULL)
-       {
-               return NULL;
-       }
+       push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
+       p = strchr_wa(ws, c);
+       if (!p) return NULL;
+       *p = 0;
+       pull_ucs2_pstring(s2, ws);
+       return (char *)(s+strlen(s2));
+}
 
-       while (bs[i].str != NULL && type != 0)
-       {
-               if (bs[i].bits == type)
-               {
-                       return bs[i].str;
-               }
-               i++;
-       }
+char *strrchr_m(const char *s, char c)
+{
+       wpstring ws;
+       pstring s2;
+       smb_ucs2_t *p;
 
-       /* oops - none found */
+       push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
+       p = strrchr_wa(ws, c);
+       if (!p) return NULL;
+       *p = 0;
+       pull_ucs2_pstring(s2, ws);
+       return (char *)(s+strlen(s2));
+}
 
-       if (first_default)
-       {
-               return bs[0].str;
-       }
+/*******************************************************************
+  convert a string to lower case
+********************************************************************/
+void strlower_m(char *s)
+{
+       /* I assume that lowercased string takes the same number of bytes
+        * as source string even in UTF-8 encoding. (VIV) */
+       unix_strlower(s,strlen(s)+1,s,strlen(s)+1);     
+}
 
-       return NULL;
+/*******************************************************************
+  convert a string to upper case
+********************************************************************/
+void strupper_m(char *s)
+{
+       /* I assume that lowercased string takes the same number of bytes
+        * as source string even in multibyte encoding. (VIV) */
+       unix_strupper(s,strlen(s)+1,s,strlen(s)+1);     
 }
+