]>
Commit | Line | Data |
---|---|---|
3a11599c DL |
1 | #!/usr/bin/python3 |
2 | # | |
3 | # YANG module to C wrapper | |
4 | # written 2018 by David Lamparter, placed in Public Domain. | |
5 | ||
261e7653 DL |
6 | import sys |
7 | import os | |
8 | import string | |
9 | import re | |
3a11599c DL |
10 | |
11 | inname = sys.argv[1] | |
12 | outname = sys.argv[2] | |
13 | ||
261e7653 DL |
14 | outdir = os.path.dirname(os.path.abspath(outname)) |
15 | if not os.path.isdir(outdir): | |
16 | os.makedirs(outdir) | |
17 | ||
3a11599c DL |
18 | # these are regexes to avoid a compile-time/host dependency on yang-tools |
19 | # or python-yang. Cross-compiling FRR is already somewhat involved, no need | |
20 | # to make it even harder. | |
21 | ||
22 | re_name = re.compile(r'\bmodule\s+([^\s]+)\s+\{') | |
23 | re_rev = re.compile(r'\brevision\s+([\d-]+)\s+\{') | |
24 | ||
25 | ||
26 | template = '''/* autogenerated by embedmodel.py. DO NOT EDIT */ | |
27 | ||
28 | #include <zebra.h> | |
29 | #include "yang.h" | |
30 | ||
31 | static const char model[] = | |
32 | \t"%s"; | |
33 | ||
34 | static struct yang_module_embed embed = { | |
35 | \t.mod_name = "%s", | |
36 | \t.mod_rev = "%s", | |
37 | \t.data = model, | |
38 | \t.format = %s, | |
39 | }; | |
40 | ||
41 | static void embed_register(void) __attribute__((_CONSTRUCTOR(2000))); | |
42 | static void embed_register(void) | |
43 | { | |
44 | \tyang_module_embed(&embed); | |
45 | } | |
46 | ''' | |
47 | ||
48 | passchars = set(string.printable) - set('\\\'"%\r\n\t\x0b\x0c') | |
49 | def escapech(char): | |
50 | if char in passchars: | |
51 | return char | |
52 | if char == '\n': | |
53 | return '\\n' | |
54 | if char == '\t': | |
55 | return '\\t' | |
56 | if char in '"\\\'': | |
57 | return '\\' + char | |
58 | return '\\x%02x' % (ord(char)) | |
59 | def escape(line): | |
60 | return ''.join([escapech(i) for i in line]) | |
61 | ||
62 | with open(inname, 'r') as fd: | |
63 | data = fd.read() | |
64 | ||
65 | # XML support isn't actively used currently, but it's here in case the need | |
66 | # arises. It does avoid the regex'ing. | |
67 | if '<?xml' in data: | |
68 | from xml.etree import ElementTree | |
69 | xml = ElementTree.fromstring(data) | |
70 | name = xml.get('name') | |
71 | rev = xml.find('{urn:ietf:params:xml:ns:yang:yin:1}revision').get('date') | |
72 | fmt = 'LYS_YIN' | |
73 | else: | |
74 | name = re_name.search(data).group(1) | |
75 | rev = re_rev.search(data).group(1) | |
76 | fmt = 'LYS_YANG' | |
77 | ||
78 | if name is None or rev is None: | |
79 | raise ValueError('cannot determine YANG module name and revision') | |
80 | ||
81 | lines = [escape(row) for row in data.split('\n')] | |
82 | text = '\\n"\n\t"'.join(lines) | |
83 | ||
84 | with open(outname, 'w') as fd: | |
85 | fd.write(template % (text, escape(name), escape(rev), fmt)) |