+
+static struct ovsdb_error *
+check_string_constraints(const char *s,
+ const struct ovsdb_string_constraints *c)
+{
+ size_t n_chars;
+ char *msg;
+
+ msg = utf8_validate(s, &n_chars);
+ if (msg) {
+ struct ovsdb_error *error;
+
+ error = ovsdb_error("constraint violation",
+ "\"%s\" is not a valid UTF-8 string: %s",
+ s, msg);
+ free(msg);
+ return error;
+ }
+
+ if (n_chars < c->minLen) {
+ return ovsdb_error(
+ "constraint violation",
+ "\"%s\" length %zu is less than minimum allowed "
+ "length %u", s, n_chars, c->minLen);
+ } else if (n_chars > c->maxLen) {
+ return ovsdb_error(
+ "constraint violation",
+ "\"%s\" length %zu is greater than maximum allowed "
+ "length %u", s, n_chars, c->maxLen);
+ }
+
+#if HAVE_PCRE
+ if (c->re) {
+ int retval;
+
+ retval = pcre_exec(c->re, NULL, s, strlen(s), 0,
+ PCRE_ANCHORED | PCRE_NO_UTF8_CHECK, NULL, 0);
+ if (retval == PCRE_ERROR_NOMATCH) {
+ if (c->reComment) {
+ return ovsdb_error("constraint violation",
+ "\"%s\" is not a %s", s, c->reComment);
+ } else {
+ return ovsdb_error("constraint violation",
+ "\"%s\" does not match regular expression "
+ "/%s/", s, c->reMatch);
+ }
+ } else if (retval < 0) {
+ /* PCRE doesn't have a function to translate an error code to a
+ * description. Bizarre. See pcreapi(3) for error details. */
+ return ovsdb_error("internal error", "PCRE returned error %d",
+ retval);
+ }
+ }
+#endif /* HAVE_PCRE */
+
+ return NULL;
+}
+
+/* Checks whether 'atom' meets the constraints (if any) defined in 'base'.
+ * (base->type must specify 'atom''s type.) Returns a null pointer if the
+ * constraints are met, otherwise an error that explains the violation. */
+struct ovsdb_error *
+ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
+ const struct ovsdb_base_type *base)
+{
+ switch (base->type) {
+ case OVSDB_TYPE_VOID:
+ NOT_REACHED();
+
+ case OVSDB_TYPE_INTEGER:
+ if (atom->integer >= base->u.integer.min
+ && atom->integer <= base->u.integer.max) {
+ return NULL;
+ } else if (base->u.integer.min != INT64_MIN) {
+ if (base->u.integer.max != INT64_MAX) {
+ return ovsdb_error("constraint violation",
+ "%"PRId64" is not in the valid range "
+ "%"PRId64" to %"PRId64" (inclusive)",
+ atom->integer,
+ base->u.integer.min, base->u.integer.max);
+ } else {
+ return ovsdb_error("constraint violation",
+ "%"PRId64" is less than minimum allowed "
+ "value %"PRId64,
+ atom->integer, base->u.integer.min);
+ }
+ } else {
+ return ovsdb_error("constraint violation",
+ "%"PRId64" is greater than maximum allowed "
+ "value %"PRId64,
+ atom->integer, base->u.integer.max);
+ }
+ NOT_REACHED();
+
+ case OVSDB_TYPE_REAL:
+ if (atom->real >= base->u.real.min && atom->real <= base->u.real.max) {
+ return NULL;
+ } else if (base->u.real.min != -DBL_MAX) {
+ if (base->u.real.max != DBL_MAX) {
+ return ovsdb_error("constraint violation",
+ "%.*g is not in the valid range "
+ "%.*g to %.*g (inclusive)",
+ DBL_DIG, atom->real,
+ DBL_DIG, base->u.real.min,
+ DBL_DIG, base->u.real.max);
+ } else {
+ return ovsdb_error("constraint violation",
+ "%.*g is less than minimum allowed "
+ "value %.*g",
+ DBL_DIG, atom->real,
+ DBL_DIG, base->u.real.min);
+ }
+ } else {
+ return ovsdb_error("constraint violation",
+ "%.*g is greater than maximum allowed "
+ "value %.*g",
+ DBL_DIG, atom->real,
+ DBL_DIG, base->u.real.max);
+ }
+ NOT_REACHED();
+
+ case OVSDB_TYPE_BOOLEAN:
+ return NULL;
+
+ case OVSDB_TYPE_STRING:
+ return check_string_constraints(atom->string, &base->u.string);
+
+ case OVSDB_TYPE_UUID:
+ return NULL;
+
+ case OVSDB_N_TYPES:
+ default:
+ NOT_REACHED();
+ }
+}