Implementation of argp_replace.
[kopensolaris-gnu/glibc.git] / string / argz-replace.c
1 /* String replacement in an argz vector
2    Copyright (C) 1997 Free Software Foundation, Inc.
3    Written by Miles Bader <miles@gnu.ai.mit.edu>
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <stdlib.h>
21 #include <argz.h>
22
23 /* Append BUF, of length BUF_LEN to *TO, of length *TO_LEN, reallocating and
24    updating *TO & *TO_LEN appropriately.  If an allocation error occurs,
25    *TO's old value is freed, and *TO is set to 0.  */
26 static void
27 str_append (char **to, size_t *to_len, const char *buf, const size_t buf_len)
28 {
29   size_t new_len = *to_len + buf_len;
30   char *new_to = realloc (*to, new_len + 1);
31
32   if (new_to)
33     {
34       memcpy (new_to + *to_len, buf, buf_len);
35       new_to[new_len] = '\0';
36       *to = new_to;
37       *to_len = new_len;
38     }
39   else
40     {
41       free (*to);
42       *to = 0;
43     }
44 }
45
46 /* Replace any occurances of the string STR in ARGZ with WITH, reallocating
47    ARGZ as necessary.  If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be
48    incremented by number of replacements performed.  */
49 error_t
50 __argz_replace (char **argz, size_t *argz_len, const char *str, const char *with,
51                 unsigned *replace_count)
52 {
53   error_t err = 0;
54
55   if (str && *str)
56     {
57       char *arg = 0;
58       char *src = *argz;
59       size_t src_len = *argz_len;
60       char *dst = 0;
61       size_t dst_len = 0;
62       int delayed_copy = 1;     /* True while we've avoided copying anything.  */
63       size_t str_len = strlen (str), with_len = strlen (with);
64
65       while (!err && (arg = argz_next (src, src_len, arg)))
66         {
67           char *match = strstr (arg, str);
68           if (match)
69             {
70               char *from = match + str_len;
71               size_t to_len = match - arg;
72               char *to = strndup (arg, to_len);
73
74               while (to && from)
75                 {
76                   str_append (&to, &to_len, with, with_len);
77                   if (to)
78                     {
79                       match = strstr (from, str);
80                       if (match)
81                         {
82                           str_append (&to, &to_len, from, match - from);
83                           from = match + str_len;
84                         }
85                       else
86                         {
87                           str_append (&to, &to_len, from, strlen (from));
88                           from = 0;
89                         }
90                     }
91                 }
92
93               if (to)
94                 {
95                   if (delayed_copy)
96                     /* We avoided copying SRC to DST until we found a match;
97                        now that we've done so, copy everything from the start
98                        of SRC.  */
99                     {
100                       if (arg > src)
101                         err = argz_append (&dst, &dst_len, src, (arg - src));
102                       delayed_copy = 0;
103                     }
104                   if (! err)
105                     err = argz_add (&dst, &dst_len, to);
106                   free (to);
107                 }
108               else
109                 err = ENOMEM;
110
111               if (replace_count)
112                 (*replace_count)++;
113             }
114           else if (! delayed_copy)
115             err = argz_add (&dst, &dst_len, arg);
116         }
117
118       if (! err)
119         {
120           if (! delayed_copy)
121             /* We never found any instances of str.  */
122             {
123               if (src)
124                 free (src);
125               *argz = dst;
126               *argz_len = dst_len;
127             }
128         }
129       else if (dst_len > 0)
130         free (dst);
131     }
132
133   return err;
134 }
135 weak_alias (__argz_replace, argz_replace)