mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-06 19:00:16 +01:00
shared: add nm_utils_strbuf_seek_end() helper
This commit is contained in:
parent
0feeeaac63
commit
0a8248af10
3 changed files with 126 additions and 2 deletions
|
|
@ -106,7 +106,7 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
|
|||
retval = g_vsnprintf (p, *len, format, args);
|
||||
va_end (args);
|
||||
|
||||
if (retval >= *len) {
|
||||
if ((gsize) retval >= *len) {
|
||||
*buf = &p[*len];
|
||||
*len = 0;
|
||||
} else {
|
||||
|
|
@ -115,6 +115,88 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_strbuf_seek_end:
|
||||
* @buf: the input/output buffer
|
||||
* @len: the input/output lenght of the buffer.
|
||||
*
|
||||
* Commonly, one uses nm_utils_strbuf_append*(), to incrementally
|
||||
* append strings to the buffer. However, sometimes we need to use
|
||||
* existing API to write to the buffer.
|
||||
* After doing so, we want to adjust the buffer counter.
|
||||
* Essentially,
|
||||
*
|
||||
* g_snprintf (buf, len, ...);
|
||||
* nm_utils_strbuf_seek_end (&buf, &len);
|
||||
*
|
||||
* is almost the same as
|
||||
*
|
||||
* nm_utils_strbuf_append (&buf, &len, ...);
|
||||
*
|
||||
* They only behave differently, if the string fits exactly
|
||||
* into the buffer without truncation. The former cannot distinguish
|
||||
* the two cases, while the latter can.
|
||||
*/
|
||||
void
|
||||
nm_utils_strbuf_seek_end (char **buf, gsize *len)
|
||||
{
|
||||
gsize l;
|
||||
char *end;
|
||||
|
||||
nm_assert (len);
|
||||
nm_assert (buf && *buf);
|
||||
|
||||
if (*len == 0)
|
||||
return;
|
||||
|
||||
end = memchr (*buf, 0, *len);
|
||||
if (!end) {
|
||||
/* hm, no NUL character within len bytes.
|
||||
* Just NUL terminate the array and consume them
|
||||
* all. */
|
||||
*buf += *len;
|
||||
(*buf)[-1] = '\0';
|
||||
*len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
l = end - *buf;
|
||||
nm_assert (l < *len);
|
||||
|
||||
*buf = end;
|
||||
*len -= l;
|
||||
if (*len == 1) {
|
||||
/* the last character of a buffer is the '\0'. There are two
|
||||
* cases why that may happen:
|
||||
* - but string was truncated
|
||||
* - the string fit exactly into the buffer.
|
||||
* Here we cannot distinguish between the two, so assume the string
|
||||
* was truncated and signal that by setting @len to 0 and pointing the
|
||||
* buffer *past* the end (like all other nm_utils_strbuf_*() functions).
|
||||
*
|
||||
* Note that nm_utils_strbuf_append_str() can distinguish between
|
||||
* the two cases, and leaves @len at 1, if the string was not actually
|
||||
* truncated.
|
||||
*
|
||||
* For consistancy, it might be better not to do this and just
|
||||
* seek to end of the buffer (not past it). However, that would mean,
|
||||
* in a series of
|
||||
* g_snprintf()
|
||||
* nm_utils_strbuf_seek_end()
|
||||
* the length would never reach zero, but stay at 1. With this,
|
||||
* it reaches len 0 early.
|
||||
* It seems better to declare the buffer as fully consumed and set
|
||||
* the length to zero.
|
||||
*
|
||||
* If the caller does not care about truncation, then this behavior
|
||||
* is more sensible. If the caller cares about truncation, it must
|
||||
* check earlier (right when the truncation occures).
|
||||
*/
|
||||
(*buf)++;
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ _nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
|
|||
void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _nm_printf (3, 4);
|
||||
void nm_utils_strbuf_append_c (char **buf, gsize *len, char c);
|
||||
void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str);
|
||||
void nm_utils_strbuf_seek_end (char **buf, gsize *len);
|
||||
|
||||
const char *nm_strquote (char *buf, gsize buf_len, const char *str);
|
||||
|
||||
|
|
|
|||
|
|
@ -1445,7 +1445,7 @@ test_nm_utils_strbuf_append (void)
|
|||
t_buf = buf;
|
||||
t_len = buf_len;
|
||||
|
||||
test_mode = nmtst_get_rand_int () % 4;
|
||||
test_mode = nmtst_get_rand_int () % 5;
|
||||
|
||||
switch (test_mode) {
|
||||
case 0:
|
||||
|
|
@ -1466,6 +1466,47 @@ test_nm_utils_strbuf_append (void)
|
|||
case 3:
|
||||
nm_utils_strbuf_append (&t_buf, &t_len, "%s", str);
|
||||
break;
|
||||
case 4:
|
||||
g_snprintf (t_buf, t_len, "%s", str);
|
||||
if ( t_len > 0
|
||||
&& strlen (str) >= buf_len
|
||||
&& (nmtst_get_rand_int () % 2)) {
|
||||
/* the string was truncated by g_snprintf(). That means, at the last position in the
|
||||
* buffer is now NUL.
|
||||
* Replace the NUL by the actual character, and check that nm_utils_strbuf_seek_end()
|
||||
* does the right thing: NUL terminate the buffer and seek past the end of the buffer. */
|
||||
g_assert_cmpmem (t_buf, t_len - 1, str, t_len - 1);
|
||||
g_assert (t_buf[t_len - 1] == '\0');
|
||||
g_assert (str[t_len - 1] != '\0');
|
||||
t_buf[t_len - 1] = str[t_len - 1];
|
||||
nm_utils_strbuf_seek_end (&t_buf, &t_len);
|
||||
g_assert (t_len == 0);
|
||||
g_assert (t_buf == &buf[buf_len]);
|
||||
g_assert (t_buf[-1] == '\0');
|
||||
} else {
|
||||
nm_utils_strbuf_seek_end (&t_buf, &t_len);
|
||||
if (strlen (str) + 1 == buf_len) {
|
||||
/* Special case: we appended a string that fit into the buffer
|
||||
* exactly, without truncation.
|
||||
* If we would append the string via nm_utils_strbuf_append(),
|
||||
* then it would have recognized that the string was not truncated
|
||||
* and leave len==1, and pointing the buffer to the terminating NUL
|
||||
* (at the very end, not past it).
|
||||
*
|
||||
* But nm_utils_strbuf_seek_end() cannot distinguish whether
|
||||
* truncation occured, and assumes the buffer was indeed truncated.
|
||||
*
|
||||
* Assert for that, but also adjust the numbers, so that the assertions
|
||||
* below pass (the assertions below theck for the nm_utils_strbuf_append()
|
||||
* case). */
|
||||
g_assert (t_len == 0);
|
||||
g_assert (t_buf == &buf[buf_len]);
|
||||
g_assert (t_buf[-1] == '\0');
|
||||
t_len = 1;
|
||||
t_buf--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assert that the source-buffer is unmodified. */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue