make sure we don't run over the end of 'name' in unix_convert()
[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
31 BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
32 {
33         const char *s;
34         BOOL quoted;
35         size_t len=1;
36
37         if (!ptr)
38                 return(False);
39
40         s = *ptr;
41
42         /* default to simple separators */
43         if (!sep)
44                 sep = " \t\n\r";
45
46         /* find the first non sep char */
47         while (*s && strchr_m(sep,*s))
48                 s++;
49         
50         /* nothing left? */
51         if (! *s)
52                 return(False);
53         
54         /* copy over the token */
55         for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
56                 if (*s == '\"') {
57                         quoted = !quoted;
58                 } else {
59                         len++;
60                         *buff++ = *s;
61                 }
62         }
63         
64         *ptr = (*s) ? s+1 : s;  
65         *buff = 0;
66         
67         return(True);
68 }
69
70 /****************************************************************************
71 This is like next_token but is not re-entrant and "remembers" the first 
72 parameter so you can pass NULL. This is useful for user interface code
73 but beware the fact that it is not re-entrant!
74 ****************************************************************************/
75
76 static char *last_ptr=NULL;
77
78 BOOL next_token_nr(const char **ptr,char *buff, const char *sep, size_t bufsize)
79 {
80         BOOL ret;
81         if (!ptr)
82                 ptr = (const char **)&last_ptr;
83
84         ret = next_token(ptr, buff, sep, bufsize);
85         last_ptr = *ptr;
86         return ret;     
87 }
88
89 static uint16 tmpbuf[sizeof(pstring)];
90
91 void set_first_token(char *ptr)
92 {
93         last_ptr = ptr;
94 }
95
96 /****************************************************************************
97  Convert list of tokens to array; dependent on above routine.
98  Uses last_ptr from above - bit of a hack.
99 ****************************************************************************/
100
101 char **toktocliplist(int *ctok, const char *sep)
102 {
103         char *s=last_ptr;
104         int ictok=0;
105         char **ret, **iret;
106
107         if (!sep)
108                 sep = " \t\n\r";
109
110         while(*s && strchr_m(sep,*s))
111                 s++;
112
113         /* nothing left? */
114         if (!*s)
115                 return(NULL);
116
117         do {
118                 ictok++;
119                 while(*s && (!strchr_m(sep,*s)))
120                         s++;
121                 while(*s && strchr_m(sep,*s))
122                         *s++=0;
123         } while(*s);
124         
125         *ctok=ictok;
126         s=last_ptr;
127         
128         if (!(ret=iret=malloc(ictok*sizeof(char *))))
129                 return NULL;
130         
131         while(ictok--) {    
132                 *iret++=s;
133                 while(*s++)
134                         ;
135                 while(!*s)
136                         s++;
137         }
138
139         return ret;
140 }
141
142 /*******************************************************************
143  Case insensitive string compararison.
144 ********************************************************************/
145
146 int StrCaseCmp(const char *s, const char *t)
147 {
148         pstring buf1, buf2;
149         unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
150         unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
151         return strcmp(buf1,buf2);
152 }
153
154 /*******************************************************************
155  Case insensitive string compararison, length limited.
156 ********************************************************************/
157
158 int StrnCaseCmp(const char *s, const char *t, size_t n)
159 {
160         pstring buf1, buf2;
161         unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
162         unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
163         return strncmp(buf1,buf2,n);
164 }
165
166 /*******************************************************************
167  Compare 2 strings.
168 ********************************************************************/
169
170 BOOL strequal(const char *s1, const char *s2)
171 {
172         if (s1 == s2)
173                 return(True);
174         if (!s1 || !s2)
175                 return(False);
176   
177         return(StrCaseCmp(s1,s2)==0);
178 }
179
180 /*******************************************************************
181  Compare 2 strings up to and including the nth char.
182 ******************************************************************/
183
184 BOOL strnequal(const char *s1,const char *s2,size_t n)
185 {
186   if (s1 == s2)
187           return(True);
188   if (!s1 || !s2 || !n)
189           return(False);
190   
191   return(StrnCaseCmp(s1,s2,n)==0);
192 }
193
194 /*******************************************************************
195  Compare 2 strings (case sensitive).
196 ********************************************************************/
197
198 BOOL strcsequal(const char *s1,const char *s2)
199 {
200   if (s1 == s2)
201           return(True);
202   if (!s1 || !s2)
203           return(False);
204   
205   return(strcmp(s1,s2)==0);
206 }
207
208 /***************************************************************************
209 Do a case-insensitive, whitespace-ignoring string compare.
210 ***************************************************************************/
211
212 int strwicmp(const char *psz1, const char *psz2)
213 {
214         /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
215         /* appropriate value. */
216         if (psz1 == psz2)
217                 return (0);
218         else if (psz1 == NULL)
219                 return (-1);
220         else if (psz2 == NULL)
221                 return (1);
222
223         /* sync the strings on first non-whitespace */
224         while (1) {
225                 while (isspace((int)*psz1))
226                         psz1++;
227                 while (isspace((int)*psz2))
228                         psz2++;
229                 if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0'
230                     || *psz2 == '\0')
231                         break;
232                 psz1++;
233                 psz2++;
234         }
235         return (*psz1 - *psz2);
236 }
237
238
239 /*******************************************************************
240  Convert a string to upper case, but don't modify it.
241 ********************************************************************/
242
243 char *strupper_static(const char *s)
244 {
245         static pstring str;
246
247         pstrcpy(str, s);
248         strupper(str);
249
250         return str;
251 }
252
253 /*******************************************************************
254  Convert a string to "normal" form.
255 ********************************************************************/
256
257 void strnorm(char *s)
258 {
259         extern int case_default;
260         if (case_default == CASE_UPPER)
261                 strupper(s);
262         else
263                 strlower(s);
264 }
265
266 /*******************************************************************
267  Check if a string is in "normal" case.
268 ********************************************************************/
269
270 BOOL strisnormal(const char *s)
271 {
272         extern int case_default;
273         if (case_default == CASE_UPPER)
274                 return(!strhaslower(s));
275         
276         return(!strhasupper(s));
277 }
278
279
280 /****************************************************************************
281  String replace.
282  NOTE: oldc and newc must be 7 bit characters
283 ****************************************************************************/
284
285 void string_replace(char *s,char oldc,char newc)
286 {
287         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
288         string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc));
289         pull_ucs2(NULL, s, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);
290 }
291
292 /*******************************************************************
293  Skip past some strings in a buffer.
294 ********************************************************************/
295
296 char *skip_string(char *buf,size_t n)
297 {
298         while (n--)
299                 buf += strlen(buf) + 1;
300         return(buf);
301 }
302
303 /*******************************************************************
304  Count the number of characters in a string. Normally this will
305  be the same as the number of bytes in a string for single byte strings,
306  but will be different for multibyte.
307 ********************************************************************/
308
309 size_t str_charnum(const char *s)
310 {
311         uint16 tmpbuf2[sizeof(pstring)];
312         push_ucs2(NULL, tmpbuf2,s, sizeof(tmpbuf2), STR_TERMINATE);
313         return strlen_w(tmpbuf2);
314 }
315
316 /*******************************************************************
317  Count the number of characters in a string. Normally this will
318  be the same as the number of bytes in a string for single byte strings,
319  but will be different for multibyte.
320 ********************************************************************/
321
322 size_t str_ascii_charnum(const char *s)
323 {
324         pstring tmpbuf2;
325         push_ascii(tmpbuf2, s, sizeof(tmpbuf2), STR_TERMINATE);
326         return strlen(tmpbuf2);
327 }
328
329 /*******************************************************************
330  Trim the specified elements off the front and back of a string.
331 ********************************************************************/
332
333 BOOL trim_string(char *s,const char *front,const char *back)
334 {
335         BOOL ret = False;
336         size_t front_len;
337         size_t back_len;
338         size_t len;
339
340         /* Ignore null or empty strings. */
341         if (!s || (s[0] == '\0'))
342                 return False;
343
344         front_len       = front? strlen(front) : 0;
345         back_len        = back? strlen(back) : 0;
346
347         len = strlen(s);
348
349         if (front_len) {
350                 while (len && strncmp(s, front, front_len)==0) {
351                         memcpy(s, s+front_len, (len-front_len)+1);
352                         len -= front_len;
353                         ret=True;
354                 }
355         }
356         
357         if (back_len) {
358                 while ((len >= back_len) && strncmp(s+len-back_len,back,back_len)==0) {
359                         s[len-back_len]='\0';
360                         len -= back_len;
361                         ret=True;
362                 }
363         }
364         return ret;
365 }
366
367 /****************************************************************************
368  Does a string have any uppercase chars in it?
369 ****************************************************************************/
370
371 BOOL strhasupper(const char *s)
372 {
373         smb_ucs2_t *ptr;
374         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
375         for(ptr=tmpbuf;*ptr;ptr++)
376                 if(isupper_w(*ptr))
377                         return True;
378         return(False);
379 }
380
381 /****************************************************************************
382  Does a string have any lowercase chars in it?
383 ****************************************************************************/
384
385 BOOL strhaslower(const char *s)
386 {
387         smb_ucs2_t *ptr;
388         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
389         for(ptr=tmpbuf;*ptr;ptr++)
390                 if(islower_w(*ptr))
391                         return True;
392         return(False);
393 }
394
395 /****************************************************************************
396  Find the number of 'c' chars in a string
397 ****************************************************************************/
398
399 size_t count_chars(const char *s,char c)
400 {
401         smb_ucs2_t *ptr;
402         int count;
403         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
404         for(count=0,ptr=tmpbuf;*ptr;ptr++)
405                 if(*ptr==UCS2_CHAR(c))
406                         count++;
407         return(count);
408 }
409
410 /*******************************************************************
411 Return True if a string consists only of one particular character.
412 ********************************************************************/
413
414 BOOL str_is_all(const char *s,char c)
415 {
416         smb_ucs2_t *ptr;
417
418         if(s == NULL)
419                 return False;
420         if(!*s)
421                 return False;
422   
423         push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
424         for(ptr=tmpbuf;*ptr;ptr++)
425                 if(*ptr!=UCS2_CHAR(c))
426                         return False;
427
428         return True;
429 }
430
431 /*******************************************************************
432  Safe string copy into a known length string. maxlength does not
433  include the terminating zero.
434 ********************************************************************/
435
436 char *safe_strcpy(char *dest,const char *src, size_t maxlength)
437 {
438         size_t len;
439
440         if (!dest) {
441                 DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
442                 return NULL;
443         }
444
445         if (!src) {
446                 *dest = 0;
447                 return dest;
448         }  
449
450         len = strlen(src);
451
452         if (len > maxlength) {
453                 DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
454                          (int)(len-maxlength), src));
455                 len = maxlength;
456         }
457       
458         memmove(dest, src, len);
459         dest[len] = 0;
460         return dest;
461 }  
462
463 /*******************************************************************
464  Safe string cat into a string. maxlength does not
465  include the terminating zero.
466 ********************************************************************/
467
468 char *safe_strcat(char *dest, const char *src, size_t maxlength)
469 {
470         size_t src_len, dest_len;
471
472         if (!dest) {
473                 DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
474                 return NULL;
475         }
476
477         if (!src)
478                 return dest;
479         
480         src_len = strlen(src);
481         dest_len = strlen(dest);
482
483         if (src_len + dest_len > maxlength) {
484                 DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
485                          (int)(src_len + dest_len - maxlength), src));
486                 if (maxlength > dest_len) {
487                         memcpy(&dest[dest_len], src, maxlength - dest_len);
488                 }
489                 dest[maxlength] = 0;
490                 return NULL;
491         }
492         
493         memcpy(&dest[dest_len], src, src_len);
494         dest[dest_len + src_len] = 0;
495         return dest;
496 }
497
498 /*******************************************************************
499  Paranoid strcpy into a buffer of given length (includes terminating
500  zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
501  and replaces with '_'. Deliberately does *NOT* check for multibyte
502  characters. Don't change it !
503 ********************************************************************/
504
505 char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
506 {
507         size_t len, i;
508
509         if (!dest) {
510                 DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
511                 return NULL;
512         }
513
514         if (!src) {
515                 *dest = 0;
516                 return dest;
517         }  
518
519         len = strlen(src);
520         if (len >= maxlength)
521                 len = maxlength - 1;
522
523         if (!other_safe_chars)
524                 other_safe_chars = "";
525
526         for(i = 0; i < len; i++) {
527                 int val = (src[i] & 0xff);
528                 if (isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val))
529                         dest[i] = src[i];
530                 else
531                         dest[i] = '_';
532         }
533
534         dest[i] = '\0';
535
536         return dest;
537 }
538
539 /****************************************************************************
540  Like strncpy but always null terminates. Make sure there is room!
541  The variable n should always be one less than the available size.
542 ****************************************************************************/
543
544 char *StrnCpy(char *dest,const char *src,size_t n)
545 {
546         char *d = dest;
547         if (!dest)
548                 return(NULL);
549         if (!src) {
550                 *dest = 0;
551                 return(dest);
552         }
553         while (n-- && (*d++ = *src++))
554                 ;
555         *d = 0;
556         return(dest);
557 }
558
559 /****************************************************************************
560  Like strncpy but copies up to the character marker.  always null terminates.
561  returns a pointer to the character marker in the source string (src).
562 ****************************************************************************/
563
564 char *strncpyn(char *dest, const char *src, size_t n, char c)
565 {
566         char *p;
567         size_t str_len;
568
569         p = strchr_m(src, c);
570         if (p == NULL) {
571                 DEBUG(5, ("strncpyn: separator character (%c) not found\n", c));
572                 return NULL;
573         }
574
575         str_len = PTR_DIFF(p, src);
576         strncpy(dest, src, MIN(n, str_len));
577         dest[str_len] = '\0';
578
579         return p;
580 }
581
582 /*************************************************************
583  Routine to get hex characters and turn them into a 16 byte array.
584  the array can be variable length, and any non-hex-numeric
585  characters are skipped.  "0xnn" or "0Xnn" is specially catered
586  for.
587
588  valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
589
590 **************************************************************/
591
592 size_t strhex_to_str(char *p, size_t len, const char *strhex)
593 {
594         size_t i;
595         size_t num_chars = 0;
596         unsigned char   lonybble, hinybble;
597         const char     *hexchars = "0123456789ABCDEF";
598         char           *p1 = NULL, *p2 = NULL;
599
600         for (i = 0; i < len && strhex[i] != 0; i++) {
601                 if (strnequal(hexchars, "0x", 2)) {
602                         i++; /* skip two chars */
603                         continue;
604                 }
605
606                 if (!(p1 = strchr_m(hexchars, toupper(strhex[i]))))
607                         break;
608
609                 i++; /* next hex digit */
610
611                 if (!(p2 = strchr_m(hexchars, toupper(strhex[i]))))
612                         break;
613
614                 /* get the two nybbles */
615                 hinybble = PTR_DIFF(p1, hexchars);
616                 lonybble = PTR_DIFF(p2, hexchars);
617
618                 p[num_chars] = (hinybble << 4) | lonybble;
619                 num_chars++;
620
621                 p1 = NULL;
622                 p2 = NULL;
623         }
624         return num_chars;
625 }
626
627 /****************************************************************************
628  Check if a string is part of a list.
629 ****************************************************************************/
630
631 BOOL in_list(char *s,char *list,BOOL casesensitive)
632 {
633         pstring tok;
634         const char *p=list;
635
636         if (!list)
637                 return(False);
638
639         while (next_token(&p,tok,LIST_SEP,sizeof(tok))) {
640                 if (casesensitive) {
641                         if (strcmp(tok,s) == 0)
642                                 return(True);
643                 } else {
644                         if (StrCaseCmp(tok,s) == 0)
645                                 return(True);
646                 }
647         }
648         return(False);
649 }
650
651 /* this is used to prevent lots of mallocs of size 1 */
652 static char *null_string = NULL;
653
654 /****************************************************************************
655  Set a string value, allocing the space for the string
656 ****************************************************************************/
657
658 static BOOL string_init(char **dest,const char *src)
659 {
660         size_t l;
661         if (!src)     
662                 src = "";
663
664         l = strlen(src);
665
666         if (l == 0) {
667                 if (!null_string) {
668                         if((null_string = (char *)malloc(1)) == NULL) {
669                                 DEBUG(0,("string_init: malloc fail for null_string.\n"));
670                                 return False;
671                         }
672                         *null_string = 0;
673                 }
674                 *dest = null_string;
675         } else {
676                 (*dest) = strdup(src);
677                 if ((*dest) == NULL) {
678                         DEBUG(0,("Out of memory in string_init\n"));
679                         return False;
680                 }
681         }
682         return(True);
683 }
684
685 /****************************************************************************
686  Free a string value.
687 ****************************************************************************/
688
689 void string_free(char **s)
690 {
691         if (!s || !(*s))
692                 return;
693         if (*s == null_string)
694                 *s = NULL;
695         SAFE_FREE(*s);
696 }
697
698 /****************************************************************************
699  Set a string value, deallocating any existing space, and allocing the space
700  for the string
701 ****************************************************************************/
702
703 BOOL string_set(char **dest,const char *src)
704 {
705         string_free(dest);
706         return(string_init(dest,src));
707 }
708
709 /****************************************************************************
710  Substitute a string for a pattern in another string. Make sure there is 
711  enough room!
712
713  This routine looks for pattern in s and replaces it with 
714  insert. It may do multiple replacements.
715
716  Any of " ; ' $ or ` in the insert string are replaced with _
717  if len==0 then the string cannot be extended. This is different from the old
718  use of len==0 which was for no length checks to be done.
719 ****************************************************************************/
720
721 void string_sub(char *s,const char *pattern, const char *insert, size_t len)
722 {
723         char *p;
724         ssize_t ls,lp,li, i;
725
726         if (!insert || !pattern || !*pattern || !s)
727                 return;
728
729         ls = (ssize_t)strlen(s);
730         lp = (ssize_t)strlen(pattern);
731         li = (ssize_t)strlen(insert);
732
733         if (len == 0)
734                 len = ls + 1; /* len is number of *bytes* */
735
736         while (lp <= ls && (p = strstr(s,pattern))) {
737                 if (ls + (li-lp) >= len) {
738                         DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n", 
739                                  (int)(ls + (li-lp) - len),
740                                  pattern, (int)len));
741                         break;
742                 }
743                 if (li != lp) {
744                         memmove(p+li,p+lp,strlen(p+lp)+1);
745                 }
746                 for (i=0;i<li;i++) {
747                         switch (insert[i]) {
748                         case '`':
749                         case '"':
750                         case '\'':
751                         case ';':
752                         case '$':
753                         case '%':
754                         case '\r':
755                         case '\n':
756                                 p[i] = '_';
757                                 break;
758                         default:
759                                 p[i] = insert[i];
760                         }
761                 }
762                 s = p + li;
763                 ls += (li-lp);
764         }
765 }
766
767 void fstring_sub(char *s,const char *pattern,const char *insert)
768 {
769         string_sub(s, pattern, insert, sizeof(fstring));
770 }
771
772 void pstring_sub(char *s,const char *pattern,const char *insert)
773 {
774         string_sub(s, pattern, insert, sizeof(pstring));
775 }
776
777 /****************************************************************************
778  Similar to string_sub, but it will accept only allocated strings
779  and may realloc them so pay attention at what you pass on no
780  pointers inside strings, no pstrings or const may be passed
781  as string.
782 ****************************************************************************/
783
784 char *realloc_string_sub(char *string, const char *pattern, const char *insert)
785 {
786         char *p, *in;
787         char *s;
788         ssize_t ls,lp,li,ld, i;
789
790         if (!insert || !pattern || !*pattern || !string || !*string)
791                 return NULL;
792
793         s = string;
794
795         in = strdup(insert);
796         if (!in) {
797                 DEBUG(0, ("realloc_string_sub: out of memory!\n"));
798                 return NULL;
799         }
800         ls = (ssize_t)strlen(s);
801         lp = (ssize_t)strlen(pattern);
802         li = (ssize_t)strlen(insert);
803         ld = li - lp;
804         for (i=0;i<li;i++) {
805                 switch (in[i]) {
806                         case '`':
807                         case '"':
808                         case '\'':
809                         case ';':
810                         case '$':
811                         case '%':
812                         case '\r':
813                         case '\n':
814                                 in[i] = '_';
815                         default:
816                                 /* ok */
817                                 break;
818                 }
819         }
820         
821         while ((p = strstr(s,pattern))) {
822                 if (ld > 0) {
823                         char *t = Realloc(string, ls + ld + 1);
824                         if (!t) {
825                                 DEBUG(0, ("realloc_string_sub: out of memory!\n"));
826                                 SAFE_FREE(in);
827                                 return NULL;
828                         }
829                         string = t;
830                         p = t + (p - s);
831                 }
832                 if (li != lp) {
833                         memmove(p+li,p+lp,strlen(p+lp)+1);
834                 }
835                 memcpy(p, in, li);
836                 s = p + li;
837                 ls += ld;
838         }
839         SAFE_FREE(in);
840         return string;
841 }
842
843 /****************************************************************************
844  Similar to string_sub() but allows for any character to be substituted. 
845  Use with caution!
846  if len==0 then the string cannot be extended. This is different from the old
847  use of len==0 which was for no length checks to be done.
848 ****************************************************************************/
849
850 void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
851 {
852         char *p;
853         ssize_t ls,lp,li;
854
855         if (!insert || !pattern || !s)
856                 return;
857
858         ls = (ssize_t)strlen(s);
859         lp = (ssize_t)strlen(pattern);
860         li = (ssize_t)strlen(insert);
861
862         if (!*pattern)
863                 return;
864         
865         if (len == 0)
866                 len = ls + 1; /* len is number of *bytes* */
867         
868         while (lp <= ls && (p = strstr(s,pattern))) {
869                 if (ls + (li-lp) >= len) {
870                         DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n", 
871                                  (int)(ls + (li-lp) - len),
872                                  pattern, (int)len));
873                         break;
874                 }
875                 if (li != lp) {
876                         memmove(p+li,p+lp,strlen(p+lp)+1);
877                 }
878                 memcpy(p, insert, li);
879                 s = p + li;
880                 ls += (li-lp);
881         }
882 }
883
884 /****************************************************************************
885  Similar to all_string_sub but for unicode strings.
886  Return a new allocated unicode string.
887  similar to string_sub() but allows for any character to be substituted.
888  Use with caution!
889 ****************************************************************************/
890
891 smb_ucs2_t *all_string_sub_w(const smb_ucs2_t *s, const smb_ucs2_t *pattern,
892                                 const smb_ucs2_t *insert)
893 {
894         smb_ucs2_t *r, *rp;
895         const smb_ucs2_t *sp;
896         size_t  lr, lp, li, lt;
897
898         if (!insert || !pattern || !*pattern || !s)
899                 return NULL;
900
901         lt = (size_t)strlen_w(s);
902         lp = (size_t)strlen_w(pattern);
903         li = (size_t)strlen_w(insert);
904
905         if (li > lp) {
906                 const smb_ucs2_t *st = s;
907                 int ld = li - lp;
908                 while ((sp = strstr_w(st, pattern))) {
909                         st = sp + lp;
910                         lt += ld;
911                 }
912         }
913
914         r = rp = (smb_ucs2_t *)malloc((lt + 1)*(sizeof(smb_ucs2_t)));
915         if (!r) {
916                 DEBUG(0, ("all_string_sub_w: out of memory!\n"));
917                 return NULL;
918         }
919
920         while ((sp = strstr_w(s, pattern))) {
921                 memcpy(rp, s, (sp - s));
922                 rp += ((sp - s) / sizeof(smb_ucs2_t));
923                 memcpy(rp, insert, (li * sizeof(smb_ucs2_t)));
924                 s = sp + lp;
925                 rp += li;
926         }
927         lr = ((rp - r) / sizeof(smb_ucs2_t));
928         if (lr < lt) {
929                 memcpy(rp, s, ((lt - lr) * sizeof(smb_ucs2_t)));
930                 rp += (lt - lr);
931         }
932         *rp = 0;
933
934         return r;
935 }
936
937 smb_ucs2_t *all_string_sub_wa(smb_ucs2_t *s, const char *pattern,
938                                              const char *insert)
939 {
940         wpstring p, i;
941
942         if (!insert || !pattern || !s)
943                 return NULL;
944         push_ucs2(NULL, p, pattern, sizeof(wpstring) - 1, STR_TERMINATE);
945         push_ucs2(NULL, i, insert, sizeof(wpstring) - 1, STR_TERMINATE);
946         return all_string_sub_w(s, p, i);
947 }
948
949 /****************************************************************************
950  Splits out the front and back at a separator.
951 ****************************************************************************/
952
953 void split_at_last_component(char *path, char *front, char sep, char *back)
954 {
955         char *p = strrchr_m(path, sep);
956
957         if (p != NULL)
958                 *p = 0;
959
960         if (front != NULL)
961                 pstrcpy(front, path);
962
963         if (p != NULL) {
964                 if (back != NULL)
965                         pstrcpy(back, p+1);
966                 *p = '\\';
967         } else {
968                 if (back != NULL)
969                         back[0] = 0;
970         }
971 }
972
973 /****************************************************************************
974  Write an octal as a string.
975 ****************************************************************************/
976
977 const char *octal_string(int i)
978 {
979         static char ret[64];
980         if (i == -1)
981                 return "-1";
982         slprintf(ret, sizeof(ret)-1, "0%o", i);
983         return ret;
984 }
985
986
987 /****************************************************************************
988  Truncate a string at a specified length.
989 ****************************************************************************/
990
991 char *string_truncate(char *s, int length)
992 {
993         if (s && strlen(s) > length)
994                 s[length] = 0;
995         return s;
996 }
997
998 /****************************************************************************
999  Strchr and strrchr_m are very hard to do on general multi-byte strings. 
1000  We convert via ucs2 for now.
1001 ****************************************************************************/
1002
1003 char *strchr_m(const char *s, char c)
1004 {
1005         wpstring ws;
1006         pstring s2;
1007         smb_ucs2_t *p;
1008
1009         push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
1010         p = strchr_w(ws, UCS2_CHAR(c));
1011         if (!p)
1012                 return NULL;
1013         *p = 0;
1014         pull_ucs2_pstring(s2, ws);
1015         return (char *)(s+strlen(s2));
1016 }
1017
1018 char *strrchr_m(const char *s, char c)
1019 {
1020         wpstring ws;
1021         pstring s2;
1022         smb_ucs2_t *p;
1023
1024         push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
1025         p = strrchr_w(ws, UCS2_CHAR(c));
1026         if (!p)
1027                 return NULL;
1028         *p = 0;
1029         pull_ucs2_pstring(s2, ws);
1030         return (char *)(s+strlen(s2));
1031 }
1032
1033 /*******************************************************************
1034  Convert a string to lower case.
1035 ********************************************************************/
1036
1037 void strlower_m(char *s)
1038 {
1039         /* this is quite a common operation, so we want it to be
1040            fast. We optimise for the ascii case, knowing that all our
1041            supported multi-byte character sets are ascii-compatible
1042            (ie. they match for the first 128 chars) */
1043
1044         while (*s && !(((unsigned char)s[0]) & 0x7F)) {
1045                 *s = tolower((unsigned char)*s);
1046                 s++;
1047         }
1048
1049         if (!*s)
1050                 return;
1051
1052         /* I assume that lowercased string takes the same number of bytes
1053          * as source string even in UTF-8 encoding. (VIV) */
1054         unix_strlower(s,strlen(s)+1,s,strlen(s)+1);     
1055 }
1056
1057 /*******************************************************************
1058  Duplicate convert a string to lower case.
1059 ********************************************************************/
1060
1061 char *strdup_lower(const char *s)
1062 {
1063         char *t = strdup(s);
1064         if (t == NULL) {
1065                 DEBUG(0, ("strdup_lower: Out of memory!\n"));
1066                 return NULL;
1067         }
1068         strlower_m(t);
1069         return t;
1070 }
1071
1072 /*******************************************************************
1073  Convert a string to upper case.
1074 ********************************************************************/
1075
1076 void strupper_m(char *s)
1077 {
1078         /* this is quite a common operation, so we want it to be
1079            fast. We optimise for the ascii case, knowing that all our
1080            supported multi-byte character sets are ascii-compatible
1081            (ie. they match for the first 128 chars) */
1082
1083         while (*s && !(((unsigned char)s[0]) & 0x7F)) {
1084                 *s = toupper((unsigned char)*s);
1085                 s++;
1086         }
1087
1088         if (!*s)
1089                 return;
1090
1091         /* I assume that lowercased string takes the same number of bytes
1092          * as source string even in multibyte encoding. (VIV) */
1093         unix_strupper(s,strlen(s)+1,s,strlen(s)+1);     
1094 }
1095
1096 /*******************************************************************
1097  Convert a string to upper case.
1098 ********************************************************************/
1099
1100 char *strdup_upper(const char *s)
1101 {
1102         char *t = strdup(s);
1103         if (t == NULL) {
1104                 DEBUG(0, ("strdup_upper: Out of memory!\n"));
1105                 return NULL;
1106         }
1107         strupper_m(t);
1108         return t;
1109 }
1110
1111 /*******************************************************************
1112  Return a RFC2254 binary string representation of a buffer.
1113  Used in LDAP filters.
1114  Caller must free.
1115 ********************************************************************/
1116
1117 char *binary_string(char *buf, int len)
1118 {
1119         char *s;
1120         int i, j;
1121         const char *hex = "0123456789ABCDEF";
1122         s = malloc(len * 3 + 1);
1123         if (!s)
1124                 return NULL;
1125         for (j=i=0;i<len;i++) {
1126                 s[j] = '\\';
1127                 s[j+1] = hex[((unsigned char)buf[i]) >> 4];
1128                 s[j+2] = hex[((unsigned char)buf[i]) & 0xF];
1129                 j += 3;
1130         }
1131         s[j] = 0;
1132         return s;
1133 }
1134
1135 /*******************************************************************
1136  Just a typesafety wrapper for snprintf into a pstring.
1137 ********************************************************************/
1138
1139  int pstr_sprintf(pstring s, const char *fmt, ...)
1140 {
1141         va_list ap;
1142         int ret;
1143
1144         va_start(ap, fmt);
1145         ret = vsnprintf(s, PSTRING_LEN, fmt, ap);
1146         va_end(ap);
1147         return ret;
1148 }
1149
1150 /*******************************************************************
1151  Just a typesafety wrapper for snprintf into a fstring.
1152 ********************************************************************/
1153
1154  int fstr_sprintf(fstring s, const char *fmt, ...)
1155 {
1156         va_list ap;
1157         int ret;
1158
1159         va_start(ap, fmt);
1160         ret = vsnprintf(s, FSTRING_LEN, fmt, ap);
1161         va_end(ap);
1162         return ret;
1163 }
1164
1165 #ifndef HAVE_STRNDUP
1166 /*******************************************************************
1167  Some platforms don't have strndup.
1168 ********************************************************************/
1169
1170  char *strndup(const char *s, size_t n)
1171 {
1172         char *ret;
1173         
1174         n = strnlen(s, n);
1175         ret = malloc(n+1);
1176         if (!ret)
1177                 return NULL;
1178         memcpy(ret, s, n);
1179         ret[n] = 0;
1180
1181         return ret;
1182 }
1183 #endif
1184
1185 #ifndef HAVE_STRNLEN
1186 /*******************************************************************
1187  Some platforms don't have strnlen
1188 ********************************************************************/
1189
1190  size_t strnlen(const char *s, size_t n)
1191 {
1192         int i;
1193         for (i=0; s[i] && i<n; i++)
1194                 /* noop */ ;
1195         return i;
1196 }
1197 #endif
1198
1199 /***********************************************************
1200  List of Strings manipulation functions
1201 ***********************************************************/
1202
1203 #define S_LIST_ABS 16 /* List Allocation Block Size */
1204
1205 char **str_list_make(const char *string, const char *sep)
1206 {
1207         char **list, **rlist;
1208         const char *str;
1209         char *s;
1210         int num, lsize;
1211         pstring tok;
1212         
1213         if (!string || !*string)
1214                 return NULL;
1215         s = strdup(string);
1216         if (!s) {
1217                 DEBUG(0,("str_list_make: Unable to allocate memory"));
1218                 return NULL;
1219         }
1220         if (!sep) sep = LIST_SEP;
1221         
1222         num = lsize = 0;
1223         list = NULL;
1224         
1225         str = s;
1226         while (next_token(&str, tok, sep, sizeof(tok))) {               
1227                 if (num == lsize) {
1228                         lsize += S_LIST_ABS;
1229                         rlist = (char **)Realloc(list, ((sizeof(char **)) * (lsize +1)));
1230                         if (!rlist) {
1231                                 DEBUG(0,("str_list_make: Unable to allocate memory"));
1232                                 str_list_free(&list);
1233                                 SAFE_FREE(s);
1234                                 return NULL;
1235                         } else
1236                                 list = rlist;
1237                         memset (&list[num], 0, ((sizeof(char**)) * (S_LIST_ABS +1)));
1238                 }
1239                 
1240                 list[num] = strdup(tok);
1241                 if (!list[num]) {
1242                         DEBUG(0,("str_list_make: Unable to allocate memory"));
1243                         str_list_free(&list);
1244                         SAFE_FREE(s);
1245                         return NULL;
1246                 }
1247         
1248                 num++;  
1249         }
1250         
1251         SAFE_FREE(s);
1252         return list;
1253 }
1254
1255 BOOL str_list_copy(char ***dest, const char **src)
1256 {
1257         char **list, **rlist;
1258         int num, lsize;
1259         
1260         *dest = NULL;
1261         if (!src)
1262                 return False;
1263         
1264         num = lsize = 0;
1265         list = NULL;
1266                 
1267         while (src[num]) {
1268                 if (num == lsize) {
1269                         lsize += S_LIST_ABS;
1270                         rlist = (char **)Realloc(list, ((sizeof(char **)) * (lsize +1)));
1271                         if (!rlist) {
1272                                 DEBUG(0,("str_list_copy: Unable to re-allocate memory"));
1273                                 str_list_free(&list);
1274                                 return False;
1275                         } else
1276                                 list = rlist;
1277                         memset (&list[num], 0, ((sizeof(char **)) * (S_LIST_ABS +1)));
1278                 }
1279                 
1280                 list[num] = strdup(src[num]);
1281                 if (!list[num]) {
1282                         DEBUG(0,("str_list_copy: Unable to allocate memory"));
1283                         str_list_free(&list);
1284                         return False;
1285                 }
1286
1287                 num++;
1288         }
1289         
1290         *dest = list;
1291         return True;    
1292 }
1293
1294 /***********************************************************
1295  Return true if all the elements of the list match exactly.
1296 ***********************************************************/
1297
1298 BOOL str_list_compare(char **list1, char **list2)
1299 {
1300         int num;
1301         
1302         if (!list1 || !list2)
1303                 return (list1 == list2); 
1304         
1305         for (num = 0; list1[num]; num++) {
1306                 if (!list2[num])
1307                         return False;
1308                 if (!strcsequal(list1[num], list2[num]))
1309                         return False;
1310         }
1311         if (list2[num])
1312                 return False; /* if list2 has more elements than list1 fail */
1313         
1314         return True;
1315 }
1316
1317 void str_list_free(char ***list)
1318 {
1319         char **tlist;
1320         
1321         if (!list || !*list)
1322                 return;
1323         tlist = *list;
1324         for(; *tlist; tlist++)
1325                 SAFE_FREE(*tlist);
1326         SAFE_FREE(*list);
1327 }
1328
1329 BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
1330 {
1331         char *p, *s, *t;
1332         ssize_t ls, lp, li, ld, i, d;
1333
1334         if (!list)
1335                 return False;
1336         if (!pattern)
1337                 return False;
1338         if (!insert)
1339                 return False;
1340
1341         lp = (ssize_t)strlen(pattern);
1342         li = (ssize_t)strlen(insert);
1343         ld = li -lp;
1344                         
1345         while (*list) {
1346                 s = *list;
1347                 ls = (ssize_t)strlen(s);
1348
1349                 while ((p = strstr(s, pattern))) {
1350                         t = *list;
1351                         d = p -t;
1352                         if (ld) {
1353                                 t = (char *) malloc(ls +ld +1);
1354                                 if (!t) {
1355                                         DEBUG(0,("str_list_substitute: Unable to allocate memory"));
1356                                         return False;
1357                                 }
1358                                 memcpy(t, *list, d);
1359                                 memcpy(t +d +li, p +lp, ls -d -lp +1);
1360                                 SAFE_FREE(*list);
1361                                 *list = t;
1362                                 ls += ld;
1363                                 s = t +d +li;
1364                         }
1365                         
1366                         for (i = 0; i < li; i++) {
1367                                 switch (insert[i]) {
1368                                         case '`':
1369                                         case '"':
1370                                         case '\'':
1371                                         case ';':
1372                                         case '$':
1373                                         case '%':
1374                                         case '\r':
1375                                         case '\n':
1376                                                 t[d +i] = '_';
1377                                                 break;
1378                                         default:
1379                                                 t[d +i] = insert[i];
1380                                 }
1381                         }       
1382                 }
1383                 
1384                 list++;
1385         }
1386         
1387         return True;
1388 }
1389
1390
1391 #define IPSTR_LIST_SEP  ","
1392
1393 /**
1394  * Add ip string representation to ipstr list. Used also
1395  * as part of @function ipstr_list_make
1396  *
1397  * @param ipstr_list pointer to string containing ip list;
1398  *        MUST BE already allocated and IS reallocated if necessary
1399  * @param ipstr_size pointer to current size of ipstr_list (might be changed
1400  *        as a result of reallocation)
1401  * @param ip IP address which is to be added to list
1402  * @return pointer to string appended with new ip and possibly
1403  *         reallocated to new length
1404  **/
1405
1406 char* ipstr_list_add(char** ipstr_list, const struct in_addr *ip)
1407 {
1408         char* new_ipstr = NULL;
1409         
1410         /* arguments checking */
1411         if (!ipstr_list || !ip) return NULL;
1412
1413         /* attempt to convert ip to a string and append colon separator to it */
1414         if (*ipstr_list) {
1415                 asprintf(&new_ipstr, "%s%s%s", *ipstr_list, IPSTR_LIST_SEP,inet_ntoa(*ip));
1416                 SAFE_FREE(*ipstr_list);
1417         } else {
1418                 asprintf(&new_ipstr, "%s", inet_ntoa(*ip));
1419         }
1420         *ipstr_list = new_ipstr;
1421         return *ipstr_list;
1422 }
1423
1424
1425 /**
1426  * Allocate and initialise an ipstr list using ip adresses
1427  * passed as arguments.
1428  *
1429  * @param ipstr_list pointer to string meant to be allocated and set
1430  * @param ip_list array of ip addresses to place in the list
1431  * @param ip_count number of addresses stored in ip_list
1432  * @return pointer to allocated ip string
1433  **/
1434  
1435 char* ipstr_list_make(char** ipstr_list, const struct in_addr* ip_list, int ip_count)
1436 {
1437         int i;
1438         
1439         /* arguments checking */
1440         if (!ip_list && !ipstr_list) return 0;
1441
1442         *ipstr_list = NULL;
1443         
1444         /* process ip addresses given as arguments */
1445         for (i = 0; i < ip_count; i++)
1446                 *ipstr_list = ipstr_list_add(ipstr_list, &ip_list[i]);
1447         
1448         return (*ipstr_list);
1449 }
1450
1451
1452 /**
1453  * Parse given ip string list into array of ip addresses
1454  * (as in_addr structures)
1455  *
1456  * @param ipstr ip string list to be parsed 
1457  * @param ip_list pointer to array of ip addresses which is
1458  *        allocated by this function and must be freed by caller
1459  * @return number of succesfully parsed addresses
1460  **/
1461  
1462 int ipstr_list_parse(const char* ipstr_list, struct in_addr** ip_list)
1463 {
1464         fstring token_str;
1465         int count;
1466
1467         if (!ipstr_list || !ip_list) return 0;
1468         
1469         for (*ip_list = NULL, count = 0;
1470              next_token(&ipstr_list, token_str, IPSTR_LIST_SEP, FSTRING_LEN);
1471              count++) {
1472              
1473                 struct in_addr addr;
1474
1475                 /* convert single token to ip address */
1476                 if ( (addr.s_addr = inet_addr(token_str)) == INADDR_NONE )
1477                         break;
1478                 
1479                 /* prepare place for another in_addr structure */
1480                 *ip_list = Realloc(*ip_list, (count + 1) * sizeof(struct in_addr));
1481                 if (!*ip_list) return -1;
1482                 
1483                 (*ip_list)[count] = addr;
1484         }
1485         
1486         return count;
1487 }
1488
1489
1490 /**
1491  * Safely free ip string list
1492  *
1493  * @param ipstr_list ip string list to be freed
1494  **/
1495
1496 void ipstr_list_free(char* ipstr_list)
1497 {
1498         SAFE_FREE(ipstr_list);
1499 }
1500
1501
1502 /***********************************************************
1503  Unescape a URL encoded string, in place.
1504 ***********************************************************/
1505
1506 void rfc1738_unescape(char *buf)
1507 {
1508         char *p=buf;
1509
1510         while ((p=strchr_m(p,'+')))
1511                 *p = ' ';
1512
1513         p = buf;
1514
1515         while (p && *p && (p=strchr_m(p,'%'))) {
1516                 int c1 = p[1];
1517                 int c2 = p[2];
1518
1519                 if (c1 >= '0' && c1 <= '9')
1520                         c1 = c1 - '0';
1521                 else if (c1 >= 'A' && c1 <= 'F')
1522                         c1 = 10 + c1 - 'A';
1523                 else if (c1 >= 'a' && c1 <= 'f')
1524                         c1 = 10 + c1 - 'a';
1525                 else {p++; continue;}
1526
1527                 if (c2 >= '0' && c2 <= '9')
1528                         c2 = c2 - '0';
1529                 else if (c2 >= 'A' && c2 <= 'F')
1530                         c2 = 10 + c2 - 'A';
1531                 else if (c2 >= 'a' && c2 <= 'f')
1532                         c2 = 10 + c2 - 'a';
1533                 else {p++; continue;}
1534                         
1535                 *p = (c1<<4) | c2;
1536
1537                 memmove(p+1, p+3, strlen(p+3)+1);
1538                 p++;
1539         }
1540 }
1541
1542 static const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1543
1544 /***************************************************************************
1545 decode a base64 string into a DATA_BLOB - simple and slow algorithm
1546   ***************************************************************************/
1547 DATA_BLOB base64_decode_data_blob(const char *s)
1548 {
1549         int bit_offset, byte_offset, idx, i, n;
1550         DATA_BLOB decoded = data_blob(s, strlen(s)+1);
1551         unsigned char *d = decoded.data;
1552         char *p;
1553
1554         n=i=0;
1555
1556         while (*s && (p=strchr_m(b64,*s))) {
1557                 idx = (int)(p - b64);
1558                 byte_offset = (i*6)/8;
1559                 bit_offset = (i*6)%8;
1560                 d[byte_offset] &= ~((1<<(8-bit_offset))-1);
1561                 if (bit_offset < 3) {
1562                         d[byte_offset] |= (idx << (2-bit_offset));
1563                         n = byte_offset+1;
1564                 } else {
1565                         d[byte_offset] |= (idx >> (bit_offset-2));
1566                         d[byte_offset+1] = 0;
1567                         d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
1568                         n = byte_offset+2;
1569                 }
1570                 s++; i++;
1571         }
1572
1573         /* fix up length */
1574         decoded.length = n;
1575         return decoded;
1576 }
1577
1578 /***************************************************************************
1579 decode a base64 string in-place - wrapper for the above
1580 ***************************************************************************/
1581 void base64_decode(char *s)
1582 {
1583         DATA_BLOB decoded = base64_decode_data_blob(s);
1584         memcpy(s, decoded.data, decoded.length);
1585         data_blob_free(&decoded);
1586
1587         /* null terminate */
1588         s[decoded.length] = '\0';
1589 }
1590
1591 /***************************************************************************
1592 encode a base64 string into a malloc()ed string caller to free.
1593
1594 From SQUID: adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments
1595 ***************************************************************************/
1596 char * base64_encode_data_blob(DATA_BLOB data)
1597 {
1598         int bits = 0;
1599         int char_count = 0;
1600         int out_cnt = 0;
1601         size_t len = data.length;
1602         size_t output_len = data.length * 2;
1603         char *result = malloc(output_len); /* get us plenty of space */
1604
1605         while (len-- && out_cnt < (data.length * 2) - 5) {
1606                 int c = (unsigned char) *(data.data++);
1607                 bits += c;
1608                 char_count++;
1609                 if (char_count == 3) {
1610                         result[out_cnt++] = b64[bits >> 18];
1611                         result[out_cnt++] = b64[(bits >> 12) & 0x3f];
1612                         result[out_cnt++] = b64[(bits >> 6) & 0x3f];
1613             result[out_cnt++] = b64[bits & 0x3f];
1614             bits = 0;
1615             char_count = 0;
1616         } else {
1617             bits <<= 8;
1618         }
1619     }
1620     if (char_count != 0) {
1621         bits <<= 16 - (8 * char_count);
1622         result[out_cnt++] = b64[bits >> 18];
1623         result[out_cnt++] = b64[(bits >> 12) & 0x3f];
1624         if (char_count == 1) {
1625             result[out_cnt++] = '=';
1626             result[out_cnt++] = '=';
1627         } else {
1628             result[out_cnt++] = b64[(bits >> 6) & 0x3f];
1629             result[out_cnt++] = '=';
1630         }
1631     }
1632     result[out_cnt] = '\0';     /* terminate */
1633     return result;
1634 }
1635
1636 #ifdef VALGRIND
1637 size_t valgrind_strlen(const char *s)
1638 {
1639         size_t count;
1640         for(count = 0; *s++; count++)
1641                 ;
1642         return count;
1643 }
1644 #endif