/* Yash: yet another shell */
/* strbuf.h: modifiable string buffer */
/* (C) 2007-2011 magicant */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see . */
#ifndef YASH_STRBUF_H
#define YASH_STRBUF_H
#include
#include
#include
#define Size_max ((size_t) -1) // = SIZE_MAX
typedef struct xstrbuf_T {
char *contents;
size_t length, maxlength;
} xstrbuf_T;
typedef struct xwcsbuf_T {
wchar_t *contents;
size_t length, maxlength;
} xwcsbuf_T;
extern xstrbuf_T *sb_init(xstrbuf_T *buf)
__attribute__((nonnull));
extern xstrbuf_T *sb_initwith(xstrbuf_T *restrict buf, char *restrict s)
__attribute__((nonnull));
static inline void sb_destroy(xstrbuf_T *buf)
__attribute__((nonnull));
static inline char *sb_tostr(xstrbuf_T *buf)
__attribute__((nonnull));
extern xstrbuf_T *sb_setmax(xstrbuf_T *buf, size_t newmax)
__attribute__((nonnull));
extern xstrbuf_T *sb_ensuremax(xstrbuf_T *buf, size_t max)
__attribute__((nonnull));
static inline xstrbuf_T *sb_truncate(xstrbuf_T *buf, size_t newlength)
__attribute__((nonnull));
static inline xstrbuf_T *sb_clear(xstrbuf_T *buf)
__attribute__((nonnull));
extern xstrbuf_T *sb_replace_force(
xstrbuf_T *restrict buf, size_t i, size_t bn,
const char *restrict s, size_t sn)
__attribute__((nonnull));
extern xstrbuf_T *sb_replace(
xstrbuf_T *restrict buf, size_t i, size_t bn,
const char *restrict s, size_t sn)
__attribute__((nonnull));
static inline xstrbuf_T *sb_ninsert_force(
xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
__attribute__((nonnull));
static inline xstrbuf_T *sb_ninsert(
xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
__attribute__((nonnull));
static inline xstrbuf_T *sb_insert(
xstrbuf_T *restrict buf, size_t i, const char *restrict s)
__attribute__((nonnull));
static inline xstrbuf_T *sb_ncat_force(
xstrbuf_T *restrict buf, const char *restrict s, size_t n)
__attribute__((nonnull));
static inline xstrbuf_T *sb_ncat(
xstrbuf_T *restrict buf, const char *restrict s, size_t n)
__attribute__((nonnull));
static inline xstrbuf_T *sb_cat(
xstrbuf_T *restrict buf, const char *restrict s)
__attribute__((nonnull));
static inline xstrbuf_T *sb_catfree(
xstrbuf_T *restrict buf, char *restrict s)
__attribute__((nonnull));
static inline xstrbuf_T *sb_remove(xstrbuf_T *buf, size_t i, size_t n)
__attribute__((nonnull));
extern xstrbuf_T *sb_ccat(xstrbuf_T *buf, char c)
__attribute__((nonnull));
extern xstrbuf_T *sb_ccat_repeat(xstrbuf_T *buf, char c, size_t n)
__attribute__((nonnull));
extern _Bool sb_wccat(
xstrbuf_T *restrict buf, wchar_t c, mbstate_t *restrict ps)
__attribute__((nonnull));
extern wchar_t *sb_wcsncat(xstrbuf_T *restrict buf,
const wchar_t *restrict s, size_t n, mbstate_t *restrict ps)
__attribute__((nonnull));
#if HAVE_WCSNRTOMBS
static inline
#else
extern
#endif
wchar_t *sb_wcscat(xstrbuf_T *restrict buf,
const wchar_t *restrict s, mbstate_t *restrict ps)
__attribute__((nonnull));
extern int sb_vprintf(
xstrbuf_T *restrict buf, const char *restrict format, va_list ap)
__attribute__((nonnull(1,2),format(printf,2,0)));
extern int sb_printf(
xstrbuf_T *restrict buf, const char *restrict format, ...)
__attribute__((nonnull(1,2),format(printf,2,3)));
extern xwcsbuf_T *wb_init(xwcsbuf_T *buf)
__attribute__((nonnull));
extern xwcsbuf_T *wb_initwith(xwcsbuf_T *restrict buf, wchar_t *restrict s)
__attribute__((nonnull));
static inline void wb_destroy(xwcsbuf_T *buf)
__attribute__((nonnull));
static inline wchar_t *wb_towcs(xwcsbuf_T *buf)
__attribute__((nonnull));
extern xwcsbuf_T *wb_setmax(xwcsbuf_T *buf, size_t newmax)
__attribute__((nonnull));
extern xwcsbuf_T *wb_ensuremax(xwcsbuf_T *buf, size_t max)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_truncate(xwcsbuf_T *buf, size_t newlength)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_clear(xwcsbuf_T *buf)
__attribute__((nonnull));
extern xwcsbuf_T *wb_replace_force(
xwcsbuf_T *restrict buf, size_t i, size_t bn,
const wchar_t *restrict s, size_t sn)
__attribute__((nonnull));
extern xwcsbuf_T *wb_replace(
xwcsbuf_T *restrict buf, size_t i, size_t bn,
const wchar_t *restrict s, size_t sn)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_ninsert_force(
xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_ninsert(
xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_insert(
xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_ncat_force(
xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_ncat(
xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_cat(
xwcsbuf_T *restrict buf, const wchar_t *restrict s)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_catfree(
xwcsbuf_T *restrict buf, wchar_t *restrict s)
__attribute__((nonnull));
static inline xwcsbuf_T *wb_remove(xwcsbuf_T *buf, size_t i, size_t n)
__attribute__((nonnull));
extern xwcsbuf_T *wb_wccat(xwcsbuf_T *buf, wchar_t c)
__attribute__((nonnull));
extern char *wb_mbscat(xwcsbuf_T *restrict buf, const char *restrict s)
__attribute__((nonnull));
extern int wb_vwprintf(
xwcsbuf_T *restrict buf, const wchar_t *restrict format, va_list ap)
__attribute__((nonnull(1,2)));
extern int wb_wprintf(
xwcsbuf_T *restrict buf, const wchar_t *restrict format, ...)
__attribute__((nonnull(1,2)));
extern char *malloc_wcsntombs(const wchar_t *s, size_t n)
__attribute__((nonnull,malloc,warn_unused_result));
#if HAVE_WCSNRTOMBS
static inline
#else
extern
#endif
char *malloc_wcstombs(const wchar_t *s)
__attribute__((nonnull,malloc,warn_unused_result));
static inline char *realloc_wcstombs(wchar_t *s)
__attribute__((nonnull,malloc,warn_unused_result));
extern wchar_t *malloc_mbstowcs(const char *s)
__attribute__((nonnull,malloc,warn_unused_result));
static inline wchar_t *realloc_mbstowcs(char *s)
__attribute__((nonnull,malloc,warn_unused_result));
extern char *malloc_vprintf(const char *format, va_list ap)
__attribute__((nonnull(1),malloc,warn_unused_result,format(printf,1,0)));
extern char *malloc_printf(const char *format, ...)
__attribute__((nonnull(1),malloc,warn_unused_result,format(printf,1,2)));
extern wchar_t *malloc_vwprintf(const wchar_t *format, va_list ap)
__attribute__((nonnull(1),malloc,warn_unused_result));
extern wchar_t *malloc_wprintf(const wchar_t *format, ...)
__attribute__((nonnull(1),malloc,warn_unused_result));
extern wchar_t *joinwcsarray(void *const *array, const wchar_t *padding)
__attribute__((malloc,warn_unused_result,nonnull));
/* Frees the specified multibyte string buffer. The contents are lost. */
void sb_destroy(xstrbuf_T *buf)
{
free(buf->contents);
}
/* Frees the specified multibyte string buffer and returns the contents.
* The caller must `free' the return value. */
char *sb_tostr(xstrbuf_T *buf)
{
return buf->contents;
}
/* Shrinks the length of the buffer to `newlength'.
* `newlength' must not be larger than the current length.
* Characters beyond the new length are lost.
* `maxlength' of the buffer is not changed. */
xstrbuf_T *sb_truncate(xstrbuf_T *buf, size_t newlength)
{
#ifdef assert
assert(newlength <= buf->length);
#endif
buf->contents[buf->length = newlength] = '\0';
return buf;
}
/* Clears the contents of the specified string buffer.
* `maxlength' of the buffer is not changed. */
xstrbuf_T *sb_clear(xstrbuf_T *buf)
{
return sb_truncate(buf, 0);
}
/* Inserts the first `n' bytes of multibyte string `s' at offset `i' in buffer
* `buf'.
* No boundary checks are done and null characters are not considered special.
* `s' must not be part of `buf->contents'. */
xstrbuf_T *sb_ninsert_force(
xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
{
return sb_replace_force(buf, i, 0, s, n);
}
/* Inserts the first `n' bytes of multibyte string `s' at offset `i' in buffer
* `buf'.
* If (strlen(s) <= n), the whole of `s' is inserted.
* If (buf->length <= i), `s' is appended to the end of the buffer.
* `s' must not be part of `buf->contents'. */
xstrbuf_T *sb_ninsert(
xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
{
return sb_replace(buf, i, 0, s, n);
}
/* Inserts multibyte string `s' at offset `i' in buffer `buf'.
* If (buf->length <= i), `s' is appended to the end of the buffer.
* `s' must not be part of `buf->contents'. */
xstrbuf_T *sb_insert(xstrbuf_T *restrict buf, size_t i, const char *restrict s)
{
return sb_replace(buf, i, 0, s, Size_max);
}
/* Appends the first `n' bytes of multibyte string `s' to buffer `buf'.
* No boundary checks are done and null characters are not considered special.
* `s' must not be part of `buf->contents'. */
xstrbuf_T *sb_ncat_force(
xstrbuf_T *restrict buf, const char *restrict s, size_t n)
{
return sb_replace_force(buf, buf->length, 0, s, n);
}
/* Appends the first `n' bytes of multibyte string `s' to buffer `buf'.
* If (strlen(s) <= n), the whole of `s' is appended.
* `s' must not be part of `buf->contents'. */
xstrbuf_T *sb_ncat(xstrbuf_T *restrict buf, const char *restrict s, size_t n)
{
return sb_replace(buf, Size_max, 0, s, n);
}
/* Appends multibyte string `s' to buffer `buf'.
* `s' must not be part of `buf->contents'. */
xstrbuf_T *sb_cat(xstrbuf_T *restrict buf, const char *restrict s)
{
return sb_replace(buf, Size_max, 0, s, Size_max);
}
/* Appends multibyte string `s' to buffer `buf' and free the string.
* `s' must not be part of `buf->contents'. */
xstrbuf_T *sb_catfree(xstrbuf_T *restrict buf, char *restrict s)
{
sb_cat(buf, s);
free(s);
return buf;
}
/* Removes `n' bytes at offset `i' in buffer `buf'.
* If (buf->length <= i), `buf' is unchanged.
* If (buf->length <= i + n), `buf' is truncated to `i' bytes. */
xstrbuf_T *sb_remove(xstrbuf_T *buf, size_t i, size_t n)
{
return sb_replace(buf, i, n, "", 0);
}
#if HAVE_WCSNRTOMBS
wchar_t *sb_wcscat(xstrbuf_T *restrict buf,
const wchar_t *restrict s, mbstate_t *restrict ps)
{
return sb_wcsncat(buf, s, Size_max, ps);
}
#endif
/* Frees the specified wide string buffer. The contents are lost. */
void wb_destroy(xwcsbuf_T *buf)
{
free(buf->contents);
}
/* Frees the specified wide string buffer and returns the contents.
* The caller must `free' the return value. */
wchar_t *wb_towcs(xwcsbuf_T *buf)
{
return buf->contents;
}
/* Shrinks the length of the specified buffer to `newlength'.
* `newlength' must not be larger than the current length.
* Characters beyond the new length are lost.
* `maxlength' of the buffer is not changed. */
xwcsbuf_T *wb_truncate(xwcsbuf_T *buf, size_t newlength)
{
#ifdef assert
assert(newlength <= buf->length);
#endif
buf->contents[buf->length = newlength] = L'\0';
return buf;
}
/* Clears the contents of the specified string buffer.
* `maxlength' of the buffer is not changed. */
xwcsbuf_T *wb_clear(xwcsbuf_T *buf)
{
return wb_truncate(buf, 0);
}
/* Inserts the first `n' characters of wide string `s' at offset `i' in buffer
* `buf'.
* No boundary checks are done and null characters are not considered special.
* `s' must not be part of `buf->contents'. */
xwcsbuf_T *wb_ninsert_force(
xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
{
return wb_replace_force(buf, i, 0, s, n);
}
/* Inserts the first `n' characters of wide string `s` at offset `i' in buffer
* `buf'.
* If (wcslen(s) <= n), the whole of `s' is inserted.
* If (buf->length <= i), `s' is appended to the end of the buffer.
* `s' must not be part of `buf->contents'. */
xwcsbuf_T *wb_ninsert(
xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
{
return wb_replace(buf, i, 0, s, n);
}
/* Inserts wide string `s' at offset `i' in buffer `buf'.
* If (buf->length <= i), `s' is appended to the end of the buffer.
* `s' must not be part of `buf->contents'. */
xwcsbuf_T *wb_insert(
xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s)
{
return wb_replace(buf, i, 0, s, Size_max);
}
/* Appends the first `n' characters of wide string `s' to buffer `buf'.
* No boundary checks are done and null characters are not considered special.
* `s' must not be part of `buf->contents'. */
xwcsbuf_T *wb_ncat_force(
xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
{
return wb_replace_force(buf, buf->length, 0, s, n);
}
/* Appends the first `n' characters of wide string `s' to buffer `buf'.
* If (wcslen(s) <= n), the whole of `s' is appended.
* `s' must not be part of `buf->contents'. */
xwcsbuf_T *wb_ncat(xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
{
return wb_replace(buf, Size_max, 0, s, n);
}
/* Appends wide string `s' to buffer `buf'.
* `s' must not be part of `buf->contents'. */
xwcsbuf_T *wb_cat(xwcsbuf_T *restrict buf, const wchar_t *restrict s)
{
return wb_replace(buf, Size_max, 0, s, Size_max);
}
/* Appends wide string `s' to buffer and frees the string.
* `s' must not be part of `buf->contents'. */
xwcsbuf_T *wb_catfree(xwcsbuf_T *restrict buf, wchar_t *restrict s)
{
wb_cat(buf, s);
free(s);
return buf;
}
/* Removes `n' characters at offset `i' in buffer `buf'.
* If (buf->length <= i), `buf' is unchanged.
* If (buf->length <= i + n), `buf' is truncated to `i' characters. */
xwcsbuf_T *wb_remove(xwcsbuf_T *buf, size_t i, size_t n)
{
return wb_replace(buf, i, n, L"", 0);
}
#if HAVE_WCSNRTOMBS
char *malloc_wcstombs(const wchar_t *s)
{
return malloc_wcsntombs(s, Size_max);
}
#endif
/* Converts the specified wide string into a newly malloced multibyte string and
* frees the original wide string.
* Returns NULL on error. The wide string is freed anyway.
* The resulting string starts and ends in the initial shift state.*/
char *realloc_wcstombs(wchar_t *s)
{
char *result = malloc_wcstombs(s);
free(s);
return result;
}
/* Converts the specified multibyte string into a newly malloced wide string and
* frees the multibyte string.
* Returns NULL on error. The multibyte string is freed anyway. */
wchar_t *realloc_mbstowcs(char *s)
{
wchar_t *result = malloc_mbstowcs(s);
free(s);
return result;
}
#undef Size_max
#endif /* YASH_STRBUF_H */
/* vim: set ts=8 sts=4 sw=4 noet tw=80: */