1/* GNU gettext - internationalization aids 2 Copyright (C) 1995, 1998, 2000-2004, 2006 Free Software Foundation, Inc. 3 4 This file was written by Peter Miller <millerp@canb.auug.org.au> 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19#ifdef HAVE_CONFIG_H 20# include "config.h" 21#endif 22 23/* Specification. */ 24#include "str-list.h" 25 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29 30#include "xalloc.h" 31 32 33/* Initialize an empty list of strings. */ 34void 35string_list_init (string_list_ty *slp) 36{ 37 slp->item = NULL; 38 slp->nitems = 0; 39 slp->nitems_max = 0; 40} 41 42 43/* Return a fresh, empty list of strings. */ 44string_list_ty * 45string_list_alloc () 46{ 47 string_list_ty *slp; 48 49 slp = XMALLOC (string_list_ty); 50 slp->item = NULL; 51 slp->nitems = 0; 52 slp->nitems_max = 0; 53 54 return slp; 55} 56 57 58/* Append a single string to the end of a list of strings. */ 59void 60string_list_append (string_list_ty *slp, const char *s) 61{ 62 /* Grow the list. */ 63 if (slp->nitems >= slp->nitems_max) 64 { 65 size_t nbytes; 66 67 slp->nitems_max = slp->nitems_max * 2 + 4; 68 nbytes = slp->nitems_max * sizeof (slp->item[0]); 69 slp->item = (const char **) xrealloc (slp->item, nbytes); 70 } 71 72 /* Add a copy of the string to the end of the list. */ 73 slp->item[slp->nitems++] = xstrdup (s); 74} 75 76 77/* Append a single string to the end of a list of strings, unless it is 78 already contained in the list. */ 79void 80string_list_append_unique (string_list_ty *slp, const char *s) 81{ 82 size_t j; 83 84 /* Do not if the string is already in the list. */ 85 for (j = 0; j < slp->nitems; ++j) 86 if (strcmp (slp->item[j], s) == 0) 87 return; 88 89 /* Grow the list. */ 90 if (slp->nitems >= slp->nitems_max) 91 { 92 slp->nitems_max = slp->nitems_max * 2 + 4; 93 slp->item = (const char **) xrealloc (slp->item, 94 slp->nitems_max 95 * sizeof (slp->item[0])); 96 } 97 98 /* Add a copy of the string to the end of the list. */ 99 slp->item[slp->nitems++] = xstrdup (s); 100} 101 102 103/* Destroy a list of strings. */ 104void 105string_list_destroy (string_list_ty *slp) 106{ 107 size_t j; 108 109 for (j = 0; j < slp->nitems; ++j) 110 free ((char *) slp->item[j]); 111 if (slp->item != NULL) 112 free (slp->item); 113} 114 115 116/* Free a list of strings. */ 117void 118string_list_free (string_list_ty *slp) 119{ 120 size_t j; 121 122 for (j = 0; j < slp->nitems; ++j) 123 free ((char *) slp->item[j]); 124 if (slp->item != NULL) 125 free (slp->item); 126 free (slp); 127} 128 129 130/* Return a freshly allocated string obtained by concatenating all the 131 strings in the list. */ 132char * 133string_list_concat (const string_list_ty *slp) 134{ 135 size_t len; 136 size_t j; 137 char *result; 138 size_t pos; 139 140 len = 1; 141 for (j = 0; j < slp->nitems; ++j) 142 len += strlen (slp->item[j]); 143 result = XNMALLOC (len, char); 144 pos = 0; 145 for (j = 0; j < slp->nitems; ++j) 146 { 147 len = strlen (slp->item[j]); 148 memcpy (result + pos, slp->item[j], len); 149 pos += len; 150 } 151 result[pos] = '\0'; 152 return result; 153} 154 155 156/* Return a freshly allocated string obtained by concatenating all the 157 strings in the list, and destroy the list. */ 158char * 159string_list_concat_destroy (string_list_ty *slp) 160{ 161 char *result; 162 163 /* Optimize the most frequent case. */ 164 if (slp->nitems == 1) 165 { 166 result = (char *) slp->item[0]; 167 free (slp->item); 168 } 169 else 170 { 171 result = string_list_concat (slp); 172 string_list_destroy (slp); 173 } 174 return result; 175} 176 177 178/* Return a freshly allocated string obtained by concatenating all the 179 strings in the list, separated by the separator character, terminated 180 by the terminator character. The terminator character is not added if 181 drop_redundant_terminator is true and the last string already ends with 182 the terminator. */ 183char * 184string_list_join (const string_list_ty *slp, char separator, 185 char terminator, bool drop_redundant_terminator) 186{ 187 size_t len; 188 size_t j; 189 char *result; 190 size_t pos; 191 192 len = 1; 193 for (j = 0; j < slp->nitems; ++j) 194 { 195 if (separator && j > 0) 196 ++len; 197 len += strlen (slp->item[j]); 198 } 199 if (terminator) 200 ++len; 201 result = XNMALLOC (len, char); 202 pos = 0; 203 for (j = 0; j < slp->nitems; ++j) 204 { 205 if (separator && j > 0) 206 result[pos++] = separator; 207 len = strlen (slp->item[j]); 208 memcpy (result + pos, slp->item[j], len); 209 pos += len; 210 } 211 if (terminator 212 && !(drop_redundant_terminator 213 && slp->nitems > 0 214 && (len = strlen (slp->item[slp->nitems - 1])) > 0 215 && slp->item[slp->nitems - 1][len - 1] == terminator)) 216 result[pos++] = terminator; 217 result[pos] = '\0'; 218 return result; 219} 220 221 222/* Return 1 if s is contained in the list of strings, 0 otherwise. */ 223bool 224string_list_member (const string_list_ty *slp, const char *s) 225{ 226 size_t j; 227 228 for (j = 0; j < slp->nitems; ++j) 229 if (strcmp (slp->item[j], s) == 0) 230 return true; 231 return false; 232} 233