1/* GNU gettext - internationalization aids
2   Copyright (C) 1995, 1998, 2000-2004 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 2, or (at your option)
9   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, write to the Free Software Foundation,
18   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20#ifdef HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24/* Specification.  */
25#include "str-list.h"
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "xalloc.h"
32
33
34/* Initialize an empty list of strings.  */
35void
36string_list_init (string_list_ty *slp)
37{
38  slp->item = NULL;
39  slp->nitems = 0;
40  slp->nitems_max = 0;
41}
42
43
44/* Return a fresh, empty list of strings.  */
45string_list_ty *
46string_list_alloc ()
47{
48  string_list_ty *slp;
49
50  slp = (string_list_ty *) xmalloc (sizeof (*slp));
51  slp->item = NULL;
52  slp->nitems = 0;
53  slp->nitems_max = 0;
54
55  return slp;
56}
57
58
59/* Append a single string to the end of a list of strings.  */
60void
61string_list_append (string_list_ty *slp, const char *s)
62{
63  /* Grow the list.  */
64  if (slp->nitems >= slp->nitems_max)
65    {
66      size_t nbytes;
67
68      slp->nitems_max = slp->nitems_max * 2 + 4;
69      nbytes = slp->nitems_max * sizeof (slp->item[0]);
70      slp->item = (const char **) xrealloc (slp->item, nbytes);
71    }
72
73  /* Add a copy of the string to the end of the list.  */
74  slp->item[slp->nitems++] = xstrdup (s);
75}
76
77
78/* Append a single string to the end of a list of strings, unless it is
79   already contained in the list.  */
80void
81string_list_append_unique (string_list_ty *slp, const char *s)
82{
83  size_t j;
84
85  /* Do not if the string is already in the list.  */
86  for (j = 0; j < slp->nitems; ++j)
87    if (strcmp (slp->item[j], s) == 0)
88      return;
89
90  /* Grow the list.  */
91  if (slp->nitems >= slp->nitems_max)
92    {
93      slp->nitems_max = slp->nitems_max * 2 + 4;
94      slp->item = (const char **) xrealloc (slp->item,
95					    slp->nitems_max
96					    * sizeof (slp->item[0]));
97    }
98
99  /* Add a copy of the string to the end of the list.  */
100  slp->item[slp->nitems++] = xstrdup (s);
101}
102
103
104/* Destroy a list of strings.  */
105void
106string_list_destroy (string_list_ty *slp)
107{
108  size_t j;
109
110  for (j = 0; j < slp->nitems; ++j)
111    free ((char *) slp->item[j]);
112  if (slp->item != NULL)
113    free (slp->item);
114}
115
116
117/* Free a list of strings.  */
118void
119string_list_free (string_list_ty *slp)
120{
121  size_t j;
122
123  for (j = 0; j < slp->nitems; ++j)
124    free ((char *) slp->item[j]);
125  if (slp->item != NULL)
126    free (slp->item);
127  free (slp);
128}
129
130
131/* Return a freshly allocated string obtained by concatenating all the
132   strings in the list.  */
133char *
134string_list_concat (const string_list_ty *slp)
135{
136  size_t len;
137  size_t j;
138  char *result;
139  size_t pos;
140
141  len = 1;
142  for (j = 0; j < slp->nitems; ++j)
143    len += strlen (slp->item[j]);
144  result = (char *) xmalloc (len);
145  pos = 0;
146  for (j = 0; j < slp->nitems; ++j)
147    {
148      len = strlen (slp->item[j]);
149      memcpy (result + pos, slp->item[j], len);
150      pos += len;
151    }
152  result[pos] = '\0';
153  return result;
154}
155
156
157/* Return a freshly allocated string obtained by concatenating all the
158   strings in the list, and destroy the list.  */
159char *
160string_list_concat_destroy (string_list_ty *slp)
161{
162  char *result;
163
164  /* Optimize the most frequent case.  */
165  if (slp->nitems == 1)
166    {
167      result = (char *) slp->item[0];
168      free (slp->item);
169    }
170  else
171    {
172      result = string_list_concat (slp);
173      string_list_destroy (slp);
174    }
175  return result;
176}
177
178
179/* Return a freshly allocated string obtained by concatenating all the
180   strings in the list, separated by the separator character, terminated
181   by the terminator character.  The terminator character is not added if
182   drop_redundant_terminator is true and the last string already ends with
183   the terminator. */
184char *
185string_list_join (const string_list_ty *slp, char separator,
186		  char terminator, bool drop_redundant_terminator)
187{
188  size_t len;
189  size_t j;
190  char *result;
191  size_t pos;
192
193  len = 1;
194  for (j = 0; j < slp->nitems; ++j)
195    {
196      if (separator && j > 0)
197	++len;
198      len += strlen (slp->item[j]);
199    }
200  if (terminator)
201    ++len;
202  result = (char *) xmalloc (len);
203  pos = 0;
204  for (j = 0; j < slp->nitems; ++j)
205    {
206      if (separator && j > 0)
207	result[pos++] = separator;
208      len = strlen (slp->item[j]);
209      memcpy (result + pos, slp->item[j], len);
210      pos += len;
211    }
212  if (terminator
213      && !(drop_redundant_terminator
214	   && slp->nitems > 0
215	   && (len = strlen (slp->item[slp->nitems - 1])) > 0
216	   && slp->item[slp->nitems - 1][len - 1] == terminator))
217    result[pos++] = terminator;
218  result[pos] = '\0';
219  return result;
220}
221
222
223/* Return 1 if s is contained in the list of strings, 0 otherwise.  */
224bool
225string_list_member (const string_list_ty *slp, const char *s)
226{
227  size_t j;
228
229  for (j = 0; j < slp->nitems; ++j)
230    if (strcmp (slp->item[j], s) == 0)
231      return true;
232  return false;
233}
234