2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

util: Library routines for printing and scanning large hex integers.

Geneve options are variable length and up to 124 bytes long, which means
that they can't be easily manipulated by the integer string functions
like we do for other fields. This adds a few helper routines to make
these operations easier.

Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Andy Zhou <azhou@nicira.com>
This commit is contained in:
Jesse Gross
2015-05-20 18:47:21 -07:00
parent 65da723b40
commit e7ae59f990
6 changed files with 113 additions and 31 deletions

View File

@@ -361,6 +361,29 @@ ds_swap(struct ds *a, struct ds *b)
*b = temp;
}
void
ds_put_hex(struct ds *ds, const void *buf_, size_t size)
{
const uint8_t *buf = buf_;
bool printed = false;
int i;
for (i = 0; i < size; i++) {
uint8_t val = buf[i];
if (val || printed) {
if (!printed) {
ds_put_format(ds, "0x%"PRIx8, val);
} else {
ds_put_format(ds, "%02"PRIx8, val);
}
printed = true;
}
}
if (!printed) {
ds_put_char(ds, '0');
}
}
/* Writes the 'size' bytes in 'buf' to 'string' as hex bytes arranged 16 per
* line. Numeric offsets are also included, starting at 'ofs' for the first
* byte in 'buf'. If 'ascii' is true then the corresponding ASCII characters

View File

@@ -55,6 +55,7 @@ void ds_put_format(struct ds *, const char *, ...) OVS_PRINTF_FORMAT(2, 3);
void ds_put_format_valist(struct ds *, const char *, va_list)
OVS_PRINTF_FORMAT(2, 0);
void ds_put_printable(struct ds *, const char *, size_t);
void ds_put_hex(struct ds *ds, const void *buf, size_t size);
void ds_put_hex_dump(struct ds *ds, const void *buf_, size_t size,
uintptr_t ofs, bool ascii);
int ds_get_line(struct ds *, FILE *);

View File

@@ -190,29 +190,14 @@ static char * OVS_WARN_UNUSED_RESULT
learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec)
{
const char *full_s = s;
const char *arrow = strstr(s, "->");
struct mf_subfield dst;
union mf_subvalue imm;
char *error;
int err;
memset(&imm, 0, sizeof imm);
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && arrow) {
const char *in = arrow - 1;
uint8_t *out = imm.u8 + sizeof imm.u8 - 1;
int n = arrow - (s + 2);
int i;
for (i = 0; i < n; i++) {
int hexit = hexit_value(in[-i]);
if (hexit < 0) {
return xasprintf("%s: bad hex digit in value", full_s);
}
out[-(i / 2)] |= i % 2 ? hexit << 4 : hexit;
}
s = arrow;
} else {
ovs_be64 *last_be64 = &imm.be64[ARRAY_SIZE(imm.be64) - 1];
*last_be64 = htonll(strtoull(s, (char **) &s, 0));
err = parse_int_string(s, imm.u8, sizeof imm.u8, (char **) &s);
if (err) {
return xasprintf("%s: bad hex digit in value", full_s);
}
if (strncmp(s, "->", 2)) {

View File

@@ -2300,18 +2300,7 @@ mf_get_subfield(const struct mf_subfield *sf, const struct flow *flow)
void
mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s)
{
int i;
for (i = 0; i < ARRAY_SIZE(subvalue->u8); i++) {
if (subvalue->u8[i]) {
ds_put_format(s, "0x%"PRIx8, subvalue->u8[i]);
for (i++; i < ARRAY_SIZE(subvalue->u8); i++) {
ds_put_format(s, "%02"PRIx8, subvalue->u8[i]);
}
return;
}
}
ds_put_char(s, '0');
ds_put_hex(s, subvalue->u8, sizeof subvalue->u8);
}
void

View File

@@ -738,6 +738,87 @@ hexits_value(const char *s, size_t n, bool *ok)
return value;
}
/* Parses the string in 's' as an integer in either hex or decimal format and
* puts the result right justified in the array 'valuep' that is 'field_width'
* big. If the string is in hex format, the value may be arbitrarily large;
* integers are limited to 64-bit values. (The rationale is that decimal is
* likely to represent a number and 64 bits is a reasonable maximum whereas
* hex could either be a number or a byte string.)
*
* On return 'tail' points to the first character in the string that was
* not parsed as part of the value. ERANGE is returned if the value is too
* large to fit in the given field. */
int
parse_int_string(const char *s, uint8_t *valuep, int field_width, char **tail)
{
unsigned long long int integer;
int i;
if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) {
uint8_t *hexit_str;
int len = 0;
int val_idx;
int err = 0;
s += 2;
hexit_str = xmalloc(field_width * 2);
for (;;) {
uint8_t hexit;
bool ok;
s += strspn(s, " \t\r\n");
hexit = hexits_value(s, 1, &ok);
if (!ok) {
*tail = CONST_CAST(char *, s);
break;
}
if (hexit != 0 || len) {
if (DIV_ROUND_UP(len + 1, 2) > field_width) {
err = ERANGE;
goto free;
}
hexit_str[len] = hexit;
len++;
}
s++;
}
val_idx = field_width;
for (i = len - 1; i >= 0; i -= 2) {
val_idx--;
valuep[val_idx] = hexit_str[i];
if (i > 0) {
valuep[val_idx] += hexit_str[i - 1] << 4;
}
}
memset(valuep, 0, val_idx);
free:
free(hexit_str);
return err;
}
errno = 0;
integer = strtoull(s, tail, 0);
if (errno) {
return errno;
}
for (i = field_width - 1; i >= 0; i--) {
valuep[i] = integer;
integer >>= 8;
}
if (integer) {
return ERANGE;
}
return 0;
}
/* Returns the current working directory as a malloc()'d string, or a null
* pointer if the current working directory cannot be determined. */
char *

View File

@@ -314,6 +314,9 @@ bool str_to_double(const char *, double *);
int hexit_value(int c);
uintmax_t hexits_value(const char *s, size_t n, bool *ok);
int parse_int_string(const char *s, uint8_t *valuep, int field_width,
char **tail);
const char *english_list_delimiter(size_t index, size_t total);
char *get_cwd(void);