cleanup specfile for packaging
[profile/ivi/gpsd.git] / jsongen.py.in
1 #!@PYTHON@
2 #
3 # This file is Copyright (c) 2010 by the GPSD project
4 # BSD terms apply: see the file COPYING in the distribution root for details.
5 #
6 # Never hand-hack what you can generate...
7 #
8 # This code generates template declarations for AIS-JSON parsing from a
9 # declarative specification of a JSON structure - and generates those
10 # declarative specification from the Python format strings for
11 # dumping the structures
12 #
13 import sys, getopt
14
15 #
16 # Here is the information that makes it all work - attribute, type, and
17 # defult information for all fields.  We can generate either a JSON
18 # parser template spec or the C code for the correspondong dump functio
19 # from this information. Doing it this way guarantees consistency.
20 #
21 ais_specs = (
22     {
23     "initname" : "json_ais1",
24     "header": "\tAIS_HEADER,",
25     "structname": "ais->type1",
26     "fieldmap":(
27         # fieldname   type        default
28         ('status',   'uinteger', '0'),
29         ('turn',     'integer',  'AIS_TURN_NOT_AVAILABLE'),
30         ('speed',    'uinteger', 'AIS_SPEED_NOT_AVAILABLE'),
31         ('accuracy', 'boolean',  'false'),
32         ('lon',      'integer',  'AIS_LON_NOT_AVAILABLE'),
33         ('lat',      'integer',  'AIS_LAT_NOT_AVAILABLE'),
34         ('course',   'uinteger', 'AIS_COURSE_NOT_AVAILABLE'),
35         ('heading',  'uinteger', 'AIS_HEADING_NOT_AVAILABLE'),
36         ('second',   'uinteger', 'AIS_SEC_NOT_AVAILABLE'),
37         ('maneuver', 'uinteger', 'AIS_SEC_INOPERATIVE'),
38         ('raim',     'boolean',  'false'),
39         ('radio',    'uinteger', '0'),
40         ),
41     },
42     # Message types 2 and 3 duplicate 1
43     {
44     "initname" : "json_ais4",
45     "header": "\tAIS_HEADER,",
46     "structname": "ais->type4",
47     "fieldmap":(
48         # fieldname   type        default
49         ('timestamp', 'string',   None),
50         ('accuracy',  'boolean',  "true"),
51         ('lon',       'integer',  "AIS_LON_NOT_AVAILABLE"),
52         ('lat',       'integer',  "AIS_LAT_NOT_AVAILABLE"),
53         ('epfd',      'uinteger', "0"),
54         ('raim',      'boolean',  "false"),
55         ('radio',     'uinteger', "0"),
56         ),
57     "stringbuffered":("timestamp",),
58     },
59     {
60     "initname" : "json_ais5",
61     "header": "\tAIS_HEADER,",
62     "structname": "ais->type5",
63     "fieldmap":(
64         # fieldname        type            default
65         ('imo',           'uinteger',      '0'),
66         ('ais_version',   'uinteger',      '0'),
67         ('callsign',      'string',        None),
68         ('shipname',      'string',        None),
69         ('shiptype',      'uinteger',      '0'),
70         ('to_bow',        'uinteger',      '0'),
71         ('to_stern',      'uinteger',      '0'),
72         ('to_port',       'uinteger',      '0'),
73         ('to_starboard',  'uinteger',      '0'),
74         ('epfd',          'uinteger',      '0'),
75         ('eta',           'string',        None),
76         ('draught',       'uinteger',      '0'),
77         ('destination',   'string',        None),
78         ('dte',           'uinteger',      '1'),
79         ),
80     "stringbuffered":("eta",),
81     },
82     {
83     "initname" : "json_ais6",
84     "header": "\tAIS_HEADER,",
85     "structname": "ais->type6",
86     "fieldmap":(
87         # fieldname       type             default
88         ('seqno',         'uinteger',      '0'),
89         ('dest_mmsi',     'uinteger',      '0'),
90         ('retransmit',    'boolean',       'false'),
91         ('dac',           'uinteger',      '0'),
92         ('fid',           'uinteger',      '0'),
93         ('data',          'string',        None),
94         ),
95     "stringbuffered":("data",),
96     },
97     {
98     "initname" : "json_ais7",
99     "header": "\tAIS_HEADER,",
100     "structname": "ais->type7",
101     "fieldmap":(
102         # fieldname       type             default
103         ('mmsi1',         'uinteger',      '0'),
104         ('mmsi2',         'uinteger',      '0'),
105         ('mmsi3',         'uinteger',      '0'),
106         ('mmsi4',         'uinteger',      '0'),
107         ),
108     },
109     {
110     "initname" : "json_ais8",
111     "header": "\tAIS_HEADER,",
112     "structname": "ais->type8",
113     "fieldmap":(
114         # fieldname       type             default
115         ('dac',           'uinteger',      '0'),
116         ('fid',           'uinteger',      '0'),
117         ('data',          'string',        None),
118         ),
119     "stringbuffered":("data",),
120     },
121     {
122     "initname" : "json_ais9",
123     "header": "\tAIS_HEADER,",
124     "structname": "ais->type9",
125     "fieldmap":(
126         # fieldname       type             default
127         ('alt',           'uinteger',      'AIS_ALT_NOT_AVAILABLE'),
128         ('speed',         'uinteger',      'AIS_SPEED_NOT_AVAILABLE'),
129         ('accuracy',      'boolean',       'false'),
130         ('lon',           'integer',       'AIS_LON_NOT_AVAILABLE'),
131         ('lat',           'integer',       'AIS_LAT_NOT_AVAILABLE'),
132         ('course',        'uinteger',      'AIS_COURSE_NOT_AVAILABLE'),
133         ('second',        'uinteger',      'AIS_SEC_NOT_AVAILABLE'),
134         ('regional',      'uinteger',      '0'),
135         ('dte',           'uinteger',      '1'),
136         ('raim',          'boolean',       'false'),
137         ('radio',         'uinteger',      '0'),
138         ),
139     },
140     {
141     "initname" : "json_ais10",
142     "header": "\tAIS_HEADER,",
143     "structname": "ais->type10",
144     "fieldmap":(
145         # fieldname       type             default
146         ('dest_mmsi',     'uinteger',      '0'),
147         ),
148     },
149     # Message type 11 duplicates 4
150     {
151     "initname" : "json_ais12",
152     "header": "\tAIS_HEADER,",
153     "structname": "ais->type12",
154     "fieldmap":(
155         # fieldname       type             default
156         ('seqno',         'uinteger',      '0'),
157         ('dest_mmsi',     'uinteger',      '0'),
158         ('retransmit',    'boolean',       '0'),
159         ('text',          'string',        None),
160         ),
161     },
162     # Message type 13 duplicates 7 
163     {
164     "initname" : "json_ais14",
165     "header": "\tAIS_HEADER,",
166     "structname": "ais->type14",
167     "fieldmap":(
168         # fieldname       type             default
169         ('text',          'string',        None),
170         ),
171     },
172     {
173     "initname" : "json_ais15",
174     "header": "\tAIS_HEADER,",
175     "structname": "ais->type15",
176     "fieldmap":(
177         # fieldname       type             default
178         ('mmsi1',         'uinteger',      '0'),
179         ('type1_1',       'uinteger',      '0'),
180         ('offset1_1',     'uinteger',      '0'),
181         ('type1_2',       'uinteger',      '0'),
182         ('offset1_2',     'uinteger',      '0'),
183         ('mmsi2',         'uinteger',      '0'),
184         ('type2_1',       'uinteger',      '0'),
185         ('offset2_1',     'uinteger',      '0'),
186         ),
187     },
188     {
189     "initname" : "json_ais16",
190     "header": "\tAIS_HEADER,",
191     "structname": "ais->type16",
192     "fieldmap":(
193         # fieldname       type             default
194         ('mmsi1',         'uinteger',      '0'),
195         ('offset1',       'uinteger',      '0'),
196         ('increment1',    'uinteger',      '0'),
197         ('mmsi2',         'uinteger',      '0'),
198         ('offset2',       'uinteger',      '0'),
199         ('increment2',    'uinteger',      '0'),
200         ),
201     },
202     {
203     "initname" : "json_ais17",
204     "header": "\tAIS_HEADER,",
205     "structname": "ais->type17",
206     "fieldmap":(
207         # fieldname       type             default
208         ('lon',           'integer',       'AIS_GNS_LON_NOT_AVAILABLE'),
209         ('lat',           'integer',       'AIS_GNS_LAT_NOT_AVAILABLE'),
210         ('data',          'string',        None),
211         ),
212     "stringbuffered":("data",),
213     },
214     {
215     "initname" : "json_ais18",
216     "header": "\tAIS_HEADER,",
217     "structname": "ais->type18",
218     "fieldmap":(
219         # fieldname       type             default
220         ('reserved',      'uinteger',      '0'),
221         ('speed',         'uinteger',      'AIS_SPEED_NOT_AVAILABLE'),
222         ('accuracy',      'boolean',       'false'),
223         ('lon',           'integer',       'AIS_LON_NOT_AVAILABLE'),
224         ('lat',           'integer',       'AIS_LAT_NOT_AVAILABLE'),
225         ('course',        'uinteger',      'AIS_COURSE_NOT_AVAILABLE'),
226         ('heading',       'uinteger',      'AIS_HEADING_NOT_AVAILABLE'),
227         ('second',        'uinteger',      'AIS_SEC_NOT_AVAILABLE'),
228         ('regional',      'uinteger',      '0'),
229         ('cs',            'boolean',       'false'),
230         ('display',       'boolean',       'false'),
231         ('dsc',           'boolean',       'false'),
232         ('band',          'boolean',       'false'),
233         ('msg22',         'boolean',       'false'),
234         ('raim',          'boolean',       'false'),
235         ('radio',         'uinteger',      '0'),
236         ),
237     },
238     {
239     "initname" : "json_ais19",
240     "header": "\tAIS_HEADER,",
241     "structname": "ais->type19",
242     "fieldmap":(
243         # fieldname       type             default
244         ('reserved',      'uinteger',      '0'),
245         ('speed',         'uinteger',      'AIS_SPEED_NOT_AVAILABLE'),
246         ('accuracy',      'boolean',       'false'),
247         ('lon',           'integer',       'AIS_LON_NOT_AVAILABLE'),
248         ('lat',           'integer',       'AIS_LAT_NOT_AVAILABLE'),
249         ('course',        'uinteger',      'AIS_COURSE_NOT_AVAILABLE'),
250         ('heading',       'uinteger',      'AIS_HEADING_NOT_AVAILABLE'),
251         ('second',        'uinteger',      'AIS_SEC_NOT_AVAILABLE'),
252         ('regional',      'uinteger',      '0'),
253         ('shipname',      'string',        None),
254         ('shiptype',      'uinteger',      '0'),
255         ('to_bow',        'uinteger',      '0'),
256         ('to_stern',      'uinteger',      '0'),
257         ('to_port',       'uinteger',      '0'),
258         ('to_starboard',  'uinteger',      '0'),
259         ('epfd',          'uinteger',      '0'),
260         ('raim',          'boolean',       'false'),
261         ('dte',           'uinteger',      '1'),
262         ('assigned',      'boolean',       'false'),
263         ),
264     },
265     {
266     "initname" : "json_ais20",
267     "header": "\tAIS_HEADER,",
268     "structname": "ais->type20",
269     "fieldmap":(
270         # fieldname       type             default
271         ('offset1',       'uinteger',      '0'),
272         ('number1',       'uinteger',      '0'),
273         ('timeout1',      'uinteger',      '0'),
274         ('increment1',    'uinteger',      '0'),
275         ('offset2',       'uinteger',      '0'),
276         ('number2',       'uinteger',      '0'),
277         ('timeout2',      'uinteger',      '0'),
278         ('increment2',    'uinteger',      '0'),
279         ('offset3',       'uinteger',      '0'),
280         ('number3',       'uinteger',      '0'),
281         ('timeout3',      'uinteger',      '0'),
282         ('increment3',    'uinteger',      '0'),
283         ('offset4',       'uinteger',      '0'),
284         ('number4',       'uinteger',      '0'),
285         ('timeout4',      'uinteger',      '0'),
286         ('increment4',    'uinteger',      '0'),
287         ),
288     },
289     {
290     "initname" : "json_ais21",
291     "header": "\tAIS_HEADER,",
292     "structname": "ais->type21",
293     "fieldmap":(
294         # fieldname       type             default
295         ('aid_type',          'uinteger',      '0'),
296         ('name',          'string',        None),
297         ('accuracy',      'boolean',       'false'),
298         ('lon',           'integer',       'AIS_LON_NOT_AVAILABLE'),
299         ('lat',           'integer',       'AIS_LAT_NOT_AVAILABLE'),
300         ('to_bow',        'uinteger',      '0'),
301         ('to_stern',      'uinteger',      '0'),
302         ('to_port',       'uinteger',      '0'),
303         ('to_starboard',  'uinteger',      '0'),
304         ('epfd',          'uinteger',      '0'),
305         ('second',        'uinteger',      '0'),
306         ('regional',      'uinteger',      '0'),
307         ('off_position',  'boolean',       'false'),
308         ('raim',          'boolean',       'false'),
309         ('virtual_aid',   'boolean',       'false'),
310         ),
311     },
312     {
313     "initname" : "json_ais22",
314     "header": "\tAIS_HEADER,",
315     "structname": "ais->type22",
316     "fieldmap":(
317         # fieldname       type             default
318         ('channel_a',     'uinteger',      '0'),
319         ('channel_b',     'uinteger',      '0'),
320         ('txrx',          'uinteger',      '0'),
321         ('power',         'boolean',       'false'),
322         ('area.ne_lon',   'integer',       'AIS_GNS_LON_NOT_AVAILABLE'),
323         ('area.ne_lat',   'integer',       'AIS_GNS_LAT_NOT_AVAILABLE'),
324         ('area.sw_lon',   'integer',       'AIS_GNS_LON_NOT_AVAILABLE'),
325         ('area.sw_lat',   'integer',       'AIS_GNS_LAT_NOT_AVAILABLE'),
326         ('mmsi.dest1',    'uinteger',      '0'),
327         ('mmsi.dest2',    'uinteger',      '0'),
328         ('addressed',     'boolean',       'false'),
329         ('band_a',        'boolean',       'false'),
330         ('band_b',        'boolean',       'false'),
331         ('zonesize',      'uinteger',      '0'),
332         ),
333     },
334     {
335     "initname" : "json_ais23",
336     "header": "\tAIS_HEADER,",
337     "structname": "ais->type23",
338     "fieldmap":(
339         # fieldname       type             default
340         ('ne_lon',        'integer',       'AIS_GNS_LON_NOT_AVAILABLE'),
341         ('ne_lat',        'integer',       'AIS_GNS_LAT_NOT_AVAILABLE'),
342         ('sw_lon',        'integer',       'AIS_GNS_LON_NOT_AVAILABLE'),
343         ('sw_lat',        'integer',       'AIS_GNS_LAT_NOT_AVAILABLE'),
344         ('stationtype',   'uinteger',      '0'),
345         ('shiptype',      'uinteger',      '0'),
346         ('txrx',          'uinteger',      '0'),
347         ('interval',      'uinteger',      '0'),
348         ('quiet',         'uinteger',      '0'),
349         ),
350     },
351     {
352     "initname" : "json_ais24",
353     "header": "\tAIS_HEADER,",
354     "structname": "ais->type24",
355     "fieldmap":(
356         # fieldname             type             default
357         ('shipname',          'string',        None),   # Part A
358         ('shiptype',          'uinteger',      '0'),    # Part B
359         ('vendorid',          'string',        None),   # Part B
360         ('callsign',          'string',        None),   # Part B
361         ('mothership_mmsi',   'uinteger',      '0'),    # Part B
362         ('dim.to_bow',        'uinteger',      '0'),    # Part B
363         ('dim.to_stern',      'uinteger',      '0'),    # Part B
364         ('dim.to_port',       'uinteger',      '0'),    # Part B
365         ('dim.to_starboard',  'uinteger',      '0'),    # Part B
366         ),
367     },
368     {
369     "initname" : "json_ais25",
370     "header": "\tAIS_HEADER,",
371     "structname": "ais->type25",
372     "fieldmap":(
373         # fieldname       type             default
374         ('addressed',     'boolean',       'false'),
375         ('structured',    'boolean',       'false'),
376         ('dest_mmsi',     'uinteger',      '0'),
377         ('app_id',        'uinteger',      '0'),
378         ('data',          'string',        None),
379         ),
380     "stringbuffered":("data",),
381     },
382     {
383     "initname" : "json_ais26",
384     "header": "\tAIS_HEADER,",
385     "structname": "ais->type26",
386     "fieldmap":(
387         # fieldname       type             default
388         ('addressed',     'boolean',       'false'),
389         ('structured',    'boolean',       'false'),
390         ('dest_mmsi',     'uinteger',      '0'),
391         ('app_id',        'uinteger',      '0'),
392         ('data',          'string',        None),
393         ('radio',         'uinteger',      '0'),
394         ),
395     "stringbuffered":("data",),
396     },
397 )
398
399
400 # Give this global the string spec you need to convert with -g
401 # We do it this mildly odd way only because passing Python multiline
402 # string literals on the command line is inconvenient.
403 stringspec = ""
404
405 # You should not need to modify anything below this line.
406
407 def generate(spec):
408     global outboard
409     report = ""
410     for (attr, itype, default) in spec["fieldmap"]:
411         if attr in spec.get("stringbuffered", []):
412             if attr not in outboard:
413                 report += "    char %s[JSON_VAL_MAX+1];\n" % attr
414                 outboard.append(attr)
415     report += "    const struct json_attr_t %s[] = {\n" % spec["initname"]
416     if "header" in spec:
417         report += spec["header"] + "\n"
418     for (attr, itype, default) in spec["fieldmap"]:
419         structname = spec["structname"]
420         if itype == "string":
421             deref = ""
422         else:
423             deref = "&"
424         if attr in spec.get("stringbuffered", []):
425             target = attr
426         else:
427             target = structname + "." + attr
428         if "." in attr:
429             attr = attr[attr.rfind(".")+1:]
430         report += '\t{"%s",%st_%s,%s.addr.%s = %s%s,\n' % \
431                (attr, " "*(14-len(attr)), itype, " "*(10-len(itype)), itype, deref, target)
432         leader = " " * 39
433         if itype == "string":
434             report += leader + ".len = sizeof(%s)},\n" % target
435         else:
436             report += leader + ".dflt.%s = %s},\n" % (itype, default)
437
438     report += """\
439         {NULL}
440     };
441 """
442     print report
443
444 # No code for generating dump functions yet.
445 # When we do this, remembeer that we have to suppress dump function
446 # generation from any spec with a union dot in the field names;
447 # those will have to be coded by hand.
448
449 def string_to_specifier(strspec):
450     "Compile a Python-style format string to an attribute-type fieldmap."
451     # Map C and Python-type format letters to JSON parser datatypes 
452     fmtmap = {
453         "d": "integer",
454         "u": "uinteger",
455         "f": "real",
456         "s": "boolean", # Only booleans print as unquoted strings
457         "\"": "string",
458         }
459     dftmap = {
460         "integer":  "0",
461         "uinteger": "0",
462         "real":     "0.0",
463         "string":   None,
464         "boolean":  "false"
465         }
466     strspec = strspec.strip()
467     if strspec[-1] == "}":
468         strspec = strspec[:-1]
469     else:
470         print "Missing terminating }"
471         sys.exit(1)
472     print '    "fieldmap":('
473     for item in strspec.split(","):
474         itype = fmtmap[item[-1]]
475         attr = item[:item.find(":")]
476         if attr[0] == '"':
477             attr = attr[1:]
478         if attr[-1] == '"':
479             attr = attr[:-1]
480         dflt = dftmap[itype]
481         if dflt is not None:
482             dflt = `dflt`
483         print "        ('%s',%s'%s',%s%s)," % (attr, " "*(14-len(attr)), itype, " "*(14-len(itype)), dflt)
484     print "        )"
485
486
487 if __name__ == '__main__':
488     try:
489         # The --ais and --target= options are (required) placeho;lders.
490         # In the future, this script will generate more different kinds
491         # of code.
492         (options, arguments) = getopt.getopt(sys.argv[1:], "g", ["ais", "target="])
493     except getopt.GetoptError, msg:
494         print "jsongen.py: " + str(msg)
495         raise SystemExit, 1
496
497     specify = False
498     spec = None
499     target = None
500     for (switch, val) in options:
501         if switch == '-g':
502             specify = True
503         elif switch == '--ais':
504             spec = ais_specs
505         elif switch == '--target':
506             target = val
507
508     if not specify and (not target or not spec):
509         print "jsongen.py: must specify type and target."
510         sys,exit(1)
511
512
513     if specify:
514         string_to_specifier(stringspec)
515     else:
516         print """/*
517  * This is code generated by jsongen.py. Do not hand-hack it!
518  */
519  
520 /*@ -fullinitblock */
521
522 """
523         outboard = []
524         for description in spec:
525             generate(description)
526         print """
527 /*@ +fullinitblock */
528
529 /* Generated code ends. */
530 """
531 # The following sets edit modes for GNU EMACS
532 # Local Variables:
533 # mode:python
534 # End: