mirror of
https://github.com/samba-team/samba.git
synced 2024-12-25 23:21:54 +03:00
cafd60732b
In changing str_list_make to str_list_make_v3, the list can be NULL. These are some additional checks to try to avoid any problems. Where lists are dealt with, they typically check both if the list is empty or the list is NULL. Change-Id: I9012c31dbd9832ce877728bcb3346616ba64c4c5 Signed-off-by: Garming Sam <garming@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Nadezhda Ivanova <nivanova@samba.org>
591 lines
11 KiB
C
591 lines
11 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
|
|
Copyright (C) Andrew Tridgell 2005
|
|
Copyright (C) Jelmer Vernooij 2005
|
|
|
|
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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "system/locale.h"
|
|
#include "lib/util/tsort.h"
|
|
|
|
#undef strcasecmp
|
|
|
|
/**
|
|
* @file
|
|
* @brief String list manipulation
|
|
*/
|
|
|
|
/**
|
|
build an empty (only NULL terminated) list of strings (for expansion with str_list_add() etc)
|
|
*/
|
|
_PUBLIC_ char **str_list_make_empty(TALLOC_CTX *mem_ctx)
|
|
{
|
|
char **ret = NULL;
|
|
|
|
ret = talloc_array(mem_ctx, char *, 1);
|
|
if (ret == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
ret[0] = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
place the only element 'entry' into a new, NULL terminated string list
|
|
*/
|
|
_PUBLIC_ char **str_list_make_single(TALLOC_CTX *mem_ctx, const char *entry)
|
|
{
|
|
char **ret = NULL;
|
|
|
|
ret = talloc_array(mem_ctx, char *, 2);
|
|
if (ret == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
ret[0] = talloc_strdup(ret, entry);
|
|
if (!ret[0]) {
|
|
talloc_free(ret);
|
|
return NULL;
|
|
}
|
|
ret[1] = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
build a null terminated list of strings from a input string and a
|
|
separator list. The separator list must contain characters less than
|
|
or equal to 0x2f for this to work correctly on multi-byte strings
|
|
*/
|
|
_PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
|
|
{
|
|
int num_elements = 0;
|
|
char **ret = NULL;
|
|
|
|
if (sep == NULL) {
|
|
sep = LIST_SEP;
|
|
}
|
|
|
|
ret = talloc_array(mem_ctx, char *, 1);
|
|
if (ret == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
while (string && *string) {
|
|
size_t len = strcspn(string, sep);
|
|
char **ret2;
|
|
|
|
if (len == 0) {
|
|
string += strspn(string, sep);
|
|
continue;
|
|
}
|
|
|
|
ret2 = talloc_realloc(mem_ctx, ret, char *,
|
|
num_elements+2);
|
|
if (ret2 == NULL) {
|
|
talloc_free(ret);
|
|
return NULL;
|
|
}
|
|
ret = ret2;
|
|
|
|
ret[num_elements] = talloc_strndup(ret, string, len);
|
|
if (ret[num_elements] == NULL) {
|
|
talloc_free(ret);
|
|
return NULL;
|
|
}
|
|
|
|
num_elements++;
|
|
string += len;
|
|
}
|
|
|
|
ret[num_elements] = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* build a null terminated list of strings from an argv-like input string
|
|
* Entries are separated by spaces and can be enclosed by quotes.
|
|
* Does NOT support escaping
|
|
*/
|
|
_PUBLIC_ char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
|
|
{
|
|
int num_elements = 0;
|
|
char **ret = NULL;
|
|
|
|
ret = talloc_array(mem_ctx, char *, 1);
|
|
if (ret == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (sep == NULL)
|
|
sep = " \t\n\r";
|
|
|
|
while (string && *string) {
|
|
size_t len = strcspn(string, sep);
|
|
char *element;
|
|
char **ret2;
|
|
|
|
if (len == 0) {
|
|
string += strspn(string, sep);
|
|
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;
|
|
}
|
|
|
|
ret2 = talloc_realloc(mem_ctx, ret, char *, num_elements+2);
|
|
if (ret2 == NULL) {
|
|
talloc_free(ret);
|
|
return NULL;
|
|
}
|
|
ret = ret2;
|
|
|
|
ret[num_elements] = element;
|
|
|
|
num_elements++;
|
|
}
|
|
|
|
ret[num_elements] = NULL;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
/**
|
|
* join a list back to one string
|
|
*/
|
|
_PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char separator)
|
|
{
|
|
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++) {
|
|
ret = talloc_asprintf_append_buffer(ret, "%c%s", separator, list[i]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/** join a list back to one (shell-like) string; entries
|
|
* separated by spaces, using quotes where necessary */
|
|
_PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
|
|
{
|
|
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)
|
|
ret = talloc_asprintf_append_buffer(ret, "%c\"%s\"", sep, list[i]);
|
|
else
|
|
ret = talloc_asprintf_append_buffer(ret, "%c%s", sep, list[i]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
return the number of elements in a string list
|
|
*/
|
|
_PUBLIC_ size_t str_list_length(const char * const *list)
|
|
{
|
|
size_t ret;
|
|
for (ret=0;list && list[ret];ret++) /* noop */ ;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
copy a string list
|
|
*/
|
|
_PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
|
|
{
|
|
int i;
|
|
char **ret;
|
|
|
|
if (list == NULL)
|
|
return NULL;
|
|
|
|
ret = talloc_array(mem_ctx, char *, str_list_length(list)+1);
|
|
if (ret == NULL)
|
|
return NULL;
|
|
|
|
for (i=0;list && list[i];i++) {
|
|
ret[i] = talloc_strdup(ret, list[i]);
|
|
if (ret[i] == NULL) {
|
|
talloc_free(ret);
|
|
return NULL;
|
|
}
|
|
}
|
|
ret[i] = NULL;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
Return true if all the elements of the list match exactly.
|
|
*/
|
|
_PUBLIC_ bool str_list_equal(const char * const *list1,
|
|
const char * const *list2)
|
|
{
|
|
int i;
|
|
|
|
if (list1 == NULL || list2 == NULL) {
|
|
return (list1 == list2);
|
|
}
|
|
|
|
for (i=0;list1[i] && list2[i];i++) {
|
|
if (strcmp(list1[i], list2[i]) != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
if (list1[i] || list2[i]) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
add an entry to a string list
|
|
*/
|
|
_PUBLIC_ const char **str_list_add(const char **list, const char *s)
|
|
{
|
|
size_t len = str_list_length(list);
|
|
const char **ret;
|
|
|
|
ret = talloc_realloc(NULL, list, const char *, len+2);
|
|
if (ret == NULL) return NULL;
|
|
|
|
ret[len] = talloc_strdup(ret, s);
|
|
if (ret[len] == NULL) return NULL;
|
|
|
|
ret[len+1] = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
remove an entry from a string list
|
|
*/
|
|
_PUBLIC_ void str_list_remove(const char **list, const char *s)
|
|
{
|
|
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];
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
return true if a string is in a list
|
|
*/
|
|
_PUBLIC_ bool str_list_check(const char **list, const char *s)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; list != NULL && list[i] != NULL; i++) {
|
|
if (strcmp(list[i], s) == 0) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
return true if a string is in a list, case insensitively
|
|
*/
|
|
_PUBLIC_ bool str_list_check_ci(const char **list, const char *s)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; list != NULL && list[i] != NULL; i++) {
|
|
if (strcasecmp(list[i], s) == 0) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
append one list to another - expanding list1
|
|
*/
|
|
_PUBLIC_ const char **str_list_append(const char **list1,
|
|
const char * const *list2)
|
|
{
|
|
size_t len1 = str_list_length(list1);
|
|
size_t len2 = str_list_length(list2);
|
|
const char **ret;
|
|
int i;
|
|
|
|
ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
|
|
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;
|
|
}
|
|
|
|
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
|
|
*/
|
|
_PUBLIC_ const char **str_list_unique(const char **list)
|
|
{
|
|
size_t len = str_list_length(list);
|
|
const char **list2;
|
|
int i, j;
|
|
if (len < 2) {
|
|
return list;
|
|
}
|
|
list2 = (const char **)talloc_memdup(list, list,
|
|
sizeof(list[0])*(len+1));
|
|
TYPESAFE_QSORT(list2, len, list_cmp);
|
|
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;
|
|
list = talloc_realloc(NULL, list, const char *, j + 1);
|
|
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"));
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
append one list to another - expanding list1
|
|
this assumes the elements of list2 are const pointers, so we can re-use them
|
|
*/
|
|
_PUBLIC_ const char **str_list_append_const(const char **list1,
|
|
const char **list2)
|
|
{
|
|
size_t len1 = str_list_length(list1);
|
|
size_t len2 = str_list_length(list2);
|
|
const char **ret;
|
|
int i;
|
|
|
|
ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
|
|
if (ret == NULL) return NULL;
|
|
|
|
for (i=len1;i<len1+len2;i++) {
|
|
ret[i] = list2[i-len1];
|
|
}
|
|
ret[i] = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
add an entry to a string list
|
|
this assumes s will not change
|
|
*/
|
|
_PUBLIC_ const char **str_list_add_const(const char **list, const char *s)
|
|
{
|
|
size_t len = str_list_length(list);
|
|
const char **ret;
|
|
|
|
ret = talloc_realloc(NULL, list, const char *, len+2);
|
|
if (ret == NULL) return NULL;
|
|
|
|
ret[len] = s;
|
|
ret[len+1] = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
copy a string list
|
|
this assumes list will not change
|
|
*/
|
|
_PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
|
|
const char **list)
|
|
{
|
|
int i;
|
|
const char **ret;
|
|
|
|
if (list == NULL)
|
|
return NULL;
|
|
|
|
ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
|
|
if (ret == NULL)
|
|
return NULL;
|
|
|
|
for (i=0;list && list[i];i++) {
|
|
ret[i] = list[i];
|
|
}
|
|
ret[i] = NULL;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Needed for making an "unconst" list "const"
|
|
*/
|
|
_PUBLIC_ const char **const_str_list(char **list)
|
|
{
|
|
return discard_const_p(const char *, list);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|