diff options
| author | Neels Hofmeyr <neels@hofmeyr.de> | 2019-01-14 23:32:53 +0100 | 
|---|---|---|
| committer | Neels Hofmeyr <nhofmeyr@sysmocom.de> | 2019-01-28 23:58:53 +0000 | 
| commit | 0423b61aa8dd75b3141e13cf9276b8fa14ceb473 (patch) | |
| tree | 8437f60dc6f6f817f96f3118db61bf91383cbd7a /src | |
| parent | d01ef75ab876d79c9a0a73cdefb4ccfc60bb47f8 (diff) | |
add osmo_hexdump_buf() and test
Add osmo_hexdump_buf() as an all-purpose hexdump function, which all other
osmo_hexdump_*() implementations now call. It absorbs the static
_osmo_hexdump(). Add tests for osmo_hexdump_buf().
Rationale: recently during patch review, a situation came up where two hexdumps
in a single printf would have been useful. Now I've faced a similar situation
again, in ongoing development. So I decided it is time to provide this API.
The traditional osmo_hexdump() API returns a non-const char*, which should
probably have been a const instead. Particularly this new function may return a
string constant "" if the buf is NULL or empty, so return const char*. That is
why the older implementations calling osmo_hexdump_buf() separately return the
buffer instead of the const return value directly.
Change-Id: I590595567b218b24e53c9eb1fd8736c0324d371d
Diffstat (limited to 'src')
| -rw-r--r-- | src/utils.c | 49 | 
1 files changed, 38 insertions, 11 deletions
diff --git a/src/utils.c b/src/utils.c index d1da4fa8..0b2ed31d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -219,30 +219,55 @@ int osmo_hexparse(const char *str, uint8_t *b, int max_len)  static char hexd_buff[4096];  static const char hex_chars[] = "0123456789abcdef"; -static char *_osmo_hexdump(const unsigned char *buf, int len, char *delim) +/*! Convert binary sequence to hexadecimal ASCII string. + *  \param[out] out_buf  Output buffer to write the resulting string to. + *  \param[in] out_buf_size  sizeof(out_buf). + *  \param[in] buf  Input buffer, pointer to sequence of bytes. + *  \param[in] len  Length of input buf in number of bytes. + *  \param[in] delim  String to separate each byte; NULL or "" for no delim. + *  \param[in] delim_after_last  If true, end the string in delim (true: "1a:ef:d9:", false: "1a:ef:d9"); + *                               if out_buf has insufficient space, the string will always end in a delim. + *  \returns out_buf, containing a zero-terminated string, or "" (empty string) if out_buf == NULL or out_buf_size < 1. + * + * This function will print a sequence of bytes as hexadecimal numbers, adding one delim between each byte (e.g. for + * delim passed as ":", return a string like "1a:ef:d9"). + * + * The delim_after_last argument exists to be able to exactly show the original osmo_hexdump() behavior, which always + * ends the string with a delimiter. + */ +const char *osmo_hexdump_buf(char *out_buf, size_t out_buf_size, const unsigned char *buf, int len, const char *delim, +			     bool delim_after_last)  {  	int i; -	char *cur = hexd_buff; +	char *cur = out_buf; +	size_t delim_len; + +	if (!out_buf || !out_buf_size) +		return ""; + +	delim = delim ? : ""; +	delim_len = strlen(delim); -	hexd_buff[0] = 0;  	for (i = 0; i < len; i++) {  		const char *delimp = delim; -		int len_remain = sizeof(hexd_buff) - (cur - hexd_buff); -		if (len_remain < 3) +		int len_remain = out_buf_size - (cur - out_buf) - 1; +		if (len_remain < (2 + delim_len) +		    && !(!delim_after_last && i == (len - 1) && len_remain >= 2))  			break;  		*cur++ = hex_chars[buf[i] >> 4];  		*cur++ = hex_chars[buf[i] & 0xf]; +		if (i == (len - 1) && !delim_after_last) +			break; +  		while (len_remain > 1 && *delimp) {  			*cur++ = *delimp++;  			len_remain--;  		} - -		*cur = 0;  	} -	hexd_buff[sizeof(hexd_buff)-1] = 0; -	return hexd_buff; +	*cur = '\0'; +	return out_buf;  }  /*! Convert a sequence of unpacked bits to ASCII string @@ -292,7 +317,8 @@ char *osmo_ubit_dump(const uint8_t *bits, unsigned int len)   */  char *osmo_hexdump(const unsigned char *buf, int len)  { -	return _osmo_hexdump(buf, len, " "); +	osmo_hexdump_buf(hexd_buff, sizeof(hexd_buff), buf, len, " ", true); +	return hexd_buff;  }  /*! Convert binary sequence to hexadecimal ASCII string @@ -308,7 +334,8 @@ char *osmo_hexdump(const unsigned char *buf, int len)   */  char *osmo_hexdump_nospc(const unsigned char *buf, int len)  { -	return _osmo_hexdump(buf, len, ""); +	osmo_hexdump_buf(hexd_buff, sizeof(hexd_buff), buf, len, "", true); +	return hexd_buff;  }  /* Compat with previous typo to preserve abi */  | 
