util: add osmo_strbuf macros to manipulate the strbuf tail
Upcoming patch adopts osmo_strbuf in logging.c, which sometimes needs to
steal and re-add trailing newline characters, and also needs to let
ctime_r() write to the buffer before updating the osmo_strbuf state.
Related: OS#6284
Related: Ib577a5e0d7450ce93ff21f37ba3262704cbf4752
Change-Id: I997707c328eab3ffa00a78fdb9a0a2cbe18404b4
diff --git a/src/core/libosmocore.map b/src/core/libosmocore.map
index fc81650..30c4927 100644
--- a/src/core/libosmocore.map
+++ b/src/core/libosmocore.map
@@ -510,6 +510,8 @@
osmo_strrb_get_nth;
_osmo_strrb_is_bufindex_valid;
osmo_strrb_is_empty;
+osmo_strbuf_drop_tail;
+osmo_strbuf_added_tail;
osmo_str_startswith;
osmo_str_to_int;
osmo_str_to_int64;
diff --git a/src/core/utils.c b/src/core/utils.c
index 231b65c..882eb6f 100644
--- a/src/core/utils.c
+++ b/src/core/utils.c
@@ -1211,6 +1211,51 @@
return (sum * 9) % 10 + '0';
}
+/*! Remove up to N chars from the end of an osmo_strbuf.
+ * |--char-count---| - - chars_needed - - |
+ * |<---------drop----------|
+ */
+void osmo_strbuf_drop_tail(struct osmo_strbuf *sb, size_t n_chars)
+{
+ size_t drop_n;
+ if (sb->pos <= sb->buf)
+ return;
+ drop_n = OSMO_MIN(sb->chars_needed, n_chars);
+ sb->chars_needed -= drop_n;
+ /* chars_needed was reduced by n_chars, which may have been entirely behind the end of a full buffer, within the
+ * hypothetical chars_needed. Modify the buffer tail pos only if the buffer is not or longer full now. */
+ if (sb->chars_needed >= OSMO_STRBUF_CHAR_COUNT(*sb))
+ return;
+ sb->pos = sb->buf + sb->chars_needed;
+ *sb->pos = '\0';
+}
+
+/*! Let osmo_strbuf know that n_chars characters (excluding nul) were written to the end of the buffer.
+ * If sb is nonempty, the n_chars are assumed to have been written to sb->pos. If sb is still empty and pos == NULL, the
+ * n_chars are assumed to have been written to the start of the buffer.
+ * Advance sb->pos and sb->chars_needed by at most n_chars, or up to sb->len - 1.
+ * Ensure nul termination. */
+void osmo_strbuf_added_tail(struct osmo_strbuf *sb, size_t n_chars)
+{
+ /* On init of an osmo_strbuf, sb->pos == NULL, which is defined as semantically identical to pointing at the
+ * start of the buffer. A caller may just write to the buffer and call osmo_strbuf_added_tail(), in which case
+ * still pos == NULL. pos != NULL happens as soon as the first OSMO_STRBUF_*() API has acted on the strbuf. */
+ if (!sb->pos)
+ sb->pos = sb->buf;
+ sb->chars_needed += n_chars;
+ /* first get remaining space, not counting trailing nul; but safeguard against empty buffer */
+ size_t n_added = OSMO_STRBUF_REMAIN(*sb);
+ if (n_added)
+ n_added--;
+ /* do not add more than fit in sb->len, still ensuring nul termination */
+ n_added = OSMO_MIN(n_added, n_chars);
+ if (n_added)
+ sb->pos += n_added;
+ /* when a strbuf is full, sb->pos may point after the final nul, so nul terminate only when pos is valid. */
+ if (sb->pos < sb->buf + sb->len)
+ *sb->pos = '\0';
+}
+
/*! Compare start of a string.
* This is an optimisation of 'strstr(str, startswith_str) == str' because it doesn't search through the entire string.
* \param str (Longer) string to compare.