Merge "citrix" branch into "master".
[sliver-openvswitch.git] / ovsdb / ovsdb-idlc.in
index c314d61..6a0303d 100755 (executable)
@@ -8,284 +8,64 @@ import sys
 sys.path.insert(0, "@abs_top_srcdir@/ovsdb")
 import simplejson as json
 
-argv0 = sys.argv[0]
-
-class Error(Exception):
-    def __init__(self, msg):
-        Exception.__init__(self)
-        self.msg = msg
-
-def getMember(json, name, validTypes, description, default=None):
-    if name in json:
-        member = json[name]
-        if type(member) not in validTypes:
-            raise Error("%s: type mismatch for '%s' member"
-                        % (description, name))
-        return member
-    return default
-
-def mustGetMember(json, name, expectedType, description):
-    member = getMember(json, name, expectedType, description)
-    if member == None:
-        raise Error("%s: missing '%s' member" % (description, name))
-    return member
-
-class DbSchema:
-    def __init__(self, name, comment, tables, idlPrefix, idlHeader):
-        self.name = name
-        self.comment = comment
-        self.tables = tables
-        self.idlPrefix = idlPrefix
-        self.idlHeader = idlHeader
+from OVSDB import *
 
-    @staticmethod
-    def fromJson(json):
-        name = mustGetMember(json, 'name', [unicode], 'database')
-        comment = getMember(json, 'comment', [unicode], 'database')
-        tablesJson = mustGetMember(json, 'tables', [dict], 'database')
-        tables = {}
-        for tableName, tableJson in tablesJson.iteritems():
-            tables[tableName] = TableSchema.fromJson(tableJson,
-                                                     "%s table" % tableName)
-        idlPrefix = mustGetMember(json, 'idlPrefix', [unicode], 'database')
-        idlHeader = mustGetMember(json, 'idlHeader', [unicode], 'database')
-        return DbSchema(name, comment, tables, idlPrefix, idlHeader)
-
-class TableSchema:
-    def __init__(self, comment, columns):
-        self.comment = comment
-        self.columns = columns
+argv0 = sys.argv[0]
 
-    @staticmethod
-    def fromJson(json, description):
-        comment = getMember(json, 'comment', [unicode], description)
-        columnsJson = mustGetMember(json, 'columns', [dict], description)
-        columns = {}
-        for name, json in columnsJson.iteritems():
-            columns[name] = ColumnSchema.fromJson(
-                json, "column %s in %s" % (name, description))
-        return TableSchema(comment, columns)
-
-class ColumnSchema:
-    def __init__(self, comment, type, persistent):
-        self.comment = comment
+class Datum:
+    def __init__(self, type, values):
         self.type = type
-        self.persistent = persistent
+        self.values = values
 
     @staticmethod
-    def fromJson(json, description):
-        comment = getMember(json, 'comment', [unicode], description)
-        type = Type.fromJson(mustGetMember(json, 'type', [dict, unicode],
-                                           description),
-                             'type of %s' % description)
-        ephemeral = getMember(json, 'ephemeral', [bool], description)
-        persistent = ephemeral != True
-        return ColumnSchema(comment, type, persistent)
-
-def escapeCString(src):
-    dst = ""
-    for c in src:
-        if c in "\\\"":
-            dst += "\\" + c
-        elif ord(c) < 32:
-            if c == '\n':
-                dst += '\\n'
-            elif c == '\r':
-                dst += '\\r'
-            elif c == '\a':
-                dst += '\\a'
-            elif c == '\b':
-                dst += '\\b'
-            elif c == '\f':
-                dst += '\\f'
-            elif c == '\t':
-                dst += '\\t'
-            elif c == '\v':
-                dst += '\\v'
+    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:
-                dst += '\\%03o' % ord(c)
-        else:
-            dst += c
-    return dst
-
-class BaseType:
-    def __init__(self, type,
-                 refTable=None,
-                 minInteger=None, maxInteger=None,
-                 minReal=None, maxReal=None,
-                 minLength=None, maxLength=None):
-        self.type = type
-        self.refTable = refTable
-        self.minInteger = minInteger
-        self.maxInteger = maxInteger
-        self.minReal = minReal
-        self.maxReal = maxReal
-        self.minLength = minLength
-        self.maxLength = maxLength
-
-    @staticmethod
-    def fromJson(json, description):
-        if type(json) == unicode:
-            return BaseType(json)
-        else:
-            atomicType = mustGetMember(json, 'type', [unicode], description)
-            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)
-            minLength = getMember(json, 'minLength', [int], description)
-            maxLength = getMember(json, 'minLength', [int], description)
-            return BaseType(atomicType, refTable, minInteger, maxInteger, minReal, maxReal, minLength, maxLength)
-
-    def toEnglish(self):
-        if self.type == 'uuid' and self.refTable:
-            return self.refTable
+                values = [Atom.fromJson(type_.key, json)]
         else:
-            return self.type
-
-    def toCType(self, prefix):
-        if self.refTable:
-            return "struct %s%s *" % (prefix, self.refTable.lower())
-        else:
-            return {'integer': 'int64_t ',
-                    'real': 'double ',
-                    'uuid': 'struct uuid ',
-                    'boolean': 'bool ',
-                    'string': 'char *'}[self.type]
-
-    def copyCValue(self, dst, src):
-        args = {'dst': dst, 'src': src}
-        if self.refTable:
-            return ("%(dst)s = %(src)s->header_.uuid;") % args
-        elif self.type == 'string':
-            return "%(dst)s = xstrdup(%(src)s);" % args
-        else:
-            return "%(dst)s = %(src)s;" % args
-
-    def initCDefault(self, var, isOptional):
-        if self.refTable:
-            return "%s = NULL;" % var
-        elif self.type == 'string' and not isOptional:
-            return "%s = \"\";" % var
-        else:
-            return {'integer': '%s = 0;',
-                    'real': '%s = 0.0;',
-                    'uuid': 'uuid_zero(&%s);',
-                    'boolean': '%s = false;',
-                    'string': '%s = NULL;'}[self.type] % var
-
-    def cInitBaseType(self, indent, var):
-        stmts = []
-        stmts.append('ovsdb_base_type_init(&%s, OVSDB_TYPE_%s);' % (
-                var, self.type.upper()),)
-        if self.type == 'integer':
-            if self.minInteger != None:
-                stmts.append('%s.u.integer.min = %d;' % (var, self.minInteger))
-            if self.maxInteger != None:
-                stmts.append('%s.u.integer.max = %d;' % (var, self.maxInteger))
-        elif self.type == 'real':
-            if self.minReal != None:
-                stmts.append('%s.u.real.min = %d;' % (var, self.minReal))
-            if self.maxReal != None:
-                stmts.append('%s.u.real.max = %d;' % (var, self.maxReal))
-        elif self.type == 'string':
-            if self.minLength != None:
-                stmts.append('%s.u.string.minLen = %d;' % (var, self.minLength))            
-            if self.maxLength != None:
-                stmts.append('%s.u.string.maxLen = %d;' % (var, self.maxLength))
-        elif self.type == 'uuid':
-            if self.refTable != None:
-                stmts.append('%s.u.uuid.refTableName = "%s";' % (var, escapeCString(self.refTable)))
-        return '\n'.join([indent + stmt for stmt in stmts])
-
-class Type:
-    def __init__(self, key, value=None, min=1, max=1):
-        self.key = key
-        self.value = value
-        self.min = min
-        self.max = max
-    
-    @staticmethod
-    def fromJson(json, description):
-        if type(json) == unicode:
-            return Type(BaseType(json))
+            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:
-            keyJson = mustGetMember(json, 'key', [dict, unicode], description)
-            key = BaseType.fromJson(keyJson, 'key in %s' % description)
-
-            valueJson = getMember(json, 'value', [dict, unicode], description)
-            if valueJson:
-                value = BaseType.fromJson(valueJson,
-                                          'value in %s' % description)
-            else:
-                value = None
-
-            min = getMember(json, 'min', [int], description, 1)
-            max = getMember(json, 'max', [int, unicode], description, 1)
-            return Type(key, value, min, max)
-
-    def isScalar(self):
-        return self.min == 1 and self.max == 1 and not self.value
+            s += ["%s->values = NULL;" % var]
 
-    def isOptional(self):
-        return self.min == 0 and self.max == 1
+        if len(self.values) > 1:
+            s += ["ovsdb_datum_sort_assert(%s, OVSDB_TYPE_%s);"
+                  % (var, self.type.key.upper())]
 
-    def isOptionalPointer(self):
-        return (self.min == 0 and self.max == 1 and not self.value
-                and (self.key.type == 'string' or self.key.refTable))
-
-    def toEnglish(self):
-        keyName = self.key.toEnglish()
-        if self.value:
-            valueName = self.value.toEnglish()
-
-        if self.isScalar():
-            return keyName
-        elif self.isOptional():
-            if self.value:
-                return "optional %s-%s pair" % (keyName, valueName)
-            else:
-                return "optional %s" % keyName
-        else:
-            if self.max == "unlimited":
-                if self.min:
-                    quantity = "%d or more " % self.min
-                else:
-                    quantity = ""
-            elif self.min:
-                quantity = "%d to %d " % (self.min, self.max)
-            else:
-                quantity = "up to %d " % self.max
-
-            if self.value:
-                return "map of %s%s-%s pairs" % (quantity, keyName, valueName)
-            else:
-                return "set of %s%s" % (quantity, keyName)
-                
-    def cDeclComment(self):
-        if self.min == 1 and self.max == 1 and self.key.type == "string":
-            return "\t/* Always nonnull. */"
-        else:
-            return ""
-
-    def cInitType(self, indent, var):
-        initKey = self.key.cInitBaseType(indent, "%s.key" % var)
-        if self.value:
-            initValue = self.value.cInitBaseType(indent, "%s.value" % var)
-        else:
-            initValue = ('%sovsdb_base_type_init(&%s.value, '
-                         'OVSDB_TYPE_VOID);' % (indent, var))
-        initMin = "%s%s.n_min = %s;" % (indent, var, self.min)
-        if self.max == "unlimited":
-            max = "UINT_MAX"
-        else:
-            max = self.max
-        initMax = "%s%s.n_max = %s;" % (indent, var, max)
-        return "\n".join((initKey, initValue, initMin, initMax))
+        return s
 
 def parseSchema(filename):
-    return DbSchema.fromJson(json.load(open(filename, "r")))
+    return IdlSchema.fromJson(json.load(open(filename, "r")))
 
 def annotateSchema(schemaFile, annotationFile):
     schemaJson = json.load(open(schemaFile, "r"))
@@ -451,10 +231,7 @@ static struct %(s)s *
     for tableName, table in sorted(schema.tables.iteritems()):
         structName = "%s%s" % (prefix, tableName.lower())
         print "\f"
-        if table.comment != None:
-            print "/* %s table (%s). */" % (tableName, table.comment)
-        else:
-            print "/* %s table. */" % (tableName)
+        print "/* %s table. */" % (tableName)
 
         # Parse functions.
         for columnName, column in sorted(table.columns.iteritems()):
@@ -751,25 +528,7 @@ def ovsdb_escape(string):
             return '\\x%02x' % ord(c)
     return re.sub(r'["\\\000-\037]', escape, string)
 
-def printDoc(schemaFile):
-    schema = parseSchema(schemaFile)
-    print schema.name
-    if schema.comment:
-        print schema.comment
 
-    for tableName, table in sorted(schema.tables.iteritems()):
-        title = "%s table" % tableName
-        print
-        print title
-        print '-' * len(title)
-        if table.comment:
-            print table.comment
-
-        for columnName, column in sorted(table.columns.iteritems()):
-            print
-            print "%s (%s)" % (columnName, column.type.toEnglish())
-            if column.comment:
-                print "\t%s" % column.comment
 
 def usage():
     print """\
@@ -780,7 +539,7 @@ The following commands are supported:
   annotate SCHEMA ANNOTATIONS print SCHEMA combined with ANNOTATIONS
   c-idl-header IDL            print C header file for IDL
   c-idl-source IDL            print C source file for IDL implementation
-  doc IDL                     print schema documentation
+  nroff IDL                   print schema documentation in nroff format
 
 The following options are also available:
   -h, --help                  display this help message
@@ -818,8 +577,7 @@ if __name__ == "__main__":
 
         commands = {"annotate": (annotateSchema, 2),
                     "c-idl-header": (printCIDLHeader, 1),
-                    "c-idl-source": (printCIDLSource, 1),
-                    "doc": (printDoc, 1)}
+                    "c-idl-source": (printCIDLSource, 1)}
 
         if not args[0] in commands:
             sys.stderr.write("%s: unknown command \"%s\" "