6c33f07847ca17039cbf826cfacae3ecab2a292b
[sliver-openvswitch.git] / ovsdb / ovsdb-idlc.in
1 #! @PYTHON@
2
3 import getopt
4 import os
5 import re
6 import sys
7
8 sys.path.insert(0, "@abs_top_srcdir@/ovsdb")
9 import simplejson as json
10
11 from OVSDB import *
12
13 argv0 = sys.argv[0]
14
15 class Datum:
16     def __init__(self, type, values):
17         self.type = type
18         self.values = values
19
20     @staticmethod
21     def fromJson(type_, json):
22         if not type_.value:
23             if len(json) == 2 and json[0] == "set":
24                 values = []
25                 for atomJson in json[1]:
26                     values += [Atom.fromJson(type_.key, atomJson)]
27             else:
28                 values = [Atom.fromJson(type_.key, json)]
29         else:
30             if len(json) != 2 or json[0] != "map":
31                 raise Error("%s is not valid JSON for a map" % json)
32             values = []
33             for pairJson in json[1]:
34                 values += [(Atom.fromJson(type_.key, pairJson[0]),
35                             Atom.fromJson(type_.value, pairJson[1]))]
36         return Datum(type_, values)
37
38     def cInitDatum(self, var):
39         if len(self.values) == 0:
40             return ["ovsdb_datum_init_empty(%s);" % var]
41
42         s = ["%s->n = %d;" % (var, len(self.values))]
43         s += ["%s->keys = xmalloc(%d * sizeof *%s->keys);"
44               % (var, len(self.values), var)]
45
46         for i in range(len(self.values)):
47             key = self.values[i]
48             if self.type.value:
49                 key = key[0]
50             s += key.cInitAtom("%s->keys[%d]" % (var, i))
51         
52         if self.type.value:
53             s += ["%s->values = xmalloc(%d * sizeof *%s->values);"
54                   % (var, len(self.values), var)]
55             for i in range(len(self.values)):
56                 value = self.values[i][1]
57                 s += key.cInitAtom("%s->values[%d]" % (var, i))
58         else:
59             s += ["%s->values = NULL;" % var]
60
61         if len(self.values) > 1:
62             s += ["ovsdb_datum_sort_assert(%s, OVSDB_TYPE_%s);"
63                   % (var, self.type.key.upper())]
64
65         return s
66
67 def parseSchema(filename):
68     return IdlSchema.fromJson(json.load(open(filename, "r")))
69
70 def annotateSchema(schemaFile, annotationFile):
71     schemaJson = json.load(open(schemaFile, "r"))
72     execfile(annotationFile, globals(), {"s": schemaJson})
73     json.dump(schemaJson, sys.stdout)
74
75 def constify(cType, const):
76     if (const
77         and cType.endswith('*') and not cType.endswith('**')
78         and (cType.startswith('struct uuid') or cType.startswith('char'))):
79         return 'const %s' % cType
80     else:
81         return cType
82
83 def cMembers(prefix, columnName, column, const):
84     type = column.type
85     if type.min == 1 and type.max == 1:
86         singleton = True
87         pointer = ''
88     else:
89         singleton = False
90         if type.isOptionalPointer():
91             pointer = ''
92         else:
93             pointer = '*'
94
95     if type.value:
96         key = {'name': "key_%s" % columnName,
97                'type': constify(type.key.toCType(prefix) + pointer, const),
98                'comment': ''}
99         value = {'name': "value_%s" % columnName,
100                  'type': constify(type.value.toCType(prefix) + pointer, const),
101                  'comment': ''}
102         members = [key, value]
103     else:
104         m = {'name': columnName,
105              'type': constify(type.key.toCType(prefix) + pointer, const),
106              'comment': type.cDeclComment()}
107         members = [m]
108
109     if not singleton and not type.isOptionalPointer():
110         members.append({'name': 'n_%s' % columnName,
111                         'type': 'size_t ',
112                         'comment': ''})
113     return members
114
115 def printCIDLHeader(schemaFile):
116     schema = parseSchema(schemaFile)
117     prefix = schema.idlPrefix
118     print '''\
119 /* Generated automatically -- do not modify!    -*- buffer-read-only: t -*- */
120
121 #ifndef %(prefix)sIDL_HEADER
122 #define %(prefix)sIDL_HEADER 1
123
124 #include <stdbool.h>
125 #include <stddef.h>
126 #include <stdint.h>
127 #include "ovsdb-data.h"
128 #include "ovsdb-idl-provider.h"
129 #include "uuid.h"''' % {'prefix': prefix.upper()}
130
131     for tableName, table in sorted(schema.tables.iteritems()):
132         structName = "%s%s" % (prefix, tableName.lower())
133
134         print "\f"
135         print "/* %s table. */" % tableName
136         print "struct %s {" % structName
137         print "\tstruct ovsdb_idl_row header_;"
138         for columnName, column in sorted(table.columns.iteritems()):
139             print "\n\t/* %s column. */" % columnName
140             for member in cMembers(prefix, columnName, column, False):
141                 print "\t%(type)s%(name)s;%(comment)s" % member
142         print "};"
143
144         # Column indexes.
145         printEnum(["%s_COL_%s" % (structName.upper(), columnName.upper())
146                    for columnName in sorted(table.columns)]
147                   + ["%s_N_COLUMNS" % structName.upper()])
148
149         print
150         for columnName in table.columns:
151             print "#define %(s)s_col_%(c)s (%(s)s_columns[%(S)s_COL_%(C)s])" % {
152                 's': structName,
153                 'S': structName.upper(),
154                 'c': columnName,
155                 'C': columnName.upper()}
156
157         print "\nextern struct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (structName, structName.upper())
158
159         print '''
160 const struct %(s)s *%(s)s_first(const struct ovsdb_idl *);
161 const struct %(s)s *%(s)s_next(const struct %(s)s *);
162 #define %(S)s_FOR_EACH(ROW, IDL) \\
163         for ((ROW) = %(s)s_first(IDL); \\
164              (ROW); \\
165              (ROW) = %(s)s_next(ROW))
166 #define %(S)s_FOR_EACH_SAFE(ROW, NEXT, IDL) \\
167         for ((ROW) = %(s)s_first(IDL); \\
168              (ROW) ? ((NEXT) = %(s)s_next(ROW), 1) : 0; \\
169              (ROW) = (NEXT))
170
171 void %(s)s_delete(const struct %(s)s *);
172 struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *);
173 ''' % {'s': structName, 'S': structName.upper()}
174
175         for columnName, column in sorted(table.columns.iteritems()):
176             print 'void %(s)s_verify_%(c)s(const struct %(s)s *);' % {'s': structName, 'c': columnName}
177
178         print """
179 /* Functions for fetching columns as \"struct ovsdb_datum\"s.  (This is
180    rarely useful.  More often, it is easier to access columns by using
181    the members of %(s)s directly.) */""" % {'s': structName}
182         for columnName, column in sorted(table.columns.iteritems()):
183             if column.type.value:
184                 valueParam = ', enum ovsdb_atomic_type value_type'
185             else:
186                 valueParam = ''
187             print 'const struct ovsdb_datum *%(s)s_get_%(c)s(const struct %(s)s *, enum ovsdb_atomic_type key_type%(v)s);' % {
188                 's': structName, 'c': columnName, 'v': valueParam}
189
190         print
191         for columnName, column in sorted(table.columns.iteritems()):
192
193             print 'void %(s)s_set_%(c)s(const struct %(s)s *,' % {'s': structName, 'c': columnName},
194             args = ['%(type)s%(name)s' % member for member
195                     in cMembers(prefix, columnName, column, True)]
196             print '%s);' % ', '.join(args)
197
198     # Table indexes.
199     printEnum(["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in sorted(schema.tables)] + ["%sN_TABLES" % prefix.upper()])
200     print
201     for tableName in schema.tables:
202         print "#define %(p)stable_%(t)s (%(p)stable_classes[%(P)sTABLE_%(T)s])" % {
203             'p': prefix,
204             'P': prefix.upper(),
205             't': tableName.lower(),
206             'T': tableName.upper()}
207     print "\nextern struct ovsdb_idl_table_class %stable_classes[%sN_TABLES];" % (prefix, prefix.upper())
208
209     print "\nextern struct ovsdb_idl_class %sidl_class;" % prefix
210     print "\nvoid %sinit(void);" % prefix
211     print "\n#endif /* %(prefix)sIDL_HEADER */" % {'prefix': prefix.upper()}
212
213 def printEnum(members):
214     if len(members) == 0:
215         return
216
217     print "\nenum {";
218     for member in members[:-1]:
219         print "    %s," % member
220     print "    %s" % members[-1]
221     print "};"
222
223 def printCIDLSource(schemaFile):
224     schema = parseSchema(schemaFile)
225     prefix = schema.idlPrefix
226     print '''\
227 /* Generated automatically -- do not modify!    -*- buffer-read-only: t -*- */
228
229 #include <config.h>
230 #include %s
231 #include <assert.h>
232 #include <limits.h>
233 #include "ovsdb-data.h"
234 #include "ovsdb-error.h"
235
236 static bool inited;
237 ''' % schema.idlHeader
238
239     # Cast functions.
240     for tableName, table in sorted(schema.tables.iteritems()):
241         structName = "%s%s" % (prefix, tableName.lower())
242         print '''
243 static struct %(s)s *
244 %(s)s_cast(const struct ovsdb_idl_row *row)
245 {
246     return row ? CONTAINER_OF(row, struct %(s)s, header_) : NULL;
247 }\
248 ''' % {'s': structName}
249
250
251     for tableName, table in sorted(schema.tables.iteritems()):
252         structName = "%s%s" % (prefix, tableName.lower())
253         print "\f"
254         print "/* %s table. */" % (tableName)
255
256         # Parse functions.
257         for columnName, column in sorted(table.columns.iteritems()):
258             print '''
259 static void
260 %(s)s_parse_%(c)s(struct ovsdb_idl_row *row_, const struct ovsdb_datum *datum)
261 {
262     struct %(s)s *row = %(s)s_cast(row_);''' % {'s': structName,
263                                                 'c': columnName}
264
265             type = column.type
266             if type.value:
267                 keyVar = "row->key_%s" % columnName
268                 valueVar = "row->value_%s" % columnName
269             else:
270                 keyVar = "row->%s" % columnName
271                 valueVar = None
272
273             if (type.min == 1 and type.max == 1) or type.isOptionalPointer():
274                 print
275                 print "    assert(inited);"
276                 print "    if (datum->n >= 1) {"
277                 if not type.key.refTable:
278                     print "        %s = datum->keys[0].%s;" % (keyVar, type.key.type)
279                 else:
280                     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())
281
282                 if valueVar:
283                     if type.value.refTable:
284                         print "        %s = datum->values[0].%s;" % (valueVar, type.value.type)
285                     else:
286                         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())
287                 print "    } else {"
288                 print "        %s" % type.key.initCDefault(keyVar, type.min == 0)
289                 if valueVar:
290                     print "        %s" % type.value.initCDefault(valueVar, type.min == 0)
291                 print "    }"
292             else:
293                 if type.max != 'unlimited':
294                     print "    size_t n = MIN(%d, datum->n);" % type.max
295                     nMax = "n"
296                 else:
297                     nMax = "datum->n"
298                 print "    size_t i;"
299                 print
300                 print "    assert(inited);"
301                 print "    %s = NULL;" % keyVar
302                 if valueVar:
303                     print "    %s = NULL;" % valueVar
304                 print "    row->n_%s = 0;" % columnName
305                 print "    for (i = 0; i < %s; i++) {" % nMax
306                 refs = []
307                 if type.key.refTable:
308                     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())
309                     keySrc = "keyRow"
310                     refs.append('keyRow')
311                 else:
312                     keySrc = "datum->keys[i].%s" % type.key.type
313                 if type.value and type.value.refTable:
314                     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())
315                     valueSrc = "valueRow"
316                     refs.append('valueRow')
317                 elif valueVar:
318                     valueSrc = "datum->values[i].%s" % type.value.type
319                 if refs:
320                     print "        if (%s) {" % ' && '.join(refs)
321                     indent = "            "
322                 else:
323                     indent = "        "
324                 print "%sif (!row->n_%s) {" % (indent, columnName)
325                 print "%s    %s = xmalloc(%s * sizeof *%s);" % (indent, keyVar, nMax, keyVar)
326                 if valueVar:
327                     print "%s    %s = xmalloc(%s * sizeof *%s);" % (indent, valueVar, nMax, valueVar)
328                 print "%s}" % indent
329                 print "%s%s[row->n_%s] = %s;" % (indent, keyVar, columnName, keySrc)
330                 if valueVar:
331                     print "%s%s[row->n_%s] = %s;" % (indent, valueVar, columnName, valueSrc)
332                 print "%srow->n_%s++;" % (indent, columnName)
333                 if refs:
334                     print "        }"
335                 print "    }"
336             print "}"
337
338         # Unparse functions.
339         for columnName, column in sorted(table.columns.iteritems()):
340             type = column.type
341             if (type.min != 1 or type.max != 1) and not type.isOptionalPointer():
342                 print '''
343 static void
344 %(s)s_unparse_%(c)s(struct ovsdb_idl_row *row_)
345 {
346     struct %(s)s *row = %(s)s_cast(row_);
347
348     assert(inited);''' % {'s': structName, 'c': columnName}
349                 if type.value:
350                     keyVar = "row->key_%s" % columnName
351                     valueVar = "row->value_%s" % columnName
352                 else:
353                     keyVar = "row->%s" % columnName
354                     valueVar = None
355                 print "    free(%s);" % keyVar
356                 if valueVar:
357                     print "    free(%s);" % valueVar
358                 print '}'
359             else:
360                 print '''
361 static void
362 %(s)s_unparse_%(c)s(struct ovsdb_idl_row *row OVS_UNUSED)
363 {
364     /* Nothing to do. */
365 }''' % {'s': structName, 'c': columnName}
366  
367         # First, next functions.
368         print '''
369 const struct %(s)s *
370 %(s)s_first(const struct ovsdb_idl *idl)
371 {
372     return %(s)s_cast(ovsdb_idl_first_row(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s]));
373 }
374
375 const struct %(s)s *
376 %(s)s_next(const struct %(s)s *row)
377 {
378     return %(s)s_cast(ovsdb_idl_next_row(&row->header_));
379 }''' % {'s': structName,
380         'p': prefix,
381         'P': prefix.upper(),
382         'T': tableName.upper()}
383
384         print '''
385 void
386 %(s)s_delete(const struct %(s)s *row)
387 {
388     ovsdb_idl_txn_delete(&row->header_);
389 }
390
391 struct %(s)s *
392 %(s)s_insert(struct ovsdb_idl_txn *txn)
393 {
394     return %(s)s_cast(ovsdb_idl_txn_insert(txn, &%(p)stable_classes[%(P)sTABLE_%(T)s], NULL));
395 }
396 ''' % {'s': structName,
397        'p': prefix,
398        'P': prefix.upper(),
399        'T': tableName.upper()}
400
401         # Verify functions.
402         for columnName, column in sorted(table.columns.iteritems()):
403             print '''
404 void
405 %(s)s_verify_%(c)s(const struct %(s)s *row)
406 {
407     assert(inited);
408     ovsdb_idl_txn_verify(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s]);
409 }''' % {'s': structName,
410         'S': structName.upper(),
411         'c': columnName,
412         'C': columnName.upper()}
413
414         # Get functions.
415         for columnName, column in sorted(table.columns.iteritems()):
416             if column.type.value:
417                 valueParam = ',\n\tenum ovsdb_atomic_type value_type OVS_UNUSED'
418                 valueType = '\n    assert(value_type == %s);' % column.type.value.toAtomicType()
419                 valueComment = "\n * 'value_type' must be %s." % column.type.value.toAtomicType()
420             else:
421                 valueParam = ''
422                 valueType = ''
423                 valueComment = ''
424             print """
425 /* Returns the %(c)s column's value in 'row' as a struct ovsdb_datum.
426  * This is useful occasionally: for example, ovsdb_datum_find_key() is an
427  * easier and more efficient way to search for a given key than implementing
428  * the same operation on the "cooked" form in 'row'.
429  *
430  * 'key_type' must be %(kt)s.%(vc)s
431  * (This helps to avoid silent bugs if someone changes %(c)s's
432  * type without updating the caller.)
433  *
434  * The caller must not modify or free the returned value.
435  *
436  * Various kinds of changes can invalidate the returned value: modifying
437  * 'column' within 'row', deleting 'row', or completing an ongoing transaction.
438  * If the returned value is needed for a long time, it is best to make a copy
439  * of it with ovsdb_datum_clone(). */
440 const struct ovsdb_datum *
441 %(s)s_get_%(c)s(const struct %(s)s *row,
442 \tenum ovsdb_atomic_type key_type OVS_UNUSED%(v)s)
443 {
444     assert(key_type == %(kt)s);%(vt)s
445     return ovsdb_idl_read(&row->header_, &%(s)s_col_%(c)s);
446 }""" % {'s': structName, 'c': columnName,
447        'kt': column.type.key.toAtomicType(),
448        'v': valueParam, 'vt': valueType, 'vc': valueComment}
449
450         # Set functions.
451         for columnName, column in sorted(table.columns.iteritems()):
452             type = column.type
453             print '\nvoid'
454             members = cMembers(prefix, columnName, column, True)
455             keyVar = members[0]['name']
456             nVar = None
457             valueVar = None
458             if type.value:
459                 valueVar = members[1]['name']
460                 if len(members) > 2:
461                     nVar = members[2]['name']
462             else:
463                 if len(members) > 1:
464                     nVar = members[1]['name']
465             print '%(s)s_set_%(c)s(const struct %(s)s *row, %(args)s)' % \
466                 {'s': structName, 'c': columnName,
467                  'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
468             print "{"
469             print "    struct ovsdb_datum datum;"
470             if type.min == 1 and type.max == 1:
471                 print
472                 print "    assert(inited);"
473                 print "    datum.n = 1;"
474                 print "    datum.keys = xmalloc(sizeof *datum.keys);"
475                 print "    " + type.key.copyCValue("datum.keys[0].%s" % type.key.type, keyVar)
476                 if type.value:
477                     print "    datum.values = xmalloc(sizeof *datum.values);"
478                     print "    "+ type.value.copyCValue("datum.values[0].%s" % type.value.type, valueVar)
479                 else:
480                     print "    datum.values = NULL;"
481             elif type.isOptionalPointer():
482                 print
483                 print "    assert(inited);"
484                 print "    if (%s) {" % keyVar
485                 print "        datum.n = 1;"
486                 print "        datum.keys = xmalloc(sizeof *datum.keys);"
487                 print "        " + type.key.copyCValue("datum.keys[0].%s" % type.key.type, keyVar)
488                 print "    } else {"
489                 print "        datum.n = 0;"
490                 print "        datum.keys = NULL;"
491                 print "    }"
492                 print "    datum.values = NULL;"
493             else:
494                 print "    size_t i;"
495                 print
496                 print "    assert(inited);"
497                 print "    datum.n = %s;" % nVar
498                 print "    datum.keys = xmalloc(%s * sizeof *datum.keys);" % nVar
499                 if type.value:
500                     print "    datum.values = xmalloc(%s * sizeof *datum.values);" % nVar
501                 else:
502                     print "    datum.values = NULL;"
503                 print "    for (i = 0; i < %s; i++) {" % nVar
504                 print "        " + type.key.copyCValue("datum.keys[i].%s" % type.key.type, "%s[i]" % keyVar)
505                 if type.value:
506                     print "        " + type.value.copyCValue("datum.values[i].%s" % type.value.type, "%s[i]" % valueVar)
507                 print "    }"
508                 if type.value:
509                     valueType = type.value.toAtomicType()
510                 else:
511                     valueType = "OVSDB_TYPE_VOID"
512                 print "    ovsdb_datum_sort_unique(&datum, %s, %s);" % (
513                     type.key.toAtomicType(), valueType)
514             print "    ovsdb_idl_txn_write(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s], &datum);" \
515                 % {'s': structName,
516                    'S': structName.upper(),
517                    'C': columnName.upper()}
518             print "}"
519
520         # Table columns.
521         print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (
522             structName, structName.upper())
523         print """
524 static void\n%s_columns_init(void)
525 {
526     struct ovsdb_idl_column *c;\
527 """ % structName
528         for columnName, column in sorted(table.columns.iteritems()):
529             cs = "%s_col_%s" % (structName, columnName)
530             d = {'cs': cs, 'c': columnName, 's': structName}
531             print
532             print "    /* Initialize %(cs)s. */" % d
533             print "    c = &%(cs)s;" % d
534             print "    c->name = \"%(c)s\";" % d
535             print column.type.cInitType("    ", "c->type")
536             print "    c->parse = %(s)s_parse_%(c)s;" % d
537             print "    c->unparse = %(s)s_unparse_%(c)s;" % d
538         print "}"
539
540     # Table classes.
541     print "\f"
542     print "struct ovsdb_idl_table_class %stable_classes[%sN_TABLES] = {" % (prefix, prefix.upper())
543     for tableName, table in sorted(schema.tables.iteritems()):
544         structName = "%s%s" % (prefix, tableName.lower())
545         print "    {\"%s\"," % tableName
546         print "     %s_columns, ARRAY_SIZE(%s_columns)," % (
547             structName, structName)
548         print "     sizeof(struct %s)}," % structName
549     print "};"
550
551     # IDL class.
552     print "\nstruct ovsdb_idl_class %sidl_class = {" % prefix
553     print "    \"%s\", %stable_classes, ARRAY_SIZE(%stable_classes)" % (
554         schema.name, prefix, prefix)
555     print "};"
556
557     # global init function
558     print """
559 void
560 %sinit(void)
561 {
562     if (inited) {
563         return;
564     }
565     inited = true;
566 """ % prefix
567     for tableName, table in sorted(schema.tables.iteritems()):
568         structName = "%s%s" % (prefix, tableName.lower())
569         print "    %s_columns_init();" % structName
570     print "}"
571
572 def ovsdb_escape(string):
573     def escape(match):
574         c = match.group(0)
575         if c == '\0':
576             raise Error("strings may not contain null bytes")
577         elif c == '\\':
578             return '\\\\'
579         elif c == '\n':
580             return '\\n'
581         elif c == '\r':
582             return '\\r'
583         elif c == '\t':
584             return '\\t'
585         elif c == '\b':
586             return '\\b'
587         elif c == '\a':
588             return '\\a'
589         else:
590             return '\\x%02x' % ord(c)
591     return re.sub(r'["\\\000-\037]', escape, string)
592
593
594
595 def usage():
596     print """\
597 %(argv0)s: ovsdb schema compiler
598 usage: %(argv0)s [OPTIONS] COMMAND ARG...
599
600 The following commands are supported:
601   annotate SCHEMA ANNOTATIONS print SCHEMA combined with ANNOTATIONS
602   c-idl-header IDL            print C header file for IDL
603   c-idl-source IDL            print C source file for IDL implementation
604   nroff IDL                   print schema documentation in nroff format
605
606 The following options are also available:
607   -h, --help                  display this help message
608   -V, --version               display version information\
609 """ % {'argv0': argv0}
610     sys.exit(0)
611
612 if __name__ == "__main__":
613     try:
614         try:
615             options, args = getopt.gnu_getopt(sys.argv[1:], 'C:hV',
616                                               ['directory',
617                                                'help',
618                                                'version'])
619         except getopt.GetoptError, geo:
620             sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
621             sys.exit(1)
622             
623         for key, value in options:
624             if key in ['-h', '--help']:
625                 usage()
626             elif key in ['-V', '--version']:
627                 print "ovsdb-idlc (Open vSwitch) @VERSION@"
628             elif key in ['-C', '--directory']:
629                 os.chdir(value)
630             else:
631                 sys.exit(0)
632             
633         optKeys = [key for key, value in options]
634
635         if not args:
636             sys.stderr.write("%s: missing command argument "
637                              "(use --help for help)\n" % argv0)
638             sys.exit(1)
639
640         commands = {"annotate": (annotateSchema, 2),
641                     "c-idl-header": (printCIDLHeader, 1),
642                     "c-idl-source": (printCIDLSource, 1)}
643
644         if not args[0] in commands:
645             sys.stderr.write("%s: unknown command \"%s\" "
646                              "(use --help for help)\n" % (argv0, args[0]))
647             sys.exit(1)
648
649         func, n_args = commands[args[0]]
650         if len(args) - 1 != n_args:
651             sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
652                              "provided\n"
653                              % (argv0, args[0], n_args, len(args) - 1))
654             sys.exit(1)
655
656         func(*args[1:])
657     except Error, e:
658         sys.stderr.write("%s: %s\n" % (argv0, e.msg))
659         sys.exit(1)
660
661 # Local variables:
662 # mode: python
663 # End: