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