1 /* Yash: yet another shell */
2 /* strbuf.h: modifiable string buffer */
3 /* (C) 2007-2020 magicant */
5 /* This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
10 * This program 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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. */
26 #define Size_max ((size_t) -1) // = SIZE_MAX
28 #ifndef XSTRBUF_INITSIZE
29 #define XSTRBUF_INITSIZE 15
31 #ifndef XWCSBUF_INITSIZE
32 #define XWCSBUF_INITSIZE 15
36 typedef struct xstrbuf_T {
38 size_t length, maxlength;
40 typedef struct xwcsbuf_T {
42 size_t length, maxlength;
45 static inline xstrbuf_T *sb_init(xstrbuf_T *buf)
46 __attribute__((nonnull));
47 extern xstrbuf_T *sb_initwith(xstrbuf_T *restrict buf, char *restrict s)
48 __attribute__((nonnull));
49 extern xstrbuf_T *sb_initwithmax(xstrbuf_T *buf, size_t max)
50 __attribute__((nonnull));
51 static inline void sb_destroy(xstrbuf_T *buf)
52 __attribute__((nonnull));
53 static inline char *sb_tostr(xstrbuf_T *buf)
54 __attribute__((nonnull));
55 extern xstrbuf_T *sb_setmax(xstrbuf_T *buf, size_t newmax)
56 __attribute__((nonnull));
57 extern xstrbuf_T *sb_ensuremax(xstrbuf_T *buf, size_t max)
58 __attribute__((nonnull));
59 static inline xstrbuf_T *sb_truncate(xstrbuf_T *buf, size_t newlength)
60 __attribute__((nonnull));
61 static inline xstrbuf_T *sb_clear(xstrbuf_T *buf)
62 __attribute__((nonnull));
63 extern xstrbuf_T *sb_replace_force(
64 xstrbuf_T *restrict buf, size_t i, size_t bn,
65 const char *restrict s, size_t sn)
66 __attribute__((nonnull));
67 extern xstrbuf_T *sb_replace(
68 xstrbuf_T *restrict buf, size_t i, size_t bn,
69 const char *restrict s, size_t sn)
70 __attribute__((nonnull));
71 static inline xstrbuf_T *sb_ninsert_force(
72 xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
73 __attribute__((nonnull));
74 static inline xstrbuf_T *sb_ninsert(
75 xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
76 __attribute__((nonnull));
77 static inline xstrbuf_T *sb_insert(
78 xstrbuf_T *restrict buf, size_t i, const char *restrict s)
79 __attribute__((nonnull));
80 static inline xstrbuf_T *sb_ncat_force(
81 xstrbuf_T *restrict buf, const char *restrict s, size_t n)
82 __attribute__((nonnull));
83 static inline xstrbuf_T *sb_ncat(
84 xstrbuf_T *restrict buf, const char *restrict s, size_t n)
85 __attribute__((nonnull));
86 static inline xstrbuf_T *sb_cat(
87 xstrbuf_T *restrict buf, const char *restrict s)
88 __attribute__((nonnull));
89 static inline xstrbuf_T *sb_catfree(
90 xstrbuf_T *restrict buf, char *restrict s)
91 __attribute__((nonnull));
92 static inline xstrbuf_T *sb_remove(xstrbuf_T *buf, size_t i, size_t n)
93 __attribute__((nonnull));
94 extern xstrbuf_T *sb_ccat(xstrbuf_T *buf, char c)
95 __attribute__((nonnull));
96 extern xstrbuf_T *sb_ccat_repeat(xstrbuf_T *buf, char c, size_t n)
97 __attribute__((nonnull));
98 extern _Bool sb_wccat(
99 xstrbuf_T *restrict buf, wchar_t c, mbstate_t *restrict ps)
100 __attribute__((nonnull));
101 extern wchar_t *sb_wcsncat(xstrbuf_T *restrict buf,
102 const wchar_t *restrict s, size_t n, mbstate_t *restrict ps)
103 __attribute__((nonnull));
109 wchar_t *sb_wcscat(xstrbuf_T *restrict buf,
110 const wchar_t *restrict s, mbstate_t *restrict ps)
111 __attribute__((nonnull));
112 extern int sb_vprintf(
113 xstrbuf_T *restrict buf, const char *restrict format, va_list ap)
114 __attribute__((nonnull(1,2),format(printf,2,0)));
115 extern int sb_printf(
116 xstrbuf_T *restrict buf, const char *restrict format, ...)
117 __attribute__((nonnull(1,2),format(printf,2,3)));
119 static inline xwcsbuf_T *wb_init(xwcsbuf_T *buf)
120 __attribute__((nonnull));
121 extern xwcsbuf_T *wb_initwith(xwcsbuf_T *restrict buf, wchar_t *restrict s)
122 __attribute__((nonnull));
123 extern xwcsbuf_T *wb_initwithmax(xwcsbuf_T *buf, size_t max)
124 __attribute__((nonnull));
125 static inline void wb_destroy(xwcsbuf_T *buf)
126 __attribute__((nonnull));
127 static inline wchar_t *wb_towcs(xwcsbuf_T *buf)
128 __attribute__((nonnull));
129 extern xwcsbuf_T *wb_setmax(xwcsbuf_T *buf, size_t newmax)
130 __attribute__((nonnull));
131 extern xwcsbuf_T *wb_ensuremax(xwcsbuf_T *buf, size_t max)
132 __attribute__((nonnull));
133 static inline xwcsbuf_T *wb_truncate(xwcsbuf_T *buf, size_t newlength)
134 __attribute__((nonnull));
135 static inline xwcsbuf_T *wb_clear(xwcsbuf_T *buf)
136 __attribute__((nonnull));
137 extern xwcsbuf_T *wb_replace_force(
138 xwcsbuf_T *restrict buf, size_t i, size_t bn,
139 const wchar_t *restrict s, size_t sn)
140 __attribute__((nonnull));
141 extern xwcsbuf_T *wb_replace(
142 xwcsbuf_T *restrict buf, size_t i, size_t bn,
143 const wchar_t *restrict s, size_t sn)
144 __attribute__((nonnull));
145 static inline xwcsbuf_T *wb_ninsert_force(
146 xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
147 __attribute__((nonnull));
148 static inline xwcsbuf_T *wb_ninsert(
149 xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
150 __attribute__((nonnull));
151 static inline xwcsbuf_T *wb_insert(
152 xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s)
153 __attribute__((nonnull));
154 static inline xwcsbuf_T *wb_ncat_force(
155 xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
156 __attribute__((nonnull));
157 static inline xwcsbuf_T *wb_ncat(
158 xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
159 __attribute__((nonnull));
160 static inline xwcsbuf_T *wb_cat(
161 xwcsbuf_T *restrict buf, const wchar_t *restrict s)
162 __attribute__((nonnull));
163 static inline xwcsbuf_T *wb_catfree(
164 xwcsbuf_T *restrict buf, wchar_t *restrict s)
165 __attribute__((nonnull));
166 static inline xwcsbuf_T *wb_remove(xwcsbuf_T *buf, size_t i, size_t n)
167 __attribute__((nonnull));
168 extern xwcsbuf_T *wb_wccat(xwcsbuf_T *buf, wchar_t c)
169 __attribute__((nonnull));
170 extern char *wb_mbscat(xwcsbuf_T *restrict buf, const char *restrict s)
171 __attribute__((nonnull));
172 extern int wb_vwprintf(
173 xwcsbuf_T *restrict buf, const wchar_t *restrict format, va_list ap)
174 __attribute__((nonnull(1,2)));
175 extern int wb_wprintf(
176 xwcsbuf_T *restrict buf, const wchar_t *restrict format, ...)
177 __attribute__((nonnull(1,2)));
179 extern char *malloc_wcsntombs(const wchar_t *s, size_t n)
180 __attribute__((nonnull,malloc,warn_unused_result));
186 char *malloc_wcstombs(const wchar_t *s)
187 __attribute__((nonnull,malloc,warn_unused_result));
188 static inline char *realloc_wcstombs(wchar_t *s)
189 __attribute__((nonnull,malloc,warn_unused_result));
190 extern wchar_t *malloc_mbstowcs(const char *s)
191 __attribute__((nonnull,malloc,warn_unused_result));
192 static inline wchar_t *realloc_mbstowcs(char *s)
193 __attribute__((nonnull,malloc,warn_unused_result));
195 extern char *malloc_vprintf(const char *format, va_list ap)
196 __attribute__((nonnull(1),malloc,warn_unused_result,format(printf,1,0)));
197 extern char *malloc_printf(const char *format, ...)
198 __attribute__((nonnull(1),malloc,warn_unused_result,format(printf,1,2)));
199 extern wchar_t *malloc_vwprintf(const wchar_t *format, va_list ap)
200 __attribute__((nonnull(1),malloc,warn_unused_result));
201 extern wchar_t *malloc_wprintf(const wchar_t *format, ...)
202 __attribute__((nonnull(1),malloc,warn_unused_result));
204 extern wchar_t *joinwcsarray(void *const *array, const wchar_t *padding)
205 __attribute__((malloc,warn_unused_result,nonnull));
208 /* Initializes the specified string buffer as an empty string. */
209 xstrbuf_T *sb_init(xstrbuf_T *buf)
211 return sb_initwithmax(buf, XSTRBUF_INITSIZE);
214 /* Frees the specified multibyte string buffer. The contents are lost. */
215 void sb_destroy(xstrbuf_T *buf)
220 /* Frees the specified multibyte string buffer and returns the contents.
221 * The caller must `free' the return value. */
222 char *sb_tostr(xstrbuf_T *buf)
224 char *s = buf->contents;
226 buf->contents = &s[buf->maxlength];
227 buf->length = buf->maxlength = Size_max;
232 /* Shrinks the length of the buffer to `newlength'.
233 * `newlength' must not be larger than the current length.
234 * Characters beyond the new length are lost.
235 * `maxlength' of the buffer is not changed. */
236 xstrbuf_T *sb_truncate(xstrbuf_T *buf, size_t newlength)
239 assert(newlength <= buf->length);
241 buf->contents[buf->length = newlength] = '\0';
245 /* Clears the contents of the specified string buffer.
246 * `maxlength' of the buffer is not changed. */
247 xstrbuf_T *sb_clear(xstrbuf_T *buf)
249 return sb_truncate(buf, 0);
252 /* Inserts the first `n' bytes of multibyte string `s' at offset `i' in buffer
254 * No boundary checks are done and null characters are not considered special.
255 * `s' must not be part of `buf->contents'. */
256 xstrbuf_T *sb_ninsert_force(
257 xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
259 return sb_replace_force(buf, i, 0, s, n);
262 /* Inserts the first `n' bytes of multibyte string `s' at offset `i' in buffer
264 * If (strlen(s) <= n), the whole of `s' is inserted.
265 * If (buf->length <= i), `s' is appended to the end of the buffer.
266 * `s' must not be part of `buf->contents'. */
267 xstrbuf_T *sb_ninsert(
268 xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
270 return sb_replace(buf, i, 0, s, n);
273 /* Inserts multibyte string `s' at offset `i' in buffer `buf'.
274 * If (buf->length <= i), `s' is appended to the end of the buffer.
275 * `s' must not be part of `buf->contents'. */
276 xstrbuf_T *sb_insert(xstrbuf_T *restrict buf, size_t i, const char *restrict s)
278 return sb_replace(buf, i, 0, s, Size_max);
281 /* Appends the first `n' bytes of multibyte string `s' to buffer `buf'.
282 * No boundary checks are done and null characters are not considered special.
283 * `s' must not be part of `buf->contents'. */
284 xstrbuf_T *sb_ncat_force(
285 xstrbuf_T *restrict buf, const char *restrict s, size_t n)
287 return sb_replace_force(buf, buf->length, 0, s, n);
290 /* Appends the first `n' bytes of multibyte string `s' to buffer `buf'.
291 * If (strlen(s) <= n), the whole of `s' is appended.
292 * `s' must not be part of `buf->contents'. */
293 xstrbuf_T *sb_ncat(xstrbuf_T *restrict buf, const char *restrict s, size_t n)
295 return sb_replace(buf, Size_max, 0, s, n);
298 /* Appends multibyte string `s' to buffer `buf'.
299 * `s' must not be part of `buf->contents'. */
300 xstrbuf_T *sb_cat(xstrbuf_T *restrict buf, const char *restrict s)
302 return sb_replace(buf, Size_max, 0, s, Size_max);
305 /* Appends multibyte string `s' to buffer `buf' and free the string.
306 * `s' must not be part of `buf->contents'. */
307 xstrbuf_T *sb_catfree(xstrbuf_T *restrict buf, char *restrict s)
314 /* Removes `n' bytes at offset `i' in buffer `buf'.
315 * If (buf->length <= i), `buf' is unchanged.
316 * If (buf->length <= i + n), `buf' is truncated to `i' bytes. */
317 xstrbuf_T *sb_remove(xstrbuf_T *buf, size_t i, size_t n)
319 return sb_replace(buf, i, n, "", 0);
323 wchar_t *sb_wcscat(xstrbuf_T *restrict buf,
324 const wchar_t *restrict s, mbstate_t *restrict ps)
326 return sb_wcsncat(buf, s, Size_max, ps);
330 /* Initializes the specified wide string buffer as an empty string. */
331 xwcsbuf_T *wb_init(xwcsbuf_T *buf)
333 return wb_initwithmax(buf, XWCSBUF_INITSIZE);
336 /* Frees the specified wide string buffer. The contents are lost. */
337 void wb_destroy(xwcsbuf_T *buf)
342 /* Frees the specified wide string buffer and returns the contents.
343 * The caller must `free' the return value. */
344 wchar_t *wb_towcs(xwcsbuf_T *buf)
346 wchar_t *s = buf->contents;
348 buf->contents = &s[buf->maxlength];
349 buf->length = buf->maxlength = Size_max;
354 /* Shrinks the length of the specified buffer to `newlength'.
355 * `newlength' must not be larger than the current length.
356 * Characters beyond the new length are lost.
357 * `maxlength' of the buffer is not changed. */
358 xwcsbuf_T *wb_truncate(xwcsbuf_T *buf, size_t newlength)
361 assert(newlength <= buf->length);
363 buf->contents[buf->length = newlength] = L'\0';
367 /* Clears the contents of the specified string buffer.
368 * `maxlength' of the buffer is not changed. */
369 xwcsbuf_T *wb_clear(xwcsbuf_T *buf)
371 return wb_truncate(buf, 0);
374 /* Inserts the first `n' characters of wide string `s' at offset `i' in buffer
376 * No boundary checks are done and null characters are not considered special.
377 * `s' must not be part of `buf->contents'. */
378 xwcsbuf_T *wb_ninsert_force(
379 xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
381 return wb_replace_force(buf, i, 0, s, n);
384 /* Inserts the first `n' characters of wide string `s` at offset `i' in buffer
386 * If (wcslen(s) <= n), the whole of `s' is inserted.
387 * If (buf->length <= i), `s' is appended to the end of the buffer.
388 * `s' must not be part of `buf->contents'. */
389 xwcsbuf_T *wb_ninsert(
390 xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
392 return wb_replace(buf, i, 0, s, n);
395 /* Inserts wide string `s' at offset `i' in buffer `buf'.
396 * If (buf->length <= i), `s' is appended to the end of the buffer.
397 * `s' must not be part of `buf->contents'. */
398 xwcsbuf_T *wb_insert(
399 xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s)
401 return wb_replace(buf, i, 0, s, Size_max);
404 /* Appends the first `n' characters of wide string `s' to buffer `buf'.
405 * No boundary checks are done and null characters are not considered special.
406 * `s' must not be part of `buf->contents'. */
407 xwcsbuf_T *wb_ncat_force(
408 xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
410 return wb_replace_force(buf, buf->length, 0, s, n);
413 /* Appends the first `n' characters of wide string `s' to buffer `buf'.
414 * If (wcslen(s) <= n), the whole of `s' is appended.
415 * `s' must not be part of `buf->contents'. */
416 xwcsbuf_T *wb_ncat(xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
418 return wb_replace(buf, Size_max, 0, s, n);
421 /* Appends wide string `s' to buffer `buf'.
422 * `s' must not be part of `buf->contents'. */
423 xwcsbuf_T *wb_cat(xwcsbuf_T *restrict buf, const wchar_t *restrict s)
425 return wb_replace(buf, Size_max, 0, s, Size_max);
428 /* Appends wide string `s' to buffer and frees the string.
429 * `s' must not be part of `buf->contents'. */
430 xwcsbuf_T *wb_catfree(xwcsbuf_T *restrict buf, wchar_t *restrict s)
437 /* Removes `n' characters at offset `i' in buffer `buf'.
438 * If (buf->length <= i), `buf' is unchanged.
439 * If (buf->length <= i + n), `buf' is truncated to `i' characters. */
440 xwcsbuf_T *wb_remove(xwcsbuf_T *buf, size_t i, size_t n)
442 return wb_replace(buf, i, n, L"", 0);
446 char *malloc_wcstombs(const wchar_t *s)
448 return malloc_wcsntombs(s, Size_max);
452 /* Converts the specified wide string into a newly malloced multibyte string and
453 * frees the original wide string.
454 * Returns NULL on error. The wide string is freed anyway.
455 * The resulting string starts and ends in the initial shift state.*/
456 char *realloc_wcstombs(wchar_t *s)
458 char *result = malloc_wcstombs(s);
463 /* Converts the specified multibyte string into a newly malloced wide string and
464 * frees the multibyte string.
465 * Returns NULL on error. The multibyte string is freed anyway. */
466 wchar_t *realloc_mbstowcs(char *s)
468 wchar_t *result = malloc_mbstowcs(s);
476 #endif /* YASH_STRBUF_H */
479 /* vim: set ts=8 sts=4 sw=4 noet tw=80: */