1/* stringlist.c - functions to handle a generic `list of strings' structure */
2
3/* Copyright (C) 2000-2002 Free Software Foundation, Inc.
4
5   This file is part of GNU Bash, the Bourne Again SHell.
6
7   Bash is free software; you can redistribute it and/or modify it under
8   the terms of the GNU General Public License as published by the Free
9   Software Foundation; either version 2, or (at your option) any later
10   version.
11
12   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or
14   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15   for more details.
16
17   You should have received a copy of the GNU General Public License along
18   with Bash; see the file COPYING.  If not, write to the Free Software
19   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21#include <config.h>
22
23#if defined (HAVE_UNISTD_H)
24#  include <unistd.h>
25#endif
26
27#include <stdio.h>
28#include <bashansi.h>
29
30#include "shell.h"
31
32#ifdef STRDUP
33#  undef STRDUP
34#endif
35#define STRDUP(x)	((x) ? savestring (x) : (char *)NULL)
36
37/* Allocate a new STRINGLIST, with room for N strings. */
38
39STRINGLIST *
40strlist_create (n)
41     int n;
42{
43  STRINGLIST *ret;
44  register int i;
45
46  ret = (STRINGLIST *)xmalloc (sizeof (STRINGLIST));
47  if (n)
48    {
49      ret->list = strvec_create (n+1);
50      ret->list_size = n;
51      for (i = 0; i < n; i++)
52	ret->list[i] = (char *)NULL;
53    }
54  else
55    {
56      ret->list = (char **)NULL;
57      ret->list_size = 0;
58    }
59  ret->list_len = 0;
60  return ret;
61}
62
63STRINGLIST *
64strlist_resize (sl, n)
65     STRINGLIST *sl;
66     int n;
67{
68  register int i;
69
70  if (sl == 0)
71    return (sl = strlist_create (n));
72
73  if (n > sl->list_size)
74    {
75      sl->list = strvec_resize (sl->list, n + 1);
76      for (i = sl->list_size; i <= n; i++)
77	sl->list[i] = (char *)NULL;
78      sl->list_size = n;
79    }
80  return sl;
81}
82
83void
84strlist_flush (sl)
85     STRINGLIST *sl;
86{
87  if (sl == 0 || sl->list == 0)
88    return;
89  strvec_flush (sl->list);
90  sl->list_len = 0;
91}
92
93void
94strlist_dispose (sl)
95     STRINGLIST *sl;
96{
97  if (sl == 0)
98    return;
99  if (sl->list)
100    strvec_dispose (sl->list);
101  free (sl);
102}
103
104int
105strlist_remove (sl, s)
106     STRINGLIST *sl;
107     char *s;
108{
109  int r;
110
111  if (sl == 0 || sl->list == 0 || sl->list_len == 0)
112    return 0;
113
114  r = strvec_remove (sl->list, s);
115  if (r)
116    sl->list_len--;
117  return r;
118}
119
120STRINGLIST *
121strlist_copy (sl)
122     STRINGLIST *sl;
123{
124  STRINGLIST *new;
125  register int i;
126
127  if (sl == 0)
128    return ((STRINGLIST *)0);
129  new = strlist_create (sl->list_size);
130  /* I'd like to use strvec_copy, but that doesn't copy everything. */
131  if (sl->list)
132    {
133      for (i = 0; i < sl->list_size; i++)
134	new->list[i] = STRDUP (sl->list[i]);
135    }
136  new->list_size = sl->list_size;
137  new->list_len = sl->list_len;
138  /* just being careful */
139  if (new->list)
140    new->list[new->list_len] = (char *)NULL;
141  return new;
142}
143
144/* Return a new STRINGLIST with everything from M1 and M2. */
145
146STRINGLIST *
147strlist_merge (m1, m2)
148     STRINGLIST *m1, *m2;
149{
150  STRINGLIST *sl;
151  int i, n, l1, l2;
152
153  l1 = m1 ? m1->list_len : 0;
154  l2 = m2 ? m2->list_len : 0;
155
156  sl = strlist_create (l1 + l2 + 1);
157  for (i = n = 0; i < l1; i++, n++)
158    sl->list[n] = STRDUP (m1->list[i]);
159  for (i = 0; i < l2; i++, n++)
160    sl->list[n] = STRDUP (m2->list[i]);
161  sl->list_len = n;
162  sl->list[n] = (char *)NULL;
163  return (sl);
164}
165
166/* Make STRINGLIST M1 contain everything in M1 and M2. */
167STRINGLIST *
168strlist_append (m1, m2)
169     STRINGLIST *m1, *m2;
170{
171  register int i, n, len1, len2;
172
173  if (m1 == 0)
174    return (m2 ? strlist_copy (m2) : (STRINGLIST *)0);
175
176  len1 = m1->list_len;
177  len2 = m2 ? m2->list_len : 0;
178
179  if (len2)
180    {
181      m1 = strlist_resize (m1, len1 + len2 + 1);
182      for (i = 0, n = len1; i < len2; i++, n++)
183	m1->list[n] = STRDUP (m2->list[i]);
184      m1->list[n] = (char *)NULL;
185      m1->list_len = n;
186    }
187
188  return m1;
189}
190
191STRINGLIST *
192strlist_prefix_suffix (sl, prefix, suffix)
193     STRINGLIST *sl;
194     char *prefix, *suffix;
195{
196  int plen, slen, tlen, llen, i;
197  char *t;
198
199  if (sl == 0 || sl->list == 0 || sl->list_len == 0)
200    return sl;
201
202  plen = STRLEN (prefix);
203  slen = STRLEN (suffix);
204
205  if (plen == 0 && slen == 0)
206    return (sl);
207
208  for (i = 0; i < sl->list_len; i++)
209    {
210      llen = STRLEN (sl->list[i]);
211      tlen = plen + llen + slen + 1;
212      t = (char *)xmalloc (tlen + 1);
213      if (plen)
214	strcpy (t, prefix);
215      strcpy (t + plen, sl->list[i]);
216      if (slen)
217	strcpy (t + plen + llen, suffix);
218      free (sl->list[i]);
219      sl->list[i] = t;
220    }
221
222  return (sl);
223}
224
225void
226strlist_print (sl, prefix)
227     STRINGLIST *sl;
228     char *prefix;
229{
230  register int i;
231
232  if (sl == 0)
233    return;
234  for (i = 0; i < sl->list_len; i++)
235    printf ("%s%s\n", prefix ? prefix : "", sl->list[i]);
236}
237
238void
239strlist_walk (sl, func)
240     STRINGLIST *sl;
241     sh_strlist_map_func_t *func;
242{
243  register int i;
244
245  if (sl == 0)
246    return;
247  for (i = 0; i < sl->list_len; i++)
248    if ((*func)(sl->list[i]) < 0)
249      break;
250}
251
252void
253strlist_sort (sl)
254     STRINGLIST *sl;
255{
256  if (sl == 0 || sl->list_len == 0 || sl->list == 0)
257    return;
258  strvec_sort (sl->list);
259}
260
261STRINGLIST *
262strlist_from_word_list (list, alloc, starting_index, ip)
263     WORD_LIST *list;
264     int alloc, starting_index, *ip;
265{
266  STRINGLIST *ret;
267  int slen, len;
268
269  if (list == 0)
270    {
271      if (ip)
272        *ip = 0;
273      return ((STRINGLIST *)0);
274    }
275  slen = list_length (list);
276  ret = (STRINGLIST *)xmalloc (sizeof (STRINGLIST));
277  ret->list = strvec_from_word_list (list, alloc, starting_index, &len);
278  ret->list_size = slen + starting_index;
279  ret->list_len = len;
280  if (ip)
281    *ip = len;
282  return ret;
283}
284
285WORD_LIST *
286strlist_to_word_list (sl, alloc, starting_index)
287     STRINGLIST *sl;
288     int alloc, starting_index;
289{
290  WORD_LIST *list;
291
292  if (sl == 0 || sl->list == 0)
293    return ((WORD_LIST *)NULL);
294
295  list = strvec_to_word_list (sl->list, alloc, starting_index);
296  return list;
297}
298