glsl: Add utility to convert text files to C strings
authorIan Romanick <ian.d.romanick@intel.com>
Tue, 23 Oct 2018 23:01:12 +0000 (16:01 -0700)
committerMatt Turner <mattst88@gmail.com>
Thu, 10 Jan 2019 00:42:40 +0000 (16:42 -0800)
Will be used to convert the .glsl source file containing software fp64
routines to a .h file that can be included while building the compiler.

This commit contains two squashed together: the first from Ian adding
the utility (with the existing title), and the second from Dylan making
the code both python2 and python3 compatible.

This is somewhat modeled after the xxd utility that comes with Vim.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
xxd.py: Make python2 and 3 compatible

This makes use of unicode_literals, so that undecorated strings are
considered text (python2 unicode, python3 str) and not bytes in python2
and text in python3. It makes use of io.open, which provides python2
with python3's open behavior (it's an alias in python3), in particular
support for the 't' and 'b' option. Finally, it decorates all of the
string literals with the 'b' prefix, so that python interprets them as
bytes.

I've removed the stdin and stdout options, as python2 always requires
these to be bytes, but python3 always treats them as text (there is a
way to get at the underlying bytes buffer, but that's even more
complexity), and makes the input files required arguments.

In the meson we use the '@INPUT@' shorthand instead of listing each
input, as meson will expand that to [prog_python, '@INPUT0@', @INPUT1@,
..., @OUTPUT@, ...]

src/compiler/Makefile.glsl.am
src/compiler/glsl/xxd.py [new file with mode: 0644]

index a323f7b05bc447fb980b9f5f617d9800fb45fcbd..9d88d1f66eed1985f52c4e71959f46e8347cc6b5 100644 (file)
@@ -28,6 +28,7 @@ EXTRA_DIST += glsl/tests glsl/glcpp/tests glsl/README \
        glsl/ir_expression_operation.py                 \
        glsl/glcpp/glcpp-lex.l                          \
        glsl/glcpp/glcpp-parse.y                        \
+       glsl/xxd.py                                     \
        SConscript.glsl
 
 TESTS += glsl/glcpp/tests/glcpp-test.sh                        \
diff --git a/src/compiler/glsl/xxd.py b/src/compiler/glsl/xxd.py
new file mode 100644 (file)
index 0000000..f8f57d7
--- /dev/null
@@ -0,0 +1,111 @@
+# encoding=utf-8
+# Copyright © 2018 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+# Converts a file to a C/C++ #include containing a string
+
+from __future__ import unicode_literals
+import argparse
+import io
+import string
+import sys
+
+
+def get_args():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('input', help="Name of input file")
+    parser.add_argument('output', help="Name of output file")
+    parser.add_argument("-n", "--name",
+                        help="Name of C variable")
+    args = parser.parse_args()
+    return args
+
+
+def filename_to_C_identifier(n):
+    if n[0] != '_' and not n[0].isalpha():
+        n = "_" + n[1:]
+
+    return "".join([c if c.isalnum() or c == "_" else "_" for c in n])
+
+
+def emit_byte(f, b):
+    if ord(b) == ord('\n'):
+        f.write(b"\\n\"\n    \"")
+        return
+    elif ord(b) == ord('\r'):
+        f.write(b"\\r\"\n    \"")
+        return
+    elif ord(b) == ord('\t'):
+        f.write(b"\\t")
+        return
+    elif ord(b) == ord('"'):
+        f.write(b"\\\"")
+        return
+    elif ord(b) == ord('\\'):
+        f.write(b"\\\\")
+        return
+
+    if ord(b) >= ord(' ') and ord(b) <= ord('~'):
+        f.write(b)
+    else:
+        hi = ord(b) >> 4
+        lo = ord(b) & 0x0f
+        f.write("\\x{:x}{:x}".format(hi, lo).encode('utf-8'))
+
+
+def process_file(args):
+    with io.open(args.input, "rb") as infile:
+        try:
+            with io.open(args.output, "wb") as outfile:
+                # If a name was not specified on the command line, pick one based on the
+                # name of the input file.  If no input filename was specified, use
+                # from_stdin.
+                if args.name is not None:
+                    name = args.name
+                else:
+                    name = filename_to_C_identifier(args.input)
+
+                outfile.write("static const char {}[] =\n \"".format(name).encode('utf-8'))
+
+                while True:
+                    byte = infile.read(1)
+                    if byte == b"":
+                        break
+
+                    emit_byte(outfile, byte)
+
+                outfile.write(b"\"\n    ;\n")
+        except Exception:
+            # In the event that anything goes wrong, delete the output file,
+            # then re-raise the exception. Deleteing the output file should
+            # ensure that the build system doesn't try to use the stale,
+            # half-generated file.
+            os.unlink(args.output)
+            raise
+
+
+def main():
+    args = get_args()
+    process_file(args)
+
+
+if __name__ == "__main__":
+    main()