1 /* Copyright (C) 2002 by  Red Hat, Incorporated. All rights reserved.
2  *
3  * Permission to use, copy, modify, and distribute this software
4  * is freely granted, provided that this notice is preserved.
5  */
6 
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <argz.h>
12 
13 #include "buf_findstr.h"
14 
15 error_t
16 _DEFUN (argz_replace, (argz, argz_len, str, with, replace_count),
17        char **argz _AND
18        size_t *argz_len _AND
19        const char *str _AND
20        const char *with _AND
21        unsigned *replace_count)
22 {
23   const int str_len = strlen(str);
24   const int with_len = strlen(with);
25   const int len_diff = with_len - str_len;
26 
27   char *buf_iter = *argz;
28   size_t buf_len = *argz_len;
29   char *last_iter = NULL;
30   char *new_argz = NULL;
31   size_t new_argz_len = 0;
32   char *new_argz_iter = NULL;
33 
34   *replace_count = 0;
35   new_argz_len = *argz_len;
36 
37   while(buf_len)
38     {
39       if(_buf_findstr(str, &buf_iter, &buf_len))
40         {
41           *replace_count += 1;
42           new_argz_len += len_diff;
43         }
44     }
45 
46   if (*replace_count)
47     {
48       new_argz = (char *)malloc(new_argz_len);
49 
50       buf_iter = *argz;
51       buf_len = *argz_len;
52       last_iter = buf_iter;
53       new_argz_iter = new_argz;
54 
55       while(buf_len)
56         {
57           if (_buf_findstr(str, &buf_iter, &buf_len))
58             {
59               /* copy everything up to, but not including str, from old argz to
60                  new argz. */
61               memcpy(new_argz_iter, last_iter, buf_iter - last_iter - str_len);
62               new_argz_iter += (buf_iter - last_iter - str_len);
63               /* copy replacement string. */
64               memcpy(new_argz_iter, with, with_len);
65               new_argz_iter += with_len;
66               last_iter = buf_iter;
67             }
68         }
69       /* copy everything after last occurrence of str. */
70       memcpy(new_argz_iter, last_iter, *argz + *argz_len - last_iter);
71 
72       /* reallocate argz, and copy over the new value. */
73       if(!(*argz = (char *)realloc(*argz, new_argz_len)))
74         return ENOMEM;
75 
76       memcpy(*argz, new_argz, new_argz_len);
77       *argz_len = new_argz_len;
78 
79       if (*argz_len == 0)
80         {
81           free(*argz);
82           *argz = NULL;
83         }
84       free(new_argz);
85     }
86 
87   return 0;
88 }
89