glib-aux: add "with_leading_zero" to nm_utils_bin2hexstr_full()

dhclient writes binary data as colon-separated hex strings
like nm_utils_bin2hexstr_full() does. But it only writes single
digits for values smaller than 0x10. Add an option to support
that mode.

However, there are many callers of nm_utils_bin2hexstr_full() already,
and they all don't care about the new option. Maybe this should this
not be a boolean argument, instead the function should accept a
flags argument. That is not done for now. Just add another "fuller"
variant. It's still easy to understand, because the "full" variant
is just a more limited functionality of "fuller".
This commit is contained in:
Thomas Haller
2022-12-14 10:37:10 +01:00
parent df0408f0f6
commit b23c505fca
2 changed files with 45 additions and 23 deletions

View File

@@ -4368,7 +4368,7 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
} }
/** /**
* nm_utils_bin2hexstr_full: * nm_utils_bin2hexstr_fuller:
* @addr: pointer of @length bytes. If @length is zero, this may * @addr: pointer of @length bytes. If @length is zero, this may
* also be %NULL. * also be %NULL.
* @length: number of bytes in @addr. May also be zero, in which * @length: number of bytes in @addr. May also be zero, in which
@@ -4376,12 +4376,17 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
* @delimiter: either '\0', otherwise the output string will have the * @delimiter: either '\0', otherwise the output string will have the
* given delimiter character between each two hex numbers. * given delimiter character between each two hex numbers.
* @upper_case: if TRUE, use upper case ASCII characters for hex. * @upper_case: if TRUE, use upper case ASCII characters for hex.
* @with_leading_zero: if TRUE, then the hex values from 0 to 0xf
* are written as "00" to "0f", respectively. Otherwise, the leading
* zero is dropped. With @with_leading_zero set to FALSE, the resulting
* string may be shorter than expected. @delimiter must be set
* if @with_leading_zero is FALSE.
* @out: if %NULL, the function will allocate a new buffer of * @out: if %NULL, the function will allocate a new buffer of
* either (@length*2+1) or (@length*3) bytes, depending on whether * either (@length*2+1) or MAX(1, (@length*3)) bytes, depending on whether
* a @delimiter is specified. In that case, the allocated buffer will * a @delimiter is specified. In that case, the allocated buffer will
* be returned and must be freed by the caller. * be returned and must be freed by the caller.
* If not %NULL, the buffer must already be preallocated and contain * If not %NULL, the buffer must already be preallocated and contain
* at least (@length*2+1) or (@length*3) bytes, depending on the delimiter. * at least (@length*2+1) or MAX(1, (@length*3)) bytes, depending on the delimiter.
* If @length is zero, then of course at least one byte will be allocated * If @length is zero, then of course at least one byte will be allocated
* or @out (if given) must contain at least room for the trailing NUL byte. * or @out (if given) must contain at least room for the trailing NUL byte.
* *
@@ -4391,37 +4396,43 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
* an empty string is returned. * an empty string is returned.
*/ */
char * char *
nm_utils_bin2hexstr_full(gconstpointer addr, nm_utils_bin2hexstr_fuller(gconstpointer addr,
gsize length, gsize length,
char delimiter, char delimiter,
gboolean upper_case, gboolean upper_case,
gboolean with_leading_zero,
char *out) char *out)
{ {
const guint8 *in = addr; const guint8 *in = addr;
const char *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef"; const char *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
char *out0; char *out0;
if (out) nm_assert(with_leading_zero || delimiter != '\0');
out0 = out;
else {
out0 = out =
g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u));
}
/* @out must contain at least @length*3 bytes if @delimiter is set, /* @out must contain at least (MAX(1, @length*3)) bytes if @delimiter is set,
* otherwise, @length*2+1. */ * otherwise, @length*2+1. */
if (!out)
out = g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u));
out0 = out;
if (length > 0) { if (length > 0) {
nm_assert(in); nm_assert(in);
for (;;) { for (;;) {
const guint8 v = *in++; const guint8 v = *in++;
guint8 v_hi;
*out++ = LOOKUP[v >> 4]; v_hi = (v >> 4);
if (v_hi != 0 || with_leading_zero) {
nm_assert(v_hi < 16);
*out++ = LOOKUP[v_hi];
}
*out++ = LOOKUP[v & 0x0F]; *out++ = LOOKUP[v & 0x0F];
length--; length--;
if (!length) if (length == 0)
break; break;
if (delimiter) if (delimiter != '\0')
*out++ = delimiter; *out++ = delimiter;
} }
} }

View File

@@ -2619,12 +2619,23 @@ nm_ascii_is_regular(char ch)
return ch >= ' ' && ch < 127; return ch >= ' ' && ch < 127;
} }
char *nm_utils_bin2hexstr_full(gconstpointer addr, char *nm_utils_bin2hexstr_fuller(gconstpointer addr,
gsize length, gsize length,
char delimiter, char delimiter,
gboolean upper_case, gboolean upper_case,
gboolean with_leading_zero,
char *out); char *out);
static inline char *
nm_utils_bin2hexstr_full(gconstpointer addr,
gsize length,
char delimiter,
gboolean upper_case,
char *out)
{
return nm_utils_bin2hexstr_fuller(addr, length, delimiter, upper_case, TRUE, out);
}
char *_nm_utils_bin2hexstr(gconstpointer src, gsize len, int final_len); char *_nm_utils_bin2hexstr(gconstpointer src, gsize len, int final_len);
#define nm_utils_bin2hexstr_a(addr, length, delimiter, upper_case, str_to_free) \ #define nm_utils_bin2hexstr_a(addr, length, delimiter, upper_case, str_to_free) \