a7eeedea3d866d54a5542bb4dd04ab755fb24a86
[kai/samba.git] / source3 / lib / util_str.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Samba utility functions
5    Copyright (C) Andrew Tridgell 1992-2001
6    Copyright (C) Simo Sorce      2001-2002
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /****************************************************************************
26   Get the next token from a string, return False if none found
27   handles double-quotes. 
28 Based on a routine by GJC@VILLAGE.COM. 
29 Extensively modified by Andrew.Tridgell@anu.edu.au
30 ****************************************************************************/
31 BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize)
32 {
33         char *s;
34         BOOL quoted;
35         size_t len=1;
36
37         if (!ptr) return(False);
38
39         s = *ptr;
40
41         /* default to simple separators */
42         if (!sep) sep = " \t\n\r";
43
44         /* find the first non sep char */
45         while (*s && strchr_m(sep,*s)) s++;
46         
47         /* nothing left? */
48         if (! *s) return(False);
49         
50         /* copy over the token */
51         for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
52                 if (*s == '\"') {
53                         quoted = !quoted;
54                 } else {
55                         len++;
56                         *buff++ = *s;
57                 }
58         }
59         
60         *ptr = (*s) ? s+1 : s;  
61         *buff = 0;
62         
63         return(True);
64 }
65
66
67
68 /****************************************************************************
69 This is like next_token but is not re-entrant and "remembers" the first 
70 parameter so you can pass NULL. This is useful for user interface code
71 but beware the fact that it is not re-entrant!
72 ****************************************************************************/
73 static char *last_ptr=NULL;
74
75 BOOL next_token_nr(char **ptr,char *buff,char *sep, size_t bufsize)
76 {
77         BOOL ret;
78         if (!ptr) ptr = &last_ptr;
79
80         ret = next_token(ptr, buff, sep, bufsize);
81         last_ptr = *ptr;
82         return ret;     
83 }
84
85 static uint16 tmpbuf[sizeof(pstring)];
86
87 void set_first_token(char *ptr)
88 {
89         last_ptr = ptr;
90 }
91
92
93 /****************************************************************************
94 Convert list of tokens to array; dependent on above routine.
95 Uses last_ptr from above - bit of a hack.
96 ****************************************************************************/
97 char **toktocliplist(int *ctok, char *sep)
98 {
99         char *s=last_ptr;
100         int ictok=0;
101         char **ret, **iret;
102
103         if (!sep) sep = " \t\n\r";
104
105         while(*s && strchr_m(sep,*s)) s++;
106
107         /* nothing left? */
108         if (!*s) return(NULL);
109
110         do {
111                 ictok++;
112                 while(*s && (!strchr_m(sep,*s))) s++;
113                 while(*s && strchr_m(sep,*s)) *s++=0;
114         } while(*s);
115         
116         *ctok=ictok;
117         s=last_ptr;
118         
119         if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL;
120         
121         while(ictok--) {    
122                 *iret++=s;
123                 while(*s++);
124                 while(!*s) s++;
125         }
126
127         return ret;
128 }
129
130 /*******************************************************************
131   case insensitive string compararison
132 ********************************************************************/
133 int StrCaseCmp(const char *s, const char *t)
134 {
135         pstring buf1, buf2;
136         unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
137         unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
138         return strcmp(buf1,buf2);
139 }
140
141 /*******************************************************************
142   case insensitive string compararison, length limited
143 ********************************************************************/
144 int StrnCaseCmp(const char *s, const char *t, size_t n)
145 {
146         pstring buf1, buf2;
147         unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
148         unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
149         return strncmp(buf1,buf2,n);
150 }
151
152 /*******************************************************************
153   compare 2 strings 
154 ********************************************************************/
155 BOOL strequal(const char *s1, const char *s2)
156 {
157         if (s1 == s2) return(True);
158         if (!s1 || !s2) return(False);
159   
160         return(StrCaseCmp(s1,s2)==0);
161 }
162
163 /*******************************************************************
164   compare 2 strings up to and including the nth char.
165   ******************************************************************/
166 BOOL strnequal(const char *s1,const char *s2,size_t n)
167 {
168   if (s1 == s2) return(True);
169   if (!s1 || !s2 || !n) return(False);
170   
171   return(StrnCaseCmp(s1,s2,n)==0);
172 }
173
174 /*******************************************************************
175   compare 2 strings (case sensitive)
176 ********************************************************************/
177 BOOL strcsequal(const char *s1,const char *s2)
178 {
179   if (s1 == s2) return(True);
180   if (!s1 || !s2) return(False);
181   
182   return(strcmp(s1,s2)==0);
183 }
184
185 /***************************************************************************
186 Do a case-insensitive, whitespace-ignoring string compare.
187 ***************************************************************************/
188 int strwicmp(const char *psz1, const char *psz2)
189 {
190         /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
191         /* appropriate value. */
192         if (psz1 == psz2)
193                 return (0);
194         else if (psz1 == NULL)
195                 return (-1);
196         else if (psz2 == NULL)
197                 return (1);
198
199         /* sync the strings on first non-whitespace */
200         while (1)
201         {
202                 while (isspace((int)*psz1))
203                         psz1++;
204                 while (isspace((int)*psz2))
205                         psz2++;
206                 if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0'
207                     || *psz2 == '\0')
208                         break;
209                 psz1++;
210                 psz2++;
211         }
212         return (*psz1 - *psz2);
213 }
214
215
216 /*******************************************************************
217   convert a string to "normal" form
218 ********************************************************************/
219 void strnorm(char *s)
220 {
221   extern int case_default;
222   if (case_default == CASE_UPPER)
223     strupper(s);
224   else
225     strlower(s);
226 }
227
228 /*******************************************************************
229 check if a string is in "normal" case
230 ********************************************************************/
231 BOOL strisnormal(char *s)
232 {
233         extern int case_default;
234         if (case_default == CASE_UPPER)
235                 return(!strhaslower(s));
236         
237         return(!strhasupper(s));
238 }
239
240
241 /****************************************************************************
242   string replace
243   NOTE: oldc and newc must be 7 bit characters
244 ****************************************************************************/
245 void string_replace(char *s,char oldc,char newc)
246 {
247         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
248         string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc));
249         pull_ucs2(NULL, s, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);
250 }
251
252
253 /*******************************************************************
254 skip past some strings in a buffer
255 ********************************************************************/
256 char *skip_string(char *buf,size_t n)
257 {
258         while (n--)
259                 buf += strlen(buf) + 1;
260         return(buf);
261 }
262
263 /*******************************************************************
264  Count the number of characters in a string. Normally this will
265  be the same as the number of bytes in a string for single byte strings,
266  but will be different for multibyte.
267 ********************************************************************/
268 size_t str_charnum(const char *s)
269 {
270         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
271         return strlen_w(tmpbuf);
272 }
273
274 /*******************************************************************
275 trim the specified elements off the front and back of a string
276 ********************************************************************/
277
278 BOOL trim_string(char *s,const char *front,const char *back)
279 {
280         BOOL ret = False;
281         size_t front_len;
282         size_t back_len;
283         size_t len;
284
285         /* Ignore null or empty strings. */
286         if (!s || (s[0] == '\0'))
287                 return False;
288
289         front_len       = front? strlen(front) : 0;
290         back_len        = back? strlen(back) : 0;
291
292         len = strlen(s);
293
294         if (front_len) {
295                 while (len && strncmp(s, front, front_len)==0) {
296                         memcpy(s, s+front_len, (len-front_len)+1);
297                         len -= front_len;
298                         ret=True;
299                 }
300         }
301         
302         if (back_len) {
303                 while (strncmp(s+len-back_len,back,back_len)==0) {
304                         s[len-back_len]='\0';
305                         len -= back_len;
306                         ret=True;
307                 }
308         }
309         return ret;
310 }
311
312
313 /****************************************************************************
314 does a string have any uppercase chars in it?
315 ****************************************************************************/
316 BOOL strhasupper(const char *s)
317 {
318         smb_ucs2_t *ptr;
319         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
320         for(ptr=tmpbuf;*ptr;ptr++)
321                 if(isupper_w(*ptr)) return True;
322         return(False);
323 }
324
325 /****************************************************************************
326 does a string have any lowercase chars in it?
327 ****************************************************************************/
328 BOOL strhaslower(const char *s)
329 {
330         smb_ucs2_t *ptr;
331         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
332         for(ptr=tmpbuf;*ptr;ptr++)
333                 if(islower_w(*ptr)) return True;
334         return(False);
335 }
336
337 /****************************************************************************
338 find the number of 'c' chars in a string
339 ****************************************************************************/
340 size_t count_chars(const char *s,char c)
341 {
342         smb_ucs2_t *ptr;
343         int count;
344         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
345         for(count=0,ptr=tmpbuf;*ptr;ptr++) if(*ptr==UCS2_CHAR(c)) count++;
346         return(count);
347 }
348
349 /*******************************************************************
350 Return True if a string consists only of one particular character.
351 ********************************************************************/
352
353 BOOL str_is_all(const char *s,char c)
354 {
355         smb_ucs2_t *ptr;
356
357         if(s == NULL) return False;
358         if(!*s) return False;
359   
360         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
361         for(ptr=tmpbuf;*ptr;ptr++) if(*ptr!=UCS2_CHAR(c)) return False;
362
363         return True;
364 }
365
366 /*******************************************************************
367 safe string copy into a known length string. maxlength does not
368 include the terminating zero.
369 ********************************************************************/
370
371 char *safe_strcpy(char *dest,const char *src, size_t maxlength)
372 {
373         size_t len;
374
375         if (!dest) {
376                 DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
377                 return NULL;
378         }
379
380         if (!src) {
381                 *dest = 0;
382                 return dest;
383         }  
384
385         len = strlen(src);
386
387         if (len > maxlength) {
388                 DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
389                          (int)(len-maxlength), src));
390                 len = maxlength;
391         }
392       
393         memmove(dest, src, len);
394         dest[len] = 0;
395         return dest;
396 }  
397
398 /*******************************************************************
399 safe string cat into a string. maxlength does not
400 include the terminating zero.
401 ********************************************************************/
402
403 char *safe_strcat(char *dest, const char *src, size_t maxlength)
404 {
405         size_t src_len, dest_len;
406
407         if (!dest) {
408                 DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
409                 return NULL;
410         }
411
412         if (!src) {
413                 return dest;
414         }  
415         
416         src_len = strlen(src);
417         dest_len = strlen(dest);
418         
419         if (src_len + dest_len > maxlength) {
420                 DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
421                          (int)(src_len + dest_len - maxlength), src));
422                 src_len = maxlength - dest_len;
423         }
424         
425         memcpy(&dest[dest_len], src, src_len);
426         dest[dest_len + src_len] = 0;
427         return dest;
428 }
429
430 /*******************************************************************
431  Paranoid strcpy into a buffer of given length (includes terminating
432  zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
433  and replaces with '_'. Deliberately does *NOT* check for multibyte
434  characters. Don't change it !
435 ********************************************************************/
436
437 char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
438 {
439         size_t len, i;
440
441         if (!dest) {
442                 DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
443                 return NULL;
444         }
445
446         if (!src) {
447                 *dest = 0;
448                 return dest;
449         }  
450
451         len = strlen(src);
452         if (len >= maxlength)
453                 len = maxlength - 1;
454
455         if (!other_safe_chars)
456                 other_safe_chars = "";
457
458         for(i = 0; i < len; i++) {
459                 int val = (src[i] & 0xff);
460                 if(isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val))
461                         dest[i] = src[i];
462                 else
463                         dest[i] = '_';
464         }
465
466         dest[i] = '\0';
467
468         return dest;
469 }
470
471 /****************************************************************************
472  Like strncpy but always null terminates. Make sure there is room!
473  The variable n should always be one less than the available size.
474 ****************************************************************************/
475
476 char *StrnCpy(char *dest,const char *src,size_t n)
477 {
478         char *d = dest;
479         if (!dest) return(NULL);
480         if (!src) {
481                 *dest = 0;
482                 return(dest);
483         }
484         while (n-- && (*d++ = *src++)) ;
485         *d = 0;
486         return(dest);
487 }
488
489 /****************************************************************************
490 like strncpy but copies up to the character marker.  always null terminates.
491 returns a pointer to the character marker in the source string (src).
492 ****************************************************************************/
493 char *strncpyn(char *dest, const char *src,size_t n, char c)
494 {
495         char *p;
496         size_t str_len;
497
498         p = strchr_m(src, c);
499         if (p == NULL)
500         {
501                 DEBUG(5, ("strncpyn: separator character (%c) not found\n", c));
502                 return NULL;
503         }
504
505         str_len = PTR_DIFF(p, src);
506         strncpy(dest, src, MIN(n, str_len));
507         dest[str_len] = '\0';
508
509         return p;
510 }
511
512
513 /*************************************************************
514  Routine to get hex characters and turn them into a 16 byte array.
515  the array can be variable length, and any non-hex-numeric
516  characters are skipped.  "0xnn" or "0Xnn" is specially catered
517  for.
518
519  valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
520
521 **************************************************************/
522 size_t strhex_to_str(char *p, size_t len, const char *strhex)
523 {
524         size_t i;
525         size_t num_chars = 0;
526         unsigned char   lonybble, hinybble;
527         char           *hexchars = "0123456789ABCDEF";
528         char           *p1 = NULL, *p2 = NULL;
529
530         for (i = 0; i < len && strhex[i] != 0; i++)
531         {
532                 if (strnequal(hexchars, "0x", 2))
533                 {
534                         i++; /* skip two chars */
535                         continue;
536                 }
537
538                 if (!(p1 = strchr_m(hexchars, toupper(strhex[i]))))
539                 {
540                         break;
541                 }
542
543                 i++; /* next hex digit */
544
545                 if (!(p2 = strchr_m(hexchars, toupper(strhex[i]))))
546                 {
547                         break;
548                 }
549
550                 /* get the two nybbles */
551                 hinybble = PTR_DIFF(p1, hexchars);
552                 lonybble = PTR_DIFF(p2, hexchars);
553
554                 p[num_chars] = (hinybble << 4) | lonybble;
555                 num_chars++;
556
557                 p1 = NULL;
558                 p2 = NULL;
559         }
560         return num_chars;
561 }
562
563 /****************************************************************************
564 check if a string is part of a list
565 ****************************************************************************/
566 BOOL in_list(char *s,char *list,BOOL casesensitive)
567 {
568   pstring tok;
569   char *p=list;
570
571   if (!list) return(False);
572
573   while (next_token(&p,tok,LIST_SEP,sizeof(tok))) {
574     if (casesensitive) {
575       if (strcmp(tok,s) == 0)
576         return(True);
577     } else {
578       if (StrCaseCmp(tok,s) == 0)
579         return(True);
580     }
581   }
582   return(False);
583 }
584
585 /* this is used to prevent lots of mallocs of size 1 */
586 static char *null_string = NULL;
587
588 /****************************************************************************
589 set a string value, allocing the space for the string
590 ****************************************************************************/
591 static BOOL string_init(char **dest,const char *src)
592 {
593   size_t l;
594   if (!src)     
595     src = "";
596
597   l = strlen(src);
598
599   if (l == 0)
600     {
601       if (!null_string) {
602         if((null_string = (char *)malloc(1)) == NULL) {
603           DEBUG(0,("string_init: malloc fail for null_string.\n"));
604           return False;
605         }
606         *null_string = 0;
607       }
608       *dest = null_string;
609     }
610   else
611     {
612       (*dest) = (char *)malloc(l+1);
613       if ((*dest) == NULL) {
614               DEBUG(0,("Out of memory in string_init\n"));
615               return False;
616       }
617
618       pstrcpy(*dest,src);
619     }
620   return(True);
621 }
622
623 /****************************************************************************
624 free a string value
625 ****************************************************************************/
626 void string_free(char **s)
627 {
628   if (!s || !(*s)) return;
629   if (*s == null_string)
630     *s = NULL;
631   SAFE_FREE(*s);
632 }
633
634 /****************************************************************************
635 set a string value, allocing the space for the string, and deallocating any 
636 existing space
637 ****************************************************************************/
638 BOOL string_set(char **dest,const char *src)
639 {
640   string_free(dest);
641
642   return(string_init(dest,src));
643 }
644
645
646 /****************************************************************************
647 substitute a string for a pattern in another string. Make sure there is 
648 enough room!
649
650 This routine looks for pattern in s and replaces it with 
651 insert. It may do multiple replacements.
652
653 any of " ; ' $ or ` in the insert string are replaced with _
654 if len==0 then no length check is performed
655 ****************************************************************************/
656 void string_sub(char *s,const char *pattern,const char *insert, size_t len)
657 {
658         char *p;
659         ssize_t ls,lp,li, i;
660
661         if (!insert || !pattern || !s) return;
662
663         ls = (ssize_t)strlen(s);
664         lp = (ssize_t)strlen(pattern);
665         li = (ssize_t)strlen(insert);
666
667         if (!*pattern) return;
668         
669         while (lp <= ls && (p = strstr(s,pattern))) {
670                 if (len && (ls + (li-lp) >= len)) {
671                         DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n", 
672                                  (int)(ls + (li-lp) - len),
673                                  pattern, (int)len));
674                         break;
675                 }
676                 if (li != lp) {
677                         memmove(p+li,p+lp,strlen(p+lp)+1);
678                 }
679                 for (i=0;i<li;i++) {
680                         switch (insert[i]) {
681                         case '`':
682                         case '"':
683                         case '\'':
684                         case ';':
685                         case '$':
686                         case '%':
687                         case '\r':
688                         case '\n':
689                                 p[i] = '_';
690                                 break;
691                         default:
692                                 p[i] = insert[i];
693                         }
694                 }
695                 s = p + li;
696                 ls += (li-lp);
697         }
698 }
699
700 void fstring_sub(char *s,const char *pattern,const char *insert)
701 {
702         string_sub(s, pattern, insert, sizeof(fstring));
703 }
704
705 void pstring_sub(char *s,const char *pattern,const char *insert)
706 {
707         string_sub(s, pattern, insert, sizeof(pstring));
708 }
709
710 /****************************************************************************
711 similar to string_sub() but allows for any character to be substituted. 
712 Use with caution!
713 if len==0 then no length check is performed
714 ****************************************************************************/
715 void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
716 {
717         char *p;
718         ssize_t ls,lp,li;
719
720         if (!insert || !pattern || !s) return;
721
722         ls = (ssize_t)strlen(s);
723         lp = (ssize_t)strlen(pattern);
724         li = (ssize_t)strlen(insert);
725
726         if (!*pattern) return;
727         
728         while (lp <= ls && (p = strstr(s,pattern))) {
729                 if (len && (ls + (li-lp) >= len)) {
730                         DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n", 
731                                  (int)(ls + (li-lp) - len),
732                                  pattern, (int)len));
733                         break;
734                 }
735                 if (li != lp) {
736                         memmove(p+li,p+lp,strlen(p+lp)+1);
737                 }
738                 memcpy(p, insert, li);
739                 s = p + li;
740                 ls += (li-lp);
741         }
742 }
743
744 /****************************************************************************
745 similar to all_string_sub but for unicode strings.
746 return a new allocate unicode string.
747 len is the number of bytes, not chars
748   similar to string_sub() but allows for any character to be substituted.
749   Use with caution!
750   if len==0 then no length check is performed
751 ****************************************************************************/
752
753 smb_ucs2_t *all_string_sub_w(const smb_ucs2_t *s, const smb_ucs2_t *pattern,
754                                 const smb_ucs2_t *insert)
755 {
756         smb_ucs2_t *r, *rp, *sp;
757         size_t  lr, lp, li, lt;
758
759         if (!insert || !pattern || !*pattern || !s) return NULL;
760
761         lt = (size_t)strlen_w(s);
762         lp = (size_t)strlen_w(pattern);
763         li = (size_t)strlen_w(insert);
764
765         if (li > lp) {
766                 smb_ucs2_t *st = s;
767                 int ld = li - lp;
768                 while ((sp = strstr_w(st, pattern))) {
769                         st = sp + lp;
770                         lt += ld;
771                 }
772         }
773
774         r = rp = (smb_ucs2_t *)malloc((lt + 1)*(sizeof(smb_ucs2_t)));
775         if (!r) {
776                 DEBUG(0, ("all_string_sub_w: out of memory!\n"));
777                 return NULL;
778         }
779
780         while ((sp = strstr_w(s, pattern))) {
781                 memcpy(rp, s, (sp - s));
782                 rp += ((sp - s) / sizeof(smb_ucs2_t));
783                 memcpy(rp, insert, (li * sizeof(smb_ucs2_t)));
784                 s = sp + lp;
785                 rp += li;
786         }
787         lr = ((rp - r) / sizeof(smb_ucs2_t));
788         if (lr < lt) {
789                 memcpy(rp, s, ((lt - lr) * sizeof(smb_ucs2_t)));
790                 rp += (lt - lr);
791         }
792         *rp = 0;
793
794         return r;
795 }
796
797 smb_ucs2_t *all_string_sub_wa(smb_ucs2_t *s, const char *pattern,
798                                              const char *insert)
799 {
800         wpstring p, i;
801
802         if (!insert || !pattern || !s) return NULL;
803         push_ucs2(NULL, p, pattern, sizeof(wpstring) - 1, STR_TERMINATE);
804         push_ucs2(NULL, i, insert, sizeof(wpstring) - 1, STR_TERMINATE);
805         return all_string_sub_w(s, p, i);
806 }
807
808 /****************************************************************************
809  splits out the front and back at a separator.
810 ****************************************************************************/
811 void split_at_last_component(char *path, char *front, char sep, char *back)
812 {
813         char *p = strrchr_m(path, sep);
814
815         if (p != NULL)
816         {
817                 *p = 0;
818         }
819         if (front != NULL)
820         {
821                 pstrcpy(front, path);
822         }
823         if (p != NULL)
824         {
825                 if (back != NULL)
826                 {
827                         pstrcpy(back, p+1);
828                 }
829                 *p = '\\';
830         }
831         else
832         {
833                 if (back != NULL)
834                 {
835                         back[0] = 0;
836                 }
837         }
838 }
839
840
841 /****************************************************************************
842 write an octal as a string
843 ****************************************************************************/
844 char *octal_string(int i)
845 {
846         static char ret[64];
847         if (i == -1) {
848                 return "-1";
849         }
850         slprintf(ret, sizeof(ret)-1, "0%o", i);
851         return ret;
852 }
853
854
855 /****************************************************************************
856 truncate a string at a specified length
857 ****************************************************************************/
858 char *string_truncate(char *s, int length)
859 {
860         if (s && strlen(s) > length) {
861                 s[length] = 0;
862         }
863         return s;
864 }
865
866
867 /****************************************************************************
868 strchr and strrchr_m are very hard to do on general multi-byte strings. 
869 we convert via ucs2 for now
870 ****************************************************************************/
871 char *strchr_m(const char *s, char c)
872 {
873         wpstring ws;
874         pstring s2;
875         smb_ucs2_t *p;
876
877         push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
878         p = strchr_w(ws, UCS2_CHAR(c));
879         if (!p) return NULL;
880         *p = 0;
881         pull_ucs2_pstring(s2, ws);
882         return (char *)(s+strlen(s2));
883 }
884
885 char *strrchr_m(const char *s, char c)
886 {
887         wpstring ws;
888         pstring s2;
889         smb_ucs2_t *p;
890
891         push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
892         p = strrchr_w(ws, UCS2_CHAR(c));
893         if (!p) return NULL;
894         *p = 0;
895         pull_ucs2_pstring(s2, ws);
896         return (char *)(s+strlen(s2));
897 }
898
899 /*******************************************************************
900   convert a string to lower case
901 ********************************************************************/
902 void strlower_m(char *s)
903 {
904         /* I assume that lowercased string takes the same number of bytes
905          * as source string even in UTF-8 encoding. (VIV) */
906         unix_strlower(s,strlen(s)+1,s,strlen(s)+1);     
907 }
908
909 /*******************************************************************
910   convert a string to upper case
911 ********************************************************************/
912 void strupper_m(char *s)
913 {
914         /* I assume that lowercased string takes the same number of bytes
915          * as source string even in multibyte encoding. (VIV) */
916         unix_strupper(s,strlen(s)+1,s,strlen(s)+1);     
917 }
918
919 /*
920   return a RFC2254 binary string representation of a buffer
921   used in LDAP filters
922   caller must free
923 */
924 char *binary_string(char *buf, int len)
925 {
926         char *s;
927         int i, j;
928         const char *hex = "0123456789ABCDEF";
929         s = malloc(len * 3 + 1);
930         if (!s) return NULL;
931         for (j=i=0;i<len;i++) {
932                 s[j] = '\\';
933                 s[j+1] = hex[((unsigned char)buf[i]) >> 4];
934                 s[j+2] = hex[((unsigned char)buf[i]) & 0xF];
935                 j += 3;
936         }
937         s[j] = 0;
938         return s;
939 }
940
941
942 /* Just a typesafety wrapper for snprintf into a pstring */
943 int pstr_sprintf(pstring s, const char *fmt, ...)
944 {
945         va_list ap;
946         int ret;
947
948         va_start(ap, fmt);
949         ret = vsnprintf(s, PSTRING_LEN, fmt, ap);
950         va_end(ap);
951         return ret;
952 }
953
954
955 /* Just a typesafety wrapper for snprintf into a fstring */
956 int fstr_sprintf(fstring s, const char *fmt, ...)
957 {
958         va_list ap;
959         int ret;
960
961         va_start(ap, fmt);
962         ret = vsnprintf(s, FSTRING_LEN, fmt, ap);
963         va_end(ap);
964         return ret;
965 }