2004-10-08 12:13:00 +04:00
/*
Unix SMB / CIFS implementation .
2005-02-04 07:58:48 +03:00
Copyright ( C ) Andrew Tridgell 2005
2005-09-26 21:42:12 +04:00
Copyright ( C ) Jelmer Vernooij 2005
2004-10-08 12:13:00 +04: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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-10-08 12:13:00 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-10-08 12:13:00 +04:00
*/
# include "includes.h"
2007-04-19 18:21:56 +04:00
# include "system/locale.h"
2010-02-14 01:58:13 +03:00
# include "lib/util/tsort.h"
2004-10-08 12:13:00 +04:00
2008-10-12 02:56:56 +04:00
# undef strcasecmp
2006-02-28 16:12:39 +03:00
/**
* @ file
* @ brief String list manipulation
*/
2009-05-13 10:49:34 +04:00
/**
build an empty ( only NULL terminated ) list of strings ( for expansion with str_list_add ( ) etc )
*/
2009-09-25 02:52:58 +04:00
_PUBLIC_ char * * str_list_make_empty ( TALLOC_CTX * mem_ctx )
2009-05-13 10:49:34 +04:00
{
2009-09-25 02:52:58 +04:00
char * * ret = NULL ;
2009-05-13 10:49:34 +04:00
2009-09-25 02:52:58 +04:00
ret = talloc_array ( mem_ctx , char * , 1 ) ;
2009-05-13 10:49:34 +04:00
if ( ret = = NULL ) {
return NULL ;
}
ret [ 0 ] = NULL ;
return ret ;
}
/**
place the only element ' entry ' into a new , NULL terminated string list
*/
2009-09-25 02:52:58 +04:00
_PUBLIC_ char * * str_list_make_single ( TALLOC_CTX * mem_ctx , const char * entry )
2009-05-13 10:49:34 +04:00
{
2009-09-25 02:52:58 +04:00
char * * ret = NULL ;
2009-05-13 10:49:34 +04:00
2009-09-25 02:52:58 +04:00
ret = talloc_array ( mem_ctx , char * , 2 ) ;
2009-05-13 10:49:34 +04:00
if ( ret = = NULL ) {
return NULL ;
}
ret [ 0 ] = talloc_strdup ( ret , entry ) ;
if ( ! ret [ 0 ] ) {
talloc_free ( ret ) ;
return NULL ;
}
ret [ 1 ] = NULL ;
return ret ;
}
2006-02-28 16:12:39 +03:00
/**
2005-02-04 07:58:48 +03:00
build a null terminated list of strings from a input string and a
2005-08-30 17:58:48 +04:00
separator list . The separator list must contain characters less than
2005-02-04 07:58:48 +03:00
or equal to 0x2f for this to work correctly on multi - byte strings
*/
2009-09-25 02:52:58 +04:00
_PUBLIC_ char * * str_list_make ( TALLOC_CTX * mem_ctx , const char * string , const char * sep )
2005-02-04 07:58:48 +03:00
{
int num_elements = 0 ;
2009-09-25 02:52:58 +04:00
char * * ret = NULL ;
2004-10-08 12:13:00 +04:00
2005-02-04 07:58:48 +03:00
if ( sep = = NULL ) {
sep = LIST_SEP ;
}
2004-10-08 12:13:00 +04:00
2009-09-25 02:52:58 +04:00
ret = talloc_array ( mem_ctx , char * , 1 ) ;
2005-02-04 07:58:48 +03:00
if ( ret = = NULL ) {
2004-10-08 12:13:00 +04:00
return NULL ;
}
2005-02-04 07:58:48 +03:00
while ( string & & * string ) {
size_t len = strcspn ( string , sep ) ;
2009-09-25 02:52:58 +04:00
char * * ret2 ;
2004-10-08 12:13:00 +04:00
2005-02-04 07:58:48 +03:00
if ( len = = 0 ) {
string + = strspn ( string , sep ) ;
continue ;
}
2009-09-25 02:52:58 +04:00
ret2 = talloc_realloc ( mem_ctx , ret , char * ,
2009-09-10 09:17:40 +04:00
num_elements + 2 ) ;
2005-02-04 07:58:48 +03:00
if ( ret2 = = NULL ) {
talloc_free ( ret ) ;
2004-10-08 12:13:00 +04:00
return NULL ;
}
2005-02-04 07:58:48 +03:00
ret = ret2 ;
ret [ num_elements ] = talloc_strndup ( ret , string , len ) ;
if ( ret [ num_elements ] = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
num_elements + + ;
string + = len ;
2004-10-08 12:13:00 +04:00
}
2005-02-04 07:58:48 +03:00
ret [ num_elements ] = NULL ;
return ret ;
2004-10-08 12:13:00 +04:00
}
2006-02-28 16:12:39 +03:00
/**
* build a null terminated list of strings from an argv - like input string
2010-02-21 08:58:07 +03:00
* Entries are separated by spaces and can be enclosed by quotes .
2006-02-28 16:12:39 +03:00
* Does NOT support escaping
2005-09-26 21:42:12 +04:00
*/
2009-09-25 02:52:58 +04:00
_PUBLIC_ char * * str_list_make_shell ( TALLOC_CTX * mem_ctx , const char * string , const char * sep )
2005-09-26 21:42:12 +04:00
{
int num_elements = 0 ;
2009-09-25 02:52:58 +04:00
char * * ret = NULL ;
2005-09-26 21:42:12 +04:00
2009-09-25 02:52:58 +04:00
ret = talloc_array ( mem_ctx , char * , 1 ) ;
2005-09-26 21:42:12 +04:00
if ( ret = = NULL ) {
return NULL ;
}
2005-09-26 22:16:23 +04:00
if ( sep = = NULL )
sep = " \t \n \r " ;
2005-09-26 21:42:12 +04:00
while ( string & & * string ) {
2005-09-26 22:16:23 +04:00
size_t len = strcspn ( string , sep ) ;
2005-09-26 21:42:12 +04:00
char * element ;
2009-09-25 02:52:58 +04:00
char * * ret2 ;
2005-09-26 21:42:12 +04:00
if ( len = = 0 ) {
2005-09-26 22:16:23 +04:00
string + = strspn ( string , sep ) ;
2005-09-26 21:42:12 +04:00
continue ;
}
if ( * string = = ' \" ' ) {
string + + ;
len = strcspn ( string , " \" " ) ;
element = talloc_strndup ( ret , string , len ) ;
string + = len + 1 ;
} else {
element = talloc_strndup ( ret , string , len ) ;
string + = len ;
}
if ( element = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
2009-09-25 02:52:58 +04:00
ret2 = talloc_realloc ( mem_ctx , ret , char * , num_elements + 2 ) ;
2005-09-26 21:42:12 +04:00
if ( ret2 = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
ret = ret2 ;
ret [ num_elements ] = element ;
num_elements + + ;
}
ret [ num_elements ] = NULL ;
return ret ;
}
2006-02-28 16:12:39 +03:00
/**
* join a list back to one string
*/
2010-02-21 08:58:07 +03:00
_PUBLIC_ char * str_list_join ( TALLOC_CTX * mem_ctx , const char * * list , char separator )
2005-08-30 17:58:48 +04:00
{
char * ret = NULL ;
int i ;
if ( list [ 0 ] = = NULL )
return talloc_strdup ( mem_ctx , " " ) ;
ret = talloc_strdup ( mem_ctx , list [ 0 ] ) ;
for ( i = 1 ; list [ i ] ; i + + ) {
2010-02-21 08:58:07 +03:00
ret = talloc_asprintf_append_buffer ( ret , " %c%s " , separator , list [ i ] ) ;
2005-08-30 17:58:48 +04:00
}
return ret ;
}
2006-02-28 16:12:39 +03:00
/** join a list back to one (shell-like) string; entries
2010-02-21 08:58:07 +03:00
* separated by spaces , using quotes where necessary */
2006-03-05 20:15:19 +03:00
_PUBLIC_ char * str_list_join_shell ( TALLOC_CTX * mem_ctx , const char * * list , char sep )
2005-09-26 21:42:12 +04:00
{
char * ret = NULL ;
int i ;
if ( list [ 0 ] = = NULL )
return talloc_strdup ( mem_ctx , " " ) ;
if ( strchr ( list [ 0 ] , ' ' ) | | strlen ( list [ 0 ] ) = = 0 )
ret = talloc_asprintf ( mem_ctx , " \" %s \" " , list [ 0 ] ) ;
else
ret = talloc_strdup ( mem_ctx , list [ 0 ] ) ;
for ( i = 1 ; list [ i ] ; i + + ) {
if ( strchr ( list [ i ] , ' ' ) | | strlen ( list [ i ] ) = = 0 )
2007-09-15 03:21:00 +04:00
ret = talloc_asprintf_append_buffer ( ret , " %c \" %s \" " , sep , list [ i ] ) ;
2005-09-26 21:42:12 +04:00
else
2007-09-15 03:21:00 +04:00
ret = talloc_asprintf_append_buffer ( ret , " %c%s " , sep , list [ i ] ) ;
2005-09-26 21:42:12 +04:00
}
return ret ;
}
2005-08-30 17:58:48 +04:00
2006-02-28 16:12:39 +03:00
/**
2005-02-04 07:58:48 +03:00
return the number of elements in a string list
*/
2009-05-03 15:08:46 +04:00
_PUBLIC_ size_t str_list_length ( const char * const * list )
2004-10-08 12:13:00 +04:00
{
2005-02-04 07:58:48 +03:00
size_t ret ;
for ( ret = 0 ; list & & list [ ret ] ; ret + + ) /* noop */ ;
return ret ;
}
2004-10-08 12:13:00 +04:00
2006-02-28 16:12:39 +03:00
/**
2005-02-04 07:58:48 +03:00
copy a string list
*/
2009-09-25 02:52:58 +04:00
_PUBLIC_ char * * str_list_copy ( TALLOC_CTX * mem_ctx , const char * * list )
2005-02-04 07:58:48 +03:00
{
int i ;
2009-09-25 02:52:58 +04:00
char * * ret ;
2007-12-12 16:09:15 +03:00
if ( list = = NULL )
return NULL ;
2009-09-25 02:52:58 +04:00
ret = talloc_array ( mem_ctx , char * , str_list_length ( list ) + 1 ) ;
2007-12-12 16:09:15 +03:00
if ( ret = = NULL )
return NULL ;
2005-02-04 07:58:48 +03:00
for ( i = 0 ; list & & list [ i ] ; i + + ) {
ret [ i ] = talloc_strdup ( ret , list [ i ] ) ;
if ( ret [ i ] = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
2004-10-08 12:13:00 +04:00
}
2005-02-04 07:58:48 +03:00
ret [ i ] = NULL ;
return ret ;
2004-10-08 12:13:00 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2004-10-08 12:13:00 +04:00
Return true if all the elements of the list match exactly .
2005-02-04 07:58:48 +03:00
*/
2009-10-16 21:06:29 +04:00
_PUBLIC_ bool str_list_equal ( const char * const * list1 ,
const char * const * list2 )
2004-10-08 12:13:00 +04:00
{
2005-02-04 07:58:48 +03:00
int i ;
2004-10-08 12:13:00 +04:00
2005-02-04 07:58:48 +03:00
if ( list1 = = NULL | | list2 = = NULL ) {
2004-10-08 12:13:00 +04:00
return ( list1 = = list2 ) ;
2005-02-04 07:58:48 +03:00
}
2004-10-08 12:13:00 +04:00
2005-02-04 07:58:48 +03:00
for ( i = 0 ; list1 [ i ] & & list2 [ i ] ; i + + ) {
if ( strcmp ( list1 [ i ] , list2 [ i ] ) ! = 0 ) {
2007-08-27 21:21:16 +04:00
return false ;
2005-02-04 07:58:48 +03:00
}
}
if ( list1 [ i ] | | list2 [ i ] ) {
2007-08-27 21:21:16 +04:00
return false ;
2004-10-08 12:13:00 +04:00
}
2007-08-27 21:21:16 +04:00
return true ;
2004-10-08 12:13:00 +04:00
}
2005-02-14 12:15:24 +03:00
2009-04-08 17:18:13 +04:00
/**
add an entry to a string list
*/
2009-05-03 15:08:46 +04:00
_PUBLIC_ const char * * str_list_add ( const char * * list , const char * s )
2009-04-08 17:18:13 +04:00
{
size_t len = str_list_length ( list ) ;
2009-05-03 15:08:46 +04:00
const char * * ret ;
2009-04-08 17:18:13 +04:00
2009-05-03 15:08:46 +04:00
ret = talloc_realloc ( NULL , list , const char * , len + 2 ) ;
2009-04-08 17:18:13 +04:00
if ( ret = = NULL ) return NULL ;
ret [ len ] = talloc_strdup ( ret , s ) ;
if ( ret [ len ] = = NULL ) return NULL ;
ret [ len + 1 ] = NULL ;
return ret ;
}
2006-02-28 16:12:39 +03:00
/**
2005-02-14 12:15:24 +03:00
remove an entry from a string list
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ void str_list_remove ( const char * * list , const char * s )
2005-02-14 12:15:24 +03:00
{
int i ;
for ( i = 0 ; list [ i ] ; i + + ) {
if ( strcmp ( list [ i ] , s ) = = 0 ) break ;
}
if ( ! list [ i ] ) return ;
for ( ; list [ i ] ; i + + ) {
list [ i ] = list [ i + 1 ] ;
}
}
2006-02-28 16:12:39 +03:00
/**
2007-08-27 21:21:16 +04:00
return true if a string is in a list
2005-02-14 12:15:24 +03:00
*/
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool str_list_check ( const char * * list , const char * s )
2005-02-14 12:15:24 +03:00
{
int i ;
2014-03-14 00:30:52 +04:00
for ( i = 0 ; list ! = NULL & & list [ i ] ! = NULL ; i + + ) {
2007-08-27 21:21:16 +04:00
if ( strcmp ( list [ i ] , s ) = = 0 ) return true ;
2005-02-14 12:15:24 +03:00
}
2007-08-27 21:21:16 +04:00
return false ;
2005-02-14 12:15:24 +03:00
}
2005-05-28 12:47:01 +04:00
2006-02-28 16:12:39 +03:00
/**
2007-08-27 21:21:16 +04:00
return true if a string is in a list , case insensitively
2005-05-28 12:47:01 +04:00
*/
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool str_list_check_ci ( const char * * list , const char * s )
2005-05-28 12:47:01 +04:00
{
int i ;
2014-03-14 00:30:52 +04:00
for ( i = 0 ; list ! = NULL & & list [ i ] ! = NULL ; i + + ) {
2007-08-27 21:21:16 +04:00
if ( strcasecmp ( list [ i ] , s ) = = 0 ) return true ;
2005-05-28 12:47:01 +04:00
}
2007-08-27 21:21:16 +04:00
return false ;
2005-05-28 12:47:01 +04:00
}
2007-04-19 18:21:56 +04:00
2009-04-07 10:33:26 +04:00
/**
append one list to another - expanding list1
*/
2009-09-10 09:17:40 +04:00
_PUBLIC_ const char * * str_list_append ( const char * * list1 ,
const char * const * list2 )
2009-04-07 10:33:26 +04:00
{
size_t len1 = str_list_length ( list1 ) ;
size_t len2 = str_list_length ( list2 ) ;
2009-09-10 09:17:40 +04:00
const char * * ret ;
2009-04-07 10:33:26 +04:00
int i ;
2009-09-10 09:17:40 +04:00
ret = talloc_realloc ( NULL , list1 , const char * , len1 + len2 + 1 ) ;
2009-04-07 10:33:26 +04:00
if ( ret = = NULL ) return NULL ;
for ( i = len1 ; i < len1 + len2 ; i + + ) {
ret [ i ] = talloc_strdup ( ret , list2 [ i - len1 ] ) ;
if ( ret [ i ] = = NULL ) {
return NULL ;
}
}
ret [ i ] = NULL ;
return ret ;
}
2009-04-09 07:44:27 +04:00
static int list_cmp ( const char * * el1 , const char * * el2 )
{
return strcmp ( * el1 , * el2 ) ;
}
/*
return a list that only contains the unique elements of a list ,
removing any duplicates
*/
2009-05-03 15:08:46 +04:00
_PUBLIC_ const char * * str_list_unique ( const char * * list )
2009-04-09 07:44:27 +04:00
{
size_t len = str_list_length ( list ) ;
2009-05-03 15:08:46 +04:00
const char * * list2 ;
2009-04-09 07:44:27 +04:00
int i , j ;
if ( len < 2 ) {
return list ;
}
2009-05-03 15:08:46 +04:00
list2 = ( const char * * ) talloc_memdup ( list , list ,
sizeof ( list [ 0 ] ) * ( len + 1 ) ) ;
2010-02-14 01:58:13 +03:00
TYPESAFE_QSORT ( list2 , len , list_cmp ) ;
2009-04-09 07:44:27 +04:00
list [ 0 ] = list2 [ 0 ] ;
for ( i = j = 1 ; i < len ; i + + ) {
if ( strcmp ( list2 [ i ] , list [ j - 1 ] ) ! = 0 ) {
list [ j ] = list2 [ i ] ;
j + + ;
}
}
list [ j ] = NULL ;
2009-11-13 04:57:48 +03:00
list = talloc_realloc ( NULL , list , const char * , j + 1 ) ;
2009-04-09 07:44:27 +04:00
talloc_free ( list2 ) ;
return list ;
}
/*
very useful when debugging complex list related code
*/
_PUBLIC_ void str_list_show ( const char * * list )
{
int i ;
DEBUG ( 0 , ( " { " ) ) ;
for ( i = 0 ; list & & list [ i ] ; i + + ) {
DEBUG ( 0 , ( " \" %s \" , " , list [ i ] ) ) ;
}
DEBUG ( 0 , ( " } \n " ) ) ;
}
2009-04-09 08:28:38 +04:00
/**
append one list to another - expanding list1
this assumes the elements of list2 are const pointers , so we can re - use them
*/
2009-05-03 15:08:46 +04:00
_PUBLIC_ const char * * str_list_append_const ( const char * * list1 ,
const char * * list2 )
2009-04-09 08:28:38 +04:00
{
size_t len1 = str_list_length ( list1 ) ;
size_t len2 = str_list_length ( list2 ) ;
2009-05-03 15:08:46 +04:00
const char * * ret ;
2009-04-09 08:28:38 +04:00
int i ;
2009-05-03 15:08:46 +04:00
ret = talloc_realloc ( NULL , list1 , const char * , len1 + len2 + 1 ) ;
2009-04-09 08:28:38 +04:00
if ( ret = = NULL ) return NULL ;
for ( i = len1 ; i < len1 + len2 ; i + + ) {
ret [ i ] = list2 [ i - len1 ] ;
}
ret [ i ] = NULL ;
return ret ;
}
2011-04-08 06:02:40 +04:00
/**
* Add a string to an array of strings .
*
* num should be a pointer to an integer that holds the current
* number of elements in strings . It will be updated by this function .
*/
_PUBLIC_ bool add_string_to_array ( TALLOC_CTX * mem_ctx ,
const char * str , const char * * * strings , int * num )
{
char * dup_str = talloc_strdup ( mem_ctx , str ) ;
* strings = talloc_realloc ( mem_ctx ,
* strings ,
const char * , ( ( * num ) + 1 ) ) ;
if ( ( * strings = = NULL ) | | ( dup_str = = NULL ) ) {
* num = 0 ;
return false ;
}
( * strings ) [ * num ] = dup_str ;
* num + = 1 ;
return true ;
}
2009-04-09 08:28:38 +04:00
/**
add an entry to a string list
this assumes s will not change
*/
2009-05-03 15:08:46 +04:00
_PUBLIC_ const char * * str_list_add_const ( const char * * list , const char * s )
2009-04-09 08:28:38 +04:00
{
size_t len = str_list_length ( list ) ;
2009-05-03 15:08:46 +04:00
const char * * ret ;
2009-04-09 08:28:38 +04:00
2009-05-03 15:08:46 +04:00
ret = talloc_realloc ( NULL , list , const char * , len + 2 ) ;
2009-04-09 08:28:38 +04:00
if ( ret = = NULL ) return NULL ;
ret [ len ] = s ;
ret [ len + 1 ] = NULL ;
return ret ;
}
/**
copy a string list
this assumes list will not change
*/
2009-05-03 15:08:46 +04:00
_PUBLIC_ const char * * str_list_copy_const ( TALLOC_CTX * mem_ctx ,
const char * * list )
2009-04-09 08:28:38 +04:00
{
int i ;
2009-05-03 15:08:46 +04:00
const char * * ret ;
2009-04-09 08:28:38 +04:00
if ( list = = NULL )
return NULL ;
2009-05-03 15:08:46 +04:00
ret = talloc_array ( mem_ctx , const char * , str_list_length ( list ) + 1 ) ;
2009-04-09 08:28:38 +04:00
if ( ret = = NULL )
return NULL ;
for ( i = 0 ; list & & list [ i ] ; i + + ) {
ret [ i ] = list [ i ] ;
}
ret [ i ] = NULL ;
return ret ;
}
2009-11-25 11:15:39 +03:00
/**
* Needed for making an " unconst " list " const "
*/
_PUBLIC_ const char * * const_str_list ( char * * list )
{
2014-02-26 10:38:07 +04:00
return discard_const_p ( const char * , list ) ;
2009-11-25 11:15:39 +03:00
}
2014-02-24 08:33:57 +04:00
/**
* str_list_make , v3 version . The v4 version does not
* look at quoted strings with embedded blanks , so
* do NOT merge this function please !
*/
# define S_LIST_ABS 16 /* List Allocation Block Size */
char * * str_list_make_v3 ( TALLOC_CTX * mem_ctx , const char * string ,
const char * sep )
{
char * * list ;
const char * str ;
char * s , * tok ;
int num , lsize ;
if ( ! string | | ! * string )
return NULL ;
list = talloc_array ( mem_ctx , char * , S_LIST_ABS + 1 ) ;
if ( list = = NULL ) {
return NULL ;
}
lsize = S_LIST_ABS ;
s = talloc_strdup ( list , string ) ;
if ( s = = NULL ) {
DEBUG ( 0 , ( " str_list_make: Unable to allocate memory " ) ) ;
TALLOC_FREE ( list ) ;
return NULL ;
}
if ( ! sep ) sep = LIST_SEP ;
num = 0 ;
str = s ;
while ( next_token_talloc ( list , & str , & tok , sep ) ) {
if ( num = = lsize ) {
char * * tmp ;
lsize + = S_LIST_ABS ;
tmp = talloc_realloc ( mem_ctx , list , char * ,
lsize + 1 ) ;
if ( tmp = = NULL ) {
DEBUG ( 0 , ( " str_list_make: "
" Unable to allocate memory " ) ) ;
TALLOC_FREE ( list ) ;
return NULL ;
}
list = tmp ;
memset ( & list [ num ] , 0 ,
( ( sizeof ( char * ) ) * ( S_LIST_ABS + 1 ) ) ) ;
}
list [ num ] = tok ;
num + = 1 ;
}
list [ num ] = NULL ;
TALLOC_FREE ( s ) ;
return list ;
}