lib: add monitor_cond_change API to C IDL lib
[cascardo/ovs.git] / ovsdb / ovsdb-idlc.in
1 #! @PYTHON@
2
3 import getopt
4 import os
5 import re
6 import sys
7
8 import ovs.json
9 import ovs.db.error
10 import ovs.db.schema
11
12 argv0 = sys.argv[0]
13
14 def parseSchema(filename):
15     return ovs.db.schema.IdlSchema.from_json(ovs.json.from_file(filename))
16
17 def annotateSchema(schemaFile, annotationFile):
18     schemaJson = ovs.json.from_file(schemaFile)
19     execfile(annotationFile, globals(), {"s": schemaJson})
20     ovs.json.to_stream(schemaJson, sys.stdout)
21     sys.stdout.write('\n')
22
23 def constify(cType, const):
24     if (const
25         and cType.endswith('*') and
26         (cType == 'char **' or not cType.endswith('**'))):
27         return 'const %s' % cType
28     else:
29         return cType
30
31 def cMembers(prefix, tableName, columnName, column, const):
32     comment = ""
33     type = column.type
34
35     if type.is_smap():
36         comment = """
37 /* Sets the "%(c)s" column's value from the "%(t)s" table in 'row'
38  * to '%(c)s'.
39  *
40  * The caller retains ownership of '%(c)s' and everything in it. */""" \
41              % {'c': columnName,
42                 't': tableName}
43         return (comment, [{'name': columnName,
44                            'type': 'struct smap ',
45                            'comment': ''}])
46
47     comment = """\n/* Sets the "%s" column from the "%s" table in """\
48               """'row' to\n""" % (columnName, tableName)
49
50     if type.n_min == 1 and type.n_max == 1:
51         singleton = True
52         pointer = ''
53     else:
54         singleton = False
55         if type.is_optional_pointer():
56             pointer = ''
57         else:
58             pointer = '*'
59
60
61     if type.value:
62         keyName = "key_%s" % columnName
63         valueName = "value_%s" % columnName
64
65         key = {'name': keyName,
66                'type': constify(type.key.toCType(prefix) + pointer, const),
67                'comment': ''}
68         value = {'name': valueName,
69                  'type': constify(type.value.toCType(prefix) + pointer, const),
70                  'comment': ''}
71
72         if singleton:
73             comment += " * the map with key '%s' and value '%s'\n *" \
74                        % (keyName, valueName)
75         else:
76             comment += " * the map with keys '%s' and values '%s'\n *" \
77                        % (keyName, valueName)
78         members = [key, value]
79     else:
80         m = {'name': columnName,
81              'type': constify(type.key.toCType(prefix) + pointer, const),
82              'comment': type.cDeclComment()}
83
84         if singleton:
85             comment += " * '%s'" % columnName
86         else:
87             comment += " * the '%s' set" % columnName
88         members = [m]
89
90     if not singleton and not type.is_optional_pointer():
91         sizeName = "n_%s" % columnName
92
93         comment += " with '%s' entries" % sizeName
94         members.append({'name': sizeName,
95                         'type': 'size_t ',
96                         'comment': ''})
97
98     comment += ".\n"
99
100     if type.is_optional() and not type.is_optional_pointer():
101         comment += """ *
102  * '%s' may be 0 or 1; if it is 0, then '%s'
103  * may be NULL.\n""" \
104         % ("n_%s" % columnName, columnName)
105
106     if type.is_optional_pointer():
107         comment += """ *
108  * If "%s" is null, the column will be the empty set,
109  * otherwise it will contain the specified value.\n""" % columnName
110
111     if type.constraintsToEnglish():
112         comment += """ *
113  * Argument constraints: %s\n""" \
114         % type.constraintsToEnglish(lambda s : '"%s"' % s)
115
116     comment += " *\n * The caller retains ownership of the arguments. */"
117
118     return (comment, members)
119
120 def printCIDLHeader(schemaFile):
121     schema = parseSchema(schemaFile)
122     prefix = schema.idlPrefix
123     print '''\
124 /* Generated automatically -- do not modify!    -*- buffer-read-only: t -*- */
125
126 #ifndef %(prefix)sIDL_HEADER
127 #define %(prefix)sIDL_HEADER 1
128
129 #include <stdbool.h>
130 #include <stddef.h>
131 #include <stdint.h>
132 #include "ovsdb-data.h"
133 #include "ovsdb-idl-provider.h"
134 #include "smap.h"
135 #include "uuid.h"''' % {'prefix': prefix.upper()}
136
137     for tableName, table in sorted(schema.tables.iteritems()):
138         structName = "%s%s" % (prefix, tableName.lower())
139
140         print "\f"
141         print "/* %s table. */" % tableName
142         print "struct %s {" % structName
143         print "\tstruct ovsdb_idl_row header_;"
144         for columnName, column in sorted(table.columns.iteritems()):
145             print "\n\t/* %s column. */" % columnName
146             comment, members = cMembers(prefix, tableName,
147                                         columnName, column, False)
148             for member in members:
149                 print "\t%(type)s%(name)s;%(comment)s" % member
150         print "};"
151
152         # Column indexes.
153         printEnum("%s_column_id" % structName.lower(), ["%s_COL_%s" % (structName.upper(), columnName.upper())
154                    for columnName in sorted(table.columns)]
155                   + ["%s_N_COLUMNS" % structName.upper()])
156
157         print
158         for columnName in table.columns:
159             print "#define %(s)s_col_%(c)s (%(s)s_columns[%(S)s_COL_%(C)s])" % {
160                 's': structName,
161                 'S': structName.upper(),
162                 'c': columnName,
163                 'C': columnName.upper()}
164
165         print "\nextern struct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (structName, structName.upper())
166
167         print '''
168 const struct %(s)s *%(s)s_get_for_uuid(const struct ovsdb_idl *, const struct uuid *);
169 const struct %(s)s *%(s)s_first(const struct ovsdb_idl *);
170 const struct %(s)s *%(s)s_next(const struct %(s)s *);
171 #define %(S)s_FOR_EACH(ROW, IDL) \\
172         for ((ROW) = %(s)s_first(IDL); \\
173              (ROW); \\
174              (ROW) = %(s)s_next(ROW))
175 #define %(S)s_FOR_EACH_SAFE(ROW, NEXT, IDL) \\
176         for ((ROW) = %(s)s_first(IDL); \\
177              (ROW) ? ((NEXT) = %(s)s_next(ROW), 1) : 0; \\
178              (ROW) = (NEXT))
179
180 unsigned int %(s)s_get_seqno(const struct ovsdb_idl *);
181 unsigned int %(s)s_row_get_seqno(const struct %(s)s *row, enum ovsdb_idl_change change);
182 const struct %(s)s *%(s)s_track_get_first(const struct ovsdb_idl *);
183 const struct %(s)s *%(s)s_track_get_next(const struct %(s)s *);
184 #define %(S)s_FOR_EACH_TRACKED(ROW, IDL) \\
185         for ((ROW) = %(s)s_track_get_first(IDL); \\
186              (ROW); \\
187              (ROW) = %(s)s_track_get_next(ROW))
188
189 /* Returns true if 'row' was inserted since the last change tracking reset. */
190 static inline bool %(s)s_is_new(const struct %(s)s *row)
191 {
192     return %(s)s_row_get_seqno(row, OVSDB_IDL_CHANGE_MODIFY) == 0;
193 }
194
195 /* Returns true if 'row' was deleted since the last change tracking reset. */
196 static inline bool %(s)s_is_deleted(const struct %(s)s *row)
197 {
198     return %(s)s_row_get_seqno(row, OVSDB_IDL_CHANGE_DELETE) > 0;
199 }
200
201 void %(s)s_init(struct %(s)s *);
202 void %(s)s_delete(const struct %(s)s *);
203 struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *);
204 bool %(s)s_is_updated(const struct %(s)s *, enum %(s)s_column_id);
205 ''' % {'s': structName, 'S': structName.upper()}
206
207         for columnName, column in sorted(table.columns.iteritems()):
208             print 'void %(s)s_verify_%(c)s(const struct %(s)s *);' % {'s': structName, 'c': columnName}
209
210         print
211         for columnName, column in sorted(table.columns.iteritems()):
212             if column.type.value:
213                 valueParam = ', enum ovsdb_atomic_type value_type'
214             else:
215                 valueParam = ''
216             print 'const struct ovsdb_datum *%(s)s_get_%(c)s(const struct %(s)s *, enum ovsdb_atomic_type key_type%(v)s);' % {
217                 's': structName, 'c': columnName, 'v': valueParam}
218
219         print
220         for columnName, column in sorted(table.columns.iteritems()):
221             print 'void %(s)s_set_%(c)s(const struct %(s)s *,' % {'s': structName, 'c': columnName},
222             if column.type.is_smap():
223                 args = ['const struct smap *']
224             else:
225                 comment, members = cMembers(prefix, tableName, columnName,
226                                             column, True)
227                 args = ['%(type)s%(name)s' % member for member in members]
228             print '%s);' % ', '.join(args)
229
230         print
231         for columnName, column in sorted(table.columns.iteritems()):
232             if column.type.is_map():
233                 print 'void %(s)s_update_%(c)s_setkey(const struct %(s)s *, ' % {'s': structName, 'c': columnName},
234                 print '%(coltype)s, %(valtype)s);' % {'coltype':column.type.key.toCType(prefix), 'valtype':column.type.value.toCType(prefix)}
235                 print 'void %(s)s_update_%(c)s_delkey(const struct %(s)s *, ' % {'s': structName, 'c': columnName},
236                 print '%(coltype)s);' % {'coltype':column.type.key.toCType(prefix)},
237
238             print 'void %(s)s_add_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function,' % {'s': structName, 'c': columnName},
239             if column.type.is_smap():
240                 args = ['const struct smap *']
241             else:
242                 comment, members = cMembers(prefix, tableName, columnName,
243                                             column, True)
244                 args = ['%(type)s%(name)s' % member for member in members]
245             print '%s);' % ', '.join(args)
246
247         print 'void %s_add_clause_true(struct ovsdb_idl *idl);' % structName
248         print 'void %s_add_clause_false(struct ovsdb_idl *idl);' % structName
249
250         print
251         for columnName, column in sorted(table.columns.iteritems()):
252             print 'void %(s)s_remove_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function,' % {'s': structName, 'c': columnName},
253             if column.type.is_smap():
254                 args = ['const struct smap *']
255             else:
256                 comment, members = cMembers(prefix, tableName, columnName,
257                                             column, True)
258                 args = ['%(type)s%(name)s' % member for member in members]
259             print '%s);' % ', '.join(args)
260
261         print 'void %s_remove_clause_true(struct ovsdb_idl *idl);' % structName
262         print 'void %s_remove_clause_false(struct ovsdb_idl *idl);' % structName
263
264         print
265
266     # Table indexes.
267     printEnum("%stable_id" % prefix.lower(), ["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in sorted(schema.tables)] + ["%sN_TABLES" % prefix.upper()])
268     print
269     for tableName in schema.tables:
270         print "#define %(p)stable_%(t)s (%(p)stable_classes[%(P)sTABLE_%(T)s])" % {
271             'p': prefix,
272             'P': prefix.upper(),
273             't': tableName.lower(),
274             'T': tableName.upper()}
275     print "\nextern struct ovsdb_idl_table_class %stable_classes[%sN_TABLES];" % (prefix, prefix.upper())
276
277     print "\nextern struct ovsdb_idl_class %sidl_class;" % prefix
278     print "\nvoid %sinit(void);" % prefix
279
280     print "\nconst char * %sget_db_version(void);" % prefix
281     print "\n#endif /* %(prefix)sIDL_HEADER */" % {'prefix': prefix.upper()}
282
283 def printEnum(type, members):
284     if len(members) == 0:
285         return
286
287     print "\nenum %s {" % type
288     for member in members[:-1]:
289         print "    %s," % member
290     print "    %s" % members[-1]
291     print "};"
292
293 def printCIDLSource(schemaFile):
294     schema = parseSchema(schemaFile)
295     prefix = schema.idlPrefix
296     print '''\
297 /* Generated automatically -- do not modify!    -*- buffer-read-only: t -*- */
298
299 #include <config.h>
300 #include %s
301 #include <limits.h>
302 #include "ovs-thread.h"
303 #include "ovsdb-data.h"
304 #include "ovsdb-error.h"
305 #include "util.h"
306
307 #ifdef __CHECKER__
308 /* Sparse dislikes sizeof(bool) ("warning: expression using sizeof bool"). */
309 enum { sizeof_bool = 1 };
310 #else
311 enum { sizeof_bool = sizeof(bool) };
312 #endif
313
314 static bool inited;
315 ''' % schema.idlHeader
316
317     # Cast functions.
318     for tableName, table in sorted(schema.tables.iteritems()):
319         structName = "%s%s" % (prefix, tableName.lower())
320         print '''
321 static struct %(s)s *
322 %(s)s_cast(const struct ovsdb_idl_row *row)
323 {
324     return row ? CONTAINER_OF(row, struct %(s)s, header_) : NULL;
325 }\
326 ''' % {'s': structName}
327
328
329     for tableName, table in sorted(schema.tables.iteritems()):
330         structName = "%s%s" % (prefix, tableName.lower())
331         print "\f"
332         print "/* %s table. */" % (tableName)
333
334         # Parse functions.
335         for columnName, column in sorted(table.columns.iteritems()):
336             print '''
337 static void
338 %(s)s_parse_%(c)s(struct ovsdb_idl_row *row_, const struct ovsdb_datum *datum)
339 {
340     struct %(s)s *row = %(s)s_cast(row_);''' % {'s': structName,
341                                                 'c': columnName}
342             type = column.type
343             if type.value:
344                 keyVar = "row->key_%s" % columnName
345                 valueVar = "row->value_%s" % columnName
346             else:
347                 keyVar = "row->%s" % columnName
348                 valueVar = None
349
350             if type.is_smap():
351                 print "    size_t i;"
352                 print
353                 print "    ovs_assert(inited);"
354                 print "    smap_init(&row->%s);" % columnName
355                 print "    for (i = 0; i < datum->n; i++) {"
356                 print "        smap_add(&row->%s," % columnName
357                 print "                 datum->keys[i].string,"
358                 print "                 datum->values[i].string);"
359                 print "    }"
360             elif (type.n_min == 1 and type.n_max == 1) or type.is_optional_pointer():
361                 print
362                 print "    ovs_assert(inited);"
363                 print "    if (datum->n >= 1) {"
364                 if not type.key.ref_table:
365                     print "        %s = datum->keys[0].%s;" % (keyVar, type.key.type.to_string())
366                 else:
367                     print "        %s = %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_classes[%sTABLE_%s], &datum->keys[0].uuid));" % (keyVar, prefix, type.key.ref_table.name.lower(), prefix, prefix.upper(), type.key.ref_table.name.upper())
368
369                 if valueVar:
370                     if type.value.ref_table:
371                         print "        %s = datum->values[0].%s;" % (valueVar, type.value.type.to_string())
372                     else:
373                         print "        %s = %s%s_cast(ovsdb_idl_get_row_arc(row_, &%stable_classes[%sTABLE_%s], &datum->values[0].uuid));" % (valueVar, prefix, type.value.ref_table.name.lower(), prefix, prefix.upper(), type.value.ref_table.name.upper())
374                 print "    } else {"
375                 print "        %s" % type.key.initCDefault(keyVar, type.n_min == 0)
376                 if valueVar:
377                     print "        %s" % type.value.initCDefault(valueVar, type.n_min == 0)
378                 print "    }"
379             else:
380                 if type.n_max != sys.maxint:
381                     print "    size_t n = MIN(%d, datum->n);" % type.n_max
382                     nMax = "n"
383                 else:
384                     nMax = "datum->n"
385                 print "    size_t i;"
386                 print
387                 print "    ovs_assert(inited);"
388                 print "    %s = NULL;" % keyVar
389                 if valueVar:
390                     print "    %s = NULL;" % valueVar
391                 print "    row->n_%s = 0;" % columnName
392                 print "    for (i = 0; i < %s; i++) {" % nMax
393                 refs = []
394                 if type.key.ref_table:
395                     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.ref_table.name.lower(), prefix, type.key.ref_table.name.lower(), prefix, prefix.upper(), type.key.ref_table.name.upper())
396                     keySrc = "keyRow"
397                     refs.append('keyRow')
398                 else:
399                     keySrc = "datum->keys[i].%s" % type.key.type.to_string()
400                 if type.value and type.value.ref_table:
401                     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.ref_table.name.lower(), prefix, type.value.ref_table.name.lower(), prefix, prefix.upper(), type.value.ref_table.name.upper())
402                     valueSrc = "valueRow"
403                     refs.append('valueRow')
404                 elif valueVar:
405                     valueSrc = "datum->values[i].%s" % type.value.type.to_string()
406                 if refs:
407                     print "        if (%s) {" % ' && '.join(refs)
408                     indent = "            "
409                 else:
410                     indent = "        "
411                 print "%sif (!row->n_%s) {" % (indent, columnName)
412
413                 # Special case for boolean types.  This is only here because
414                 # sparse does not like the "normal" case ("warning: expression
415                 # using sizeof bool").
416                 if type.key.type == ovs.db.types.BooleanType:
417                     sizeof = "sizeof_bool"
418                 else:
419                     sizeof = "sizeof *%s" % keyVar
420                 print "%s    %s = xmalloc(%s * %s);" % (indent, keyVar, nMax,
421                                                         sizeof)
422                 if valueVar:
423                     # Special case for boolean types (see above).
424                     if type.value.type == ovs.db.types.BooleanType:
425                         sizeof = " * sizeof_bool"
426                     else:
427                         sizeof = "sizeof *%s" % valueVar
428                     print "%s    %s = xmalloc(%s * %s);" % (indent, valueVar,
429                                                             nMax, sizeof)
430                 print "%s}" % indent
431                 print "%s%s[row->n_%s] = %s;" % (indent, keyVar, columnName, keySrc)
432                 if valueVar:
433                     print "%s%s[row->n_%s] = %s;" % (indent, valueVar, columnName, valueSrc)
434                 print "%srow->n_%s++;" % (indent, columnName)
435                 if refs:
436                     print "        }"
437                 print "    }"
438             print "}"
439
440         # Unparse functions.
441         for columnName, column in sorted(table.columns.iteritems()):
442             type = column.type
443             if type.is_smap() or (type.n_min != 1 or type.n_max != 1) and not type.is_optional_pointer():
444                 print '''
445 static void
446 %(s)s_unparse_%(c)s(struct ovsdb_idl_row *row_)
447 {
448     struct %(s)s *row = %(s)s_cast(row_);
449
450     ovs_assert(inited);''' % {'s': structName, 'c': columnName}
451
452                 if type.is_smap():
453                     print "    smap_destroy(&row->%s);" % columnName
454                 else:
455                     if type.value:
456                         keyVar = "row->key_%s" % columnName
457                         valueVar = "row->value_%s" % columnName
458                     else:
459                         keyVar = "row->%s" % columnName
460                         valueVar = None
461                     print "    free(%s);" % keyVar
462                     if valueVar:
463                         print "    free(%s);" % valueVar
464                 print '}'
465             else:
466                 print '''
467 static void
468 %(s)s_unparse_%(c)s(struct ovsdb_idl_row *row OVS_UNUSED)
469 {
470     /* Nothing to do. */
471 }''' % {'s': structName, 'c': columnName}
472
473         # Generic Row Initialization function.
474         print """
475 static void
476 %(s)s_init__(struct ovsdb_idl_row *row)
477 {
478     %(s)s_init(%(s)s_cast(row));
479 }""" % {'s': structName}
480
481         # Row Initialization function.
482         print """
483 /* Clears the contents of 'row' in table "%(t)s". */
484 void
485 %(s)s_init(struct %(s)s *row)
486 {
487     memset(row, 0, sizeof *row); """ % {'s': structName, 't': tableName}
488         for columnName, column in sorted(table.columns.iteritems()):
489             if column.type.is_smap():
490                 print "    smap_init(&row->%s);" % columnName
491         print "}"
492
493         # First, next functions.
494         print '''
495 /* Searches table "%(t)s" in 'idl' for a row with UUID 'uuid'.  Returns
496  * a pointer to the row if there is one, otherwise a null pointer.  */
497 const struct %(s)s *
498 %(s)s_get_for_uuid(const struct ovsdb_idl *idl, const struct uuid *uuid)
499 {
500     return %(s)s_cast(ovsdb_idl_get_row_for_uuid(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], uuid));
501 }
502
503 /* Returns a row in table "%(t)s" in 'idl', or a null pointer if that
504  * table is empty.
505  *
506  * Database tables are internally maintained as hash tables, so adding or
507  * removing rows while traversing the same table can cause some rows to be
508  * visited twice or not at apply. */
509 const struct %(s)s *
510 %(s)s_first(const struct ovsdb_idl *idl)
511 {
512     return %(s)s_cast(ovsdb_idl_first_row(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s]));
513 }
514
515 /* Returns a row following 'row' within its table, or a null pointer if 'row'
516  * is the last row in its table. */
517 const struct %(s)s *
518 %(s)s_next(const struct %(s)s *row)
519 {
520     return %(s)s_cast(ovsdb_idl_next_row(&row->header_));
521 }
522
523 unsigned int %(s)s_get_seqno(const struct ovsdb_idl *idl)
524 {
525     return ovsdb_idl_table_get_seqno(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s]);
526 }
527
528 unsigned int %(s)s_row_get_seqno(const struct %(s)s *row, enum ovsdb_idl_change change)
529 {
530     return ovsdb_idl_row_get_seqno(&row->header_, change);
531 }
532
533 const struct %(s)s *
534 %(s)s_track_get_first(const struct ovsdb_idl *idl)
535 {
536     return %(s)s_cast(ovsdb_idl_track_get_first(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s]));
537 }
538
539 const struct %(s)s
540 *%(s)s_track_get_next(const struct %(s)s *row)
541 {
542     return %(s)s_cast(ovsdb_idl_track_get_next(&row->header_));
543 }''' % {'s': structName,
544         'p': prefix,
545         'P': prefix.upper(),
546         't': tableName,
547         'T': tableName.upper()}
548
549         print '''
550
551 /* Deletes 'row' from table "%(t)s".  'row' may be freed, so it must not be
552  * accessed afterward.
553  *
554  * The caller must have started a transaction with ovsdb_idl_txn_create(). */
555 void
556 %(s)s_delete(const struct %(s)s *row)
557 {
558     ovsdb_idl_txn_delete(&row->header_);
559 }
560
561 /* Inserts and returns a new row in the table "%(t)s" in the database
562  * with open transaction 'txn'.
563  *
564  * The new row is assigned a randomly generated provisional UUID.
565  * ovsdb-server will assign a different UUID when 'txn' is committed,
566  * but the IDL will replace any uses of the provisional UUID in the
567  * data to be to be committed by the UUID assigned by ovsdb-server. */
568 struct %(s)s *
569 %(s)s_insert(struct ovsdb_idl_txn *txn)
570 {
571     return %(s)s_cast(ovsdb_idl_txn_insert(txn, &%(p)stable_classes[%(P)sTABLE_%(T)s], NULL));
572 }
573
574 bool
575 %(s)s_is_updated(const struct %(s)s *row, enum %(s)s_column_id column)
576 {
577     return ovsdb_idl_track_is_updated(&row->header_, &%(s)s_columns[column]);
578 }''' % {'s': structName,
579         'p': prefix,
580         'P': prefix.upper(),
581         't': tableName,
582         'T': tableName.upper()}
583
584         # Verify functions.
585         for columnName, column in sorted(table.columns.iteritems()):
586             print '''
587 /* Causes the original contents of column "%(c)s" in 'row' to be
588  * verified as a prerequisite to completing the transaction.  That is, if
589  * "%(c)s" in 'row' changed (or if 'row' was deleted) between the
590  * time that the IDL originally read its contents and the time that the
591  * transaction commits, then the transaction aborts and ovsdb_idl_txn_commit()
592  * returns TXN_AGAIN_WAIT or TXN_AGAIN_NOW (depending on whether the database
593  * change has already been received).
594  *
595  * The intention is that, to ensure that no transaction commits based on dirty
596  * reads, an application should call this function any time "%(c)s" is
597  * read as part of a read-modify-write operation.
598  *
599  * In some cases this function reduces to a no-op, because the current value
600  * of "%(c)s" is already known:
601  *
602  *   - If 'row' is a row created by the current transaction (returned by
603  *     %(s)s_insert()).
604  *
605  *   - If "%(c)s" has already been modified (with
606  *     %(s)s_set_%(c)s()) within the current transaction.
607  *
608  * Because of the latter property, always call this function *before*
609  * %(s)s_set_%(c)s() for a given read-modify-write.
610  *
611  * The caller must have started a transaction with ovsdb_idl_txn_create(). */
612 void
613 %(s)s_verify_%(c)s(const struct %(s)s *row)
614 {
615     ovs_assert(inited);
616     ovsdb_idl_txn_verify(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s]);
617 }''' % {'s': structName,
618         'S': structName.upper(),
619         'c': columnName,
620         'C': columnName.upper()}
621
622         # Get functions.
623         for columnName, column in sorted(table.columns.iteritems()):
624             if column.type.value:
625                 valueParam = ',\n\tenum ovsdb_atomic_type value_type OVS_UNUSED'
626                 valueType = '\n    ovs_assert(value_type == %s);' % column.type.value.toAtomicType()
627                 valueComment = "\n * 'value_type' must be %s." % column.type.value.toAtomicType()
628             else:
629                 valueParam = ''
630                 valueType = ''
631                 valueComment = ''
632             print """
633 /* Returns the "%(c)s" column's value from the "%(t)s" table in 'row'
634  * as a struct ovsdb_datum.  This is useful occasionally: for example,
635  * ovsdb_datum_find_key() is an easier and more efficient way to search
636  * for a given key than implementing the same operation on the "cooked"
637  * form in 'row'.
638  *
639  * 'key_type' must be %(kt)s.%(vc)s
640  * (This helps to avoid silent bugs if someone changes %(c)s's
641  * type without updating the caller.)
642  *
643  * The caller must not modify or free the returned value.
644  *
645  * Various kinds of changes can invalidate the returned value: modifying
646  * 'column' within 'row', deleting 'row', or completing an ongoing transaction.
647  * If the returned value is needed for a long time, it is best to make a copy
648  * of it with ovsdb_datum_clone().
649  *
650  * This function is rarely useful, since it is easier to access the value
651  * directly through the "%(c)s" member in %(s)s. */
652 const struct ovsdb_datum *
653 %(s)s_get_%(c)s(const struct %(s)s *row,
654 \tenum ovsdb_atomic_type key_type OVS_UNUSED%(v)s)
655 {
656     ovs_assert(key_type == %(kt)s);%(vt)s
657     return ovsdb_idl_read(&row->header_, &%(s)s_col_%(c)s);
658 }""" % {'t': tableName, 's': structName, 'c': columnName,
659        'kt': column.type.key.toAtomicType(),
660        'v': valueParam, 'vt': valueType, 'vc': valueComment}
661
662         # Set functions.
663         for columnName, column in sorted(table.columns.iteritems()):
664             type = column.type
665
666             comment, members = cMembers(prefix, tableName, columnName,
667                                         column, True)
668
669             if type.is_smap():
670                 print comment
671                 print """void
672 %(s)s_set_%(c)s(const struct %(s)s *row, const struct smap *%(c)s)
673 {
674     struct ovsdb_datum datum;
675
676     ovs_assert(inited);
677     if (%(c)s) {
678         struct smap_node *node;
679         size_t i;
680
681         datum.n = smap_count(%(c)s);
682         datum.keys = xmalloc(datum.n * sizeof *datum.keys);
683         datum.values = xmalloc(datum.n * sizeof *datum.values);
684
685         i = 0;
686         SMAP_FOR_EACH (node, %(c)s) {
687             datum.keys[i].string = xstrdup(node->key);
688             datum.values[i].string = xstrdup(node->value);
689             i++;
690         }
691         ovsdb_datum_sort_unique(&datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
692     } else {
693         ovsdb_datum_init_empty(&datum);
694     }
695     ovsdb_idl_txn_write(&row->header_,
696                         &%(s)s_columns[%(S)s_COL_%(C)s],
697                         &datum);
698 }
699 """ % {'t': tableName,
700        's': structName,
701        'S': structName.upper(),
702        'c': columnName,
703        'C': columnName.upper()}
704                 continue
705
706             keyVar = members[0]['name']
707             nVar = None
708             valueVar = None
709             if type.value:
710                 valueVar = members[1]['name']
711                 if len(members) > 2:
712                     nVar = members[2]['name']
713             else:
714                 if len(members) > 1:
715                     nVar = members[1]['name']
716
717             print comment
718             print 'void'
719             print '%(s)s_set_%(c)s(const struct %(s)s *row, %(args)s)' % \
720                 {'s': structName, 'c': columnName,
721                  'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
722             print "{"
723             print "    struct ovsdb_datum datum;"
724             if type.n_min == 1 and type.n_max == 1:
725                 print "    union ovsdb_atom key;"
726                 if type.value:
727                     print "    union ovsdb_atom value;"
728                 print
729                 print "    ovs_assert(inited);"
730                 print "    datum.n = 1;"
731                 print "    datum.keys = &key;"
732                 print "    " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
733                 if type.value:
734                     print "    datum.values = &value;"
735                     print "    "+ type.value.assign_c_value_casting_away_const("value.%s" % type.value.type.to_string(), valueVar)
736                 else:
737                     print "    datum.values = NULL;"
738                 txn_write_func = "ovsdb_idl_txn_write_clone"
739             elif type.is_optional_pointer():
740                 print "    union ovsdb_atom key;"
741                 print
742                 print "    ovs_assert(inited);"
743                 print "    if (%s) {" % keyVar
744                 print "        datum.n = 1;"
745                 print "        datum.keys = &key;"
746                 print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
747                 print "    } else {"
748                 print "        datum.n = 0;"
749                 print "        datum.keys = NULL;"
750                 print "    }"
751                 print "    datum.values = NULL;"
752                 txn_write_func = "ovsdb_idl_txn_write_clone"
753             elif type.n_max == 1:
754                 print "    union ovsdb_atom key;"
755                 print
756                 print "    ovs_assert(inited);"
757                 print "    if (%s) {" % nVar
758                 print "        datum.n = 1;"
759                 print "        datum.keys = &key;"
760                 print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), "*" + keyVar)
761                 print "    } else {"
762                 print "        datum.n = 0;"
763                 print "        datum.keys = NULL;"
764                 print "    }"
765                 print "    datum.values = NULL;"
766                 txn_write_func = "ovsdb_idl_txn_write_clone"
767             else:
768                 print "    size_t i;"
769                 print
770                 print "    ovs_assert(inited);"
771                 print "    datum.n = %s;" % nVar
772                 print "    datum.keys = %s ? xmalloc(%s * sizeof *datum.keys) : NULL;" % (nVar, nVar)
773                 if type.value:
774                     print "    datum.values = xmalloc(%s * sizeof *datum.values);" % nVar
775                 else:
776                     print "    datum.values = NULL;"
777                 print "    for (i = 0; i < %s; i++) {" % nVar
778                 print "        " + type.key.copyCValue("datum.keys[i].%s" % type.key.type.to_string(), "%s[i]" % keyVar)
779                 if type.value:
780                     print "        " + type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), "%s[i]" % valueVar)
781                 print "    }"
782                 if type.value:
783                     valueType = type.value.toAtomicType()
784                 else:
785                     valueType = "OVSDB_TYPE_VOID"
786                 print "    ovsdb_datum_sort_unique(&datum, %s, %s);" % (
787                     type.key.toAtomicType(), valueType)
788                 txn_write_func = "ovsdb_idl_txn_write"
789             print "    %(f)s(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s], &datum);" \
790                 % {'f': txn_write_func,
791                    's': structName,
792                    'S': structName.upper(),
793                    'C': columnName.upper()}
794             print "}"
795         # Update/Delete of partial map column functions
796         for columnName, column in sorted(table.columns.iteritems()):
797             type = column.type
798             if type.is_map():
799                 print '''
800 /* Sets an element of the "%(c)s" map column from the "%(t)s" table in 'row'
801  * to 'new_value' given the key value 'new_key'.
802  *
803  */
804 void
805 %(s)s_update_%(c)s_setkey(const struct %(s)s *row, %(coltype)snew_key, %(valtype)snew_value)
806 {
807     struct ovsdb_datum *datum;
808
809     ovs_assert(inited);
810
811     datum = xmalloc(sizeof *datum);
812     datum->n = 1;
813     datum->keys = xmalloc(datum->n * sizeof *datum->keys);
814     datum->values = xmalloc(datum->n * sizeof *datum->values);
815 ''' % {'s': structName, 'c': columnName,'coltype':column.type.key.toCType(prefix),
816         'valtype':column.type.value.toCType(prefix), 'S': structName.upper(),
817         'C': columnName.upper(), 't': tableName}
818
819                 print "    "+ type.key.copyCValue("datum->keys[0].%s" % type.key.type.to_string(), "new_key")
820                 print "    "+ type.value.copyCValue("datum->values[0].%s" % type.value.type.to_string(), "new_value")
821                 print '''
822     ovsdb_idl_txn_write_partial_map(&row->header_,
823                                     &%(s)s_columns[%(S)s_COL_%(C)s],
824                                     datum);
825 }''' % {'s': structName, 'c': columnName,'coltype':column.type.key.toCType(prefix),
826         'valtype':column.type.value.toCType(prefix), 'S': structName.upper(),
827         'C': columnName.upper()}
828                 print '''
829 /* Deletes an element of the "%(c)s" map column from the "%(t)s" table in 'row'
830  * given the key value 'delete_key'.
831  *
832  */
833 void
834 %(s)s_update_%(c)s_delkey(const struct %(s)s *row, %(coltype)sdelete_key)
835 {
836     struct ovsdb_datum *datum;
837
838     ovs_assert(inited);
839
840     datum = xmalloc(sizeof *datum);
841     datum->n = 1;
842     datum->keys = xmalloc(datum->n * sizeof *datum->keys);
843     datum->values = NULL;
844 ''' % {'s': structName, 'c': columnName,'coltype':column.type.key.toCType(prefix),
845         'valtype':column.type.value.toCType(prefix), 'S': structName.upper(),
846         'C': columnName.upper(), 't': tableName}
847
848                 print "    "+ type.key.copyCValue("datum->keys[0].%s" % type.key.type.to_string(), "delete_key")
849                 print '''
850     ovsdb_idl_txn_delete_partial_map(&row->header_,
851                                     &%(s)s_columns[%(S)s_COL_%(C)s],
852                                     datum);
853 }''' % {'s': structName, 'c': columnName,'coltype':column.type.key.toCType(prefix),
854         'valtype':column.type.value.toCType(prefix), 'S': structName.upper(),
855         'C': columnName.upper()}
856         # End Update/Delete of partial maps
857
858         # Add clause functions.
859         for columnName, column in sorted(table.columns.iteritems()):
860             type = column.type
861
862             comment, members = cMembers(prefix, tableName, columnName,
863                                         column, True)
864
865             if type.is_smap():
866                 print comment
867                 print """void
868 %(s)s_add_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function, const struct smap *%(c)s)
869 {
870     struct ovsdb_datum datum;
871
872     ovs_assert(inited);
873     if (%(c)s) {
874         struct smap_node *node;
875         size_t i;
876
877         datum.n = smap_count(%(c)s);
878         datum.keys = xmalloc(datum.n * sizeof *datum.keys);
879         datum.values = xmalloc(datum.n * sizeof *datum.values);
880
881         i = 0;
882         SMAP_FOR_EACH (node, %(c)s) {
883             datum.keys[i].string = xstrdup(node->key);
884             datum.values[i].string = xstrdup(node->value);
885             i++;
886         }
887         ovsdb_datum_sort_unique(&datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
888     } else {
889         ovsdb_datum_init_empty(&datum);
890     }
891
892     ovsdb_idl_condition_add_clause(idl,
893                                    &%(p)stable_classes[%(P)sTABLE_%(T)s],
894                                    function,
895                                    &%(s)s_columns[%(S)s_COL_%(C)s],
896                                    &datum);
897 }
898 """ % {'t': tableName,
899        'T': tableName.upper(),
900        'p': prefix,
901        'P': prefix.upper(),
902        's': structName,
903        'S': structName.upper(),
904        'c': columnName,
905        'C': columnName.upper()}
906                 continue
907
908             keyVar = members[0]['name']
909             nVar = None
910             valueVar = None
911             if type.value:
912                 valueVar = members[1]['name']
913                 if len(members) > 2:
914                     nVar = members[2]['name']
915             else:
916                 if len(members) > 1:
917                     nVar = members[1]['name']
918
919             print comment
920             print 'void'
921             print '%(s)s_add_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function, %(args)s)' % \
922                 {'s': structName, 'c': columnName,
923                  'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
924             print "{"
925             print "    struct ovsdb_datum datum;"
926             if type.n_min == 1 and type.n_max == 1:
927                 print "    union ovsdb_atom key;"
928                 if type.value:
929                     print "    union ovsdb_atom value;"
930                 print
931                 print "    ovs_assert(inited);"
932                 print "    datum.n = 1;"
933                 print "    datum.keys = &key;"
934                 print "    " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
935                 if type.value:
936                     print "    datum.values = &value;"
937                     print "    "+ type.value.assign_c_value_casting_away_const("value.%s" % type.value.type.to_string(), valueVar)
938                 else:
939                     print "    datum.values = NULL;"
940             elif type.is_optional_pointer():
941                 print "    union ovsdb_atom key;"
942                 print
943                 print "    ovs_assert(inited);"
944                 print "    if (%s) {" % keyVar
945                 print "        datum.n = 1;"
946                 print "        datum.keys = &key;"
947                 print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
948                 print "    } else {"
949                 print "        datum.n = 0;"
950                 print "        datum.keys = NULL;"
951                 print "    }"
952                 print "    datum.values = NULL;"
953             elif type.n_max == 1:
954                 print "    union ovsdb_atom key;"
955                 print
956                 print "    ovs_assert(inited);"
957                 print "    if (%s) {" % nVar
958                 print "        datum.n = 1;"
959                 print "        datum.keys = &key;"
960                 print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), "*" + keyVar)
961                 print "    } else {"
962                 print "        datum.n = 0;"
963                 print "        datum.keys = NULL;"
964                 print "    }"
965                 print "    datum.values = NULL;"
966             else:
967                 print "    size_t i;"
968                 print
969                 print "    ovs_assert(inited);"
970                 print "    datum.n = %s;" % nVar
971                 print "    datum.keys = %s ? xmalloc(%s * sizeof *datum.keys) : NULL;" % (nVar, nVar)
972                 if type.value:
973                     print "    datum.values = xmalloc(%s * sizeof *datum.values);" % nVar
974                 else:
975                     print "    datum.values = NULL;"
976                 print "    for (i = 0; i < %s; i++) {" % nVar
977                 print "        " + type.key.copyCValue("datum.keys[i].%s" % type.key.type.to_string(), "%s[i]" % keyVar)
978                 if type.value:
979                     print "        " + type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), "%s[i]" % valueVar)
980                 print "    }"
981                 if type.value:
982                     valueType = type.value.toAtomicType()
983                 else:
984                     valueType = "OVSDB_TYPE_VOID"
985                 print "    ovsdb_datum_sort_unique(&datum, %s, %s);" % (
986                     type.key.toAtomicType(), valueType)
987
988             print"""    ovsdb_idl_condition_add_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s],
989                           function,
990                           &%(s)s_columns[%(S)s_COL_%(C)s],
991                           &datum);
992 }""" % {'t': tableName,
993        'T': tableName.upper(),
994        'p': prefix,
995        'P': prefix.upper(),
996        's': structName,
997        'S': structName.upper(),
998        'c': columnName,
999        'C': columnName.upper()}
1000
1001         print """void
1002 %(s)s_add_clause_false(struct ovsdb_idl *idl)
1003 {
1004     struct ovsdb_datum datum;
1005
1006     ovsdb_datum_init_empty(&datum);
1007     ovsdb_idl_condition_add_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], OVSDB_F_FALSE, NULL, &datum);
1008 }""" % {'s': structName,
1009         'T': tableName.upper(),
1010         'p': prefix,
1011         'P': prefix.upper()}
1012
1013         print """void
1014 %(s)s_add_clause_true(struct ovsdb_idl *idl)
1015 {
1016     struct ovsdb_datum datum;
1017
1018     ovsdb_datum_init_empty(&datum);
1019     ovsdb_idl_condition_add_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], OVSDB_F_TRUE, NULL, &datum);
1020 }""" % {'s': structName,
1021         'T': tableName.upper(),
1022         'p': prefix,
1023         'P': prefix.upper()}
1024
1025         # Remove clause functions.
1026         for columnName, column in sorted(table.columns.iteritems()):
1027             type = column.type
1028
1029             comment, members = cMembers(prefix, tableName, columnName,
1030                                         column, True)
1031
1032             if type.is_smap():
1033                 print comment
1034                 print """void
1035 %(s)s_remove_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function, const struct smap *%(c)s)
1036 {
1037     struct ovsdb_datum datum;
1038
1039     ovs_assert(inited);
1040     if (%(c)s) {
1041         struct smap_node *node;
1042         size_t i;
1043
1044         datum.n = smap_count(%(c)s);
1045         datum.keys = xmalloc(datum.n * sizeof *datum.keys);
1046         datum.values = xmalloc(datum.n * sizeof *datum.values);
1047
1048         i = 0;
1049         SMAP_FOR_EACH (node, %(c)s) {
1050             datum.keys[i].string = xstrdup(node->key);
1051             datum.values[i].string = xstrdup(node->value);
1052             i++;
1053         }
1054         ovsdb_datum_sort_unique(&datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
1055     } else {
1056         ovsdb_datum_init_empty(&datum);
1057     }
1058
1059     ovsdb_idl_condition_remove_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s],
1060                                       function,
1061                                       &%(s)s_columns[%(S)s_COL_%(C)s],
1062                                       &datum);
1063 }
1064 """ % {'t': tableName,
1065        'T': tableName.upper(),
1066        'p': prefix,
1067        'P': prefix.upper(),
1068        's': structName,
1069        'S': structName.upper(),
1070        'c': columnName,
1071        'C': columnName.upper()}
1072                 continue
1073
1074             keyVar = members[0]['name']
1075             nVar = None
1076             valueVar = None
1077             if type.value:
1078                 valueVar = members[1]['name']
1079                 if len(members) > 2:
1080                     nVar = members[2]['name']
1081             else:
1082                 if len(members) > 1:
1083                     nVar = members[1]['name']
1084
1085             print comment
1086             print 'void'
1087             print '%(s)s_remove_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function, %(args)s)' % \
1088                 {'s': structName, 'c': columnName,
1089                  'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
1090             print "{"
1091             print "    struct ovsdb_datum datum;"
1092             if type.n_min == 1 and type.n_max == 1:
1093                 print "    union ovsdb_atom key;"
1094                 if type.value:
1095                     print "    union ovsdb_atom value;"
1096                 print
1097                 print "    ovs_assert(inited);"
1098                 print "    datum.n = 1;"
1099                 print "    datum.keys = &key;"
1100                 print "    " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
1101                 if type.value:
1102                     print "    datum.values = &value;"
1103                     print "    "+ type.value.assign_c_value_casting_away_const("value.%s" % type.value.type.to_string(), valueVar)
1104                 else:
1105                     print "    datum.values = NULL;"
1106             elif type.is_optional_pointer():
1107                 print "    union ovsdb_atom key;"
1108                 print
1109                 print "    ovs_assert(inited);"
1110                 print "    if (%s) {" % keyVar
1111                 print "        datum.n = 1;"
1112                 print "        datum.keys = &key;"
1113                 print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
1114                 print "    } else {"
1115                 print "        datum.n = 0;"
1116                 print "        datum.keys = NULL;"
1117                 print "    }"
1118                 print "    datum.values = NULL;"
1119             elif type.n_max == 1:
1120                 print "    union ovsdb_atom key;"
1121                 print
1122                 print "    ovs_assert(inited);"
1123                 print "    if (%s) {" % nVar
1124                 print "        datum.n = 1;"
1125                 print "        datum.keys = &key;"
1126                 print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), "*" + keyVar)
1127                 print "    } else {"
1128                 print "        datum.n = 0;"
1129                 print "        datum.keys = NULL;"
1130                 print "    }"
1131                 print "    datum.values = NULL;"
1132             else:
1133                 print "    size_t i;"
1134                 print
1135                 print "    ovs_assert(inited);"
1136                 print "    datum.n = %s;" % nVar
1137                 print "    datum.keys = %s ? xmalloc(%s * sizeof *datum.keys) : NULL;" % (nVar, nVar)
1138                 if type.value:
1139                     print "    datum.values = xmalloc(%s * sizeof *datum.values);" % nVar
1140                 else:
1141                     print "    datum.values = NULL;"
1142                 print "    for (i = 0; i < %s; i++) {" % nVar
1143                 print "        " + type.key.copyCValue("datum.keys[i].%s" % type.key.type.to_string(), "%s[i]" % keyVar)
1144                 if type.value:
1145                     print "        " + type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), "%s[i]" % valueVar)
1146                 print "    }"
1147                 if type.value:
1148                     valueType = type.value.toAtomicType()
1149                 else:
1150                     valueType = "OVSDB_TYPE_VOID"
1151                 print "    ovsdb_datum_sort_unique(&datum, %s, %s);" % (
1152                     type.key.toAtomicType(), valueType)
1153
1154             print"""    ovsdb_idl_condition_remove_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s],
1155                           function,
1156                           &%(s)s_columns[%(S)s_COL_%(C)s],
1157                           &datum);
1158 }""" % {'t': tableName,
1159        'T': tableName.upper(),
1160        'p': prefix,
1161        'P': prefix.upper(),
1162        's': structName,
1163        'S': structName.upper(),
1164        'c': columnName,
1165        'C': columnName.upper()}
1166
1167         print """void
1168 %(s)s_remove_clause_false(struct ovsdb_idl *idl)
1169 {
1170     struct ovsdb_datum datum;
1171
1172     ovsdb_datum_init_empty(&datum);
1173     ovsdb_idl_condition_remove_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], OVSDB_F_FALSE, NULL, &datum);
1174 }""" % {'s': structName,
1175        'T': tableName.upper(),
1176        'p': prefix,
1177        'P': prefix.upper()}
1178
1179         print """void
1180 %(s)s_remove_clause_true(struct ovsdb_idl *idl)
1181 {
1182     struct ovsdb_datum datum;
1183
1184     ovsdb_datum_init_empty(&datum);
1185     ovsdb_idl_condition_remove_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], OVSDB_F_TRUE, NULL, &datum);
1186 }""" % {'s': structName,
1187         'T': tableName.upper(),
1188         'p': prefix,
1189         'P': prefix.upper(),}
1190
1191         # Table columns.
1192         print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (
1193             structName, structName.upper())
1194         print """
1195 static void\n%s_columns_init(void)
1196 {
1197     struct ovsdb_idl_column *c;\
1198 """ % structName
1199         for columnName, column in sorted(table.columns.iteritems()):
1200             cs = "%s_col_%s" % (structName, columnName)
1201             d = {'cs': cs, 'c': columnName, 's': structName}
1202             if column.mutable:
1203                 mutable = "true"
1204             else:
1205                 mutable = "false"
1206             print
1207             print "    /* Initialize %(cs)s. */" % d
1208             print "    c = &%(cs)s;" % d
1209             print "    c->name = \"%(c)s\";" % d
1210             print column.type.cInitType("    ", "c->type")
1211             print "    c->mutable = %s;" % mutable
1212             print "    c->parse = %(s)s_parse_%(c)s;" % d
1213             print "    c->unparse = %(s)s_unparse_%(c)s;" % d
1214         print "}"
1215
1216     # Table classes.
1217     print "\f"
1218     print "struct ovsdb_idl_table_class %stable_classes[%sN_TABLES] = {" % (prefix, prefix.upper())
1219     for tableName, table in sorted(schema.tables.iteritems()):
1220         structName = "%s%s" % (prefix, tableName.lower())
1221         if table.is_root:
1222             is_root = "true"
1223         else:
1224             is_root = "false"
1225         print "    {\"%s\", %s," % (tableName, is_root)
1226         print "     %s_columns, ARRAY_SIZE(%s_columns)," % (
1227             structName, structName)
1228         print "     sizeof(struct %s), %s_init__}," % (structName, structName)
1229     print "};"
1230
1231     # IDL class.
1232     print "\nstruct ovsdb_idl_class %sidl_class = {" % prefix
1233     print "    \"%s\", %stable_classes, ARRAY_SIZE(%stable_classes)" % (
1234         schema.name, prefix, prefix)
1235     print "};"
1236
1237     # global init function
1238     print """
1239 void
1240 %sinit(void)
1241 {
1242     if (inited) {
1243         return;
1244     }
1245     assert_single_threaded();
1246     inited = true;
1247 """ % prefix
1248     for tableName, table in sorted(schema.tables.iteritems()):
1249         structName = "%s%s" % (prefix, tableName.lower())
1250         print "    %s_columns_init();" % structName
1251     print "}"
1252
1253     print """
1254 /* Return the schema version.  The caller must not free the returned value. */
1255 const char *
1256 %sget_db_version(void)
1257 {
1258     return "%s";
1259 }
1260 """ % (prefix, schema.version)
1261
1262
1263
1264 def ovsdb_escape(string):
1265     def escape(match):
1266         c = match.group(0)
1267         if c == '\0':
1268             raise ovs.db.error.Error("strings may not contain null bytes")
1269         elif c == '\\':
1270             return '\\\\'
1271         elif c == '\n':
1272             return '\\n'
1273         elif c == '\r':
1274             return '\\r'
1275         elif c == '\t':
1276             return '\\t'
1277         elif c == '\b':
1278             return '\\b'
1279         elif c == '\a':
1280             return '\\a'
1281         else:
1282             return '\\x%02x' % ord(c)
1283     return re.sub(r'["\\\000-\037]', escape, string)
1284
1285 def usage():
1286     print """\
1287 %(argv0)s: ovsdb schema compiler
1288 usage: %(argv0)s [OPTIONS] COMMAND ARG...
1289
1290 The following commands are supported:
1291   annotate SCHEMA ANNOTATIONS print SCHEMA combined with ANNOTATIONS
1292   c-idl-header IDL            print C header file for IDL
1293   c-idl-source IDL            print C source file for IDL implementation
1294   nroff IDL                   print schema documentation in nroff format
1295
1296 The following options are also available:
1297   -h, --help                  display this help message
1298   -V, --version               display version information\
1299 """ % {'argv0': argv0}
1300     sys.exit(0)
1301
1302 if __name__ == "__main__":
1303     try:
1304         try:
1305             options, args = getopt.gnu_getopt(sys.argv[1:], 'C:hV',
1306                                               ['directory',
1307                                                'help',
1308                                                'version'])
1309         except getopt.GetoptError, geo:
1310             sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
1311             sys.exit(1)
1312
1313         for key, value in options:
1314             if key in ['-h', '--help']:
1315                 usage()
1316             elif key in ['-V', '--version']:
1317                 print "ovsdb-idlc (Open vSwitch) @VERSION@"
1318             elif key in ['-C', '--directory']:
1319                 os.chdir(value)
1320             else:
1321                 sys.exit(0)
1322
1323         optKeys = [key for key, value in options]
1324
1325         if not args:
1326             sys.stderr.write("%s: missing command argument "
1327                              "(use --help for help)\n" % argv0)
1328             sys.exit(1)
1329
1330         commands = {"annotate": (annotateSchema, 2),
1331                     "c-idl-header": (printCIDLHeader, 1),
1332                     "c-idl-source": (printCIDLSource, 1)}
1333
1334         if not args[0] in commands:
1335             sys.stderr.write("%s: unknown command \"%s\" "
1336                              "(use --help for help)\n" % (argv0, args[0]))
1337             sys.exit(1)
1338
1339         func, n_args = commands[args[0]]
1340         if len(args) - 1 != n_args:
1341             sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
1342                              "provided\n"
1343                              % (argv0, args[0], n_args, len(args) - 1))
1344             sys.exit(1)
1345
1346         func(*args[1:])
1347     except ovs.db.error.Error, e:
1348         sys.stderr.write("%s: %s\n" % (argv0, e))
1349         sys.exit(1)
1350
1351 # Local variables:
1352 # mode: python
1353 # End: