+/* 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;
+}
+