xenserver: Various fixes for vif script
[openvswitch] / ovsdb / ovsdb-idlc.in
index 9a90679ec43d492c349144ebf7c88b3e93630160..2426e2dacc9d966052e4c3075d0eca6d60dedcb7 100755 (executable)
@@ -18,7 +18,7 @@ class Error(Exception):
 def getMember(json, name, validTypes, description, default=None):
     if name in json:
         member = json[name]
-        if type(member) not in validTypes:
+        if len(validTypes) and type(member) not in validTypes:
             raise Error("%s: type mismatch for '%s' member"
                         % (description, name))
         return member
@@ -108,18 +108,94 @@ def escapeCString(src):
             dst += c
     return dst
 
+class UUID:
+    x = "[0-9a-fA-f]"
+    uuidRE = re.compile("^(%s{8})-(%s{4})-(%s{4})-(%s{4})-(%s{4})(%s{8})$"
+                        % (x, x, x, x, x, x))
+
+    def __init__(self, value):
+        self.value = value
+
+    @staticmethod
+    def fromString(s):
+        if not uuidRE.match(s):
+            raise Error("%s is not a valid UUID" % s)
+        return UUID(s)
+
+    @staticmethod
+    def fromJson(json):
+        if UUID.isValidJson(json):
+            return UUID(json[1])
+        else:
+            raise Error("%s is not valid JSON for a UUID" % json)
+
+    @staticmethod
+    def isValidJson(json):
+        return len(json) == 2 and json[0] == "uuid" and uuidRE.match(json[1])
+            
+    def toJson(self):
+        return ["uuid", self.value]
+
+    def cInitUUID(self, var):
+        m = re.match(self.value)
+        return ["%s.parts[0] = 0x%s;" % (var, m.group(1)),
+                "%s.parts[1] = 0x%s%s;" % (var, m.group(2), m.group(3)),
+                "%s.parts[2] = 0x%s%s;" % (var, m.group(4), m.group(5)),
+                "%s.parts[3] = 0x%s;" % (var, m.group(6))]
+
+class Atom:
+    def __init__(self, type, value):
+        self.type = type
+        self.value = value
+
+    @staticmethod
+    def fromJson(type_, json):
+        if ((type_ == 'integer' and type(json) in [int, long])
+            or (type_ == 'real' and type(json) in [int, long, float])
+            or (type_ == 'boolean' and json in [True, False])
+            or (type_ == 'string' and type(json) in [str, unicode])):
+            return Atom(type_, json)
+        elif type_ == 'uuid':
+            return UUID.fromJson(json)
+        else:
+            raise Error("%s is not valid JSON for type %s" % (json, type_))
+
+    def toJson(self):
+        if self.type == 'uuid':
+            return self.value.toString()
+        else:
+            return self.value
+
+    def cInitAtom(self, var):
+        if self.type == 'integer':
+            return ['%s.integer = %d;' % (var, self.value)]
+        elif self.type == 'real':
+            return ['%s.real = %.15g;' % (var, self.value)]
+        elif self.type == 'boolean':
+            if self.value:
+                return ['%s.boolean = true;']
+            else:
+                return ['%s.boolean = false;']
+        elif self.type == 'string':
+            return ['%s.string = xstrdup("%s");'
+                    % (var, escapeCString(self.value))]
+        elif self.type == 'uuid':
+            return self.value.cInitUUID(var)        
+
 class BaseType:
-    def __init__(self, type, refTable=None, minInteger=None, maxInteger=None,
-                 minReal=None, maxReal=None, reMatch=None, reComment=None,
+    def __init__(self, type,
+                 enum=None,
+                 refTable=None,
+                 minInteger=None, maxInteger=None,
+                 minReal=None, maxReal=None,
                  minLength=None, maxLength=None):
         self.type = type
+        self.enum = enum
         self.refTable = refTable
         self.minInteger = minInteger
         self.maxInteger = maxInteger
         self.minReal = minReal
         self.maxReal = maxReal
-        self.reMatch = reMatch
-        self.reComment = reComment
         self.minLength = minLength
         self.maxLength = maxLength
 
@@ -129,16 +205,18 @@ class BaseType:
             return BaseType(json)
         else:
             atomicType = mustGetMember(json, 'type', [unicode], description)
+            enum = getMember(json, 'enum', [], description)
+            if enum:
+                enumType = Type(atomicType, None, 0, 'unlimited')
+                enum = Datum.fromJson(enumType, enum)
             refTable = getMember(json, 'refTable', [unicode], description)
             minInteger = getMember(json, 'minInteger', [int, long], description)
             maxInteger = getMember(json, 'maxInteger', [int, long], description)
             minReal = getMember(json, 'minReal', [int, long, float], description)
             maxReal = getMember(json, 'maxReal', [int, long, float], description)
-            reMatch = getMember(json, 'reMatch', [unicode], description)
-            reComment = getMember(json, 'reComment', [unicode], description)
             minLength = getMember(json, 'minLength', [int], description)
             maxLength = getMember(json, 'minLength', [int], description)
-            return BaseType(atomicType, refTable, minInteger, maxInteger, minReal, maxReal, reMatch, reComment, minLength, maxLength)
+            return BaseType(atomicType, enum, refTable, minInteger, maxInteger, minReal, maxReal, minLength, maxLength)
 
     def toEnglish(self):
         if self.type == 'uuid' and self.refTable:
@@ -181,6 +259,10 @@ class BaseType:
         stmts = []
         stmts.append('ovsdb_base_type_init(&%s, OVSDB_TYPE_%s);' % (
                 var, self.type.upper()),)
+        if self.enum:
+            stmts.append("%s.enum_ = xmalloc(sizeof *%s.enum_);"
+                         % (var, var))
+            stmts += self.enum.cInitDatum("%s.enum_" % var)
         if self.type == 'integer':
             if self.minInteger != None:
                 stmts.append('%s.u.integer.min = %d;' % (var, self.minInteger))
@@ -192,13 +274,6 @@ class BaseType:
             if self.maxReal != None:
                 stmts.append('%s.u.real.max = %d;' % (var, self.maxReal))
         elif self.type == 'string':
-            if self.reMatch != None:
-                if self.reComment != None:
-                    reComment = '"%s"' % escapeCString(self.reComment)
-                else:
-                    reComment = NULL
-                stmts.append('do_set_regex(&%s, "%s", %s);' % (
-                        var, escapeCString(self.reMatch), reComment))
             if self.minLength != None:
                 stmts.append('%s.u.string.minLen = %d;' % (var, self.minLength))            
             if self.maxLength != None:
@@ -293,6 +368,58 @@ class Type:
         initMax = "%s%s.n_max = %s;" % (indent, var, max)
         return "\n".join((initKey, initValue, initMin, initMax))
 
+class Datum:
+    def __init__(self, type, values):
+        self.type = type
+        self.values = values
+
+    @staticmethod
+    def fromJson(type_, json):
+        if not type_.value:
+            if len(json) == 2 and json[0] == "set":
+                values = []
+                for atomJson in json[1]:
+                    values += [Atom.fromJson(type_.key, atomJson)]
+            else:
+                values = [Atom.fromJson(type_.key, json)]
+        else:
+            if len(json) != 2 or json[0] != "map":
+                raise Error("%s is not valid JSON for a map" % json)
+            values = []
+            for pairJson in json[1]:
+                values += [(Atom.fromJson(type_.key, pairJson[0]),
+                            Atom.fromJson(type_.value, pairJson[1]))]
+        return Datum(type_, values)
+
+    def cInitDatum(self, var):
+        if len(self.values) == 0:
+            return ["ovsdb_datum_init_empty(%s);" % var]
+
+        s = ["%s->n = %d;" % (var, len(self.values))]
+        s += ["%s->keys = xmalloc(%d * sizeof *%s->keys);"
+              % (var, len(self.values), var)]
+
+        for i in range(len(self.values)):
+            key = self.values[i]
+            if self.type.value:
+                key = key[0]
+            s += key.cInitAtom("%s->keys[%d]" % (var, i))
+        
+        if self.type.value:
+            s += ["%s->values = xmalloc(%d * sizeof *%s->values);"
+                  % (var, len(self.values), var)]
+            for i in range(len(self.values)):
+                value = self.values[i][1]
+                s += key.cInitAtom("%s->values[%d]" % (var, i))
+        else:
+            s += ["%s->values = NULL;" % var]
+
+        if len(self.values) > 1:
+            s += ["ovsdb_datum_sort_assert(%s, OVSDB_TYPE_%s);"
+                  % (var, self.type.key.upper())]
+
+        return s
+
 def parseSchema(filename):
     return DbSchema.fromJson(json.load(open(filename, "r")))
 
@@ -443,21 +570,7 @@ def printCIDLSource(schemaFile):
 #include "ovsdb-error.h"
 
 static bool inited;
-
-static void OVS_UNUSED
-do_set_regex(struct ovsdb_base_type *base, const char *reMatch,
-             const char *reComment)
-{
-    struct ovsdb_error *error;
-
-    error = ovsdb_base_type_set_regex(base, reMatch, reComment);
-    if (error) {
-        char *s = ovsdb_error_to_string(error);
-        ovs_error(0, "%%s", s);
-        free(s);
-        ovsdb_error_destroy(error);
-    }
-}''' % schema.idlHeader
+''' % schema.idlHeader
 
     # Cast functions.
     for tableName, table in sorted(schema.tables.iteritems()):