Add xstring module - bounded string builder with three valued comparator
[ccan] / ccan / xstring / xstring.c
1 #include <errno.h>
2 #include <stdarg.h>
3 #include <stdlib.h>
4 #define _XOPEN_SOURCE 700
5 #include <string.h>
6 #include "xstring.h"
7
8 xstring *xstrNew(const size_t size)
9 {
10         char *str;
11         xstring *x;
12
13         if (size < 1) {
14                 errno = EINVAL;
15                 return NULL;
16         }
17
18         str = malloc(size);
19         if (!str)
20                 return NULL;
21
22         x = malloc(sizeof(struct xstring));
23         if (!x) {
24                 free(str);
25                 return NULL;
26         }
27
28         xstrInit(x, str, size, 0);
29         return x;
30 }
31
32 int xstrInit(xstring *x, char *str, const size_t size, int keep)
33 {
34         assert(x && str && size > 0);
35         memset(x, 0, sizeof(*x));
36
37         x->str = str;
38         x->cap = size;
39
40         if (keep) {
41                 x->len = strnlen(str, x->cap);
42                 if (x->cap == x->len) {
43                         x->truncated = -1;
44                         x->len--;
45                 }
46         }
47
48         *(x->str + x->len) = '\0';
49
50         return x->truncated;
51 }
52
53 int xstrAddChar(xstring *x, const char c)
54 {
55         assert(x);
56
57         if (x->truncated || c == '\0')
58                 return x->truncated;
59
60         if (x->len + 1 < x->cap) {
61                 char *p = x->str + x->len;
62                 *p++ = c;
63                 *p = '\0';
64                 x->len++;
65         }
66         else
67                 x->truncated = -1;
68
69         return x->truncated;
70 }
71
72 int xstrAdd(xstring *x, const char *src)
73 {
74         char *p, *q, *s;
75
76         assert(x);
77
78         if (x->truncated || !src || *src == '\0')
79                 return x->truncated;
80
81         for (s = (char *)src,
82              p = x->str + x->len,
83              q = x->str + x->cap - 1;
84              *s != '\0' && p < q; p++, s++) {
85                 *p = *s;
86         }
87
88         *p = '\0';
89         x->len = (size_t) (p - x->str);
90
91         if (*s != '\0')
92                 x->truncated = -1;
93
94         return x->truncated;
95 }
96
97 int xstrAddSub(xstring *x, const char *src, size_t len)
98 {
99         assert(x);
100
101         if (x->truncated || !src || len == 0)
102                 return x->truncated;
103
104         if (x->len + len + 1 > x->cap)
105                 return x->truncated = -1;
106
107         memcpy(x->str + x->len, src, len);
108
109         x->len += len;
110         *(x->str + x->len) = '\0';
111
112         return x->truncated;
113 }
114
115 int xstrCat(xstring *x, ...)
116 {
117         va_list ap;
118         char *s;
119
120         assert(x);
121         va_start(ap, x);
122         while ((s = va_arg(ap, char *)) != NULL) {
123                 if (xstrAdd(x, s) == -1)
124                         break;
125         }
126         va_end(ap);
127         return x->truncated;
128 }
129
130 int xstrJoin(xstring *x, const char *sep, ...)
131 {
132         va_list ap;
133         char *s;
134         int i;
135
136         assert(x && sep);
137         va_start(ap, sep);
138         for (i = 0; (s = va_arg(ap, char *)) != NULL; i++) {
139                 if (i && xstrAdd(x, sep) == -1)
140                         break;
141                 if (xstrAdd(x, s) == -1)
142                         break;
143         }
144         va_end(ap);
145         return x->truncated;
146 }
147
148 int xstrAddSubs(xstring *x, ...)
149 {
150         va_list ap;
151         char *s;
152
153         assert(x);
154         va_start(ap, x);
155         while ((s = va_arg(ap, char *)) != NULL) {
156                 size_t n = va_arg(ap, size_t);
157                 if (xstrAddSub(x, s, n) == -1)
158                         break;
159         }
160         va_end(ap);
161         return x->truncated;
162 }
163
164 int xstrEq3(xstring *x, xstring *y)
165 {
166         assert(x && y);
167
168         if (x->truncated || y->truncated)
169                 return unknown;
170
171         return x->len == y->len && xstrContains3(x, y, 1);
172 }
173
174 /* Does the first string contain the second */
175 int xstrContains3(xstring *x, xstring *y, int where)
176 {
177         int b;
178
179         assert(x && y && where >= -1 && where <= 1);
180
181         if (y->truncated)
182                 return unknown;
183
184         if (x->len < y->len)
185                 return 0;
186
187         switch (where) {
188         case -1:
189                 b = strncmp(x->str + x->len - y->len, y->str, y->len) == 0;
190                 break;
191         case 0:
192                 b = strstr(x->str, y->str) != NULL;
193                 break;
194         case 1:
195                 b = strncmp(x->str, y->str, y->len) == 0;
196                 break;
197         }
198
199         return b ? 1 : x->truncated ? unknown : 0;
200 }
201
202 void xstrFree(xstring *x)
203 {
204         assert(x);
205         free(x->str);
206         free(x);
207 }