1 /* multi-purpose string _strbuf, will be initialized to be
2 * at least 1024 bytes long.
14 #include "fmtmacros.h"
19 size_t sz; /* allocated size */
20 size_t end; /* offset to terminating null byte */
23 static inline void realloc_strbuf(struct _strbuf *str, size_t nusz, const char* what)
26 REALLOC(str->buf, nusz, what);
31 static inline void reset_strbuf(struct _strbuf *str)
34 if (str->buf) str->buf[0] = '\0';
37 static inline void init_strbuf(struct _strbuf *str, const char *what)
42 realloc_strbuf(str, 1024, what);
45 static inline void free_strbuf(struct _strbuf *str)
52 static inline void strbuf_append(const char *what, struct _strbuf *str, const char *fmt, ...)
55 size_t room = str->sz - str->end - 1;
58 /* write if we have room */
60 written = vsnprintf(str->buf + str->end, room, fmt, ap);
63 /* if we would have written more, we need to expand the storage */
64 if (written >= room) {
65 realloc_strbuf(str, str->end + written + 1, what);
66 room = str->sz - str->end;
70 written = vsnprintf(str->buf + str->end, room, fmt, ap);
76 static inline void strbuf_append_str_len(const char *what, struct _strbuf *str,
77 const char *to_append, /* string to append */
78 size_t len) /* length of string to append */
80 size_t room = str->sz - str->end - 1;
83 realloc_strbuf(str, str->end + len + 1, what);
85 /* copy up to the terminating NULL */
86 memcpy(str->buf + str->end, to_append, len + 1);
90 static inline void strbuf_append_str(const char *what, struct _strbuf *str, const char *to_append)
92 strbuf_append_str_len(what, str, to_append, strlen(to_append));
95 #define strbuf_printf(str, ...) snprintf((str)->buf, (str)->sz, __VA_ARGS__)
97 #define GET_STRING(str, err, cmd, param, param_str, ...) do { \
99 err = cmd(__VA_ARGS__, param, 0, NULL, &nusz); \
100 if (REPORT_ERROR(str, err, "get " param_str " size")) break; \
101 realloc_strbuf(str, nusz, #param); \
102 err = cmd(__VA_ARGS__, param, (str)->sz, (str)->buf, NULL); \
103 if (REPORT_ERROR(str, err, "get " param_str)) break; \
107 #define GET_STRING_LOC(ret, loc, cmd, ...) do { \
109 ret->err = REPORT_ERROR_LOC(ret, \
110 cmd(__VA_ARGS__, 0, NULL, &nusz), \
111 loc, "get %s size"); \
113 realloc_strbuf(&ret->str, nusz, loc->sname); \
114 ret->err = REPORT_ERROR_LOC(ret, \
115 cmd(__VA_ARGS__, ret->str.sz, ret->str.buf, NULL), \
119 ret->str.end = nusz; \
123 /* Skip leading whitespace in a string */
124 static inline const char* skip_leading_ws(const char *str)
126 const char *ret = str;
127 while (isspace(*ret)) ++ret;
131 /* replace last 3 chars in _strbuf with ... */
132 static const char ellip[] = "...";
134 static inline void trunc_strbuf(struct _strbuf *str)
136 memcpy(str->buf + str->sz - 4, ellip, 4);
139 /* copy a string to _strbuf, at the given offset,
140 * returning the amount of bytes written (excluding the
143 static inline size_t bufcpy_len(struct _strbuf *str,
144 size_t offset, const char *src, size_t len)
146 size_t maxlen = str->sz - offset - 1;
147 char *dst = str->buf + offset;
149 if (str->sz < offset) {
150 fprintf(stderr, "bufcpy overflow copying %s at offset %" PRIuS "/%" PRIuS " (%s)\n",
151 src, offset, str->sz, str->buf);
158 /* TODO enlarge str->buf instead, if maxlen > 0 */
160 memcpy(dst, src, len);
165 str->buf[offset] = '\0';
169 /* As above, auto-compute string length */
170 static inline size_t bufcpy(struct _strbuf *str, size_t offset, const char *src)
172 return bufcpy_len(str, offset, src, strlen(src));
176 /* Separators: we want to be able to prepend separators as needed to _strbuf,
177 * which we do only if halfway through the buffer. The callers should first
178 * call a 'set_separator' and then use add_separator(&offset) to add it, where szval
179 * is an offset inside the buffer, which will be incremented as needed
185 void set_separator(const char* _sep)
191 /* Note that no overflow check is done: it is assumed that _strbuf will have enough room */
192 void add_separator(struct _strbuf *str, size_t *offset)
195 *offset += bufcpy_len(str, *offset, sep, sepsz);