]>
Commit | Line | Data |
---|---|---|
d879a707 BP |
1 | #! @PYTHON@ |
2 | ||
3 | import getopt | |
00732bf5 | 4 | import os |
d879a707 | 5 | import re |
d879a707 BP |
6 | import sys |
7 | ||
8 | sys.path.insert(0, "@abs_top_srcdir@/ovsdb") | |
9 | import simplejson as json | |
10 | ||
11 | argv0 = sys.argv[0] | |
12 | ||
13 | class Error(Exception): | |
14 | def __init__(self, msg): | |
15 | Exception.__init__(self) | |
16 | self.msg = msg | |
17 | ||
18 | def getMember(json, name, validTypes, description, default=None): | |
19 | if name in json: | |
20 | member = json[name] | |
21 | if type(member) not in validTypes: | |
22 | raise Error("%s: type mismatch for '%s' member" | |
23 | % (description, name)) | |
24 | return member | |
25 | return default | |
26 | ||
27 | def mustGetMember(json, name, expectedType, description): | |
28 | member = getMember(json, name, expectedType, description) | |
29 | if member == None: | |
30 | raise Error("%s: missing '%s' member" % (description, name)) | |
31 | return member | |
32 | ||
33 | class DbSchema: | |
c3bb4bd7 | 34 | def __init__(self, name, comment, tables, idlPrefix, idlHeader): |
d879a707 BP |
35 | self.name = name |
36 | self.comment = comment | |
37 | self.tables = tables | |
c3bb4bd7 BP |
38 | self.idlPrefix = idlPrefix |
39 | self.idlHeader = idlHeader | |
d879a707 BP |
40 | |
41 | @staticmethod | |
42 | def fromJson(json): | |
43 | name = mustGetMember(json, 'name', [unicode], 'database') | |
44 | comment = getMember(json, 'comment', [unicode], 'database') | |
45 | tablesJson = mustGetMember(json, 'tables', [dict], 'database') | |
46 | tables = {} | |
45a7de56 BP |
47 | for tableName, tableJson in tablesJson.iteritems(): |
48 | tables[tableName] = TableSchema.fromJson(tableJson, | |
49 | "%s table" % tableName) | |
c3bb4bd7 BP |
50 | idlPrefix = mustGetMember(json, 'idlPrefix', [unicode], 'database') |
51 | idlHeader = mustGetMember(json, 'idlHeader', [unicode], 'database') | |
52 | return DbSchema(name, comment, tables, idlPrefix, idlHeader) | |
d879a707 | 53 | |
d879a707 BP |
54 | class TableSchema: |
55 | def __init__(self, comment, columns): | |
56 | self.comment = comment | |
57 | self.columns = columns | |
58 | ||
59 | @staticmethod | |
60 | def fromJson(json, description): | |
61 | comment = getMember(json, 'comment', [unicode], description) | |
62 | columnsJson = mustGetMember(json, 'columns', [dict], description) | |
63 | columns = {} | |
64 | for name, json in columnsJson.iteritems(): | |
65 | columns[name] = ColumnSchema.fromJson( | |
66 | json, "column %s in %s" % (name, description)) | |
67 | return TableSchema(comment, columns) | |
68 | ||
d879a707 BP |
69 | class ColumnSchema: |
70 | def __init__(self, comment, type, persistent): | |
71 | self.comment = comment | |
72 | self.type = type | |
73 | self.persistent = persistent | |
74 | ||
75 | @staticmethod | |
76 | def fromJson(json, description): | |
77 | comment = getMember(json, 'comment', [unicode], description) | |
78 | type = Type.fromJson(mustGetMember(json, 'type', [dict, unicode], | |
79 | description), | |
80 | 'type of %s' % description) | |
1264cb08 | 81 | ephemeral = getMember(json, 'ephemeral', [bool], description) |
d879a707 BP |
82 | persistent = ephemeral != True |
83 | return ColumnSchema(comment, type, persistent) | |
84 | ||
bd76d25d BP |
85 | def escapeCString(src): |
86 | dst = "" | |
87 | for c in src: | |
88 | if c in "\\\"": | |
89 | dst += "\\" + c | |
90 | elif ord(c) < 32: | |
91 | if c == '\n': | |
92 | dst += '\\n' | |
93 | elif c == '\r': | |
94 | dst += '\\r' | |
95 | elif c == '\a': | |
96 | dst += '\\a' | |
97 | elif c == '\b': | |
98 | dst += '\\b' | |
99 | elif c == '\f': | |
100 | dst += '\\f' | |
101 | elif c == '\t': | |
102 | dst += '\\t' | |
103 | elif c == '\v': | |
104 | dst += '\\v' | |
105 | else: | |
106 | dst += '\\%03o' % ord(c) | |
107 | else: | |
108 | dst += c | |
109 | return dst | |
110 | ||
111 | class BaseType: | |
112 | def __init__(self, type, refTable=None, minInteger=None, maxInteger=None, | |
113 | minReal=None, maxReal=None, reMatch=None, reComment=None, | |
114 | minLength=None, maxLength=None): | |
115 | self.type = type | |
116 | self.refTable = refTable | |
117 | self.minInteger = minInteger | |
118 | self.maxInteger = maxInteger | |
119 | self.minReal = minReal | |
120 | self.maxReal = maxReal | |
121 | self.reMatch = reMatch | |
122 | self.reComment = reComment | |
123 | self.minLength = minLength | |
124 | self.maxLength = maxLength | |
125 | ||
126 | @staticmethod | |
127 | def fromJson(json, description): | |
128 | if type(json) == unicode: | |
129 | return BaseType(json) | |
130 | else: | |
131 | atomicType = mustGetMember(json, 'type', [unicode], description) | |
132 | refTable = getMember(json, 'refTable', [unicode], description) | |
133 | minInteger = getMember(json, 'minInteger', [int, long], description) | |
134 | maxInteger = getMember(json, 'maxInteger', [int, long], description) | |
135 | minReal = getMember(json, 'minReal', [int, long, float], description) | |
136 | maxReal = getMember(json, 'maxReal', [int, long, float], description) | |
137 | reMatch = getMember(json, 'reMatch', [unicode], description) | |
138 | reComment = getMember(json, 'reComment', [unicode], description) | |
139 | minLength = getMember(json, 'minLength', [int], description) | |
140 | maxLength = getMember(json, 'minLength', [int], description) | |
141 | return BaseType(atomicType, refTable, minInteger, maxInteger, minReal, maxReal, reMatch, reComment, minLength, maxLength) | |
142 | ||
143 | def toEnglish(self): | |
144 | if self.type == 'uuid' and self.refTable: | |
145 | return self.refTable | |
146 | else: | |
147 | return self.type | |
148 | ||
149 | def toCType(self, prefix): | |
150 | if self.refTable: | |
151 | return "struct %s%s *" % (prefix, self.refTable.lower()) | |
152 | else: | |
153 | return {'integer': 'int64_t ', | |
154 | 'real': 'double ', | |
155 | 'uuid': 'struct uuid ', | |
156 | 'boolean': 'bool ', | |
157 | 'string': 'char *'}[self.type] | |
158 | ||
159 | def copyCValue(self, dst, src): | |
160 | args = {'dst': dst, 'src': src} | |
161 | if self.refTable: | |
162 | return ("%(dst)s = %(src)s->header_.uuid;") % args | |
163 | elif self.type == 'string': | |
164 | return "%(dst)s = xstrdup(%(src)s);" % args | |
165 | else: | |
166 | return "%(dst)s = %(src)s;" % args | |
167 | ||
168 | def initCDefault(self, var, isOptional): | |
169 | if self.refTable: | |
170 | return "%s = NULL;" % var | |
171 | elif self.type == 'string' and not isOptional: | |
172 | return "%s = \"\";" % var | |
173 | else: | |
174 | return {'integer': '%s = 0;', | |
175 | 'real': '%s = 0.0;', | |
176 | 'uuid': 'uuid_zero(&%s);', | |
177 | 'boolean': '%s = false;', | |
178 | 'string': '%s = NULL;'}[self.type] % var | |
179 | ||
180 | def cInitBaseType(self, indent, var): | |
181 | stmts = [] | |
182 | stmts.append('ovsdb_base_type_init(&%s, OVSDB_TYPE_%s);' % ( | |
183 | var, self.type.upper()),) | |
184 | if self.type == 'integer': | |
185 | if self.minInteger != None: | |
186 | stmts.append('%s.u.integer.min = %d;' % (var, self.minInteger)) | |
187 | if self.maxInteger != None: | |
188 | stmts.append('%s.u.integer.max = %d;' % (var, self.maxInteger)) | |
189 | elif self.type == 'real': | |
190 | if self.minReal != None: | |
191 | stmts.append('%s.u.real.min = %d;' % (var, self.minReal)) | |
192 | if self.maxReal != None: | |
193 | stmts.append('%s.u.real.max = %d;' % (var, self.maxReal)) | |
194 | elif self.type == 'string': | |
195 | if self.reMatch != None: | |
196 | if self.reComment != None: | |
197 | reComment = '"%s"' % escapeCString(self.reComment) | |
198 | else: | |
199 | reComment = NULL | |
200 | stmts.append('do_set_regex(&%s, "%s", %s);' % ( | |
201 | var, escapeCString(self.reMatch), reComment)) | |
202 | if self.minLength != None: | |
203 | stmts.append('%s.u.string.minLen = %d;' % (var, self.minLength)) | |
204 | if self.maxLength != None: | |
205 | stmts.append('%s.u.string.maxLen = %d;' % (var, self.maxLength)) | |
0d0f05b9 BP |
206 | elif self.type == 'uuid': |
207 | if self.refTable != None: | |
208 | stmts.append('%s.u.uuid.refTableName = "%s";' % (var, escapeCString(self.refTable))) | |
bd76d25d | 209 | return '\n'.join([indent + stmt for stmt in stmts]) |
d879a707 BP |
210 | |
211 | class Type: | |
bd76d25d | 212 | def __init__(self, key, value=None, min=1, max=1): |
d879a707 | 213 | self.key = key |
d879a707 | 214 | self.value = value |
d879a707 BP |
215 | self.min = min |
216 | self.max = max | |
217 | ||
218 | @staticmethod | |
219 | def fromJson(json, description): | |
220 | if type(json) == unicode: | |
bd76d25d | 221 | return Type(BaseType(json)) |
d879a707 | 222 | else: |
bd76d25d BP |
223 | keyJson = mustGetMember(json, 'key', [dict, unicode], description) |
224 | key = BaseType.fromJson(keyJson, 'key in %s' % description) | |
bd76d25d BP |
225 | |
226 | valueJson = getMember(json, 'value', [dict, unicode], description) | |
227 | if valueJson: | |
228 | value = BaseType.fromJson(valueJson, | |
229 | 'value in %s' % description) | |
bd76d25d BP |
230 | else: |
231 | value = None | |
232 | ||
d879a707 BP |
233 | min = getMember(json, 'min', [int], description, 1) |
234 | max = getMember(json, 'max', [int, unicode], description, 1) | |
bd76d25d | 235 | return Type(key, value, min, max) |
d879a707 | 236 | |
45a7de56 BP |
237 | def isScalar(self): |
238 | return self.min == 1 and self.max == 1 and not self.value | |
239 | ||
240 | def isOptional(self): | |
241 | return self.min == 0 and self.max == 1 | |
242 | ||
bd76d25d BP |
243 | def isOptionalPointer(self): |
244 | return (self.min == 0 and self.max == 1 and not self.value | |
245 | and (self.key.type == 'string' or self.key.refTable)) | |
246 | ||
45a7de56 | 247 | def toEnglish(self): |
bd76d25d | 248 | keyName = self.key.toEnglish() |
45a7de56 | 249 | if self.value: |
bd76d25d | 250 | valueName = self.value.toEnglish() |
45a7de56 BP |
251 | |
252 | if self.isScalar(): | |
bd76d25d | 253 | return keyName |
45a7de56 BP |
254 | elif self.isOptional(): |
255 | if self.value: | |
256 | return "optional %s-%s pair" % (keyName, valueName) | |
257 | else: | |
258 | return "optional %s" % keyName | |
259 | else: | |
260 | if self.max == "unlimited": | |
261 | if self.min: | |
262 | quantity = "%d or more " % self.min | |
263 | else: | |
264 | quantity = "" | |
265 | elif self.min: | |
266 | quantity = "%d to %d " % (self.min, self.max) | |
267 | else: | |
268 | quantity = "up to %d " % self.max | |
269 | ||
270 | if self.value: | |
271 | return "map of %s%s-%s pairs" % (quantity, keyName, valueName) | |
272 | else: | |
273 | return "set of %s%s" % (quantity, keyName) | |
274 | ||
bd76d25d BP |
275 | def cDeclComment(self): |
276 | if self.min == 1 and self.max == 1 and self.key.type == "string": | |
277 | return "\t/* Always nonnull. */" | |
278 | else: | |
279 | return "" | |
45a7de56 | 280 | |
bd76d25d BP |
281 | def cInitType(self, indent, var): |
282 | initKey = self.key.cInitBaseType(indent, "%s.key" % var) | |
283 | if self.value: | |
284 | initValue = self.value.cInitBaseType(indent, "%s.value" % var) | |
285 | else: | |
286 | initValue = ('%sovsdb_base_type_init(&%s.value, ' | |
287 | 'OVSDB_TYPE_VOID);' % (indent, var)) | |
288 | initMin = "%s%s.n_min = %s;" % (indent, var, self.min) | |
289 | if self.max == "unlimited": | |
290 | max = "UINT_MAX" | |
291 | else: | |
292 | max = self.max | |
293 | initMax = "%s%s.n_max = %s;" % (indent, var, max) | |
294 | return "\n".join((initKey, initValue, initMin, initMax)) | |
45a7de56 | 295 | |
d879a707 | 296 | def parseSchema(filename): |
00732bf5 BP |
297 | return DbSchema.fromJson(json.load(open(filename, "r"))) |
298 | ||
299 | def annotateSchema(schemaFile, annotationFile): | |
300 | schemaJson = json.load(open(schemaFile, "r")) | |
301 | execfile(annotationFile, globals(), {"s": schemaJson}) | |
302 | json.dump(schemaJson, sys.stdout) | |
d879a707 | 303 | |
02630ff2 BP |
304 | def constify(cType, const): |
305 | if (const | |
306 | and cType.endswith('*') and not cType.endswith('**') | |
307 | and (cType.startswith('struct uuid') or cType.startswith('char'))): | |
308 | return 'const %s' % cType | |
309 | else: | |
310 | return cType | |
311 | ||
312 | def cMembers(prefix, columnName, column, const): | |
475281c0 BP |
313 | type = column.type |
314 | if type.min == 1 and type.max == 1: | |
315 | singleton = True | |
316 | pointer = '' | |
317 | else: | |
318 | singleton = False | |
bd76d25d | 319 | if type.isOptionalPointer(): |
475281c0 BP |
320 | pointer = '' |
321 | else: | |
322 | pointer = '*' | |
323 | ||
324 | if type.value: | |
325 | key = {'name': "key_%s" % columnName, | |
bd76d25d | 326 | 'type': constify(type.key.toCType(prefix) + pointer, const), |
475281c0 BP |
327 | 'comment': ''} |
328 | value = {'name': "value_%s" % columnName, | |
bd76d25d | 329 | 'type': constify(type.value.toCType(prefix) + pointer, const), |
475281c0 BP |
330 | 'comment': ''} |
331 | members = [key, value] | |
332 | else: | |
333 | m = {'name': columnName, | |
bd76d25d BP |
334 | 'type': constify(type.key.toCType(prefix) + pointer, const), |
335 | 'comment': type.cDeclComment()} | |
475281c0 BP |
336 | members = [m] |
337 | ||
bd76d25d | 338 | if not singleton and not type.isOptionalPointer(): |
475281c0 BP |
339 | members.append({'name': 'n_%s' % columnName, |
340 | 'type': 'size_t ', | |
341 | 'comment': ''}) | |
342 | return members | |
343 | ||
00732bf5 BP |
344 | def printCIDLHeader(schemaFile): |
345 | schema = parseSchema(schemaFile) | |
c3bb4bd7 | 346 | prefix = schema.idlPrefix |
d879a707 BP |
347 | print '''\ |
348 | /* Generated automatically -- do not modify! -*- buffer-read-only: t -*- */ | |
349 | ||
350 | #ifndef %(prefix)sIDL_HEADER | |
351 | #define %(prefix)sIDL_HEADER 1 | |
352 | ||
353 | #include <stdbool.h> | |
354 | #include <stddef.h> | |
355 | #include <stdint.h> | |
c3bb4bd7 | 356 | #include "ovsdb-idl-provider.h" |
d879a707 | 357 | #include "uuid.h"''' % {'prefix': prefix.upper()} |
979821c0 | 358 | |
bd76d25d | 359 | for tableName, table in sorted(schema.tables.iteritems()): |
c3bb4bd7 | 360 | structName = "%s%s" % (prefix, tableName.lower()) |
979821c0 BP |
361 | |
362 | print "\f" | |
363 | print "/* %s table. */" % tableName | |
c3bb4bd7 BP |
364 | print "struct %s {" % structName |
365 | print "\tstruct ovsdb_idl_row header_;" | |
bd76d25d | 366 | for columnName, column in sorted(table.columns.iteritems()): |
d879a707 | 367 | print "\n\t/* %s column. */" % columnName |
02630ff2 | 368 | for member in cMembers(prefix, columnName, column, False): |
475281c0 | 369 | print "\t%(type)s%(name)s;%(comment)s" % member |
979821c0 | 370 | print "};" |
c3bb4bd7 | 371 | |
979821c0 BP |
372 | # Column indexes. |
373 | printEnum(["%s_COL_%s" % (structName.upper(), columnName.upper()) | |
bd76d25d | 374 | for columnName in sorted(table.columns)] |
979821c0 BP |
375 | + ["%s_N_COLUMNS" % structName.upper()]) |
376 | ||
377 | ||
378 | for columnName in table.columns: | |
379 | print "#define %(s)s_col_%(c)s (%(s)s_columns[%(S)s_COL_%(C)s])" % { | |
380 | 's': structName, | |
381 | 'S': structName.upper(), | |
382 | 'c': columnName, | |
383 | 'C': columnName.upper()} | |
384 | ||
385 | print "\nextern struct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (structName, structName.upper()) | |
386 | ||
387 | print ''' | |
c3bb4bd7 BP |
388 | const struct %(s)s *%(s)s_first(const struct ovsdb_idl *); |
389 | const struct %(s)s *%(s)s_next(const struct %(s)s *); | |
475281c0 BP |
390 | #define %(S)s_FOR_EACH(ROW, IDL) for ((ROW) = %(s)s_first(IDL); (ROW); (ROW) = %(s)s_next(ROW)) |
391 | ||
392 | void %(s)s_delete(const struct %(s)s *); | |
393 | struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *); | |
394 | ''' % {'s': structName, 'S': structName.upper()} | |
395 | ||
bd76d25d | 396 | for columnName, column in sorted(table.columns.iteritems()): |
475281c0 BP |
397 | print 'void %(s)s_verify_%(c)s(const struct %(s)s *);' % {'s': structName, 'c': columnName} |
398 | ||
399 | ||
bd76d25d | 400 | for columnName, column in sorted(table.columns.iteritems()): |
475281c0 BP |
401 | |
402 | print 'void %(s)s_set_%(c)s(const struct %(s)s *,' % {'s': structName, 'c': columnName}, | |
403 | args = ['%(type)s%(name)s' % member for member | |
02630ff2 | 404 | in cMembers(prefix, columnName, column, True)] |
475281c0 BP |
405 | print '%s);' % ', '.join(args) |
406 | ||
979821c0 | 407 | # Table indexes. |
bd76d25d | 408 | printEnum(["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in sorted(schema.tables)] + ["%sN_TABLES" % prefix.upper()]) |
979821c0 BP |
409 | |
410 | for tableName in schema.tables: | |
411 | print "#define %(p)stable_%(t)s (%(p)stable_classes[%(P)sTABLE_%(T)s])" % { | |
412 | 'p': prefix, | |
413 | 'P': prefix.upper(), | |
414 | 't': tableName.lower(), | |
415 | 'T': tableName.upper()} | |
416 | print "\nextern struct ovsdb_idl_table_class %stable_classes[%sN_TABLES];" % (prefix, prefix.upper()) | |
417 | ||
c3bb4bd7 | 418 | print "\nextern struct ovsdb_idl_class %sidl_class;" % prefix |
bd76d25d | 419 | print "\nvoid %sinit(void);" % prefix |
c3bb4bd7 BP |
420 | print "\n#endif /* %(prefix)sIDL_HEADER */" % {'prefix': prefix.upper()} |
421 | ||
422 | def printEnum(members): | |
423 | if len(members) == 0: | |
424 | return | |
425 | ||
426 | print "\nenum {"; | |
427 | for member in members[:-1]: | |
428 | print " %s," % member | |
429 | print " %s" % members[-1] | |
430 | print "};" | |
431 | ||
00732bf5 BP |
432 | def printCIDLSource(schemaFile): |
433 | schema = parseSchema(schemaFile) | |
c3bb4bd7 BP |
434 | prefix = schema.idlPrefix |
435 | print '''\ | |
436 | /* Generated automatically -- do not modify! -*- buffer-read-only: t -*- */ | |
437 | ||
438 | #include <config.h> | |
439 | #include %s | |
bd76d25d | 440 | #include <assert.h> |
c3bb4bd7 | 441 | #include <limits.h> |
bd76d25d BP |
442 | #include "ovsdb-data.h" |
443 | #include "ovsdb-error.h" | |
444 | ||
445 | static bool inited; | |
446 | ||
c69ee87c | 447 | static void OVS_UNUSED |
bd76d25d BP |
448 | do_set_regex(struct ovsdb_base_type *base, const char *reMatch, |
449 | const char *reComment) | |
450 | { | |
451 | struct ovsdb_error *error; | |
452 | ||
453 | error = ovsdb_base_type_set_regex(base, reMatch, reComment); | |
454 | if (error) { | |
455 | char *s = ovsdb_error_to_string(error); | |
456 | ovs_error(0, "%%s", s); | |
457 | free(s); | |
458 | ovsdb_error_destroy(error); | |
459 | } | |
460 | }''' % schema.idlHeader | |
c3bb4bd7 | 461 | |
66095e15 | 462 | # Cast functions. |
bd76d25d | 463 | for tableName, table in sorted(schema.tables.iteritems()): |
66095e15 BP |
464 | structName = "%s%s" % (prefix, tableName.lower()) |
465 | print ''' | |
466 | static struct %(s)s * | |
979821c0 | 467 | %(s)s_cast(const struct ovsdb_idl_row *row) |
66095e15 BP |
468 | { |
469 | return row ? CONTAINER_OF(row, struct %(s)s, header_) : NULL; | |
470 | }\ | |
471 | ''' % {'s': structName} | |
472 | ||
473 | ||
bd76d25d | 474 | for tableName, table in sorted(schema.tables.iteritems()): |
c3bb4bd7 BP |
475 | structName = "%s%s" % (prefix, tableName.lower()) |
476 | print "\f" | |
477 | if table.comment != None: | |
478 | print "/* %s table (%s). */" % (tableName, table.comment) | |
479 | else: | |
480 | print "/* %s table. */" % (tableName) | |
481 | ||
979821c0 | 482 | # Parse functions. |
bd76d25d | 483 | for columnName, column in sorted(table.columns.iteritems()): |
979821c0 | 484 | print ''' |
c3bb4bd7 | 485 | static void |
979821c0 | 486 | %(s)s_parse_%(c)s(struct ovsdb_idl_row *row_, const struct ovsdb_datum *datum) |
c3bb4bd7 | 487 | { |
979821c0 BP |
488 | struct %(s)s *row = %(s)s_cast(row_);''' % {'s': structName, |
489 | 'c': columnName} | |
c3bb4bd7 | 490 | |
c3bb4bd7 | 491 | type = column.type |
c3bb4bd7 BP |
492 | if type.value: |
493 | keyVar = "row->key_%s" % columnName | |
494 | valueVar = "row->value_%s" % columnName | |
495 | else: | |
496 | keyVar = "row->%s" % columnName | |
497 | valueVar = None | |
498 | ||
bd76d25d | 499 | if (type.min == 1 and type.max == 1) or type.isOptionalPointer(): |
979821c0 | 500 | |
bd76d25d | 501 | print " assert(inited);" |
c3bb4bd7 | 502 | print " if (datum->n >= 1) {" |
bd76d25d BP |
503 | if not type.key.refTable: |
504 | print " %s = datum->keys[0].%s;" % (keyVar, type.key.type) | |
c3bb4bd7 | 505 | else: |
bd76d25d | 506 | print " %s = %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_classes[%sTABLE_%s], &datum->keys[0].uuid));" % (keyVar, prefix, type.key.refTable.lower(), prefix, prefix.upper(), type.key.refTable.upper()) |
c3bb4bd7 BP |
507 | |
508 | if valueVar: | |
bd76d25d BP |
509 | if type.value.refTable: |
510 | print " %s = datum->values[0].%s;" % (valueVar, type.value.type) | |
c3bb4bd7 | 511 | else: |
bd76d25d | 512 | print " %s = %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_classes[%sTABLE_%s], &datum->values[0].uuid));" % (valueVar, prefix, type.value.refTable.lower(), prefix, prefix.upper(), type.value.refTable.upper()) |
979821c0 | 513 | print " } else {" |
bd76d25d | 514 | print " %s" % type.key.initCDefault(keyVar, type.min == 0) |
979821c0 | 515 | if valueVar: |
bd76d25d | 516 | print " %s" % type.value.initCDefault(valueVar, type.min == 0) |
c3bb4bd7 BP |
517 | print " }" |
518 | else: | |
519 | if type.max != 'unlimited': | |
979821c0 BP |
520 | print " size_t n = MIN(%d, datum->n);" % type.max |
521 | nMax = "n" | |
c3bb4bd7 BP |
522 | else: |
523 | nMax = "datum->n" | |
979821c0 BP |
524 | print " size_t i;" |
525 | ||
bd76d25d | 526 | print " assert(inited);" |
979821c0 BP |
527 | print " %s = NULL;" % keyVar |
528 | if valueVar: | |
529 | print " %s = NULL;" % valueVar | |
530 | print " row->n_%s = 0;" % columnName | |
c3bb4bd7 BP |
531 | print " for (i = 0; i < %s; i++) {" % nMax |
532 | refs = [] | |
bd76d25d BP |
533 | if type.key.refTable: |
534 | print " struct %s%s *keyRow = %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_classes[%sTABLE_%s], &datum->keys[i].uuid));" % (prefix, type.key.refTable.lower(), prefix, type.key.refTable.lower(), prefix, prefix.upper(), type.key.refTable.upper()) | |
c3bb4bd7 BP |
535 | keySrc = "keyRow" |
536 | refs.append('keyRow') | |
537 | else: | |
bd76d25d BP |
538 | keySrc = "datum->keys[i].%s" % type.key.type |
539 | if type.value and type.value.refTable: | |
540 | print " struct %s%s *valueRow = %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_classes[%sTABLE_%s], &datum->values[i].uuid));" % (prefix, type.value.refTable.lower(), prefix, type.value.refTable.lower(), prefix, prefix.upper(), type.value.refTable.upper()) | |
c3bb4bd7 BP |
541 | valueSrc = "valueRow" |
542 | refs.append('valueRow') | |
543 | elif valueVar: | |
bd76d25d | 544 | valueSrc = "datum->values[i].%s" % type.value.type |
c3bb4bd7 BP |
545 | if refs: |
546 | print " if (%s) {" % ' && '.join(refs) | |
547 | indent = " " | |
548 | else: | |
549 | indent = " " | |
550 | print "%sif (!row->n_%s) {" % (indent, columnName) | |
551 | print "%s %s = xmalloc(%s * sizeof *%s);" % (indent, keyVar, nMax, keyVar) | |
552 | if valueVar: | |
66095e15 | 553 | print "%s %s = xmalloc(%s * sizeof %s);" % (indent, valueVar, nMax, valueVar) |
c3bb4bd7 BP |
554 | print "%s}" % indent |
555 | print "%s%s[row->n_%s] = %s;" % (indent, keyVar, columnName, keySrc) | |
556 | if valueVar: | |
66095e15 | 557 | print "%s%s[row->n_%s] = %s;" % (indent, valueVar, columnName, valueSrc) |
c3bb4bd7 BP |
558 | print "%srow->n_%s++;" % (indent, columnName) |
559 | if refs: | |
560 | print " }" | |
561 | print " }" | |
979821c0 | 562 | print "}" |
c3bb4bd7 | 563 | |
979821c0 | 564 | # Unparse functions. |
bd76d25d | 565 | for columnName, column in sorted(table.columns.iteritems()): |
c3bb4bd7 | 566 | type = column.type |
bd76d25d | 567 | if (type.min != 1 or type.max != 1) and not type.isOptionalPointer(): |
979821c0 | 568 | print ''' |
c3bb4bd7 | 569 | static void |
979821c0 | 570 | %(s)s_unparse_%(c)s(struct ovsdb_idl_row *row_) |
c3bb4bd7 | 571 | { |
979821c0 | 572 | struct %(s)s *row = %(s)s_cast(row_); |
bd76d25d BP |
573 | |
574 | assert(inited);''' % {'s': structName, 'c': columnName} | |
c3bb4bd7 BP |
575 | if type.value: |
576 | keyVar = "row->key_%s" % columnName | |
577 | valueVar = "row->value_%s" % columnName | |
578 | else: | |
579 | keyVar = "row->%s" % columnName | |
580 | valueVar = None | |
581 | print " free(%s);" % keyVar | |
582 | if valueVar: | |
583 | print " free(%s);" % valueVar | |
979821c0 BP |
584 | print '}' |
585 | else: | |
586 | print ''' | |
c3bb4bd7 | 587 | static void |
c69ee87c | 588 | %(s)s_unparse_%(c)s(struct ovsdb_idl_row *row OVS_UNUSED) |
979821c0 BP |
589 | { |
590 | /* Nothing to do. */ | |
591 | }''' % {'s': structName, 'c': columnName} | |
592 | ||
c3bb4bd7 BP |
593 | # First, next functions. |
594 | print ''' | |
66095e15 BP |
595 | const struct %(s)s * |
596 | %(s)s_first(const struct ovsdb_idl *idl) | |
c3bb4bd7 | 597 | { |
66095e15 | 598 | return %(s)s_cast(ovsdb_idl_first_row(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s])); |
c3bb4bd7 BP |
599 | } |
600 | ||
66095e15 BP |
601 | const struct %(s)s * |
602 | %(s)s_next(const struct %(s)s *row) | |
c3bb4bd7 | 603 | { |
66095e15 | 604 | return %(s)s_cast(ovsdb_idl_next_row(&row->header_)); |
475281c0 BP |
605 | }''' % {'s': structName, |
606 | 'p': prefix, | |
607 | 'P': prefix.upper(), | |
608 | 'T': tableName.upper()} | |
609 | ||
610 | print ''' | |
611 | void | |
9e336f49 | 612 | %(s)s_delete(const struct %(s)s *row) |
475281c0 | 613 | { |
475281c0 BP |
614 | ovsdb_idl_txn_delete(&row->header_); |
615 | } | |
616 | ||
617 | struct %(s)s * | |
618 | %(s)s_insert(struct ovsdb_idl_txn *txn) | |
619 | { | |
620 | return %(s)s_cast(ovsdb_idl_txn_insert(txn, &%(p)stable_classes[%(P)sTABLE_%(T)s])); | |
621 | } | |
622 | ''' % {'s': structName, | |
623 | 'p': prefix, | |
624 | 'P': prefix.upper(), | |
625 | 'T': tableName.upper()} | |
626 | ||
627 | # Verify functions. | |
bd76d25d | 628 | for columnName, column in sorted(table.columns.iteritems()): |
475281c0 BP |
629 | print ''' |
630 | void | |
631 | %(s)s_verify_%(c)s(const struct %(s)s *row) | |
632 | { | |
bd76d25d | 633 | assert(inited); |
475281c0 BP |
634 | ovsdb_idl_txn_verify(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s]); |
635 | }''' % {'s': structName, | |
636 | 'S': structName.upper(), | |
637 | 'c': columnName, | |
638 | 'C': columnName.upper()} | |
639 | ||
640 | # Set functions. | |
bd76d25d | 641 | for columnName, column in sorted(table.columns.iteritems()): |
475281c0 BP |
642 | type = column.type |
643 | print '\nvoid' | |
02630ff2 | 644 | members = cMembers(prefix, columnName, column, True) |
475281c0 BP |
645 | keyVar = members[0]['name'] |
646 | nVar = None | |
647 | valueVar = None | |
648 | if type.value: | |
649 | valueVar = members[1]['name'] | |
650 | if len(members) > 2: | |
651 | nVar = members[2]['name'] | |
652 | else: | |
653 | if len(members) > 1: | |
654 | nVar = members[1]['name'] | |
979821c0 | 655 | print '%(s)s_set_%(c)s(const struct %(s)s *row, %(args)s)' % \ |
475281c0 BP |
656 | {'s': structName, 'c': columnName, |
657 | 'args': ', '.join(['%(type)s%(name)s' % m for m in members])} | |
658 | print "{" | |
475281c0 BP |
659 | print " struct ovsdb_datum datum;" |
660 | if type.min == 1 and type.max == 1: | |
661 | ||
bd76d25d | 662 | print " assert(inited);" |
475281c0 BP |
663 | print " datum.n = 1;" |
664 | print " datum.keys = xmalloc(sizeof *datum.keys);" | |
bd76d25d | 665 | print " " + type.key.copyCValue("datum.keys[0].%s" % type.key.type, keyVar) |
475281c0 BP |
666 | if type.value: |
667 | print " datum.values = xmalloc(sizeof *datum.values);" | |
bd76d25d | 668 | print " "+ type.value.copyCValue("datum.values[0].%s" % type.value.type, valueVar) |
475281c0 BP |
669 | else: |
670 | print " datum.values = NULL;" | |
bd76d25d | 671 | elif type.isOptionalPointer(): |
475281c0 | 672 | |
bd76d25d | 673 | print " assert(inited);" |
475281c0 BP |
674 | print " if (%s) {" % keyVar |
675 | print " datum.n = 1;" | |
676 | print " datum.keys = xmalloc(sizeof *datum.keys);" | |
bd76d25d | 677 | print " " + type.key.copyCValue("datum.keys[0].%s" % type.key.type, keyVar) |
475281c0 BP |
678 | print " } else {" |
679 | print " datum.n = 0;" | |
680 | print " datum.keys = NULL;" | |
681 | print " }" | |
682 | print " datum.values = NULL;" | |
683 | else: | |
684 | print " size_t i;" | |
685 | ||
bd76d25d | 686 | print " assert(inited);" |
475281c0 BP |
687 | print " datum.n = %s;" % nVar |
688 | print " datum.keys = xmalloc(%s * sizeof *datum.keys);" % nVar | |
689 | if type.value: | |
690 | print " datum.values = xmalloc(%s * sizeof *datum.values);" % nVar | |
691 | else: | |
692 | print " datum.values = NULL;" | |
693 | print " for (i = 0; i < %s; i++) {" % nVar | |
bd76d25d | 694 | print " " + type.key.copyCValue("datum.keys[i].%s" % type.key.type, "%s[i]" % keyVar) |
475281c0 | 695 | if type.value: |
bd76d25d | 696 | print " " + type.value.copyCValue("datum.values[i].%s" % type.value.type, "%s[i]" % valueVar) |
475281c0 BP |
697 | print " }" |
698 | print " ovsdb_idl_txn_write(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s], &datum);" \ | |
699 | % {'s': structName, | |
700 | 'S': structName.upper(), | |
701 | 'C': columnName.upper()} | |
702 | print "}" | |
c3bb4bd7 BP |
703 | |
704 | # Table columns. | |
bd76d25d | 705 | print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % ( |
c3bb4bd7 | 706 | structName, structName.upper()) |
bd76d25d BP |
707 | print """ |
708 | static void\n%s_columns_init(void) | |
709 | { | |
710 | struct ovsdb_idl_column *c;\ | |
711 | """ % structName | |
712 | for columnName, column in sorted(table.columns.iteritems()): | |
713 | cs = "%s_col_%s" % (structName, columnName) | |
714 | d = {'cs': cs, 'c': columnName, 's': structName} | |
715 | ||
716 | print " /* Initialize %(cs)s. */" % d | |
717 | print " c = &%(cs)s;" % d | |
718 | print " c->name = \"%(c)s\";" % d | |
719 | print column.type.cInitType(" ", "c->type") | |
720 | print " c->parse = %(s)s_parse_%(c)s;" % d | |
721 | print " c->unparse = %(s)s_unparse_%(c)s;" % d | |
722 | print "}" | |
c3bb4bd7 BP |
723 | |
724 | # Table classes. | |
725 | print "\f" | |
979821c0 | 726 | print "struct ovsdb_idl_table_class %stable_classes[%sN_TABLES] = {" % (prefix, prefix.upper()) |
bd76d25d | 727 | for tableName, table in sorted(schema.tables.iteritems()): |
c3bb4bd7 BP |
728 | structName = "%s%s" % (prefix, tableName.lower()) |
729 | print " {\"%s\"," % tableName | |
730 | print " %s_columns, ARRAY_SIZE(%s_columns)," % ( | |
731 | structName, structName) | |
979821c0 | 732 | print " sizeof(struct %s)}," % structName |
c3bb4bd7 BP |
733 | print "};" |
734 | ||
735 | # IDL class. | |
736 | print "\nstruct ovsdb_idl_class %sidl_class = {" % prefix | |
9cb53f26 BP |
737 | print " \"%s\", %stable_classes, ARRAY_SIZE(%stable_classes)" % ( |
738 | schema.name, prefix, prefix) | |
c3bb4bd7 | 739 | print "};" |
d879a707 | 740 | |
bd76d25d BP |
741 | # global init function |
742 | print """ | |
743 | void | |
744 | %sinit(void) | |
745 | { | |
746 | if (inited) { | |
747 | return; | |
748 | } | |
749 | inited = true; | |
750 | """ % prefix | |
751 | for tableName, table in sorted(schema.tables.iteritems()): | |
752 | structName = "%s%s" % (prefix, tableName.lower()) | |
753 | print " %s_columns_init();" % structName | |
754 | print "}" | |
755 | ||
d879a707 BP |
756 | def ovsdb_escape(string): |
757 | def escape(match): | |
758 | c = match.group(0) | |
759 | if c == '\0': | |
760 | raise Error("strings may not contain null bytes") | |
761 | elif c == '\\': | |
762 | return '\\\\' | |
763 | elif c == '\n': | |
764 | return '\\n' | |
765 | elif c == '\r': | |
766 | return '\\r' | |
767 | elif c == '\t': | |
768 | return '\\t' | |
769 | elif c == '\b': | |
770 | return '\\b' | |
771 | elif c == '\a': | |
772 | return '\\a' | |
773 | else: | |
774 | return '\\x%02x' % ord(c) | |
775 | return re.sub(r'["\\\000-\037]', escape, string) | |
776 | ||
00732bf5 BP |
777 | def printDoc(schemaFile): |
778 | schema = parseSchema(schemaFile) | |
45a7de56 BP |
779 | print schema.name |
780 | if schema.comment: | |
781 | print schema.comment | |
782 | ||
8fdf8457 | 783 | for tableName, table in sorted(schema.tables.iteritems()): |
45a7de56 BP |
784 | title = "%s table" % tableName |
785 | ||
786 | print title | |
787 | print '-' * len(title) | |
788 | if table.comment: | |
789 | print table.comment | |
790 | ||
8fdf8457 | 791 | for columnName, column in sorted(table.columns.iteritems()): |
45a7de56 BP |
792 | |
793 | print "%s (%s)" % (columnName, column.type.toEnglish()) | |
794 | if column.comment: | |
795 | print "\t%s" % column.comment | |
796 | ||
d879a707 BP |
797 | def usage(): |
798 | print """\ | |
799 | %(argv0)s: ovsdb schema compiler | |
00732bf5 | 800 | usage: %(argv0)s [OPTIONS] COMMAND ARG... |
d879a707 | 801 | |
00732bf5 BP |
802 | The following commands are supported: |
803 | annotate SCHEMA ANNOTATIONS print SCHEMA combined with ANNOTATIONS | |
804 | c-idl-header IDL print C header file for IDL | |
805 | c-idl-source IDL print C source file for IDL implementation | |
806 | doc IDL print schema documentation | |
d879a707 BP |
807 | |
808 | The following options are also available: | |
809 | -h, --help display this help message | |
810 | -V, --version display version information\ | |
811 | """ % {'argv0': argv0} | |
812 | sys.exit(0) | |
813 | ||
814 | if __name__ == "__main__": | |
815 | try: | |
816 | try: | |
00732bf5 BP |
817 | options, args = getopt.gnu_getopt(sys.argv[1:], 'C:hV', |
818 | ['directory', | |
819 | 'help', | |
d879a707 BP |
820 | 'version']) |
821 | except getopt.GetoptError, geo: | |
822 | sys.stderr.write("%s: %s\n" % (argv0, geo.msg)) | |
823 | sys.exit(1) | |
824 | ||
00732bf5 BP |
825 | for key, value in options: |
826 | if key in ['-h', '--help']: | |
827 | usage() | |
828 | elif key in ['-V', '--version']: | |
829 | print "ovsdb-idlc (Open vSwitch) @VERSION@" | |
830 | elif key in ['-C', '--directory']: | |
831 | os.chdir(value) | |
832 | else: | |
833 | sys.exit(0) | |
834 | ||
d879a707 | 835 | optKeys = [key for key, value in options] |
00732bf5 BP |
836 | |
837 | if not args: | |
838 | sys.stderr.write("%s: missing command argument " | |
839 | "(use --help for help)\n" % argv0) | |
d879a707 BP |
840 | sys.exit(1) |
841 | ||
00732bf5 BP |
842 | commands = {"annotate": (annotateSchema, 2), |
843 | "c-idl-header": (printCIDLHeader, 1), | |
844 | "c-idl-source": (printCIDLSource, 1), | |
845 | "doc": (printDoc, 1)} | |
846 | ||
847 | if not args[0] in commands: | |
848 | sys.stderr.write("%s: unknown command \"%s\" " | |
849 | "(use --help for help)\n" % (argv0, args[0])) | |
d879a707 | 850 | sys.exit(1) |
00732bf5 BP |
851 | |
852 | func, n_args = commands[args[0]] | |
853 | if len(args) - 1 != n_args: | |
854 | sys.stderr.write("%s: \"%s\" requires %d arguments but %d " | |
855 | "provided\n" | |
856 | % (argv0, args[0], n_args, len(args) - 1)) | |
857 | sys.exit(1) | |
858 | ||
859 | func(*args[1:]) | |
d879a707 BP |
860 | except Error, e: |
861 | sys.stderr.write("%s: %s\n" % (argv0, e.msg)) | |
862 | sys.exit(1) | |
863 | ||
864 | # Local variables: | |
865 | # mode: python | |
866 | # End: |