a big one:
[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    
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(*psz1))
202                         psz1++;
203                 while (isspace(*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         smb_ucs2_t *ptr;
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(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  ls, lp, li, lt;
758
759         if (!insert || !pattern || !*pattern || !s) return NULL;
760
761         ls = lt = (size_t)strlen_w(s) * sizeof(smb_ucs2_t);
762         lp = (size_t)strlen_w(pattern) * sizeof(smb_ucs2_t);
763         li = (size_t)strlen_w(insert) * sizeof(smb_ucs2_t);
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);
783                 memcpy(rp, insert, li);
784                 s = sp + lp;
785                 rp += li;
786         }
787         *rp = 0;
788
789         return r;
790 }
791
792 smb_ucs2_t *all_string_sub_wa(smb_ucs2_t *s, const char *pattern,
793                                              const char *insert)
794 {
795         wpstring p, i;
796
797         if (!insert || !pattern || !s) return NULL;
798         push_ucs2(NULL, p, pattern, sizeof(wpstring) - 1, STR_TERMINATE);
799         push_ucs2(NULL, i, insert, sizeof(wpstring) - 1, STR_TERMINATE);
800         return all_string_sub_w(s, p, i);
801 }
802
803 /****************************************************************************
804  splits out the front and back at a separator.
805 ****************************************************************************/
806 void split_at_last_component(char *path, char *front, char sep, char *back)
807 {
808         char *p = strrchr_m(path, sep);
809
810         if (p != NULL)
811         {
812                 *p = 0;
813         }
814         if (front != NULL)
815         {
816                 pstrcpy(front, path);
817         }
818         if (p != NULL)
819         {
820                 if (back != NULL)
821                 {
822                         pstrcpy(back, p+1);
823                 }
824                 *p = '\\';
825         }
826         else
827         {
828                 if (back != NULL)
829                 {
830                         back[0] = 0;
831                 }
832         }
833 }
834
835
836 /****************************************************************************
837 write an octal as a string
838 ****************************************************************************/
839 char *octal_string(int i)
840 {
841         static char ret[64];
842         if (i == -1) {
843                 return "-1";
844         }
845         slprintf(ret, sizeof(ret)-1, "0%o", i);
846         return ret;
847 }
848
849
850 /****************************************************************************
851 truncate a string at a specified length
852 ****************************************************************************/
853 char *string_truncate(char *s, int length)
854 {
855         if (s && strlen(s) > length) {
856                 s[length] = 0;
857         }
858         return s;
859 }
860
861
862 /****************************************************************************
863 strchr and strrchr_m are very hard to do on general multi-byte strings. 
864 we convert via ucs2 for now
865 ****************************************************************************/
866 char *strchr_m(const char *s, char c)
867 {
868         wpstring ws;
869         pstring s2;
870         smb_ucs2_t *p;
871
872         push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
873         p = strchr_w(ws, UCS2_CHAR(c));
874         if (!p) return NULL;
875         *p = 0;
876         pull_ucs2_pstring(s2, ws);
877         return (char *)(s+strlen(s2));
878 }
879
880 char *strrchr_m(const char *s, char c)
881 {
882         wpstring ws;
883         pstring s2;
884         smb_ucs2_t *p;
885
886         push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
887         p = strrchr_w(ws, UCS2_CHAR(c));
888         if (!p) return NULL;
889         *p = 0;
890         pull_ucs2_pstring(s2, ws);
891         return (char *)(s+strlen(s2));
892 }
893
894 /*******************************************************************
895   convert a string to lower case
896 ********************************************************************/
897 void strlower_m(char *s)
898 {
899         /* I assume that lowercased string takes the same number of bytes
900          * as source string even in UTF-8 encoding. (VIV) */
901         unix_strlower(s,strlen(s)+1,s,strlen(s)+1);     
902 }
903
904 /*******************************************************************
905   convert a string to upper case
906 ********************************************************************/
907 void strupper_m(char *s)
908 {
909         /* I assume that lowercased string takes the same number of bytes
910          * as source string even in multibyte encoding. (VIV) */
911         unix_strupper(s,strlen(s)+1,s,strlen(s)+1);     
912 }