Skip to content

Commit

Permalink
util: Library routines for printing and scanning large hex integers.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Andy Zhou <[email protected]>
  • Loading branch information
jessegross committed May 29, 2015
1 parent 65da723 commit e7ae59f
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 31 deletions.
23 changes: 23 additions & 0 deletions lib/dynamic-string.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/dynamic-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
23 changes: 4 additions & 19 deletions lib/learn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
13 changes: 1 addition & 12 deletions lib/meta-flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
81 changes: 81 additions & 0 deletions lib/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down
3 changes: 3 additions & 0 deletions lib/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit e7ae59f

Please sign in to comment.