Add a tool to generate locale_strings.h from .cs file

In case locale_strings.h is not provided, this allows to re-generate it
from the .cs file on non-Amiga systems where SimpleCat is not available.
diff --git a/generate_header.py b/generate_header.py
new file mode 100755
index 0000000..ea85576
--- /dev/null
+++ b/generate_header.py
@@ -0,0 +1,184 @@
+#!python3
+# -*- coding: utf-8 -*-
+# vim:fenc=utf-8
+#
+# Copyright © 2023 Adrien Destugues <pulkomandy@pulkomandy.tk>
+#
+# Distributed under terms of the MIT license.
+
+"""
+generate locale_strings.h from .cs file
+
+This is normally done on Amiga systems using SimpleCat. However, that is not open source, and
+cannot be run anywhere else.
+"""
+
+import argparse
+
+parser = argparse.ArgumentParser(prog = "generate_locale_strings_header",
+    description = "Generate locale_strings.h from SimpleCat .cs file")
+
+parser.add_argument("input")
+parser.add_argument("-o", "--output", default="locale_strings.h")
+
+args = parser.parse_args()
+
+# Parse input
+# Generate "strings" array with dictionaries of 'name' -> 'text' strings
+
+infile = open(args.input, "r", encoding="iso-8859-15")
+
+state = 0
+strings = []
+
+for line in infile:
+    line = line.strip()
+
+    # Ignore comments and empty lines
+    if len(line) == 0 or line[0] == '#':
+        continue
+
+    if state == 0:
+        name = line
+        state = 1
+    elif state == 1:
+        strings.append({"name": name, "text": line})
+        state = 2
+    elif state == 2 and line[0] == ';':
+        state = 0
+
+# Write output
+
+outfile = open(args.output, "w", encoding="iso-8859-15")
+
+outfile.write("""
+#ifndef Locale_Strings
+#define Locale_Strings 1
+
+/* Locale Catalog Source File
+ *
+ * Automatically generated by generate_header.py
+ * Do NOT edit by hand!
+ *
+ */
+
+
+
+/****************************************************************************/
+
+
+#ifndef EXEC_TYPES_H
+#include <exec/types.h>
+#endif
+
+#ifdef CATCOMP_ARRAY
+#undef CATCOMP_NUMBERS
+#undef CATCOMP_STRINGS
+#define CATCOMP_NUMBERS
+#define CATCOMP_STRINGS
+#endif
+
+#ifdef CATCOMP_BLOCK
+#undef CATCOMP_STRINGS
+#define CATCOMP_STRINGS
+#endif
+
+
+
+/****************************************************************************/
+
+
+#ifdef CATCOMP_NUMBERS
+
+""")
+
+i = 0
+for string in strings:
+    outfile.write(f"#define {string['name']} {i}\n")
+    i = i + 1
+
+outfile.write(f"\n#define CATCOMP_LASTID {i - 1}")
+
+outfile.write("""
+
+#endif /* CATCOMP_NUMBERS */
+
+
+/****************************************************************************/
+
+
+#ifdef CATCOMP_STRINGS
+
+""")
+
+for string in strings:
+    outfile.write(f"#define {string['name']}_STR \"{string['text']}\"\n")
+
+outfile.write("""
+#endif /* CATCOMP_STRINGS */
+
+
+/****************************************************************************/
+
+
+#ifdef CATCOMP_ARRAY
+
+struct CatCompArrayType
+{
+    LONG   cca_ID;
+    STRPTR cca_Str;
+};
+
+static const struct CatCompArrayType CatCompArray[] =
+{
+""")
+
+for string in strings:
+    outfile.write(f"    {{{string['name']},(STRPTR){string['name']}_STR}},\n")
+
+outfile.write("""};
+
+#endif /* CATCOMP_ARRAY */
+
+
+/****************************************************************************/
+
+
+#ifdef CATCOMP_BLOCK
+
+static const char CatCompBlock[] =
+{
+""")
+
+i = 0
+for string in strings:
+    i0 = i >> 24
+    i1 = i >> 16
+    i2 = i >> 8
+    i3 = i >> 0
+    l = len(string['text']) + 1
+    odd = False
+    if (l & 1) != 0:
+        odd = True
+        l = l + 1
+    l0 = l >> 8
+    l1 = l
+    outfile.write(f"    \"\\x{i0:02X}\\x{i1:02X}\\x{i2:02X}\\x{i3:02X}\\x{l0:02X}\\x{l1:02X}\"\n")
+    if odd:
+        outfile.write(f"    {string['name']}_STR \"\\x00\\x00\"\n")
+    else:
+        outfile.write(f"    {string['name']}_STR \"\\x00\"\n")
+    i = i + 1
+
+outfile.write("""};
+
+#endif /* CATCOMP_BLOCK */
+
+
+/****************************************************************************/
+
+
+
+#endif /* Locale_Strings */
+
+""")