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