#include <config.h>
#include "util.h"
+#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
+#include "bitmap.h"
#include "byte-order.h"
#include "coverage.h"
#include "ovs-thread.h"
n_bits);
return ntohll(value);
}
+\f
+/* ovs_scan */
+
+struct scan_spec {
+ unsigned int width;
+ enum {
+ SCAN_DISCARD,
+ SCAN_CHAR,
+ SCAN_SHORT,
+ SCAN_INT,
+ SCAN_LONG,
+ SCAN_LLONG,
+ SCAN_INTMAX_T,
+ SCAN_PTRDIFF_T,
+ SCAN_SIZE_T
+ } type;
+};
+
+static const char *
+skip_spaces(const char *s)
+{
+ while (isspace((unsigned char) *s)) {
+ s++;
+ }
+ return s;
+}
+
+static const char *
+scan_int(const char *s, const struct scan_spec *spec, int base, va_list *args)
+{
+ const char *start = s;
+ uintmax_t value;
+ bool negative;
+ int n_digits;
+
+ negative = *s == '-';
+ s += *s == '-' || *s == '+';
+
+ if ((!base || base == 16) && *s == '0' && (s[1] == 'x' || s[1] == 'X')) {
+ base = 16;
+ s += 2;
+ } else if (!base) {
+ base = *s == '0' ? 8 : 10;
+ }
+
+ if (s - start >= spec->width) {
+ return NULL;
+ }
+
+ value = 0;
+ n_digits = 0;
+ while (s - start < spec->width) {
+ int digit = hexit_value(*s);
+
+ if (digit < 0 || digit >= base) {
+ break;
+ }
+ value = value * base + digit;
+ n_digits++;
+ s++;
+ }
+ if (!n_digits) {
+ return NULL;
+ }
+
+ if (negative) {
+ value = -value;
+ }
+
+ switch (spec->type) {
+ case SCAN_DISCARD:
+ break;
+ case SCAN_CHAR:
+ *va_arg(*args, char *) = value;
+ break;
+ case SCAN_SHORT:
+ *va_arg(*args, short int *) = value;
+ break;
+ case SCAN_INT:
+ *va_arg(*args, int *) = value;
+ break;
+ case SCAN_LONG:
+ *va_arg(*args, long int *) = value;
+ break;
+ case SCAN_LLONG:
+ *va_arg(*args, long long int *) = value;
+ break;
+ case SCAN_INTMAX_T:
+ *va_arg(*args, intmax_t *) = value;
+ break;
+ case SCAN_PTRDIFF_T:
+ *va_arg(*args, ptrdiff_t *) = value;
+ break;
+ case SCAN_SIZE_T:
+ *va_arg(*args, size_t *) = value;
+ break;
+ }
+ return s;
+}
+
+static const char *
+skip_digits(const char *s)
+{
+ while (*s >= '0' && *s <= '9') {
+ s++;
+ }
+ return s;
+}
+
+static const char *
+scan_float(const char *s, const struct scan_spec *spec, va_list *args)
+{
+ const char *start = s;
+ long double value;
+ char *tail;
+ char *copy;
+ bool ok;
+
+ s += *s == '+' || *s == '-';
+ s = skip_digits(s);
+ if (*s == '.') {
+ s = skip_digits(s + 1);
+ }
+ if (*s == 'e' || *s == 'E') {
+ s++;
+ s += *s == '+' || *s == '-';
+ s = skip_digits(s);
+ }
+
+ if (s - start > spec->width) {
+ s = start + spec->width;
+ }
+
+ copy = xmemdup0(start, s - start);
+ value = strtold(copy, &tail);
+ ok = *tail == '\0';
+ free(copy);
+ if (!ok) {
+ return NULL;
+ }
+
+ switch (spec->type) {
+ case SCAN_DISCARD:
+ break;
+ case SCAN_INT:
+ *va_arg(*args, float *) = value;
+ break;
+ case SCAN_LONG:
+ *va_arg(*args, double *) = value;
+ break;
+ case SCAN_LLONG:
+ *va_arg(*args, long double *) = value;
+ break;
+
+ case SCAN_CHAR:
+ case SCAN_SHORT:
+ case SCAN_INTMAX_T:
+ case SCAN_PTRDIFF_T:
+ case SCAN_SIZE_T:
+ NOT_REACHED();
+ }
+ return s;
+}
+
+static void
+scan_output_string(const struct scan_spec *spec,
+ const char *s, size_t n,
+ va_list *args)
+{
+ if (spec->type != SCAN_DISCARD) {
+ char *out = va_arg(*args, char *);
+ memcpy(out, s, n);
+ out[n] = '\0';
+ }
+}
+
+static const char *
+scan_string(const char *s, const struct scan_spec *spec, va_list *args)
+{
+ size_t n;
+
+ for (n = 0; n < spec->width; n++) {
+ if (!s[n] || isspace((unsigned char) s[n])) {
+ break;
+ }
+ }
+ if (!n) {
+ return NULL;
+ }
+
+ scan_output_string(spec, s, n, args);
+ return s + n;
+}
+
+static const char *
+parse_scanset(const char *p_, unsigned long *set, bool *complemented)
+{
+ const uint8_t *p = (const uint8_t *) p_;
+
+ *complemented = *p == '^';
+ p += *complemented;
+
+ if (*p == ']') {
+ bitmap_set1(set, ']');
+ p++;
+ }
+
+ while (*p && *p != ']') {
+ if (p[1] == '-' && p[2] != ']' && p[2] > *p) {
+ bitmap_set_multiple(set, *p, p[2] - *p + 1, true);
+ p += 3;
+ } else {
+ bitmap_set1(set, *p++);
+ }
+ }
+ if (*p == ']') {
+ p++;
+ }
+ return (const char *) p;
+}
+
+static const char *
+scan_set(const char *s, const struct scan_spec *spec, const char **pp,
+ va_list *args)
+{
+ unsigned long set[BITMAP_N_LONGS(UCHAR_MAX + 1)];
+ bool complemented;
+ unsigned int n;
+
+ /* Parse the scan set. */
+ memset(set, 0, sizeof set);
+ *pp = parse_scanset(*pp, set, &complemented);
+
+ /* Parse the data. */
+ n = 0;
+ while (s[n]
+ && bitmap_is_set(set, (unsigned char) s[n]) == !complemented
+ && n < spec->width) {
+ n++;
+ }
+ if (!n) {
+ return NULL;
+ }
+ scan_output_string(spec, s, n, args);
+ return s + n;
+}
+
+static const char *
+scan_chars(const char *s, const struct scan_spec *spec, va_list *args)
+{
+ unsigned int n = spec->width == SIZE_MAX ? 1 : spec->width;
+
+ if (strlen(s) < n) {
+ return NULL;
+ }
+ if (spec->type != SCAN_DISCARD) {
+ memcpy(va_arg(*args, char *), s, n);
+ }
+ return s + n;
+}
+
+/* This is an implementation of the standard sscanf() function, with the
+ * following exceptions:
+ *
+ * - It returns true if the entire template was successfully scanned and
+ * converted, false if any conversion failed.
+ *
+ * - The standard doesn't define sscanf() behavior when an out-of-range value
+ * is scanned, e.g. if a "%"PRIi8 conversion scans "-1" or "0x1ff". Some
+ * implementations consider this an error and stop scanning. This
+ * implementation never considers an out-of-range value an error; instead,
+ * it stores the least-significant bits of the converted value in the
+ * destination, e.g. the value 255 for both examples earlier.
+ *
+ * - Only single-byte characters are supported, that is, the 'l' modifier
+ * on %s, %[, and %c is not supported. The GNU extension 'a' modifier is
+ * also not supported.
+ *
+ * - %p is not supported.
+ */
+bool
+ovs_scan(const char *s, const char *template, ...)
+{
+ const char *const start = s;
+ bool ok = false;
+ const char *p;
+ va_list args;
+
+ va_start(args, template);
+ p = template;
+ while (*p != '\0') {
+ struct scan_spec spec;
+ unsigned char c = *p++;
+ bool discard;
+
+ if (isspace(c)) {
+ s = skip_spaces(s);
+ continue;
+ } else if (c != '%') {
+ if (*s != c) {
+ goto exit;
+ }
+ s++;
+ continue;
+ } else if (*p == '%') {
+ if (*s++ != '%') {
+ goto exit;
+ }
+ p++;
+ continue;
+ }
+
+ /* Parse '*' flag. */
+ discard = *p == '*';
+ p += discard;
+
+ /* Parse field width. */
+ spec.width = 0;
+ while (*p >= '0' && *p <= '9') {
+ spec.width = spec.width * 10 + (*p++ - '0');
+ }
+ if (spec.width == 0) {
+ spec.width = UINT_MAX;
+ }
+
+ /* Parse type modifier. */
+ switch (*p) {
+ case 'h':
+ if (p[1] == 'h') {
+ spec.type = SCAN_CHAR;
+ p += 2;
+ } else {
+ spec.type = SCAN_SHORT;
+ p++;
+ }
+ break;
+
+ case 'j':
+ spec.type = SCAN_INTMAX_T;
+ p++;
+ break;
+
+ case 'l':
+ if (p[1] == 'l') {
+ spec.type = SCAN_LLONG;
+ p += 2;
+ } else {
+ spec.type = SCAN_LONG;
+ p++;
+ }
+ break;
+
+ case 'L':
+ case 'q':
+ spec.type = SCAN_LLONG;
+ p++;
+ break;
+
+ case 't':
+ spec.type = SCAN_PTRDIFF_T;
+ p++;
+ break;
+
+ case 'z':
+ spec.type = SCAN_SIZE_T;
+ p++;
+ break;
+
+ default:
+ spec.type = SCAN_INT;
+ break;
+ }
+
+ if (discard) {
+ spec.type = SCAN_DISCARD;
+ }
+
+ c = *p++;
+ if (c != 'c' && c != 'n' && c != '[') {
+ s = skip_spaces(s);
+ }
+ switch (c) {
+ case 'd':
+ s = scan_int(s, &spec, 10, &args);
+ break;
+
+ case 'i':
+ s = scan_int(s, &spec, 0, &args);
+ break;
+
+ case 'o':
+ s = scan_int(s, &spec, 8, &args);
+ break;
+
+ case 'u':
+ s = scan_int(s, &spec, 10, &args);
+ break;
+
+ case 'x':
+ case 'X':
+ s = scan_int(s, &spec, 16, &args);
+ break;
+
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'E':
+ case 'G':
+ s = scan_float(s, &spec, &args);
+ break;
+
+ case 's':
+ s = scan_string(s, &spec, &args);
+ break;
+
+ case '[':
+ s = scan_set(s, &spec, &p, &args);
+ break;
+
+ case 'c':
+ s = scan_chars(s, &spec, &args);
+ break;
+
+ case 'n':
+ if (spec.type != SCAN_DISCARD) {
+ *va_arg(args, int *) = s - start;
+ }
+ break;
+ }
+
+ if (!s) {
+ goto exit;
+ }
+ }
+ ok = true;
+
+exit:
+ va_end(args);
+ return ok;
+}
+
{
ovs_assert(false);
}
+
+static void
+test_ovs_scan(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ char str[16], str2[16], str3[16];
+ long double ld, ld2;
+ long long ll, ll2;
+ signed char c, c2;
+ ptrdiff_t pd, pd2;
+ intmax_t im, im2;
+ size_t sz, sz2;
+ int n, n2, n3;
+ double d, d2;
+ short s, s2;
+ float f, f2;
+ long l, l2;
+ int i, i2;
+
+ ovs_assert(ovs_scan("", ""));
+ ovs_assert(ovs_scan("", " "));
+ ovs_assert(ovs_scan(" ", " "));
+ ovs_assert(ovs_scan(" ", " "));
+ ovs_assert(ovs_scan(" \t ", " "));
+
+ ovs_assert(ovs_scan("xyzzy", "xyzzy"));
+ ovs_assert(ovs_scan("xy%zzy", "xy%%zzy"));
+ ovs_assert(!ovs_scan(" xy%zzy", "xy%%zzy"));
+ ovs_assert(ovs_scan(" xy%\tzzy", " xy%% zzy"));
+
+ ovs_assert(ovs_scan("123", "%d", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("0", "%d", &i));
+ ovs_assert(i == 0);
+ ovs_assert(!ovs_scan("123", "%d%d", &i, &i2));
+ ovs_assert(ovs_scan("+123", "%d", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("-123", "%d", &i));
+ ovs_assert(i == -123);
+ ovs_assert(ovs_scan("0123", "%d", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan(" 123", "%d", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("0x123", "%d", &i));
+ ovs_assert(i == 0);
+ ovs_assert(ovs_scan("123", "%2d %d", &i, &i2));
+ ovs_assert(i == 12);
+ ovs_assert(i2 == 3);
+ ovs_assert(ovs_scan("+123", "%2d %d", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("-123", "%2d %d", &i, &i2));
+ ovs_assert(i == -1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("0123", "%2d %d", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("123", "%*2d %d", &i));
+ ovs_assert(i == 3);
+ ovs_assert(ovs_scan("+123", "%2d %*d", &i));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("-123", "%*2d %*d"));
+
+ ovs_assert(ovs_scan("123", "%u", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("0", "%u", &i));
+ ovs_assert(i == 0);
+ ovs_assert(!ovs_scan("123", "%u%u", &i, &i2));
+ ovs_assert(ovs_scan("+123", "%u", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("-123", "%u", &i));
+ ovs_assert(i == -123);
+ ovs_assert(ovs_scan("0123", "%u", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan(" 123", "%u", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("0x123", "%u", &i));
+ ovs_assert(i == 0);
+ ovs_assert(ovs_scan("123", "%2u %u", &i, &i2));
+ ovs_assert(i == 12);
+ ovs_assert(i2 == 3);
+ ovs_assert(ovs_scan("+123", "%2u %u", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("-123", "%2u %u", &i, &i2));
+ ovs_assert(i == -1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("0123", "%2u %u", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("123", "%*2u %u", &i));
+ ovs_assert(i == 3);
+ ovs_assert(ovs_scan("+123", "%2u %*u", &i));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("-123", "%*2u %*u"));
+
+ ovs_assert(ovs_scan("123", "%i", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("0", "%i", &i));
+ ovs_assert(i == 0);
+ ovs_assert(!ovs_scan("123", "%i%i", &i, &i2));
+ ovs_assert(ovs_scan("+123", "%i", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("-123", "%i", &i));
+ ovs_assert(i == -123);
+ ovs_assert(ovs_scan("0123", "%i", &i));
+ ovs_assert(i == 0123);
+ ovs_assert(ovs_scan(" 123", "%i", &i));
+ ovs_assert(i == 123);
+ ovs_assert(ovs_scan("0x123", "%i", &i));
+ ovs_assert(i == 0x123);
+ ovs_assert(ovs_scan("123", "%2i %i", &i, &i2));
+ ovs_assert(i == 12);
+ ovs_assert(i2 == 3);
+ ovs_assert(ovs_scan("+123", "%2i %i", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("-123", "%2i %i", &i, &i2));
+ ovs_assert(i == -1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("0123", "%2i %i", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("123", "%*2i %i", &i));
+ ovs_assert(i == 3);
+ ovs_assert(ovs_scan("+123", "%2i %*i", &i));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 23);
+ ovs_assert(ovs_scan("-123", "%*2i %*i"));
+
+ ovs_assert(ovs_scan("123", "%o", &i));
+ ovs_assert(i == 0123);
+ ovs_assert(ovs_scan("0", "%o", &i));
+ ovs_assert(i == 0);
+ ovs_assert(!ovs_scan("123", "%o%o", &i, &i2));
+ ovs_assert(ovs_scan("+123", "%o", &i));
+ ovs_assert(i == 0123);
+ ovs_assert(ovs_scan("-123", "%o", &i));
+ ovs_assert(i == -0123);
+ ovs_assert(ovs_scan("0123", "%o", &i));
+ ovs_assert(i == 0123);
+ ovs_assert(ovs_scan(" 123", "%o", &i));
+ ovs_assert(i == 0123);
+ ovs_assert(ovs_scan("0x123", "%o", &i));
+ ovs_assert(i == 0);
+ ovs_assert(ovs_scan("123", "%2o %o", &i, &i2));
+ ovs_assert(i == 012);
+ ovs_assert(i2 == 3);
+ ovs_assert(ovs_scan("+123", "%2o %o", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 023);
+ ovs_assert(ovs_scan("-123", "%2o %o", &i, &i2));
+ ovs_assert(i == -1);
+ ovs_assert(i2 == 023);
+ ovs_assert(ovs_scan("0123", "%2o %o", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 023);
+ ovs_assert(ovs_scan("123", "%*2o %o", &i));
+ ovs_assert(i == 3);
+ ovs_assert(ovs_scan("+123", "%2o %*o", &i));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 023);
+ ovs_assert(ovs_scan("-123", "%*2o %*o"));
+
+ ovs_assert(ovs_scan("123", "%x", &i));
+ ovs_assert(i == 0x123);
+ ovs_assert(ovs_scan("0", "%x", &i));
+ ovs_assert(i == 0);
+ ovs_assert(!ovs_scan("123", "%x%x", &i, &i2));
+ ovs_assert(ovs_scan("+123", "%x", &i));
+ ovs_assert(i == 0x123);
+ ovs_assert(ovs_scan("-123", "%x", &i));
+ ovs_assert(i == -0x123);
+ ovs_assert(ovs_scan("0123", "%x", &i));
+ ovs_assert(i == 0x123);
+ ovs_assert(ovs_scan(" 123", "%x", &i));
+ ovs_assert(i == 0x123);
+ ovs_assert(ovs_scan("0x123", "%x", &i));
+ ovs_assert(i == 0x123);
+ ovs_assert(ovs_scan("123", "%2x %x", &i, &i2));
+ ovs_assert(i == 0x12);
+ ovs_assert(i2 == 3);
+ ovs_assert(ovs_scan("+123", "%2x %x", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 0x23);
+ ovs_assert(ovs_scan("-123", "%2x %x", &i, &i2));
+ ovs_assert(i == -1);
+ ovs_assert(i2 == 0x23);
+ ovs_assert(ovs_scan("0123", "%2x %x", &i, &i2));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 0x23);
+ ovs_assert(ovs_scan("123", "%*2x %x", &i));
+ ovs_assert(i == 3);
+ ovs_assert(ovs_scan("+123", "%2x %*x", &i));
+ ovs_assert(i == 1);
+ ovs_assert(i2 == 0x23);
+ ovs_assert(ovs_scan("-123", "%*2x %*x"));
+
+ ovs_assert(ovs_scan("123", "%hd", &s));
+ ovs_assert(s == 123);
+ ovs_assert(!ovs_scan("123", "%hd%hd", &s, &s2));
+ ovs_assert(ovs_scan("+123", "%hd", &s));
+ ovs_assert(s == 123);
+ ovs_assert(ovs_scan("-123", "%hd", &s));
+ ovs_assert(s == -123);
+ ovs_assert(ovs_scan("0123", "%hd", &s));
+ ovs_assert(s == 123);
+ ovs_assert(ovs_scan(" 123", "%hd", &s));
+ ovs_assert(s == 123);
+ ovs_assert(ovs_scan("0x123", "%hd", &s));
+ ovs_assert(s == 0);
+ ovs_assert(ovs_scan("123", "%2hd %hd", &s, &s2));
+ ovs_assert(s == 12);
+ ovs_assert(s2 == 3);
+ ovs_assert(ovs_scan("+123", "%2hd %hd", &s, &s2));
+ ovs_assert(s == 1);
+ ovs_assert(s2 == 23);
+ ovs_assert(ovs_scan("-123", "%2hd %hd", &s, &s2));
+ ovs_assert(s == -1);
+ ovs_assert(s2 == 23);
+ ovs_assert(ovs_scan("0123", "%2hd %hd", &s, &s2));
+ ovs_assert(s == 1);
+ ovs_assert(s2 == 23);
+
+ ovs_assert(ovs_scan("123", "%hhd", &c));
+ ovs_assert(c == 123);
+ ovs_assert(ovs_scan("0", "%hhd", &c));
+ ovs_assert(c == 0);
+ ovs_assert(!ovs_scan("123", "%hhd%hhd", &c, &c2));
+ ovs_assert(ovs_scan("+123", "%hhd", &c));
+ ovs_assert(c == 123);
+ ovs_assert(ovs_scan("-123", "%hhd", &c));
+ ovs_assert(c == -123);
+ ovs_assert(ovs_scan("0123", "%hhd", &c));
+ ovs_assert(c == 123);
+ ovs_assert(ovs_scan(" 123", "%hhd", &c));
+ ovs_assert(c == 123);
+ ovs_assert(ovs_scan("0x123", "%hhd", &c));
+ ovs_assert(c == 0);
+ ovs_assert(ovs_scan("123", "%2hhd %hhd", &c, &c2));
+ ovs_assert(c == 12);
+ ovs_assert(c2 == 3);
+ ovs_assert(ovs_scan("+123", "%2hhd %hhd", &c, &c2));
+ ovs_assert(c == 1);
+ ovs_assert(c2 == 23);
+ ovs_assert(ovs_scan("-123", "%2hhd %hhd", &c, &c2));
+ ovs_assert(c == -1);
+ ovs_assert(c2 == 23);
+ ovs_assert(ovs_scan("0123", "%2hhd %hhd", &c, &c2));
+ ovs_assert(c == 1);
+ ovs_assert(c2 == 23);
+
+ ovs_assert(ovs_scan("123", "%ld", &l));
+ ovs_assert(l == 123);
+ ovs_assert(ovs_scan("0", "%ld", &l));
+ ovs_assert(l == 0);
+ ovs_assert(!ovs_scan("123", "%ld%ld", &l, &l2));
+ ovs_assert(ovs_scan("+123", "%ld", &l));
+ ovs_assert(l == 123);
+ ovs_assert(ovs_scan("-123", "%ld", &l));
+ ovs_assert(l == -123);
+ ovs_assert(ovs_scan("0123", "%ld", &l));
+ ovs_assert(l == 123);
+ ovs_assert(ovs_scan(" 123", "%ld", &l));
+ ovs_assert(l == 123);
+ ovs_assert(ovs_scan("0x123", "%ld", &l));
+ ovs_assert(l == 0);
+ ovs_assert(ovs_scan("123", "%2ld %ld", &l, &l2));
+ ovs_assert(l == 12);
+ ovs_assert(l2 == 3);
+ ovs_assert(ovs_scan("+123", "%2ld %ld", &l, &l2));
+ ovs_assert(l == 1);
+ ovs_assert(l2 == 23);
+ ovs_assert(ovs_scan("-123", "%2ld %ld", &l, &l2));
+ ovs_assert(l == -1);
+ ovs_assert(l2 == 23);
+ ovs_assert(ovs_scan("0123", "%2ld %ld", &l, &l2));
+ ovs_assert(l == 1);
+ ovs_assert(l2 == 23);
+
+ ovs_assert(ovs_scan("123", "%lld", &ll));
+ ovs_assert(ll == 123);
+ ovs_assert(ovs_scan("0", "%lld", &ll));
+ ovs_assert(ll == 0);
+ ovs_assert(!ovs_scan("123", "%lld%lld", &ll, &ll2));
+ ovs_assert(ovs_scan("+123", "%lld", &ll));
+ ovs_assert(ll == 123);
+ ovs_assert(ovs_scan("-123", "%lld", &ll));
+ ovs_assert(ll == -123);
+ ovs_assert(ovs_scan("0123", "%lld", &ll));
+ ovs_assert(ll == 123);
+ ovs_assert(ovs_scan(" 123", "%lld", &ll));
+ ovs_assert(ll == 123);
+ ovs_assert(ovs_scan("0x123", "%lld", &ll));
+ ovs_assert(ll == 0);
+ ovs_assert(ovs_scan("123", "%2lld %lld", &ll, &ll2));
+ ovs_assert(ll == 12);
+ ovs_assert(ll2 == 3);
+ ovs_assert(ovs_scan("+123", "%2lld %lld", &ll, &ll2));
+ ovs_assert(ll == 1);
+ ovs_assert(ll2 == 23);
+ ovs_assert(ovs_scan("-123", "%2lld %lld", &ll, &ll2));
+ ovs_assert(ll == -1);
+ ovs_assert(ll2 == 23);
+ ovs_assert(ovs_scan("0123", "%2lld %lld", &ll, &ll2));
+ ovs_assert(ll == 1);
+ ovs_assert(ll2 == 23);
+
+ ovs_assert(ovs_scan("123", "%jd", &im));
+ ovs_assert(im == 123);
+ ovs_assert(ovs_scan("0", "%jd", &im));
+ ovs_assert(im == 0);
+ ovs_assert(!ovs_scan("123", "%jd%jd", &im, &im2));
+ ovs_assert(ovs_scan("+123", "%jd", &im));
+ ovs_assert(im == 123);
+ ovs_assert(ovs_scan("-123", "%jd", &im));
+ ovs_assert(im == -123);
+ ovs_assert(ovs_scan("0123", "%jd", &im));
+ ovs_assert(im == 123);
+ ovs_assert(ovs_scan(" 123", "%jd", &im));
+ ovs_assert(im == 123);
+ ovs_assert(ovs_scan("0x123", "%jd", &im));
+ ovs_assert(im == 0);
+ ovs_assert(ovs_scan("123", "%2jd %jd", &im, &im2));
+ ovs_assert(im == 12);
+ ovs_assert(im2 == 3);
+ ovs_assert(ovs_scan("+123", "%2jd %jd", &im, &im2));
+ ovs_assert(im == 1);
+ ovs_assert(im2 == 23);
+ ovs_assert(ovs_scan("-123", "%2jd %jd", &im, &im2));
+ ovs_assert(im == -1);
+ ovs_assert(im2 == 23);
+ ovs_assert(ovs_scan("0123", "%2jd %jd", &im, &im2));
+ ovs_assert(im == 1);
+ ovs_assert(im2 == 23);
+
+ ovs_assert(ovs_scan("123", "%td", &pd));
+ ovs_assert(pd == 123);
+ ovs_assert(ovs_scan("0", "%td", &pd));
+ ovs_assert(pd == 0);
+ ovs_assert(!ovs_scan("123", "%td%td", &pd, &pd2));
+ ovs_assert(ovs_scan("+123", "%td", &pd));
+ ovs_assert(pd == 123);
+ ovs_assert(ovs_scan("-123", "%td", &pd));
+ ovs_assert(pd == -123);
+ ovs_assert(ovs_scan("0123", "%td", &pd));
+ ovs_assert(pd == 123);
+ ovs_assert(ovs_scan(" 123", "%td", &pd));
+ ovs_assert(pd == 123);
+ ovs_assert(ovs_scan("0x123", "%td", &pd));
+ ovs_assert(pd == 0);
+ ovs_assert(ovs_scan("123", "%2td %td", &pd, &pd2));
+ ovs_assert(pd == 12);
+ ovs_assert(pd2 == 3);
+ ovs_assert(ovs_scan("+123", "%2td %td", &pd, &pd2));
+ ovs_assert(pd == 1);
+ ovs_assert(pd2 == 23);
+ ovs_assert(ovs_scan("-123", "%2td %td", &pd, &pd2));
+ ovs_assert(pd == -1);
+ ovs_assert(pd2 == 23);
+ ovs_assert(ovs_scan("0123", "%2td %td", &pd, &pd2));
+ ovs_assert(pd == 1);
+ ovs_assert(pd2 == 23);
+
+ ovs_assert(ovs_scan("123", "%zd", &sz));
+ ovs_assert(sz == 123);
+ ovs_assert(ovs_scan("0", "%zd", &sz));
+ ovs_assert(sz == 0);
+ ovs_assert(!ovs_scan("123", "%zd%zd", &sz, &sz2));
+ ovs_assert(ovs_scan("+123", "%zd", &sz));
+ ovs_assert(sz == 123);
+ ovs_assert(ovs_scan("-123", "%zd", &sz));
+ ovs_assert(sz == -123);
+ ovs_assert(ovs_scan("0123", "%zd", &sz));
+ ovs_assert(sz == 123);
+ ovs_assert(ovs_scan(" 123", "%zd", &sz));
+ ovs_assert(sz == 123);
+ ovs_assert(ovs_scan("0x123", "%zd", &sz));
+ ovs_assert(sz == 0);
+ ovs_assert(ovs_scan("123", "%2zd %zd", &sz, &sz2));
+ ovs_assert(sz == 12);
+ ovs_assert(sz2 == 3);
+ ovs_assert(ovs_scan("+123", "%2zd %zd", &sz, &sz2));
+ ovs_assert(sz == 1);
+ ovs_assert(sz2 == 23);
+ ovs_assert(ovs_scan("-123", "%2zd %zd", &sz, &sz2));
+ ovs_assert(sz == -1);
+ ovs_assert(sz2 == 23);
+ ovs_assert(ovs_scan("0123", "%2zd %zd", &sz, &sz2));
+ ovs_assert(sz == 1);
+ ovs_assert(sz2 == 23);
+
+ ovs_assert(ovs_scan("0.25", "%f", &f));
+ ovs_assert(f == 0.25);
+ ovs_assert(ovs_scan("1.0", "%f", &f));
+ ovs_assert(f == 1.0);
+ ovs_assert(ovs_scan("-5", "%f", &f));
+ ovs_assert(f == -5.0);
+ ovs_assert(ovs_scan("+6", "%f", &f));
+ ovs_assert(f == 6.0);
+ ovs_assert(ovs_scan("-1e5", "%f", &f));
+ ovs_assert(f == -1e5);
+ ovs_assert(ovs_scan("-.25", "%f", &f));
+ ovs_assert(f == -.25);
+ ovs_assert(ovs_scan("+123.e1", "%f", &f));
+ ovs_assert(f == 1230.0);
+ ovs_assert(ovs_scan("25e-2", "%f", &f));
+ ovs_assert(f == 0.25);
+ ovs_assert(ovs_scan("0.25", "%1f %f", &f, &f2));
+ ovs_assert(f == 0);
+ ovs_assert(f2 == 0.25);
+ ovs_assert(ovs_scan("1.0", "%2f %f", &f, &f2));
+ ovs_assert(f == 1.0);
+ ovs_assert(f2 == 0.0);
+ ovs_assert(!ovs_scan("-5", "%1f", &f));
+ ovs_assert(!ovs_scan("+6", "%1f", &f));
+ ovs_assert(!ovs_scan("-1e5", "%2f %*f", &f));
+ ovs_assert(f == -1);
+ ovs_assert(!ovs_scan("-.25", "%2f", &f));
+ ovs_assert(!ovs_scan("+123.e1", "%6f", &f));
+ ovs_assert(!ovs_scan("25e-2", "%4f", &f));
+
+ ovs_assert(ovs_scan("0.25", "%lf", &d));
+ ovs_assert(d == 0.25);
+ ovs_assert(ovs_scan("1.0", "%lf", &d));
+ ovs_assert(d == 1.0);
+ ovs_assert(ovs_scan("-5", "%lf", &d));
+ ovs_assert(d == -5.0);
+ ovs_assert(ovs_scan("+6", "%lf", &d));
+ ovs_assert(d == 6.0);
+ ovs_assert(ovs_scan("-1e5", "%lf", &d));
+ ovs_assert(d == -1e5);
+ ovs_assert(ovs_scan("-.25", "%lf", &d));
+ ovs_assert(d == -.25);
+ ovs_assert(ovs_scan("+123.e1", "%lf", &d));
+ ovs_assert(d == 1230.0);
+ ovs_assert(ovs_scan("25e-2", "%lf", &d));
+ ovs_assert(d == 0.25);
+ ovs_assert(ovs_scan("0.25", "%1lf %lf", &d, &d2));
+ ovs_assert(d == 0);
+ ovs_assert(d2 == 0.25);
+ ovs_assert(ovs_scan("1.0", "%2lf %lf", &d, &d2));
+ ovs_assert(d == 1.0);
+ ovs_assert(d2 == 0.0);
+ ovs_assert(!ovs_scan("-5", "%1lf", &d));
+ ovs_assert(!ovs_scan("+6", "%1lf", &d));
+ ovs_assert(!ovs_scan("-1e5", "%2lf %*f", &d));
+ ovs_assert(d == -1);
+ ovs_assert(!ovs_scan("-.25", "%2lf", &d));
+ ovs_assert(!ovs_scan("+123.e1", "%6lf", &d));
+ ovs_assert(!ovs_scan("25e-2", "%4lf", &d));
+
+ ovs_assert(ovs_scan("0.25", "%Lf", &ld));
+ ovs_assert(ld == 0.25);
+ ovs_assert(ovs_scan("1.0", "%Lf", &ld));
+ ovs_assert(ld == 1.0);
+ ovs_assert(ovs_scan("-5", "%Lf", &ld));
+ ovs_assert(ld == -5.0);
+ ovs_assert(ovs_scan("+6", "%Lf", &ld));
+ ovs_assert(ld == 6.0);
+ ovs_assert(ovs_scan("-1e5", "%Lf", &ld));
+ ovs_assert(ld == -1e5);
+ ovs_assert(ovs_scan("-.25", "%Lf", &ld));
+ ovs_assert(ld == -.25);
+ ovs_assert(ovs_scan("+123.e1", "%Lf", &ld));
+ ovs_assert(ld == 1230.0);
+ ovs_assert(ovs_scan("25e-2", "%Lf", &ld));
+ ovs_assert(ld == 0.25);
+ ovs_assert(ovs_scan("0.25", "%1Lf %Lf", &ld, &ld2));
+ ovs_assert(ld == 0);
+ ovs_assert(ld2 == 0.25);
+ ovs_assert(ovs_scan("1.0", "%2Lf %Lf", &ld, &ld2));
+ ovs_assert(ld == 1.0);
+ ovs_assert(ld2 == 0.0);
+ ovs_assert(!ovs_scan("-5", "%1Lf", &ld));
+ ovs_assert(!ovs_scan("+6", "%1Lf", &ld));
+ ovs_assert(!ovs_scan("-1e5", "%2Lf %*f", &ld));
+ ovs_assert(ld == -1);
+ ovs_assert(!ovs_scan("-.25", "%2Lf", &ld));
+ ovs_assert(!ovs_scan("+123.e1", "%6Lf", &ld));
+ ovs_assert(!ovs_scan("25e-2", "%4Lf", &ld));
+
+ ovs_assert(ovs_scan(" Hello,\tworld ", "%*s%n%*s%n", &n, &n2));
+ ovs_assert(n == 7);
+ ovs_assert(n2 == 13);
+ ovs_assert(!ovs_scan(" Hello,\tworld ", "%*s%*s%*s"));
+ ovs_assert(ovs_scan(" Hello,\tworld ", "%6s%n%5s%n", str, &n, str2, &n2));
+ ovs_assert(!strcmp(str, "Hello,"));
+ ovs_assert(n == 7);
+ ovs_assert(!strcmp(str2, "world"));
+ ovs_assert(n2 == 13);
+ ovs_assert(ovs_scan(" Hello,\tworld ", "%5s%5s%5s", str, str2, str3));
+ ovs_assert(!strcmp(str, "Hello"));
+ ovs_assert(!strcmp(str2, ","));
+ ovs_assert(!strcmp(str3, "world"));
+ ovs_assert(!ovs_scan(" ", "%*s"));
+
+ ovs_assert(ovs_scan(" Hello,\tworld ", "%*c%n%*c%n%c%n",
+ &n, &n2, &c, &n3));
+ ovs_assert(n == 1);
+ ovs_assert(n2 == 2);
+ ovs_assert(c == 'e');
+ ovs_assert(n3 == 3);
+ ovs_assert(ovs_scan(" Hello,\tworld ", "%*5c%5c", str));
+ ovs_assert(!memcmp(str, "o,\two", 5));
+ ovs_assert(!ovs_scan(" Hello,\tworld ", "%*15c"));
+
+ ovs_assert(ovs_scan("0x1234xyzzy", "%9[x0-9a-fA-F]%n", str, &n));
+ ovs_assert(!strcmp(str, "0x1234x"));
+ ovs_assert(n == 7);
+ ovs_assert(ovs_scan("foo:bar=baz", "%5[^:=]%n:%5[^:=]%n=%5[^:=]%n",
+ str, &n, str2, &n2, str3, &n3));
+ ovs_assert(!strcmp(str, "foo"));
+ ovs_assert(n == 3);
+ ovs_assert(!strcmp(str2, "bar"));
+ ovs_assert(n2 == 7);
+ ovs_assert(!strcmp(str3, "baz"));
+ ovs_assert(n3 == 11);
+ ovs_assert(!ovs_scan(" ", "%*[0-9]"));
+ ovs_assert(ovs_scan("0x123a]4xyzzy-", "%[]x0-9a-fA-F]", str));
+ ovs_assert(!strcmp(str, "0x123a]4x"));
+ ovs_assert(ovs_scan("abc]xyz","%[^]xyz]", str));
+ ovs_assert(!strcmp(str, "abc"));
+ ovs_assert(!ovs_scan("0x123a]4xyzzy-", "%[x0-9]a-fA-F]", str));
+ ovs_assert(ovs_scan("0x12-3]xyz", "%[x0-9a-f-]", str));
+ ovs_assert(!strcmp(str, "0x12-3"));
+ ovs_assert(ovs_scan("0x12-3]xyz", "%[^a-f-]", str));
+ ovs_assert(!strcmp(str, "0x12"));
+ ovs_assert(sscanf("0x12-3]xyz", "%[^-a-f]", str));
+ ovs_assert(!strcmp(str, "0x12"));
+}
\f
static const struct command commands[] = {
{"ctz", 0, 0, test_ctz},
{"bitwise_is_all_zeros", 0, 0, test_bitwise_is_all_zeros},
{"follow-symlinks", 1, INT_MAX, test_follow_symlinks},
{"assert", 0, 0, test_assert},
+ {"ovs_scan", 0, 0, test_ovs_scan},
{NULL, 0, 0, NULL},
};