add header file generators

keymap-gen can create header files that include the length of the array.  Using
ARRAY_SIZE on the array becomes then possible, and this can be preferrable to
the "x_len" symbols because static analysis cannot necessarily see the value of
"x_len".

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/tests/Makefile b/tests/Makefile
index b25c77c..e1b3875 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -13,49 +13,81 @@
 
 .DELETE_ON_ERROR:
 
-stdc: stdc.c osx2win32.h osx2win32_name.h \
-             osx2xkb.h osx2xkb_name.h \
-             html2win32.h html2win32_name.h \
-             osx.h osx_name.h
-	$(CC) -Wall -o $@ $^
-osx2win32.h: $(SOURCES)
+stdc: stdc.c osx2win32.h osx2win32.c osx2win32_name.h osx2win32_name.c \
+             osx2xkb.h osx2xkb.c osx2xkb_name.h osx2xkb_name.c \
+             html2win32.h html2win32.c html2win32_name.h html2win32_name.c \
+             osx.h osx.c osx_name.h osx_name.c
+	$(CC) -Wall -o $@ $(filter %.c, $^)
+osx2win32.c: $(SOURCES)
 	$(GEN) --lang stdc code-map $(DATA) osx win32 > $@
-osx2win32_name.h: $(SOURCES)
+osx2win32.h: $(SOURCES)
+	$(GEN) --lang stdc-header code-map $(DATA) osx win32 > $@
+osx2win32_name.c: $(SOURCES)
 	$(GEN) --lang stdc name-map $(DATA) osx win32 > $@
-osx2xkb.h: $(SOURCES)
+osx2win32_name.h: $(SOURCES)
+	$(GEN) --lang stdc-header name-map $(DATA) osx win32 > $@
+osx2xkb.c: $(SOURCES)
 	$(GEN) --lang stdc code-map $(DATA) osx xkb > $@
-osx2xkb_name.h: $(SOURCES)
+osx2xkb.h: $(SOURCES)
+	$(GEN) --lang stdc-header code-map $(DATA) osx xkb > $@
+osx2xkb_name.c: $(SOURCES)
 	$(GEN) --lang stdc name-map $(DATA) osx xkb > $@
-html2win32.h: $(SOURCES)
+osx2xkb_name.h: $(SOURCES)
+	$(GEN) --lang stdc-header name-map $(DATA) osx xkb > $@
+html2win32.c: $(SOURCES)
 	$(GEN) --lang stdc code-map $(DATA) html win32 > $@
-html2win32_name.h: $(SOURCES)
+html2win32.h: $(SOURCES)
+	$(GEN) --lang stdc-header code-map $(DATA) html win32 > $@
+html2win32_name.c: $(SOURCES)
 	$(GEN) --lang stdc name-map $(DATA) html win32 > $@
-osx.h: $(SOURCES)
+html2win32_name.h: $(SOURCES)
+	$(GEN) --lang stdc-header name-map $(DATA) html win32 > $@
+osx.c: $(SOURCES)
 	$(GEN) --lang stdc code-table $(DATA) osx > $@
-osx_name.h: $(SOURCES)
+osx.h: $(SOURCES)
+	$(GEN) --lang stdc-header code-table $(DATA) osx > $@
+osx_name.c: $(SOURCES)
 	$(GEN) --lang stdc name-table $(DATA) osx > $@
+osx_name.h: $(SOURCES)
+	$(GEN) --lang stdc-header name-table $(DATA) osx > $@
 
-stdc++: stdc++.cc osx2win32.hh osx2win32_name.hh \
-             osx2xkb.hh osx2xkb_name.hh \
-             html2win32.hh html2win32_name.hh \
-             osx.hh osx_name.hh
-	$(CXX) -Wall -std=c++11 -o $@ $^
-osx2win32.hh: $(SOURCES)
+stdc++: stdc++.cc osx2win32.hh osx2win32.cc osx2win32_name.hh osx2win32_name.cc \
+             osx2xkb.hh osx2xkb.cc osx2xkb_name.hh osx2xkb_name.cc \
+             html2win32.hh html2win32.cc html2win32_name.hh html2win32_name.cc \
+             osx.hh osx.cc osx_name.hh osx_name.cc
+	$(CXX) -Wall -std=c++11 -o $@ $(filter %.cc, $^)
+osx2win32.cc: $(SOURCES)
 	$(GEN) --lang stdc++ code-map $(DATA) osx win32 > $@
-osx2win32_name.hh: $(SOURCES)
+osx2win32.hh: $(SOURCES)
+	$(GEN) --lang stdc++-header code-map $(DATA) osx win32 > $@
+osx2win32_name.cc: $(SOURCES)
 	$(GEN) --lang stdc++ name-map $(DATA) osx win32 > $@
-osx2xkb.hh: $(SOURCES)
+osx2win32_name.hh: $(SOURCES)
+	$(GEN) --lang stdc++-header name-map $(DATA) osx win32 > $@
+osx2xkb.cc: $(SOURCES)
 	$(GEN) --lang stdc++ code-map $(DATA) osx xkb > $@
-osx2xkb_name.hh: $(SOURCES)
+osx2xkb.hh: $(SOURCES)
+	$(GEN) --lang stdc++-header code-map $(DATA) osx xkb > $@
+osx2xkb_name.cc: $(SOURCES)
 	$(GEN) --lang stdc++ name-map $(DATA) osx xkb > $@
-html2win32.hh: $(SOURCES)
+osx2xkb_name.hh: $(SOURCES)
+	$(GEN) --lang stdc++-header name-map $(DATA) osx xkb > $@
+html2win32.cc: $(SOURCES)
 	$(GEN) --lang stdc++ code-map $(DATA) html win32 > $@
-html2win32_name.hh: $(SOURCES)
+html2win32.hh: $(SOURCES)
+	$(GEN) --lang stdc++-header code-map $(DATA) html win32 > $@
+html2win32_name.cc: $(SOURCES)
 	$(GEN) --lang stdc++ name-map $(DATA) html win32 > $@
-osx.hh: $(SOURCES)
+html2win32_name.hh: $(SOURCES)
+	$(GEN) --lang stdc++-header name-map $(DATA) html win32 > $@
+osx.cc: $(SOURCES)
 	$(GEN) --lang stdc++ code-table $(DATA) osx > $@
-osx_name.hh: $(SOURCES)
+osx.hh: $(SOURCES)
+	$(GEN) --lang stdc++-header code-table $(DATA) osx > $@
+osx_name.cc: $(SOURCES)
 	$(GEN) --lang stdc++ name-table $(DATA) osx > $@
+osx_name.hh: $(SOURCES)
+	$(GEN) --lang stdc++-header name-table $(DATA) osx > $@
 
 python2: osx2win32.py osx2win32_name.py \
          osx2xkb.py osx2xkb_name.py \
diff --git a/tools/keymap-gen b/tools/keymap-gen
index 5d4dca3..cd5a391 100755
--- a/tools/keymap-gen
+++ b/tools/keymap-gen
@@ -633,6 +633,58 @@
     def __init__(self):
         super(GLib2LanguageGenerator, self).__init__("guint16", "gchar *", "guint")
 
+class CHeaderLanguageGenerator(LanguageSrcGenerator):
+
+    def __init__(self, inttypename, strtypename, lentypename):
+        self.inttypename = inttypename
+        self.strtypename = strtypename
+        self.lentypename = lentypename
+
+    def _boilerplate(self, lines):
+        print("/*")
+        for line in lines:
+            print(" * %s" % line)
+        print("*/")
+
+    def _array_start(self, varname, length, defvalue, fromtype, totype):
+        self._varname = varname
+        if fromtype == self.TYPE_STRING:
+            self._length = 0
+        else:
+            self._length = length
+
+    def _array_end(self, fromtype, totype):
+        totypename = self.strtypename if totype == self.TYPE_STRING else self.inttypename
+        if fromtype == self.TYPE_STRING:
+            vartypename = "struct _%s" % self._varname
+            print("%s {" % vartypename)
+            print("  const %s from;" % self.strtypename)
+            print("  const %s to;" % totypename)
+            print("};")
+        else:
+            vartypename = totypename
+        if type(self._length) == str:
+            print("extern const %s %s[%s];" % (vartypename, self._varname, self._length))
+        else:
+            print("extern const %s %s[%d];" % (vartypename, self._varname, self._length))
+        print("extern const %s %s_len;" % (self.lentypename, self._varname))
+
+    def _array_entry(self, index, value, comment, fromtype, totype):
+        if value is None:
+            return
+        if fromtype == self.TYPE_STRING:
+            self._length += 1
+
+class StdCHeaderLanguageGenerator(CHeaderLanguageGenerator):
+
+    def __init__(self):
+        super(StdCHeaderLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
+
+class GLib2HeaderLanguageGenerator(CHeaderLanguageGenerator):
+
+    def __init__(self):
+        super(GLib2HeaderLanguageGenerator, self).__init__("guint16", "gchar *", "guint")
+
 class CppLanguageGenerator(CLanguageGenerator):
 
     def _array_start(self, varname, length, defvalue, fromtype, totype):
@@ -671,6 +723,32 @@
     def __init__(self):
         super(StdCppLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
 
+class CppHeaderLanguageGenerator(CHeaderLanguageGenerator):
+
+    def _array_start(self, varname, length, defvalue, fromtype, totype):
+        if fromtype == self.TYPE_ENUM:
+            raise NotImplementedError("Enums not supported as source in C++ generator")
+        totypename = "const " + self.strtypename if totype == self.TYPE_STRING else self.inttypename
+        if fromtype == self.TYPE_INT:
+            print("#include <vector>")
+            print("extern const std::vector<%s> %s;" % (totypename, varname));
+        else:
+            print("#include <map>")
+            print("#include <string>")
+            print("extern const std::map<const std::string, %s> %s;" % (totypename, varname))
+
+    def _array_end(self, fromtype, totype):
+        pass
+
+    # designated initializers not available in C++
+    def _array_entry(self, index, value, comment, fromtype, totype):
+        pass
+
+class StdCppHeaderLanguageGenerator(CppHeaderLanguageGenerator):
+
+    def __init__(self):
+        super(StdCppHeaderLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
+
 class PythonLanguageGenerator(LanguageSrcGenerator):
 
     def _boilerplate(self, lines):
@@ -829,8 +907,11 @@
 
 SRC_GENERATORS = {
     "stdc": StdCLanguageGenerator(),
+    "stdc-header": StdCHeaderLanguageGenerator(),
     "stdc++": StdCppLanguageGenerator(),
+    "stdc++-header": StdCppHeaderLanguageGenerator(),
     "glib2": GLib2LanguageGenerator(),
+    "glib2-header": GLib2HeaderLanguageGenerator(),
     "python2": PythonLanguageGenerator(),
     "python3": PythonLanguageGenerator(),
     "perl": PerlLanguageGenerator(),