1998-11-05 19:48:35 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-11-05 19:48:35 +03:00
Samba utility functions
2003-03-19 00:21:21 +03:00
2001-07-04 11:15:53 +04:00
Copyright ( C ) Andrew Tridgell 1992 - 2001
2002-01-25 03:35:14 +03:00
Copyright ( C ) Simo Sorce 2001 - 2002
2003-03-19 00:21:21 +03:00
Copyright ( C ) Martin Pool 2003
1998-11-05 19:48:35 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2003-03-19 00:21:21 +03:00
/**
* @ file
* @ brief String utilities .
* */
2003-03-18 04:48:11 +03:00
2003-02-24 06:09:08 +03:00
/**
* Get the next token from a string , return False if none found .
* Handles double - quotes .
*
* Based on a routine by GJC @ VILLAGE . COM .
* Extensively modified by Andrew . Tridgell @ anu . edu . au
* */
2002-11-13 02:20:50 +03:00
BOOL next_token ( const char * * ptr , char * buff , const char * sep , size_t bufsize )
1998-11-05 19:48:35 +03:00
{
2002-11-13 02:20:50 +03:00
const char * s ;
2001-06-21 13:10:42 +04:00
BOOL quoted ;
size_t len = 1 ;
2002-10-02 23:12:14 +04:00
if ( ! ptr )
return ( False ) ;
2001-06-21 13:10:42 +04:00
s = * ptr ;
/* default to simple separators */
2002-10-02 23:12:14 +04:00
if ( ! sep )
sep = " \t \n \r " ;
2001-06-21 13:10:42 +04:00
/* find the first non sep char */
2002-10-02 23:12:14 +04:00
while ( * s & & strchr_m ( sep , * s ) )
s + + ;
2001-06-21 13:10:42 +04:00
/* nothing left? */
2002-10-02 23:12:14 +04:00
if ( ! * s )
return ( False ) ;
2001-06-21 13:10:42 +04:00
/* copy over the token */
2001-07-04 11:36:09 +04:00
for ( quoted = False ; len < bufsize & & * s & & ( quoted | | ! strchr_m ( sep , * s ) ) ; s + + ) {
2001-06-21 13:10:42 +04:00
if ( * s = = ' \" ' ) {
quoted = ! quoted ;
} else {
len + + ;
* buff + + = * s ;
}
}
* ptr = ( * s ) ? s + 1 : s ;
* buff = 0 ;
return ( True ) ;
}
1998-11-05 19:48:35 +03:00
2003-02-24 06:09:08 +03:00
/**
2001-06-21 13:10:42 +04:00
This is like next_token but is not re - entrant and " remembers " the first
parameter so you can pass NULL . This is useful for user interface code
but beware the fact that it is not re - entrant !
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2003-03-18 04:48:11 +03:00
static const char * last_ptr = NULL ;
1998-11-05 19:48:35 +03:00
2002-11-13 02:20:50 +03:00
BOOL next_token_nr ( const char * * ptr , char * buff , const char * sep , size_t bufsize )
2001-06-21 13:10:42 +04:00
{
BOOL ret ;
2002-10-02 23:12:14 +04:00
if ( ! ptr )
2002-11-13 02:20:50 +03:00
ptr = ( const char * * ) & last_ptr ;
1998-11-05 19:48:35 +03:00
2001-06-21 13:10:42 +04:00
ret = next_token ( ptr , buff , sep , bufsize ) ;
last_ptr = * ptr ;
return ret ;
}
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
static uint16 tmpbuf [ sizeof ( pstring ) ] ;
2001-06-21 13:10:42 +04:00
void set_first_token ( char * ptr )
{
last_ptr = ptr ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Convert list of tokens to array ; dependent on above routine .
Uses last_ptr from above - bit of a hack .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
char * * toktocliplist ( int * ctok , const char * sep )
1998-11-05 19:48:35 +03:00
{
2001-06-21 13:10:42 +04:00
char * s = last_ptr ;
int ictok = 0 ;
char * * ret , * * iret ;
2002-10-02 23:12:14 +04:00
if ( ! sep )
sep = " \t \n \r " ;
2001-06-21 13:10:42 +04:00
2002-10-02 23:12:14 +04:00
while ( * s & & strchr_m ( sep , * s ) )
s + + ;
2001-06-21 13:10:42 +04:00
/* nothing left? */
2002-10-02 23:12:14 +04:00
if ( ! * s )
return ( NULL ) ;
2001-06-21 13:10:42 +04:00
do {
ictok + + ;
2002-10-02 23:12:14 +04:00
while ( * s & & ( ! strchr_m ( sep , * s ) ) )
s + + ;
while ( * s & & strchr_m ( sep , * s ) )
* s + + = 0 ;
2001-06-21 13:10:42 +04:00
} while ( * s ) ;
* ctok = ictok ;
s = last_ptr ;
2002-10-02 23:12:14 +04:00
if ( ! ( ret = iret = malloc ( ictok * sizeof ( char * ) ) ) )
return NULL ;
2001-06-21 13:10:42 +04:00
while ( ictok - - ) {
* iret + + = s ;
2002-10-02 23:12:14 +04:00
while ( * s + + )
;
while ( ! * s )
s + + ;
2001-06-21 13:10:42 +04:00
}
return ret ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2003-03-19 00:21:21 +03:00
* Case insensitive string compararison .
*
* iconv does not directly give us a way to compare strings in
* arbitrary unix character sets - - all we can is convert and then
* compare . This is expensive .
*
* As an optimization , we do a first pass that considers only the
* prefix of the strings that is entirely 7 - bit . Within this , we
* check whether they have the same value .
*
* Hopefully this will often give the answer without needing to copy .
* In particular it should speed comparisons to literal ascii strings
* or comparisons of strings that are " obviously " different .
*
* If we find a non - ascii character we fall back to converting via
* iconv .
*
* This should never be slower than convering the whole thing , and
* often faster .
*
* A different optimization would be to compare for bitwise equality
* in the binary encoding . ( It would be possible thought hairy to do
* both simultaneously . ) But in that case if they turn out to be
* different , we ' d need to restart the whole thing .
*
* Even better is to implement strcasecmp for each encoding and use a
* function pointer .
* */
1998-11-12 09:12:19 +03:00
int StrCaseCmp ( const char * s , const char * t )
1998-11-05 19:48:35 +03:00
{
2003-03-19 00:21:21 +03:00
const char * ps , * pt ;
2001-07-06 15:50:45 +04:00
pstring buf1 , buf2 ;
2003-03-19 00:21:21 +03:00
for ( ps = s , pt = t ; ; ps + + , pt + + ) {
char us , ut ;
if ( ! * ps & & ! * pt )
return 0 ; /* both ended */
else if ( ! * ps )
return - 1 ; /* s is a prefix */
else if ( ! * pt )
return + 1 ; /* t is a prefix */
else if ( ( * ps & 0x80 ) | | ( * pt & 0x80 ) )
/* not ascii anymore, do it the hard way from here on in */
break ;
us = toupper ( * ps ) ;
ut = toupper ( * pt ) ;
if ( us = = ut )
continue ;
else if ( us < ut )
return - 1 ;
else if ( us > ut )
return + 1 ;
}
/* TODO: Don't do this with a fixed-length buffer. This could
* still be much more efficient . */
/* TODO: Hardcode a char-by-char comparison for UTF-8, which
* can be much faster . */
/* TODO: Test case for this! */
unix_strupper ( ps , strlen ( ps ) + 1 , buf1 , sizeof ( buf1 ) ) ;
unix_strupper ( pt , strlen ( pt ) + 1 , buf2 , sizeof ( buf2 ) ) ;
return strcmp ( buf1 , buf2 ) ;
1998-11-05 19:48:35 +03:00
}
2003-03-19 00:21:21 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Case insensitive string compararison , length limited .
2003-02-24 06:09:08 +03:00
* */
1998-11-17 23:50:07 +03:00
int StrnCaseCmp ( const char * s , const char * t , size_t n )
1998-11-05 19:48:35 +03:00
{
2001-10-03 16:18:20 +04:00
pstring buf1 , buf2 ;
unix_strupper ( s , strlen ( s ) + 1 , buf1 , sizeof ( buf1 ) ) ;
unix_strupper ( t , strlen ( t ) + 1 , buf2 , sizeof ( buf2 ) ) ;
return strncmp ( buf1 , buf2 , n ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2003-03-18 01:42:01 +03:00
* Compare 2 strings .
*
* @ note The comparison is case - insensitive .
* */
1998-11-12 09:12:19 +03:00
BOOL strequal ( const char * s1 , const char * s2 )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
if ( s1 = = s2 )
return ( True ) ;
if ( ! s1 | | ! s2 )
return ( False ) ;
1998-11-05 19:48:35 +03:00
2001-07-06 15:50:45 +04:00
return ( StrCaseCmp ( s1 , s2 ) = = 0 ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2003-03-18 01:42:01 +03:00
* Compare 2 strings up to and including the nth char .
*
* @ note The comparison is case - insensitive .
* */
1998-11-17 23:50:07 +03:00
BOOL strnequal ( const char * s1 , const char * s2 , size_t n )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
if ( s1 = = s2 )
return ( True ) ;
if ( ! s1 | | ! s2 | | ! n )
return ( False ) ;
1998-11-05 19:48:35 +03:00
return ( StrnCaseCmp ( s1 , s2 , n ) = = 0 ) ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Compare 2 strings ( case sensitive ) .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
BOOL strcsequal ( const char * s1 , const char * s2 )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
if ( s1 = = s2 )
return ( True ) ;
if ( ! s1 | | ! s2 )
return ( False ) ;
1998-11-05 19:48:35 +03:00
return ( strcmp ( s1 , s2 ) = = 0 ) ;
}
2003-02-24 06:09:08 +03:00
/**
2000-08-29 18:33:39 +04:00
Do a case - insensitive , whitespace - ignoring string compare .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2001-10-31 09:22:19 +03:00
int strwicmp ( const char * psz1 , const char * psz2 )
2000-08-29 18:33:39 +04:00
{
/* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
/* appropriate value. */
if ( psz1 = = psz2 )
return ( 0 ) ;
else if ( psz1 = = NULL )
return ( - 1 ) ;
else if ( psz2 = = NULL )
return ( 1 ) ;
/* sync the strings on first non-whitespace */
2002-10-02 23:12:14 +04:00
while ( 1 ) {
2001-12-20 13:02:30 +03:00
while ( isspace ( ( int ) * psz1 ) )
2000-08-29 18:33:39 +04:00
psz1 + + ;
2001-12-20 13:02:30 +03:00
while ( isspace ( ( int ) * psz2 ) )
2000-08-29 18:33:39 +04:00
psz2 + + ;
if ( toupper ( * psz1 ) ! = toupper ( * psz2 ) | | * psz1 = = ' \0 '
| | * psz2 = = ' \0 ' )
break ;
psz1 + + ;
psz2 + + ;
}
return ( * psz1 - * psz2 ) ;
}
1998-11-05 19:48:35 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Convert a string to upper case , but don ' t modify it .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
char * strupper_static ( const char * s )
{
static pstring str ;
pstrcpy ( str , s ) ;
strupper ( str ) ;
return str ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Convert a string to " normal " form .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-05 19:48:35 +03:00
void strnorm ( char * s )
{
2002-10-02 23:12:14 +04:00
extern int case_default ;
if ( case_default = = CASE_UPPER )
strupper ( s ) ;
else
strlower ( s ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Check if a string is in " normal " case .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
BOOL strisnormal ( const char * s )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
extern int case_default ;
if ( case_default = = CASE_UPPER )
return ( ! strhaslower ( s ) ) ;
return ( ! strhasupper ( s ) ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
String replace .
NOTE : oldc and newc must be 7 bit characters
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-05 19:48:35 +03:00
void string_replace ( char * s , char oldc , char newc )
{
2001-07-04 11:15:53 +04:00
push_ucs2 ( NULL , tmpbuf , s , sizeof ( tmpbuf ) , STR_TERMINATE ) ;
2001-11-04 21:26:53 +03:00
string_replace_w ( tmpbuf , UCS2_CHAR ( oldc ) , UCS2_CHAR ( newc ) ) ;
2001-07-04 11:15:53 +04:00
pull_ucs2 ( NULL , s , tmpbuf , - 1 , sizeof ( tmpbuf ) , STR_TERMINATE ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Skip past some strings in a buffer .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-26 00:17:20 +03:00
char * skip_string ( char * buf , size_t n )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
while ( n - - )
buf + = strlen ( buf ) + 1 ;
return ( buf ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
1998-11-05 19:48:35 +03:00
Count the number of characters in a string . Normally this will
be the same as the number of bytes in a string for single byte strings ,
but will be different for multibyte .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
size_t str_charnum ( const char * s )
1998-11-05 19:48:35 +03:00
{
2003-01-15 21:57:41 +03:00
uint16 tmpbuf2 [ sizeof ( pstring ) ] ;
push_ucs2 ( NULL , tmpbuf2 , s , sizeof ( tmpbuf2 ) , STR_TERMINATE ) ;
return strlen_w ( tmpbuf2 ) ;
}
2003-02-24 06:09:08 +03:00
/**
2003-01-15 21:57:41 +03:00
Count the number of characters in a string . Normally this will
be the same as the number of bytes in a string for single byte strings ,
but will be different for multibyte .
2003-02-24 06:09:08 +03:00
* */
2003-01-15 21:57:41 +03:00
size_t str_ascii_charnum ( const char * s )
{
pstring tmpbuf2 ;
push_ascii ( tmpbuf2 , s , sizeof ( tmpbuf2 ) , STR_TERMINATE ) ;
return strlen ( tmpbuf2 ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Trim the specified elements off the front and back of a string .
2003-02-24 06:09:08 +03:00
* */
1998-11-05 19:48:35 +03:00
1998-11-17 23:50:07 +03:00
BOOL trim_string ( char * s , const char * front , const char * back )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
BOOL ret = False ;
size_t front_len ;
size_t back_len ;
size_t len ;
2001-04-16 02:21:04 +04:00
2001-05-11 03:17:46 +04:00
/* Ignore null or empty strings. */
2001-07-04 11:15:53 +04:00
if ( ! s | | ( s [ 0 ] = = ' \0 ' ) )
return False ;
2001-05-11 03:17:46 +04:00
2001-07-04 11:15:53 +04:00
front_len = front ? strlen ( front ) : 0 ;
back_len = back ? strlen ( back ) : 0 ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
len = strlen ( s ) ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
if ( front_len ) {
while ( len & & strncmp ( s , front , front_len ) = = 0 ) {
memcpy ( s , s + front_len , ( len - front_len ) + 1 ) ;
len - = front_len ;
ret = True ;
}
}
if ( back_len ) {
2002-08-17 21:00:51 +04:00
while ( ( len > = back_len ) & & strncmp ( s + len - back_len , back , back_len ) = = 0 ) {
2001-07-04 11:15:53 +04:00
s [ len - back_len ] = ' \0 ' ;
len - = back_len ;
ret = True ;
}
}
return ret ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Does a string have any uppercase chars in it ?
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
BOOL strhasupper ( const char * s )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
smb_ucs2_t * ptr ;
push_ucs2 ( NULL , tmpbuf , s , sizeof ( tmpbuf ) , STR_TERMINATE ) ;
for ( ptr = tmpbuf ; * ptr ; ptr + + )
2002-10-02 23:12:14 +04:00
if ( isupper_w ( * ptr ) )
return True ;
2001-07-04 11:15:53 +04:00
return ( False ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Does a string have any lowercase chars in it ?
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
BOOL strhaslower ( const char * s )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
smb_ucs2_t * ptr ;
push_ucs2 ( NULL , tmpbuf , s , sizeof ( tmpbuf ) , STR_TERMINATE ) ;
for ( ptr = tmpbuf ; * ptr ; ptr + + )
2002-10-02 23:12:14 +04:00
if ( islower_w ( * ptr ) )
return True ;
2001-07-04 11:15:53 +04:00
return ( False ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Find the number of ' c ' chars in a string
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
size_t count_chars ( const char * s , char c )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
smb_ucs2_t * ptr ;
int count ;
push_ucs2 ( NULL , tmpbuf , s , sizeof ( tmpbuf ) , STR_TERMINATE ) ;
2002-10-02 23:12:14 +04:00
for ( count = 0 , ptr = tmpbuf ; * ptr ; ptr + + )
if ( * ptr = = UCS2_CHAR ( c ) )
count + + ;
2001-07-04 11:15:53 +04:00
return ( count ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Safe string copy into a known length string . maxlength does not
include the terminating zero .
2003-02-24 06:09:08 +03:00
* */
1999-12-13 16:27:58 +03:00
2003-03-18 04:48:11 +03:00
char * safe_strcpy_fn ( const char * fn , int line , char * dest , const char * src , size_t maxlength )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
size_t len ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
if ( ! dest ) {
DEBUG ( 0 , ( " ERROR: NULL dest in safe_strcpy \n " ) ) ;
return NULL ;
}
1998-11-05 19:48:35 +03:00
2003-03-18 04:48:11 +03:00
clobber_region ( fn , line , dest , maxlength + 1 ) ;
2003-02-24 06:09:08 +03:00
2001-07-04 11:15:53 +04:00
if ( ! src ) {
* dest = 0 ;
return dest ;
}
1998-11-05 19:48:35 +03:00
2003-03-19 23:50:56 +03:00
len = strnlen ( src , maxlength + 1 ) ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
if ( len > maxlength ) {
2003-02-24 06:09:08 +03:00
DEBUG ( 0 , ( " ERROR: string overflow by %u (%u - %u) in safe_strcpy [%.50s] \n " ,
( unsigned int ) ( len - maxlength ) , len , maxlength , src ) ) ;
2001-07-04 11:15:53 +04:00
len = maxlength ;
}
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
memmove ( dest , src , len ) ;
dest [ len ] = 0 ;
return dest ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Safe string cat into a string . maxlength does not
include the terminating zero .
2003-02-24 06:09:08 +03:00
* */
2003-03-18 04:48:11 +03:00
char * safe_strcat_fn ( const char * fn , int line , char * dest , const char * src , size_t maxlength )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
size_t src_len , dest_len ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
if ( ! dest ) {
DEBUG ( 0 , ( " ERROR: NULL dest in safe_strcat \n " ) ) ;
return NULL ;
}
1998-11-05 19:48:35 +03:00
2002-10-02 23:12:14 +04:00
if ( ! src )
2001-07-04 11:15:53 +04:00
return dest ;
2003-03-19 23:50:56 +03:00
src_len = strnlen ( src , maxlength + 1 ) ;
dest_len = strnlen ( dest , maxlength + 1 ) ;
2003-02-07 07:11:36 +03:00
2003-03-18 04:48:11 +03:00
clobber_region ( fn , line , dest + dest_len , maxlength + 1 - dest_len ) ;
2001-07-04 11:15:53 +04:00
if ( src_len + dest_len > maxlength ) {
DEBUG ( 0 , ( " ERROR: string overflow by %d in safe_strcat [%.50s] \n " ,
( int ) ( src_len + dest_len - maxlength ) , src ) ) ;
2003-02-07 07:11:36 +03:00
if ( maxlength > dest_len ) {
memcpy ( & dest [ dest_len ] , src , maxlength - dest_len ) ;
}
dest [ maxlength ] = 0 ;
return NULL ;
2001-07-04 11:15:53 +04:00
}
2003-03-18 04:48:11 +03:00
2001-07-04 11:15:53 +04:00
memcpy ( & dest [ dest_len ] , src , src_len ) ;
dest [ dest_len + src_len ] = 0 ;
return dest ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
1999-12-13 16:27:58 +03:00
Paranoid strcpy into a buffer of given length ( includes terminating
2001-06-23 11:22:16 +04:00
zero . Strips out all but ' a - Z0 - 9 ' and the character in other_safe_chars
and replaces with ' _ ' . Deliberately does * NOT * check for multibyte
characters . Don ' t change it !
2003-02-24 06:09:08 +03:00
* */
2003-03-18 04:48:11 +03:00
char * alpha_strcpy_fn ( const char * fn , int line , char * dest , const char * src , const char * other_safe_chars , size_t maxlength )
1998-11-05 19:48:35 +03:00
{
1999-12-13 16:27:58 +03:00
size_t len , i ;
1998-11-05 19:48:35 +03:00
2003-03-18 04:48:11 +03:00
clobber_region ( fn , line , dest , maxlength ) ;
1999-12-13 16:27:58 +03:00
if ( ! dest ) {
DEBUG ( 0 , ( " ERROR: NULL dest in alpha_strcpy \n " ) ) ;
return NULL ;
}
1998-11-05 19:48:35 +03:00
1999-12-13 16:27:58 +03:00
if ( ! src ) {
* dest = 0 ;
return dest ;
}
len = strlen ( src ) ;
if ( len > = maxlength )
len = maxlength - 1 ;
2001-06-23 11:22:16 +04:00
if ( ! other_safe_chars )
other_safe_chars = " " ;
1999-12-13 16:27:58 +03:00
for ( i = 0 ; i < len ; i + + ) {
int val = ( src [ i ] & 0xff ) ;
2002-10-01 22:26:00 +04:00
if ( isupper ( val ) | | islower ( val ) | | isdigit ( val ) | | strchr_m ( other_safe_chars , val ) )
1999-12-13 16:27:58 +03:00
dest [ i ] = src [ i ] ;
else
dest [ i ] = ' _ ' ;
}
dest [ i ] = ' \0 ' ;
return dest ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
1999-12-13 16:27:58 +03:00
Like strncpy but always null terminates . Make sure there is room !
The variable n should always be one less than the available size .
2003-02-24 06:09:08 +03:00
* */
2003-03-18 04:48:11 +03:00
char * StrnCpy_fn ( const char * fn , int line , char * dest , const char * src , size_t n )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
char * d = dest ;
2003-03-18 04:48:11 +03:00
clobber_region ( fn , line , dest , n + 1 ) ;
2002-10-02 23:12:14 +04:00
if ( ! dest )
return ( NULL ) ;
2003-03-18 04:48:11 +03:00
2001-07-04 11:15:53 +04:00
if ( ! src ) {
* dest = 0 ;
return ( dest ) ;
}
2003-03-24 12:54:13 +03:00
while ( n - - & & ( * d = * src ) ) {
d + + ;
src + + ;
}
2001-07-04 11:15:53 +04:00
* d = 0 ;
return ( dest ) ;
1998-11-05 19:48:35 +03:00
}
2003-03-18 04:48:11 +03:00
#if 0
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Like strncpy but copies up to the character marker . always null terminates .
returns a pointer to the character marker in the source string ( src ) .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2003-03-18 04:48:11 +03:00
static char * strncpyn ( char * dest , const char * src , size_t n , char c )
1998-11-05 19:48:35 +03:00
{
char * p ;
1998-11-17 23:50:07 +03:00
size_t str_len ;
1998-11-05 19:48:35 +03:00
2003-03-18 04:48:11 +03:00
clobber_region ( dest , n + 1 ) ;
2001-07-04 11:36:09 +04:00
p = strchr_m ( src , c ) ;
2002-10-02 23:12:14 +04:00
if ( p = = NULL ) {
1998-11-05 19:48:35 +03:00
DEBUG ( 5 , ( " strncpyn: separator character (%c) not found \n " , c ) ) ;
return NULL ;
}
str_len = PTR_DIFF ( p , src ) ;
strncpy ( dest , src , MIN ( n , str_len ) ) ;
dest [ str_len ] = ' \0 ' ;
return p ;
}
2003-03-18 04:48:11 +03:00
# endif
1998-11-05 19:48:35 +03:00
2003-02-24 06:09:08 +03:00
/**
1998-11-10 22:05:00 +03:00
Routine to get hex characters and turn them into a 16 byte array .
the array can be variable length , and any non - hex - numeric
characters are skipped . " 0xnn " or " 0Xnn " is specially catered
for .
valid examples : " 0A5D15 " ; " 0x15, 0x49, 0xa2 " ; " 59 \t a9 \t e3 \n "
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
size_t strhex_to_str ( char * p , size_t len , const char * strhex )
1998-11-10 22:05:00 +03:00
{
1998-11-17 23:50:07 +03:00
size_t i ;
size_t num_chars = 0 ;
1998-11-10 22:05:00 +03:00
unsigned char lonybble , hinybble ;
2003-01-03 11:28:12 +03:00
const char * hexchars = " 0123456789ABCDEF " ;
1998-11-10 22:05:00 +03:00
char * p1 = NULL , * p2 = NULL ;
2002-10-02 23:12:14 +04:00
for ( i = 0 ; i < len & & strhex [ i ] ! = 0 ; i + + ) {
if ( strnequal ( hexchars , " 0x " , 2 ) ) {
1998-11-10 22:05:00 +03:00
i + + ; /* skip two chars */
continue ;
}
2001-07-04 11:36:09 +04:00
if ( ! ( p1 = strchr_m ( hexchars , toupper ( strhex [ i ] ) ) ) )
1999-03-23 17:56:25 +03:00
break ;
1998-11-10 22:05:00 +03:00
i + + ; /* next hex digit */
2001-07-04 11:36:09 +04:00
if ( ! ( p2 = strchr_m ( hexchars , toupper ( strhex [ i ] ) ) ) )
1999-03-23 17:56:25 +03:00
break ;
1998-11-10 22:05:00 +03:00
/* get the two nybbles */
hinybble = PTR_DIFF ( p1 , hexchars ) ;
lonybble = PTR_DIFF ( p2 , hexchars ) ;
p [ num_chars ] = ( hinybble < < 4 ) | lonybble ;
num_chars + + ;
p1 = NULL ;
p2 = NULL ;
}
return num_chars ;
}
2003-03-24 12:54:13 +03:00
/**
* Routine to print a buffer as HEX digits , into an allocated string .
*/
void hex_encode ( const unsigned char * buff_in , size_t len , char * * out_hex_buffer )
{
int i ;
char * hex_buffer ;
* out_hex_buffer = smb_xmalloc ( ( len * 2 ) + 1 ) ;
hex_buffer = * out_hex_buffer ;
for ( i = 0 ; i < len ; i + + )
slprintf ( & hex_buffer [ i * 2 ] , 3 , " %02X " , buff_in [ i ] ) ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Check if a string is part of a list .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-05 19:48:35 +03:00
BOOL in_list ( char * s , char * list , BOOL casesensitive )
{
2002-10-02 23:12:14 +04:00
pstring tok ;
2002-11-13 02:20:50 +03:00
const char * p = list ;
2002-10-02 23:12:14 +04:00
if ( ! list )
return ( False ) ;
while ( next_token ( & p , tok , LIST_SEP , sizeof ( tok ) ) ) {
if ( casesensitive ) {
if ( strcmp ( tok , s ) = = 0 )
return ( True ) ;
} else {
if ( StrCaseCmp ( tok , s ) = = 0 )
return ( True ) ;
}
}
return ( False ) ;
1998-11-05 19:48:35 +03:00
}
/* this is used to prevent lots of mallocs of size 1 */
static char * null_string = NULL ;
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Set a string value , allocing the space for the string
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2000-01-16 14:07:11 +03:00
static BOOL string_init ( char * * dest , const char * src )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
size_t l ;
if ( ! src )
src = " " ;
l = strlen ( src ) ;
if ( l = = 0 ) {
if ( ! null_string ) {
if ( ( null_string = ( char * ) malloc ( 1 ) ) = = NULL ) {
DEBUG ( 0 , ( " string_init: malloc fail for null_string. \n " ) ) ;
return False ;
}
* null_string = 0 ;
}
* dest = null_string ;
} else {
2003-01-15 21:57:41 +03:00
( * dest ) = strdup ( src ) ;
2002-10-02 23:12:14 +04:00
if ( ( * dest ) = = NULL ) {
DEBUG ( 0 , ( " Out of memory in string_init \n " ) ) ;
return False ;
}
}
return ( True ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Free a string value .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-05 19:48:35 +03:00
void string_free ( char * * s )
{
2002-10-02 23:12:14 +04:00
if ( ! s | | ! ( * s ) )
return ;
if ( * s = = null_string )
* s = NULL ;
SAFE_FREE ( * s ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Set a string value , deallocating any existing space , and allocing the space
for the string
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
BOOL string_set ( char * * dest , const char * src )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
string_free ( dest ) ;
return ( string_init ( dest , src ) ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Substitute a string for a pattern in another string . Make sure there is
enough room !
1998-11-05 19:48:35 +03:00
2002-10-02 23:12:14 +04:00
This routine looks for pattern in s and replaces it with
insert . It may do multiple replacements .
1998-11-05 19:48:35 +03:00
2002-10-02 23:12:14 +04:00
Any of " ; ' $ or ` in the insert string are replaced with _
if len = = 0 then the string cannot be extended . This is different from the old
use of len = = 0 which was for no length checks to be done .
2003-02-24 06:09:08 +03:00
* */
2002-07-15 14:35:28 +04:00
void string_sub ( char * s , const char * pattern , const char * insert , size_t len )
1998-11-05 19:48:35 +03:00
{
1998-11-23 06:36:10 +03:00
char * p ;
1999-12-13 16:27:58 +03:00
ssize_t ls , lp , li , i ;
1998-11-23 06:36:10 +03:00
2002-07-15 14:35:28 +04:00
if ( ! insert | | ! pattern | | ! * pattern | | ! s )
return ;
1998-11-23 06:36:10 +03:00
1999-12-13 16:27:58 +03:00
ls = ( ssize_t ) strlen ( s ) ;
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
1998-11-23 06:36:10 +03:00
2002-07-15 14:35:28 +04:00
if ( len = = 0 )
2002-08-17 21:00:51 +04:00
len = ls + 1 ; /* len is number of *bytes* */
2002-07-15 14:35:28 +04:00
1998-11-23 06:36:10 +03:00
while ( lp < = ls & & ( p = strstr ( s , pattern ) ) ) {
2002-07-15 14:35:28 +04:00
if ( ls + ( li - lp ) > = len ) {
1999-12-13 16:27:58 +03:00
DEBUG ( 0 , ( " ERROR: string overflow by %d in string_sub(%.50s, %d) \n " ,
( int ) ( ls + ( li - lp ) - len ) ,
pattern , ( int ) len ) ) ;
break ;
}
if ( li ! = lp ) {
memmove ( p + li , p + lp , strlen ( p + lp ) + 1 ) ;
}
1998-11-23 06:36:10 +03:00
for ( i = 0 ; i < li ; i + + ) {
switch ( insert [ i ] ) {
case ' ` ' :
case ' " ' :
1998-11-23 06:46:51 +03:00
case ' \' ' :
1998-11-23 06:36:10 +03:00
case ' ; ' :
1999-12-13 16:27:58 +03:00
case ' $ ' :
case ' % ' :
case ' \r ' :
case ' \n ' :
1998-11-23 06:36:10 +03:00
p [ i ] = ' _ ' ;
break ;
default :
p [ i ] = insert [ i ] ;
}
}
s = p + li ;
ls + = ( li - lp ) ;
}
}
1998-11-05 19:48:35 +03:00
1999-12-13 16:27:58 +03:00
void fstring_sub ( char * s , const char * pattern , const char * insert )
{
string_sub ( s , pattern , insert , sizeof ( fstring ) ) ;
}
void pstring_sub ( char * s , const char * pattern , const char * insert )
{
string_sub ( s , pattern , insert , sizeof ( pstring ) ) ;
}
1998-11-05 19:48:35 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Similar to string_sub , but it will accept only allocated strings
and may realloc them so pay attention at what you pass on no
pointers inside strings , no pstrings or const may be passed
as string .
2003-02-24 06:09:08 +03:00
* */
2002-07-15 14:35:28 +04:00
char * realloc_string_sub ( char * string , const char * pattern , const char * insert )
{
char * p , * in ;
char * s ;
ssize_t ls , lp , li , ld , i ;
if ( ! insert | | ! pattern | | ! * pattern | | ! string | | ! * string )
return NULL ;
s = string ;
in = strdup ( insert ) ;
if ( ! in ) {
DEBUG ( 0 , ( " realloc_string_sub: out of memory! \n " ) ) ;
return NULL ;
}
ls = ( ssize_t ) strlen ( s ) ;
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
ld = li - lp ;
for ( i = 0 ; i < li ; i + + ) {
switch ( in [ i ] ) {
case ' ` ' :
case ' " ' :
case ' \' ' :
case ' ; ' :
case ' $ ' :
case ' % ' :
case ' \r ' :
case ' \n ' :
in [ i ] = ' _ ' ;
default :
/* ok */
break ;
}
}
while ( ( p = strstr ( s , pattern ) ) ) {
if ( ld > 0 ) {
char * t = Realloc ( string , ls + ld + 1 ) ;
if ( ! t ) {
DEBUG ( 0 , ( " realloc_string_sub: out of memory! \n " ) ) ;
SAFE_FREE ( in ) ;
return NULL ;
}
string = t ;
p = t + ( p - s ) ;
}
if ( li ! = lp ) {
memmove ( p + li , p + lp , strlen ( p + lp ) + 1 ) ;
}
memcpy ( p , in , li ) ;
s = p + li ;
ls + = ld ;
}
SAFE_FREE ( in ) ;
return string ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Similar to string_sub ( ) but allows for any character to be substituted .
Use with caution !
if len = = 0 then the string cannot be extended . This is different from the old
use of len = = 0 which was for no length checks to be done .
2003-02-24 06:09:08 +03:00
* */
2002-07-15 14:35:28 +04:00
1999-12-13 16:27:58 +03:00
void all_string_sub ( char * s , const char * pattern , const char * insert , size_t len )
1998-11-23 06:36:10 +03:00
{
char * p ;
1999-12-13 16:27:58 +03:00
ssize_t ls , lp , li ;
1998-11-05 19:48:35 +03:00
2002-07-15 14:35:28 +04:00
if ( ! insert | | ! pattern | | ! s )
return ;
1998-11-05 19:48:35 +03:00
1999-12-13 16:27:58 +03:00
ls = ( ssize_t ) strlen ( s ) ;
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
1998-11-23 06:36:10 +03:00
2002-07-15 14:35:28 +04:00
if ( ! * pattern )
return ;
if ( len = = 0 )
2002-08-17 21:00:51 +04:00
len = ls + 1 ; /* len is number of *bytes* */
1998-11-23 06:36:10 +03:00
while ( lp < = ls & & ( p = strstr ( s , pattern ) ) ) {
2002-07-15 14:35:28 +04:00
if ( ls + ( li - lp ) > = len ) {
1999-12-13 16:27:58 +03:00
DEBUG ( 0 , ( " ERROR: string overflow by %d in all_string_sub(%.50s, %d) \n " ,
( int ) ( ls + ( li - lp ) - len ) ,
pattern , ( int ) len ) ) ;
break ;
}
if ( li ! = lp ) {
memmove ( p + li , p + lp , strlen ( p + lp ) + 1 ) ;
}
1998-11-23 06:36:10 +03:00
memcpy ( p , insert , li ) ;
s = p + li ;
ls + = ( li - lp ) ;
}
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Similar to all_string_sub but for unicode strings .
Return a new allocated unicode string .
similar to string_sub ( ) but allows for any character to be substituted .
Use with caution !
2003-02-24 06:09:08 +03:00
* */
2001-11-04 21:26:53 +03:00
2003-03-18 04:48:11 +03:00
static smb_ucs2_t * all_string_sub_w ( const smb_ucs2_t * s , const smb_ucs2_t * pattern ,
2002-01-25 03:35:14 +03:00
const smb_ucs2_t * insert )
2001-11-04 21:26:53 +03:00
{
2002-08-17 21:00:51 +04:00
smb_ucs2_t * r , * rp ;
const smb_ucs2_t * sp ;
2001-11-18 19:12:11 +03:00
size_t lr , lp , li , lt ;
2001-11-04 21:26:53 +03:00
2002-10-02 23:12:14 +04:00
if ( ! insert | | ! pattern | | ! * pattern | | ! s )
return NULL ;
2001-11-04 21:26:53 +03:00
2001-11-18 19:12:11 +03:00
lt = ( size_t ) strlen_w ( s ) ;
lp = ( size_t ) strlen_w ( pattern ) ;
li = ( size_t ) strlen_w ( insert ) ;
2001-11-04 21:26:53 +03:00
if ( li > lp ) {
2002-08-17 21:00:51 +04:00
const smb_ucs2_t * st = s ;
2001-11-04 21:26:53 +03:00
int ld = li - lp ;
2001-11-18 19:12:11 +03:00
while ( ( sp = strstr_w ( st , pattern ) ) ) {
2001-11-04 21:26:53 +03:00
st = sp + lp ;
lt + = ld ;
}
}
r = rp = ( smb_ucs2_t * ) malloc ( ( lt + 1 ) * ( sizeof ( smb_ucs2_t ) ) ) ;
if ( ! r ) {
DEBUG ( 0 , ( " all_string_sub_w: out of memory! \n " ) ) ;
return NULL ;
}
2001-11-18 19:12:11 +03:00
while ( ( sp = strstr_w ( s , pattern ) ) ) {
memcpy ( rp , s , ( sp - s ) ) ;
rp + = ( ( sp - s ) / sizeof ( smb_ucs2_t ) ) ;
memcpy ( rp , insert , ( li * sizeof ( smb_ucs2_t ) ) ) ;
2001-11-04 21:26:53 +03:00
s = sp + lp ;
rp + = li ;
}
2001-11-18 19:12:11 +03:00
lr = ( ( rp - r ) / sizeof ( smb_ucs2_t ) ) ;
if ( lr < lt ) {
memcpy ( rp , s , ( ( lt - lr ) * sizeof ( smb_ucs2_t ) ) ) ;
rp + = ( lt - lr ) ;
}
2001-11-04 21:26:53 +03:00
* rp = 0 ;
return r ;
}
smb_ucs2_t * all_string_sub_wa ( smb_ucs2_t * s , const char * pattern ,
const char * insert )
{
wpstring p , i ;
2002-10-02 23:12:14 +04:00
if ( ! insert | | ! pattern | | ! s )
return NULL ;
2001-11-04 21:26:53 +03:00
push_ucs2 ( NULL , p , pattern , sizeof ( wpstring ) - 1 , STR_TERMINATE ) ;
push_ucs2 ( NULL , i , insert , sizeof ( wpstring ) - 1 , STR_TERMINATE ) ;
return all_string_sub_w ( s , p , i ) ;
}
2003-03-18 04:48:11 +03:00
#if 0
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Splits out the front and back at a separator .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-03-18 04:48:11 +03:00
static void split_at_last_component ( char * path , char * front , char sep , char * back )
1998-11-11 17:23:55 +03:00
{
2001-07-04 11:36:09 +04:00
char * p = strrchr_m ( path , sep ) ;
1998-11-11 17:23:55 +03:00
if ( p ! = NULL )
* p = 0 ;
2002-08-17 21:00:51 +04:00
1998-11-11 17:23:55 +03:00
if ( front ! = NULL )
pstrcpy ( front , path ) ;
2002-08-17 21:00:51 +04:00
if ( p ! = NULL ) {
1998-11-11 17:23:55 +03:00
if ( back ! = NULL )
pstrcpy ( back , p + 1 ) ;
1999-12-13 16:27:58 +03:00
* p = ' \\ ' ;
2002-08-17 21:00:51 +04:00
} else {
1998-11-11 17:23:55 +03:00
if ( back ! = NULL )
back [ 0 ] = 0 ;
}
}
2003-03-18 04:48:11 +03:00
# endif
1999-02-16 21:02:50 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Write an octal as a string .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-01-03 11:28:12 +03:00
const char * octal_string ( int i )
1999-02-16 21:02:50 +03:00
{
1999-12-13 16:27:58 +03:00
static char ret [ 64 ] ;
2002-08-17 21:00:51 +04:00
if ( i = = - 1 )
1999-12-13 16:27:58 +03:00
return " -1 " ;
2001-04-09 00:22:39 +04:00
slprintf ( ret , sizeof ( ret ) - 1 , " 0%o " , i ) ;
1999-12-13 16:27:58 +03:00
return ret ;
1999-02-16 21:02:50 +03:00
}
1999-12-13 16:27:58 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Truncate a string at a specified length .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-03-18 04:48:11 +03:00
char * string_truncate ( char * s , unsigned int length )
1999-02-16 21:02:50 +03:00
{
2002-08-17 21:00:51 +04:00
if ( s & & strlen ( s ) > length )
1999-12-13 16:27:58 +03:00
s [ length ] = 0 ;
return s ;
1999-02-16 21:02:50 +03:00
}
2001-07-04 11:15:53 +04:00
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Strchr and strrchr_m are very hard to do on general multi - byte strings .
We convert via ucs2 for now .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2001-07-04 11:15:53 +04:00
char * strchr_m ( const char * s , char c )
{
wpstring ws ;
pstring s2 ;
smb_ucs2_t * p ;
push_ucs2 ( NULL , ws , s , sizeof ( ws ) , STR_TERMINATE ) ;
2001-11-04 21:26:53 +03:00
p = strchr_w ( ws , UCS2_CHAR ( c ) ) ;
2002-08-17 21:00:51 +04:00
if ( ! p )
return NULL ;
2001-07-04 11:15:53 +04:00
* p = 0 ;
pull_ucs2_pstring ( s2 , ws ) ;
return ( char * ) ( s + strlen ( s2 ) ) ;
}
char * strrchr_m ( const char * s , char c )
{
wpstring ws ;
pstring s2 ;
smb_ucs2_t * p ;
push_ucs2 ( NULL , ws , s , sizeof ( ws ) , STR_TERMINATE ) ;
2001-11-04 21:26:53 +03:00
p = strrchr_w ( ws , UCS2_CHAR ( c ) ) ;
2002-08-17 21:00:51 +04:00
if ( ! p )
return NULL ;
2001-07-04 11:15:53 +04:00
* p = 0 ;
pull_ucs2_pstring ( s2 , ws ) ;
return ( char * ) ( s + strlen ( s2 ) ) ;
}
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Convert a string to lower case .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2001-07-04 11:15:53 +04:00
void strlower_m ( char * s )
{
2002-04-11 13:56:38 +04:00
/* this is quite a common operation, so we want it to be
fast . We optimise for the ascii case , knowing that all our
supported multi - byte character sets are ascii - compatible
( ie . they match for the first 128 chars ) */
2002-08-17 21:00:51 +04:00
2003-01-17 09:40:12 +03:00
while ( * s & & ! ( ( ( unsigned char ) s [ 0 ] ) & 0x7F ) ) {
* s = tolower ( ( unsigned char ) * s ) ;
s + + ;
}
2002-04-11 13:56:38 +04:00
2002-08-17 21:00:51 +04:00
if ( ! * s )
return ;
2002-04-11 13:56:38 +04:00
2001-07-04 11:15:53 +04:00
/* I assume that lowercased string takes the same number of bytes
* as source string even in UTF - 8 encoding . ( VIV ) */
unix_strlower ( s , strlen ( s ) + 1 , s , strlen ( s ) + 1 ) ;
}
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Duplicate convert a string to lower case .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2002-07-15 14:35:28 +04:00
char * strdup_lower ( const char * s )
{
char * t = strdup ( s ) ;
if ( t = = NULL ) {
DEBUG ( 0 , ( " strdup_lower: Out of memory! \n " ) ) ;
return NULL ;
}
strlower_m ( t ) ;
return t ;
}
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Convert a string to upper case .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2001-07-04 11:15:53 +04:00
void strupper_m ( char * s )
{
2002-04-11 13:56:38 +04:00
/* this is quite a common operation, so we want it to be
fast . We optimise for the ascii case , knowing that all our
supported multi - byte character sets are ascii - compatible
( ie . they match for the first 128 chars ) */
2002-08-17 21:00:51 +04:00
2003-01-17 09:40:12 +03:00
while ( * s & & ! ( ( ( unsigned char ) s [ 0 ] ) & 0x7F ) ) {
* s = toupper ( ( unsigned char ) * s ) ;
s + + ;
}
2002-04-11 13:56:38 +04:00
2002-08-17 21:00:51 +04:00
if ( ! * s )
return ;
2002-04-11 13:56:38 +04:00
2001-07-04 11:15:53 +04:00
/* I assume that lowercased string takes the same number of bytes
* as source string even in multibyte encoding . ( VIV ) */
unix_strupper ( s , strlen ( s ) + 1 , s , strlen ( s ) + 1 ) ;
}
2001-12-10 03:39:01 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Convert a string to upper case .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2002-07-15 14:35:28 +04:00
char * strdup_upper ( const char * s )
{
char * t = strdup ( s ) ;
if ( t = = NULL ) {
DEBUG ( 0 , ( " strdup_upper: Out of memory! \n " ) ) ;
return NULL ;
}
strupper_m ( t ) ;
return t ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Return a RFC2254 binary string representation of a buffer .
Used in LDAP filters .
Caller must free .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2001-12-10 03:39:01 +03:00
char * binary_string ( char * buf , int len )
{
char * s ;
int i , j ;
const char * hex = " 0123456789ABCDEF " ;
s = malloc ( len * 3 + 1 ) ;
2002-08-17 21:00:51 +04:00
if ( ! s )
return NULL ;
2001-12-10 03:39:01 +03:00
for ( j = i = 0 ; i < len ; i + + ) {
s [ j ] = ' \\ ' ;
s [ j + 1 ] = hex [ ( ( unsigned char ) buf [ i ] ) > > 4 ] ;
s [ j + 2 ] = hex [ ( ( unsigned char ) buf [ i ] ) & 0xF ] ;
j + = 3 ;
}
s [ j ] = 0 ;
return s ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Just a typesafety wrapper for snprintf into a pstring .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-01-03 06:24:23 +03:00
int pstr_sprintf ( pstring s , const char * fmt , . . . )
2002-01-15 04:37:12 +03:00
{
va_list ap ;
int ret ;
va_start ( ap , fmt ) ;
2002-01-16 05:42:07 +03:00
ret = vsnprintf ( s , PSTRING_LEN , fmt , ap ) ;
2002-01-15 04:37:12 +03:00
va_end ( ap ) ;
return ret ;
}
2003-03-18 04:48:11 +03:00
#if 0
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Just a typesafety wrapper for snprintf into a fstring .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-03-18 04:48:11 +03:00
static int fstr_sprintf ( fstring s , const char * fmt , . . . )
2002-01-15 04:37:12 +03:00
{
va_list ap ;
int ret ;
va_start ( ap , fmt ) ;
2002-01-16 05:42:07 +03:00
ret = vsnprintf ( s , FSTRING_LEN , fmt , ap ) ;
2002-01-15 04:37:12 +03:00
va_end ( ap ) ;
return ret ;
}
2003-03-18 04:48:11 +03:00
# endif
2002-04-11 19:27:22 +04:00
# ifndef HAVE_STRNDUP
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Some platforms don ' t have strndup .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2002-04-11 19:27:22 +04:00
char * strndup ( const char * s , size_t n )
{
char * ret ;
2002-07-15 14:35:28 +04:00
n = strnlen ( s , n ) ;
ret = malloc ( n + 1 ) ;
2002-08-17 21:00:51 +04:00
if ( ! ret )
return NULL ;
2002-07-15 14:35:28 +04:00
memcpy ( ret , s , n ) ;
ret [ n ] = 0 ;
2002-04-11 19:27:22 +04:00
return ret ;
}
# endif
2002-07-15 14:35:28 +04:00
# ifndef HAVE_STRNLEN
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Some platforms don ' t have strnlen
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2002-07-15 14:35:28 +04:00
size_t strnlen ( const char * s , size_t n )
{
int i ;
2002-08-17 21:00:51 +04:00
for ( i = 0 ; s [ i ] & & i < n ; i + + )
/* noop */ ;
2002-07-15 14:35:28 +04:00
return i ;
}
# endif
2003-02-24 06:09:08 +03:00
/**
2002-07-15 14:35:28 +04:00
List of Strings manipulation functions
2003-02-24 06:09:08 +03:00
* */
2002-07-15 14:35:28 +04:00
# define S_LIST_ABS 16 /* List Allocation Block Size */
2002-08-17 21:00:51 +04:00
char * * str_list_make ( const char * string , const char * sep )
2002-07-15 14:35:28 +04:00
{
char * * list , * * rlist ;
2002-11-13 02:20:50 +03:00
const char * str ;
char * s ;
2002-07-15 14:35:28 +04:00
int num , lsize ;
pstring tok ;
2002-08-17 21:00:51 +04:00
if ( ! string | | ! * string )
return NULL ;
2002-07-15 14:35:28 +04:00
s = strdup ( string ) ;
if ( ! s ) {
DEBUG ( 0 , ( " str_list_make: Unable to allocate memory " ) ) ;
return NULL ;
}
2002-08-17 21:00:51 +04:00
if ( ! sep ) sep = LIST_SEP ;
2002-07-15 14:35:28 +04:00
num = lsize = 0 ;
list = NULL ;
str = s ;
2002-08-17 21:00:51 +04:00
while ( next_token ( & str , tok , sep , sizeof ( tok ) ) ) {
2002-07-15 14:35:28 +04:00
if ( num = = lsize ) {
lsize + = S_LIST_ABS ;
rlist = ( char * * ) Realloc ( list , ( ( sizeof ( char * * ) ) * ( lsize + 1 ) ) ) ;
if ( ! rlist ) {
DEBUG ( 0 , ( " str_list_make: Unable to allocate memory " ) ) ;
str_list_free ( & list ) ;
SAFE_FREE ( s ) ;
return NULL ;
2002-10-02 23:12:14 +04:00
} else
list = rlist ;
2002-07-15 14:35:28 +04:00
memset ( & list [ num ] , 0 , ( ( sizeof ( char * * ) ) * ( S_LIST_ABS + 1 ) ) ) ;
}
list [ num ] = strdup ( tok ) ;
if ( ! list [ num ] ) {
DEBUG ( 0 , ( " str_list_make: Unable to allocate memory " ) ) ;
str_list_free ( & list ) ;
SAFE_FREE ( s ) ;
return NULL ;
}
num + + ;
}
SAFE_FREE ( s ) ;
return list ;
}
2002-11-13 02:20:50 +03:00
BOOL str_list_copy ( char * * * dest , const char * * src )
2002-07-15 14:35:28 +04:00
{
char * * list , * * rlist ;
int num , lsize ;
* dest = NULL ;
2002-08-17 21:00:51 +04:00
if ( ! src )
return False ;
2002-07-15 14:35:28 +04:00
num = lsize = 0 ;
list = NULL ;
2002-08-17 21:00:51 +04:00
while ( src [ num ] ) {
2002-07-15 14:35:28 +04:00
if ( num = = lsize ) {
lsize + = S_LIST_ABS ;
rlist = ( char * * ) Realloc ( list , ( ( sizeof ( char * * ) ) * ( lsize + 1 ) ) ) ;
if ( ! rlist ) {
2002-10-01 17:10:57 +04:00
DEBUG ( 0 , ( " str_list_copy: Unable to re-allocate memory " ) ) ;
2002-07-15 14:35:28 +04:00
str_list_free ( & list ) ;
return False ;
2002-10-02 23:12:14 +04:00
} else
list = rlist ;
2002-07-15 14:35:28 +04:00
memset ( & list [ num ] , 0 , ( ( sizeof ( char * * ) ) * ( S_LIST_ABS + 1 ) ) ) ;
}
list [ num ] = strdup ( src [ num ] ) ;
if ( ! list [ num ] ) {
DEBUG ( 0 , ( " str_list_copy: Unable to allocate memory " ) ) ;
str_list_free ( & list ) ;
return False ;
}
num + + ;
}
* dest = list ;
return True ;
}
2003-02-24 06:09:08 +03:00
/**
* Return true if all the elements of the list match exactly .
* */
2002-07-15 14:35:28 +04:00
BOOL str_list_compare ( char * * list1 , char * * list2 )
{
int num ;
2002-08-17 21:00:51 +04:00
if ( ! list1 | | ! list2 )
return ( list1 = = list2 ) ;
2002-07-15 14:35:28 +04:00
for ( num = 0 ; list1 [ num ] ; num + + ) {
2002-08-17 21:00:51 +04:00
if ( ! list2 [ num ] )
return False ;
if ( ! strcsequal ( list1 [ num ] , list2 [ num ] ) )
return False ;
2002-07-15 14:35:28 +04:00
}
2002-08-17 21:00:51 +04:00
if ( list2 [ num ] )
return False ; /* if list2 has more elements than list1 fail */
2002-07-15 14:35:28 +04:00
return True ;
}
void str_list_free ( char * * * list )
{
char * * tlist ;
2002-08-17 21:00:51 +04:00
if ( ! list | | ! * list )
return ;
2002-07-15 14:35:28 +04:00
tlist = * list ;
2002-08-17 21:00:51 +04:00
for ( ; * tlist ; tlist + + )
SAFE_FREE ( * tlist ) ;
2002-07-15 14:35:28 +04:00
SAFE_FREE ( * list ) ;
}
BOOL str_list_substitute ( char * * list , const char * pattern , const char * insert )
{
char * p , * s , * t ;
ssize_t ls , lp , li , ld , i , d ;
2002-08-17 21:00:51 +04:00
if ( ! list )
return False ;
if ( ! pattern )
return False ;
if ( ! insert )
return False ;
2002-07-15 14:35:28 +04:00
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
ld = li - lp ;
2002-08-17 21:00:51 +04:00
while ( * list ) {
2002-07-15 14:35:28 +04:00
s = * list ;
ls = ( ssize_t ) strlen ( s ) ;
2002-08-17 21:00:51 +04:00
while ( ( p = strstr ( s , pattern ) ) ) {
2002-07-15 14:35:28 +04:00
t = * list ;
d = p - t ;
2002-08-17 21:00:51 +04:00
if ( ld ) {
2002-07-15 14:35:28 +04:00
t = ( char * ) malloc ( ls + ld + 1 ) ;
if ( ! t ) {
DEBUG ( 0 , ( " str_list_substitute: Unable to allocate memory " ) ) ;
return False ;
}
memcpy ( t , * list , d ) ;
memcpy ( t + d + li , p + lp , ls - d - lp + 1 ) ;
SAFE_FREE ( * list ) ;
* list = t ;
ls + = ld ;
s = t + d + li ;
}
for ( i = 0 ; i < li ; i + + ) {
switch ( insert [ i ] ) {
case ' ` ' :
case ' " ' :
case ' \' ' :
case ' ; ' :
case ' $ ' :
case ' % ' :
case ' \r ' :
case ' \n ' :
t [ d + i ] = ' _ ' ;
break ;
default :
t [ d + i ] = insert [ i ] ;
}
}
}
list + + ;
}
return True ;
}
2002-12-12 02:54:40 +03:00
2003-01-04 11:48:15 +03:00
# define IPSTR_LIST_SEP ","
/**
* Add ip string representation to ipstr list . Used also
* as part of @ function ipstr_list_make
*
* @ param ipstr_list pointer to string containing ip list ;
* MUST BE already allocated and IS reallocated if necessary
* @ param ipstr_size pointer to current size of ipstr_list ( might be changed
* as a result of reallocation )
* @ param ip IP address which is to be added to list
* @ return pointer to string appended with new ip and possibly
* reallocated to new length
* */
char * ipstr_list_add ( char * * ipstr_list , const struct in_addr * ip )
{
char * new_ipstr = NULL ;
/* arguments checking */
if ( ! ipstr_list | | ! ip ) return NULL ;
/* attempt to convert ip to a string and append colon separator to it */
if ( * ipstr_list ) {
asprintf ( & new_ipstr , " %s%s%s " , * ipstr_list , IPSTR_LIST_SEP , inet_ntoa ( * ip ) ) ;
SAFE_FREE ( * ipstr_list ) ;
} else {
asprintf ( & new_ipstr , " %s " , inet_ntoa ( * ip ) ) ;
}
* ipstr_list = new_ipstr ;
return * ipstr_list ;
}
/**
* Allocate and initialise an ipstr list using ip adresses
* passed as arguments .
*
* @ param ipstr_list pointer to string meant to be allocated and set
* @ param ip_list array of ip addresses to place in the list
* @ param ip_count number of addresses stored in ip_list
* @ return pointer to allocated ip string
* */
char * ipstr_list_make ( char * * ipstr_list , const struct in_addr * ip_list , int ip_count )
{
int i ;
/* arguments checking */
if ( ! ip_list & & ! ipstr_list ) return 0 ;
* ipstr_list = NULL ;
/* process ip addresses given as arguments */
for ( i = 0 ; i < ip_count ; i + + )
* ipstr_list = ipstr_list_add ( ipstr_list , & ip_list [ i ] ) ;
return ( * ipstr_list ) ;
}
/**
* Parse given ip string list into array of ip addresses
* ( as in_addr structures )
*
* @ param ipstr ip string list to be parsed
* @ param ip_list pointer to array of ip addresses which is
* allocated by this function and must be freed by caller
* @ return number of succesfully parsed addresses
* */
int ipstr_list_parse ( const char * ipstr_list , struct in_addr * * ip_list )
{
fstring token_str ;
int count ;
if ( ! ipstr_list | | ! ip_list ) return 0 ;
for ( * ip_list = NULL , count = 0 ;
next_token ( & ipstr_list , token_str , IPSTR_LIST_SEP , FSTRING_LEN ) ;
count + + ) {
struct in_addr addr ;
/* convert single token to ip address */
if ( ( addr . s_addr = inet_addr ( token_str ) ) = = INADDR_NONE )
break ;
/* prepare place for another in_addr structure */
* ip_list = Realloc ( * ip_list , ( count + 1 ) * sizeof ( struct in_addr ) ) ;
if ( ! * ip_list ) return - 1 ;
( * ip_list ) [ count ] = addr ;
}
return count ;
}
/**
* Safely free ip string list
*
* @ param ipstr_list ip string list to be freed
* */
void ipstr_list_free ( char * ipstr_list )
{
SAFE_FREE ( ipstr_list ) ;
}
2003-02-24 06:09:08 +03:00
/**
2003-01-04 11:48:15 +03:00
Unescape a URL encoded string , in place .
2003-02-24 06:09:08 +03:00
* */
2003-01-04 11:48:15 +03:00
void rfc1738_unescape ( char * buf )
{
char * p = buf ;
while ( ( p = strchr_m ( p , ' + ' ) ) )
* p = ' ' ;
p = buf ;
while ( p & & * p & & ( p = strchr_m ( p , ' % ' ) ) ) {
int c1 = p [ 1 ] ;
int c2 = p [ 2 ] ;
if ( c1 > = ' 0 ' & & c1 < = ' 9 ' )
c1 = c1 - ' 0 ' ;
else if ( c1 > = ' A ' & & c1 < = ' F ' )
c1 = 10 + c1 - ' A ' ;
else if ( c1 > = ' a ' & & c1 < = ' f ' )
c1 = 10 + c1 - ' a ' ;
else { p + + ; continue ; }
if ( c2 > = ' 0 ' & & c2 < = ' 9 ' )
c2 = c2 - ' 0 ' ;
else if ( c2 > = ' A ' & & c2 < = ' F ' )
c2 = 10 + c2 - ' A ' ;
else if ( c2 > = ' a ' & & c2 < = ' f ' )
c2 = 10 + c2 - ' a ' ;
else { p + + ; continue ; }
* p = ( c1 < < 4 ) | c2 ;
memmove ( p + 1 , p + 3 , strlen ( p + 3 ) + 1 ) ;
p + + ;
}
}
2003-01-28 15:07:02 +03:00
static const char * b64 = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ " ;
2003-02-24 06:09:08 +03:00
/**
* Decode a base64 string into a DATA_BLOB - simple and slow algorithm
* */
2003-01-28 15:07:02 +03:00
DATA_BLOB base64_decode_data_blob ( const char * s )
{
int bit_offset , byte_offset , idx , i , n ;
DATA_BLOB decoded = data_blob ( s , strlen ( s ) + 1 ) ;
unsigned char * d = decoded . data ;
char * p ;
n = i = 0 ;
while ( * s & & ( p = strchr_m ( b64 , * s ) ) ) {
idx = ( int ) ( p - b64 ) ;
byte_offset = ( i * 6 ) / 8 ;
bit_offset = ( i * 6 ) % 8 ;
d [ byte_offset ] & = ~ ( ( 1 < < ( 8 - bit_offset ) ) - 1 ) ;
if ( bit_offset < 3 ) {
d [ byte_offset ] | = ( idx < < ( 2 - bit_offset ) ) ;
n = byte_offset + 1 ;
} else {
d [ byte_offset ] | = ( idx > > ( bit_offset - 2 ) ) ;
d [ byte_offset + 1 ] = 0 ;
d [ byte_offset + 1 ] | = ( idx < < ( 8 - ( bit_offset - 2 ) ) ) & 0xFF ;
n = byte_offset + 2 ;
}
s + + ; i + + ;
}
/* fix up length */
decoded . length = n ;
return decoded ;
}
2003-02-24 06:09:08 +03:00
/**
* Decode a base64 string in - place - wrapper for the above
* */
2003-02-19 02:17:59 +03:00
void base64_decode_inplace ( char * s )
2003-01-28 15:07:02 +03:00
{
DATA_BLOB decoded = base64_decode_data_blob ( s ) ;
memcpy ( s , decoded . data , decoded . length ) ;
/* null terminate */
s [ decoded . length ] = ' \0 ' ;
2003-04-02 04:17:03 +04:00
data_blob_free ( & decoded ) ;
2003-01-28 15:07:02 +03:00
}
2003-02-24 06:09:08 +03:00
/**
* Encode a base64 string into a malloc ( ) ed string caller to free .
*
* From SQUID : adopted from http : //ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments
* */
2003-01-28 15:07:02 +03:00
char * base64_encode_data_blob ( DATA_BLOB data )
{
int bits = 0 ;
int char_count = 0 ;
size_t out_cnt = 0 ;
size_t len = data . length ;
size_t output_len = data . length * 2 ;
char * result = malloc ( output_len ) ; /* get us plenty of space */
while ( len - - & & out_cnt < ( data . length * 2 ) - 5 ) {
int c = ( unsigned char ) * ( data . data + + ) ;
bits + = c ;
char_count + + ;
if ( char_count = = 3 ) {
result [ out_cnt + + ] = b64 [ bits > > 18 ] ;
result [ out_cnt + + ] = b64 [ ( bits > > 12 ) & 0x3f ] ;
result [ out_cnt + + ] = b64 [ ( bits > > 6 ) & 0x3f ] ;
result [ out_cnt + + ] = b64 [ bits & 0x3f ] ;
bits = 0 ;
char_count = 0 ;
} else {
bits < < = 8 ;
}
}
if ( char_count ! = 0 ) {
bits < < = 16 - ( 8 * char_count ) ;
result [ out_cnt + + ] = b64 [ bits > > 18 ] ;
result [ out_cnt + + ] = b64 [ ( bits > > 12 ) & 0x3f ] ;
if ( char_count = = 1 ) {
result [ out_cnt + + ] = ' = ' ;
result [ out_cnt + + ] = ' = ' ;
} else {
result [ out_cnt + + ] = b64 [ ( bits > > 6 ) & 0x3f ] ;
result [ out_cnt + + ] = ' = ' ;
}
}
result [ out_cnt ] = ' \0 ' ; /* terminate */
return result ;
}