summaryrefslogtreecommitdiffstats
path: root/yang/embedmodel.py
diff options
context:
space:
mode:
Diffstat (limited to 'yang/embedmodel.py')
-rw-r--r--yang/embedmodel.py109
1 files changed, 109 insertions, 0 deletions
diff --git a/yang/embedmodel.py b/yang/embedmodel.py
new file mode 100644
index 0000000..a77a813
--- /dev/null
+++ b/yang/embedmodel.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python3
+#
+# YANG module to C wrapper
+# written 2018 by David Lamparter, placed in Public Domain.
+
+import sys
+import os
+import string
+import re
+
+inname = sys.argv[1]
+outname = sys.argv[2]
+
+outdir = os.path.dirname(os.path.abspath(outname))
+if not os.path.isdir(outdir):
+ os.makedirs(outdir)
+
+# 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_subname = re.compile(r"\bsubmodule\s+([^\s]+)\s+\{")
+re_mainname = re.compile(r"\bbelongs-to\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.sub_mod_name = "%s",
+\t.sub_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()
+
+sub_name = ""
+rev = ""
+sub_rev = ""
+
+# 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:
+ search_name = re_name.search(data)
+ if search_name:
+ name = search_name.group(1)
+ rev = re_rev.search(data).group(1)
+ else:
+ search_name = re_subname.search(data)
+ sub_name = search_name.group(1)
+ name = re_mainname.search(data).group(1)
+ sub_rev = re_rev.search(data).group(1)
+ fmt = "LYS_IN_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), escape(sub_name), escape(sub_rev), fmt)
+ )