| /* |
| * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. |
| * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. |
| * |
| * This file is part of LVM2. |
| * |
| * This copyrighted material is made available to anyone wishing to use, |
| * modify, copy, or redistribute it subject to the terms and conditions |
| * of the GNU Lesser General Public License v.2.1. |
| * |
| * You should have received a copy of the GNU Lesser General Public License |
| * along with this program; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include "lib.h" |
| #include "str_list.h" |
| |
| struct dm_list *str_list_create(struct dm_pool *mem) |
| { |
| struct dm_list *sl; |
| |
| if (!(sl = dm_pool_alloc(mem, sizeof(struct dm_list)))) { |
| log_errno(ENOMEM, "str_list allocation failed"); |
| return NULL; |
| } |
| |
| dm_list_init(sl); |
| |
| return sl; |
| } |
| |
| static int _str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str, int as_first) |
| { |
| struct dm_str_list *sln; |
| |
| if (!str) |
| return_0; |
| |
| if (!(sln = dm_pool_alloc(mem, sizeof(*sln)))) |
| return_0; |
| |
| sln->str = str; |
| if (as_first) |
| dm_list_add_h(sll, &sln->list); |
| else |
| dm_list_add(sll, &sln->list); |
| |
| return 1; |
| } |
| |
| int str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str) |
| { |
| return _str_list_add_no_dup_check(mem, sll, str, 0); |
| } |
| |
| int str_list_add_h_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str) |
| { |
| return _str_list_add_no_dup_check(mem, sll, str, 1); |
| } |
| |
| int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str) |
| { |
| if (!str) |
| return_0; |
| |
| /* Already in list? */ |
| if (str_list_match_item(sll, str)) |
| return 1; |
| |
| return str_list_add_no_dup_check(mem, sll, str); |
| } |
| |
| /* Add contents of sll2 to sll */ |
| int str_list_add_list(struct dm_pool *mem, struct dm_list *sll, struct dm_list *sll2) |
| { |
| struct dm_str_list *sl; |
| |
| if (!sll2) |
| return_0; |
| |
| dm_list_iterate_items(sl, sll2) |
| if (!str_list_add(mem, sll, sl->str)) |
| return_0; |
| |
| return 1; |
| } |
| |
| void str_list_del(struct dm_list *sll, const char *str) |
| { |
| struct dm_list *slh, *slht; |
| |
| dm_list_iterate_safe(slh, slht, sll) |
| if (!strcmp(str, dm_list_item(slh, struct dm_str_list)->str)) |
| dm_list_del(slh); |
| } |
| |
| void str_list_wipe(struct dm_list *sll) |
| { |
| struct dm_list *slh, *slht; |
| |
| dm_list_iterate_safe(slh, slht, sll) |
| dm_list_del(slh); |
| } |
| |
| int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew, |
| const struct dm_list *sllold) |
| { |
| struct dm_str_list *sl; |
| |
| dm_list_init(sllnew); |
| |
| dm_list_iterate_items(sl, sllold) { |
| if (!str_list_add(mem, sllnew, dm_pool_strdup(mem, sl->str))) |
| return_0; |
| } |
| |
| return 1; |
| } |
| |
| /* |
| * Is item on list? |
| */ |
| int str_list_match_item(const struct dm_list *sll, const char *str) |
| { |
| struct dm_str_list *sl; |
| |
| dm_list_iterate_items(sl, sll) |
| if (!strcmp(str, sl->str)) |
| return 1; |
| |
| return 0; |
| } |
| |
| /* |
| * Is at least one item on both lists? |
| * If tag_matched is non-NULL, it is set to the tag that matched. |
| */ |
| int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2, const char **tag_matched) |
| { |
| struct dm_str_list *sl; |
| |
| dm_list_iterate_items(sl, sll) |
| if (str_list_match_item(sll2, sl->str)) { |
| if (tag_matched) |
| *tag_matched = sl->str; |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Do both lists contain the same set of items? |
| */ |
| int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2) |
| { |
| struct dm_str_list *sl; |
| |
| if (dm_list_size(sll) != dm_list_size(sll2)) |
| return 0; |
| |
| dm_list_iterate_items(sl, sll) |
| if (!str_list_match_item(sll2, sl->str)) |
| return 0; |
| |
| return 1; |
| } |
| |
| char *str_list_to_str(struct dm_pool *mem, const struct dm_list *list, |
| const char *delim) |
| { |
| size_t delim_len = strlen(delim); |
| unsigned list_size = dm_list_size(list); |
| struct dm_str_list *sl; |
| char *str, *p; |
| size_t len = 0; |
| unsigned i = 0; |
| |
| dm_list_iterate_items(sl, list) |
| len += strlen(sl->str); |
| if (list_size > 1) |
| len += ((list_size - 1) * delim_len); |
| |
| str = dm_pool_alloc(mem, len+1); |
| if (!str) { |
| log_error("str_list_to_str: string allocation failed."); |
| return NULL; |
| } |
| str[len] = '\0'; |
| p = str; |
| |
| dm_list_iterate_items(sl, list) { |
| len = strlen(sl->str); |
| memcpy(p, sl->str, len); |
| p += len; |
| |
| if (++i != list_size) { |
| memcpy(p, delim, delim_len); |
| p += delim_len; |
| } |
| } |
| |
| return str; |
| } |
| |
| struct dm_list *str_to_str_list(struct dm_pool *mem, const char *str, |
| const char *delim, int ignore_multiple_delim) |
| { |
| size_t delim_len = strlen(delim); |
| struct dm_list *list; |
| const char *p1, *p2, *next; |
| char *str_item; |
| size_t len; |
| |
| if (!(list = str_list_create(mem))) { |
| log_error("str_to_str_list: string list allocation failed."); |
| return NULL; |
| } |
| |
| p1 = p2 = str; |
| while (*p1) { |
| if (!(p2 = strstr(p1, delim))) |
| next = p2 = str + strlen(str); |
| else |
| next = p2 + delim_len; |
| |
| len = p2 - p1; |
| str_item = dm_pool_alloc(mem, len+1); |
| if (!str_item) { |
| log_error("str_to_str_list: string list item allocation failed."); |
| goto bad; |
| } |
| memcpy(str_item, p1, len); |
| str_item[len] = '\0'; |
| |
| if (!str_list_add_no_dup_check(mem, list, str_item)) |
| goto_bad; |
| |
| if (ignore_multiple_delim) { |
| while (!strncmp(next, delim, delim_len)) |
| next += delim_len; |
| } |
| |
| p1 = next; |
| } |
| |
| return list; |
| bad: |
| dm_pool_free(mem, list); |
| |
| return NULL; |
| } |