Merge remote-tracking branch 'github/pr/2451' into collectd-5.6
[collectd.git] / src / daemon / utils_subst.c
1 /**
2  * collectd - src/utils_subst.c
3  * Copyright (C) 2008       Sebastian Harl
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Sebastian "tokkee" Harl <sh at tokkee.org>
25  **/
26
27 /*
28  * This module provides functions for string substitution.
29  */
30
31 #include "collectd.h"
32
33 #include "common.h"
34 #include "utils_subst.h"
35
36 char *subst(char *buf, size_t buflen, const char *string, size_t off1,
37             size_t off2, const char *replacement) {
38   char *out = buf;
39
40   char const *front;
41   char const *back;
42   size_t front_len;
43   size_t replacement_len;
44   size_t back_len;
45
46   if ((NULL == buf) || (0 == buflen) || (NULL == string) ||
47       (NULL == replacement))
48     return NULL;
49
50   size_t string_len = strlen(string);
51   if ((off1 > string_len) || (off2 > string_len) || (off1 > off2))
52     return NULL;
53
54   front = string;
55   back = string + off2;
56   front_len = off1;
57   replacement_len = strlen(replacement);
58   back_len = strlen(back);
59
60   if (front_len >= buflen) {
61     front_len = buflen - 1;
62     replacement_len = 0;
63     back_len = 0;
64   } else if ((front_len + replacement_len) >= buflen) {
65     replacement_len = buflen - (front_len + 1);
66     back_len = 0;
67   } else if ((front_len + replacement_len + back_len) >= buflen) {
68     back_len = buflen - (front_len + replacement_len + 1);
69   } else {
70     buflen = front_len + replacement_len + back_len + 1;
71   }
72   assert((front_len + replacement_len + back_len) == (buflen - 1));
73
74   if (front_len != 0) {
75     sstrncpy(out, front, front_len + 1);
76     out += front_len;
77   }
78
79   if (replacement_len != 0) {
80     sstrncpy(out, replacement, replacement_len + 1);
81     out += replacement_len;
82   }
83
84   if (back_len != 0) {
85     sstrncpy(out, back, back_len + 1);
86     out += back_len;
87   }
88
89   out[0] = 0;
90   return buf;
91 } /* subst */
92
93 char *asubst(const char *string, int off1, int off2, const char *replacement) {
94   char *buf;
95   int len;
96
97   char *ret;
98
99   if ((NULL == string) || (0 > off1) || (0 > off2) || (off1 > off2) ||
100       (NULL == replacement))
101     return NULL;
102
103   len = off1 + strlen(replacement) + strlen(string) - off2 + 1;
104
105   buf = malloc(len);
106   if (NULL == buf)
107     return NULL;
108
109   ret = subst(buf, len, string, off1, off2, replacement);
110   if (NULL == ret)
111     free(buf);
112   return ret;
113 } /* asubst */
114
115 char *subst_string(char *buf, size_t buflen, const char *string,
116                    const char *needle, const char *replacement) {
117   size_t needle_len;
118   size_t i;
119
120   if ((buf == NULL) || (string == NULL) || (needle == NULL) ||
121       (replacement == NULL))
122     return (NULL);
123
124   needle_len = strlen(needle);
125   sstrncpy(buf, string, buflen);
126
127   /* Limit the loop to prevent endless loops. */
128   for (i = 0; i < buflen; i++) {
129     char temp[buflen];
130     char *begin_ptr;
131     size_t begin;
132
133     /* Find `needle' in `buf'. */
134     begin_ptr = strstr(buf, needle);
135     if (begin_ptr == NULL)
136       break;
137
138     /* Calculate the start offset. */
139     begin = begin_ptr - buf;
140
141     /* Substitute the region using `subst'. The result is stored in
142      * `temp'. */
143     begin_ptr =
144         subst(temp, buflen, buf, begin, begin + needle_len, replacement);
145     if (begin_ptr == NULL) {
146       WARNING("subst_string: subst failed.");
147       break;
148     }
149
150     /* Copy the new string in `temp' to `buf' for the next round. */
151     strncpy(buf, temp, buflen);
152   }
153
154   if (i >= buflen) {
155     WARNING("subst_string: Loop exited after %zu iterations: "
156             "string = %s; needle = %s; replacement = %s;",
157             i, string, needle, replacement);
158   }
159
160   return (buf);
161 } /* char *subst_string */
162
163 /* vim: set sw=4 ts=4 tw=78 noexpandtab : */