summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErwin Jansen <jansene@google.com>2023-11-12 08:10:34 -0800
committerErwin Jansen <jansene@google.com>2023-11-14 11:07:06 -0800
commit6065c05b37f91e00145746aa0151a8ad29126b0e (patch)
tree8ba32bdb491d79a6820d109d4a7df03070d7fc88
parent86cfa9a19dfde6cd3b40118a2fa9cc5fd42f8451 (diff)
downloadglib-6065c05b37f91e00145746aa0151a8ad29126b0e.tar.gz
Fix GLIB2 build
This contains a series of small fixes and extensions: - We now compile in gmodule as well, as this is needed by qemu - Add support for regex (needed by qemu) - General cleanup - Add a workspace definition. - Fixes to compile on Win32 Bug: 310211980 Change-Id: I745c84a9cee33774e9f27b90ef8028e35d07c702
-rw-r--r--BUILD146
-rw-r--r--WORKSPACE1
-rw-r--r--os/windows/config.h4
-rw-r--r--os/windows/glib/gnulib/gnulib_math.h (renamed from os/windows/glib/gnulib_math.h)0
-rw-r--r--os/windows/gmodule/gmoduleconf.h50
-rw-r--r--os/windows/gobject/glib-genmarshal1080
-rw-r--r--os/windows/gobject/glib-mkenums810
7 files changed, 2078 insertions, 13 deletions
diff --git a/BUILD b/BUILD
index 999ab970d..f97bdd7cc 100644
--- a/BUILD
+++ b/BUILD
@@ -1,3 +1,5 @@
+load("@bazel_skylib//rules:run_binary.bzl", "run_binary")
+
objc_library(
name = "glib-darwin",
srcs = [
@@ -13,22 +15,75 @@ objc_library(
"-I $(execpath os/darwin)",
"-I $(execpath os/darwin/glib)",
"-I $(execpath glib)",
+ "-I $(execpath .)",
],
data = [
# These paths are here so we can use them in copts with $(execpath ...)
"os/darwin",
"os/darwin/glib",
"glib",
+ ".",
],
includes = [
".",
],
)
+py_binary(
+ name = "gen-visibility-macros",
+ srcs = ["tools/gen-visibility-macros.py"],
+)
+
+run_binary(
+ name = "gen_visibility_macros",
+ outs = ["gmodule/gmodule-visibility.h"],
+ args = [
+ "2.77.2",
+ "visibility-macros",
+ "GMODULE",
+ "$(location gmodule/gmodule-visibility.h)",
+ ],
+ tool = ":gen-visibility-macros",
+)
+
+cc_library(
+ name = "gnulib",
+ srcs = [
+ "glib/gnulib/asnprintf.c",
+ "glib/gnulib/isnan.c",
+ "glib/gnulib/printf.c",
+ "glib/gnulib/printf-args.c",
+ "glib/gnulib/printf-frexp.c",
+ "glib/gnulib/printf-frexpl.c",
+ "glib/gnulib/printf-parse.c",
+ # "glib/gnulib/vasnprintf.c",
+ "glib/gnulib/xsize.c",
+ ] + glob([
+ "glib/gnulib/*.h",
+ "glib/*.h",
+ "glib/deprecated/*.h",
+ ]),
+ hdrs = [
+ "glib.h",
+ "glib/gnulib/g-gnulib.h",
+ "glib/gnulib/printf-frexp.c",
+ "os/windows/config.h",
+ "os/windows/glib/glibconfig.h",
+ "os/windows/glib/gnulib/gnulib_math.h",
+ ],
+ includes = [
+ "os/windows",
+ "os/windows/glib",
+ "os/windows/glib/gnulib",
+ ],
+)
+
+# Note we merge gmodule inside this.
cc_library(
# Named "glib2" so it doesn't shadow the "glib" directory in this package.
- name = "glib2",
+ name = "glib-2.0",
srcs = [
+ "gmodule/gmodule.c",
"glib/garcbox.c",
"glib/garray.c",
"glib/gasyncqueue.c",
@@ -78,7 +133,7 @@ cc_library(
"glib/grcbox.c",
"glib/grefcount.c",
"glib/grefstring.c",
- # "gregex.c",
+ "glib/gregex.c",
"glib/gscanner.c",
"glib/gsequence.c",
"glib/gshell.c",
@@ -114,6 +169,7 @@ cc_library(
"glib/gversion.c",
"glib/gwakeup.c",
"glib/libcharset/localcharset.c",
+ "gmodule/gmodule.h",
] + select({
"@platforms//os:macos": [
"glib/giounix.c",
@@ -123,11 +179,35 @@ cc_library(
"glib/gthread-posix.c",
"os/darwin/config.h",
"os/darwin/glib/glibconfig.h",
+ "os/darwin/gmodule/gmoduleconf.h",
+ ],
+ "@platforms//os:windows": [
+ "glib/dirent/dirent.h",
+ "glib/dirent/wdirent.c",
+ "glib/giowin32.c",
+ "glib/gspawn-win32.c",
+ "glib/gthread-win32.c",
+ "glib/gwin32.c",
+ "os/windows/config.h",
+ "os/windows/glib/glibconfig.h",
+ "os/windows/gmodule/gmoduleconf.h",
+ ],
+ "@platforms//os:linux": [
+ "glib/giounix.c",
+ "glib/gjournal-private.c",
+ "glib/glib-unix.c",
+ "glib/glib-unixprivate.h",
+ "glib/gspawn.c",
+ "glib/gthread-posix.c",
+ "os/linux/config.h",
+ "os/linux/glib/glibconfig.h",
+ "os/linux/gmodule/gmoduleconf.h",
],
"//conditions:default": [],
}) + glob(
[
"glib/*.h",
+ "glib/gnulib/*.h",
"glib/deprecated/*.h",
"glib/libcharset/*.h",
],
@@ -137,13 +217,22 @@ cc_library(
),
hdrs = [
"glib.h",
- ],
+ "gmodule/gmodule-dl.c", # TODO: this technically leaks out.
+ "gmodule/gmodule-visibility.h",
+ ] + select({
+ "@platforms//os:windows": [
+ "glib/dirent/dirent.c",
+ "glib/gstdio-private.c",
+ "glib/gwin32-private.c",
+ "glib/win_iconv.c",
+ "gmodule/gmodule-win32.c",
+ ],
+ "//conditions:default": [],
+ }),
copts = [
- "-fvisibility=hidden",
"-Winvalid-pch",
"-Wextra",
"-Wpedantic",
- "-std=gnu99",
"-fno-strict-aliasing",
"-Wimplicit-fallthrough",
"-Wmisleading-indentation",
@@ -168,24 +257,58 @@ cc_library(
"-Werror=pointer-sign",
"-Wno-string-plus-int",
] + select({
+ # Needed for using <glib/xxx> vs "glib/xxxx"
"@platforms//os:macos": [
+ "-fvisibility=hidden",
+ "-std=gnu99",
"-I $(execpath os/darwin)",
"-I $(execpath os/darwin/glib)",
+ "-I $(execpath os/darwin/gmodule)",
"-I $(execpath glib)",
+ "-I $(execpath .)",
+ ],
+ "@platforms//os:windows": [
+ "-Wno-inconsistent-dllimport",
+ "-Wno-implicit-fallthrough",
+ "-Wno-unused-function",
+ "-Wno-#pragma-messages",
+ ],
+ "@platforms//os:linux": [
+ "-fvisibility=hidden",
+ "-std=gnu99",
],
"//conditions:default": [],
}),
- data = select({
+ data = [
+ # These paths are here so we can use them in copts with $(execpath ...)
+ "os/darwin",
+ "os/darwin/glib",
+ "os/darwin/gmodule",
+ "os/windows/gmodule",
+ "glib",
+ ".",
+ ],
+ includes = select({
"@platforms//os:macos": [
- # These paths are here so we can use them in copts with $(execpath ...)
"os/darwin",
"os/darwin/glib",
- "glib",
+ "os/darwin/gmodule",
+ ],
+ "@platforms//os:linux": [
+ "os/linux",
+ "os/linux/glib",
+ "os/linux/gmodule",
+ ],
+ "@platforms//os:windows": [
+ "os/windows",
+ "os/windows/glib",
+ "os/windows/gmodule",
],
"//conditions:default": [],
- }),
- includes = [
+ }) + [
".",
+ "glib",
+ "gmodule",
],
local_defines = [
"GLIB_COMPILATION",
@@ -195,6 +318,7 @@ cc_library(
],
deps = select({
"@platforms//os:macos": [":glib-darwin"],
+ "@platforms//os:windows": [":gnulib"],
"//conditions:default": [],
- }),
+ }) + ["@pcre2"],
)
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 000000000..4e7255e7a
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1 @@
+workspace(name = "glib")
diff --git a/os/windows/config.h b/os/windows/config.h
index 360cbb3de..9747b520f 100644
--- a/os/windows/config.h
+++ b/os/windows/config.h
@@ -177,7 +177,7 @@
#define _WIN32_WINNT 0x0601
-#define gl_extern_inline
+#define gl_extern_inline
/* Please see the Gnulib manual for how to use these macros.
Suppress extern inline with HP-UX cc, as it appears to be broken; see
@@ -271,7 +271,7 @@
#endif
-#define gl_unused
+#define gl_unused
/* Define as a marker that can be attached to declarations that might not
be used. This helps to reduce warnings, such as from
GCC -Wunused-parameter. */
diff --git a/os/windows/glib/gnulib_math.h b/os/windows/glib/gnulib/gnulib_math.h
index 7fa41b270..7fa41b270 100644
--- a/os/windows/glib/gnulib_math.h
+++ b/os/windows/glib/gnulib/gnulib_math.h
diff --git a/os/windows/gmodule/gmoduleconf.h b/os/windows/gmodule/gmoduleconf.h
new file mode 100644
index 000000000..42aacaba0
--- /dev/null
+++ b/os/windows/gmodule/gmoduleconf.h
@@ -0,0 +1,50 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998 Tim Janik
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __G_MODULE_CONF_H__
+#define __G_MODULE_CONF_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define G_MODULE_IMPL_NONE 0
+#define G_MODULE_IMPL_DL 1
+#define G_MODULE_IMPL_WIN32 3
+#define G_MODULE_IMPL_AR 7
+
+#define G_MODULE_IMPL G_MODULE_IMPL_WIN32
+#undef G_MODULE_HAVE_DLERROR
+#if (0)
+#define G_MODULE_HAVE_DLERROR
+#endif
+#if (0)
+#define G_MODULE_NEED_USCORE
+#endif
+#if (0)
+#define G_MODULE_BROKEN_RTLD_GLOBAL
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __G_MODULE_CONF_H__ */
diff --git a/os/windows/gobject/glib-genmarshal b/os/windows/gobject/glib-genmarshal
new file mode 100644
index 000000000..e88c461d9
--- /dev/null
+++ b/os/windows/gobject/glib-genmarshal
@@ -0,0 +1,1080 @@
+#!/usr/bin/env python3
+
+# pylint: disable=too-many-lines, missing-docstring, invalid-name
+
+# This file is part of GLib
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+import argparse
+import os
+import re
+import sys
+
+VERSION_STR = '''glib-genmarshal version 2.79.0
+glib-genmarshal comes with ABSOLUTELY NO WARRANTY.
+You may redistribute copies of glib-genmarshal under the terms of
+the GNU General Public License which can be found in the
+GLib source package. Sources, examples and contact
+information are available at http://www.gtk.org'''
+
+GETTERS_STR = '''#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_schar (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */'''
+
+DEPRECATED_MSG_STR = 'The token "{}" is deprecated; use "{}" instead'
+
+VA_ARG_STR = \
+ ' arg{:d} = ({:s}) va_arg (args_copy, {:s});'
+STATIC_CHECK_STR = \
+ '(param_types[{:d}] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && '
+BOX_TYPED_STR = \
+ ' arg{idx:d} = {box_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});'
+BOX_UNTYPED_STR = \
+ ' arg{idx:d} = {box_func} (arg{idx:d});'
+UNBOX_TYPED_STR = \
+ ' {unbox_func} (param_types[{idx:d}] & ~G_SIGNAL_TYPE_STATIC_SCOPE, arg{idx:d});'
+UNBOX_UNTYPED_STR = \
+ ' {unbox_func} (arg{idx:d});'
+
+STD_PREFIX = 'g_cclosure_marshal'
+
+# These are part of our ABI; keep this in sync with gmarshal.h
+GOBJECT_MARSHALLERS = {
+ 'g_cclosure_marshal_VOID__VOID',
+ 'g_cclosure_marshal_VOID__BOOLEAN',
+ 'g_cclosure_marshal_VOID__CHAR',
+ 'g_cclosure_marshal_VOID__UCHAR',
+ 'g_cclosure_marshal_VOID__INT',
+ 'g_cclosure_marshal_VOID__UINT',
+ 'g_cclosure_marshal_VOID__LONG',
+ 'g_cclosure_marshal_VOID__ULONG',
+ 'g_cclosure_marshal_VOID__ENUM',
+ 'g_cclosure_marshal_VOID__FLAGS',
+ 'g_cclosure_marshal_VOID__FLOAT',
+ 'g_cclosure_marshal_VOID__DOUBLE',
+ 'g_cclosure_marshal_VOID__STRING',
+ 'g_cclosure_marshal_VOID__PARAM',
+ 'g_cclosure_marshal_VOID__BOXED',
+ 'g_cclosure_marshal_VOID__POINTER',
+ 'g_cclosure_marshal_VOID__OBJECT',
+ 'g_cclosure_marshal_VOID__VARIANT',
+ 'g_cclosure_marshal_VOID__UINT_POINTER',
+ 'g_cclosure_marshal_BOOLEAN__FLAGS',
+ 'g_cclosure_marshal_STRING__OBJECT_POINTER',
+ 'g_cclosure_marshal_BOOLEAN__BOXED_BOXED',
+}
+
+
+# pylint: disable=too-few-public-methods
+class Color:
+ '''ANSI Terminal colors'''
+ GREEN = '\033[1;32m'
+ BLUE = '\033[1;34m'
+ YELLOW = '\033[1;33m'
+ RED = '\033[1;31m'
+ END = '\033[0m'
+
+
+def print_color(msg, color=Color.END, prefix='MESSAGE'):
+ '''Print a string with a color prefix'''
+ if os.isatty(sys.stderr.fileno()):
+ real_prefix = '{start}{prefix}{end}'.format(start=color, prefix=prefix, end=Color.END)
+ else:
+ real_prefix = prefix
+ sys.stderr.write('{prefix}: {msg}\n'.format(prefix=real_prefix, msg=msg))
+
+
+def print_error(msg):
+ '''Print an error, and terminate'''
+ print_color(msg, color=Color.RED, prefix='ERROR')
+ sys.exit(1)
+
+
+def print_warning(msg, fatal=False):
+ '''Print a warning, and optionally terminate'''
+ if fatal:
+ color = Color.RED
+ prefix = 'ERROR'
+ else:
+ color = Color.YELLOW
+ prefix = 'WARNING'
+ print_color(msg, color, prefix)
+ if fatal:
+ sys.exit(1)
+
+
+def print_info(msg):
+ '''Print a message'''
+ print_color(msg, color=Color.GREEN, prefix='INFO')
+
+
+def generate_licensing_comment(outfile):
+ outfile.write('/* This file is generated by glib-genmarshal, do not '
+ 'modify it. This code is licensed under the same license as '
+ 'the containing project. Note that it links to GLib, so '
+ 'must comply with the LGPL linking clauses. */\n')
+
+
+def generate_header_preamble(outfile, prefix='', std_includes=True, use_pragma=False):
+ '''Generate the preamble for the marshallers header file'''
+ generate_licensing_comment(outfile)
+
+ if use_pragma:
+ outfile.write('#pragma once\n')
+ outfile.write('\n')
+ else:
+ outfile.write('#ifndef __{}_MARSHAL_H__\n'.format(prefix.upper()))
+ outfile.write('#define __{}_MARSHAL_H__\n'.format(prefix.upper()))
+ outfile.write('\n')
+ # Maintain compatibility with the old C-based tool
+ if std_includes:
+ outfile.write('#include <glib-object.h>\n')
+ outfile.write('\n')
+
+ outfile.write('G_BEGIN_DECLS\n')
+ outfile.write('\n')
+
+
+def generate_header_postamble(outfile, prefix='', use_pragma=False):
+ '''Generate the postamble for the marshallers header file'''
+ outfile.write('\n')
+ outfile.write('G_END_DECLS\n')
+
+ if not use_pragma:
+ outfile.write('\n')
+ outfile.write('#endif /* __{}_MARSHAL_H__ */\n'.format(prefix.upper()))
+
+
+def generate_body_preamble(outfile, std_includes=True, include_headers=None, cpp_defines=None, cpp_undefines=None):
+ '''Generate the preamble for the marshallers source file'''
+ generate_licensing_comment(outfile)
+
+ for header in (include_headers or []):
+ outfile.write('#include "{}"\n'.format(header))
+ if include_headers:
+ outfile.write('\n')
+
+ for define in (cpp_defines or []):
+ s = define.split('=')
+ symbol = s[0]
+ value = s[1] if len(s) > 1 else '1'
+ outfile.write('#define {} {}\n'.format(symbol, value))
+ if cpp_defines:
+ outfile.write('\n')
+
+ for undefine in (cpp_undefines or []):
+ outfile.write('#undef {}\n'.format(undefine))
+ if cpp_undefines:
+ outfile.write('\n')
+
+ if std_includes:
+ outfile.write('#include <glib-object.h>\n')
+ outfile.write('\n')
+
+ outfile.write(GETTERS_STR)
+ outfile.write('\n\n')
+
+
+# Marshaller arguments, as a dictionary where the key is the token used in
+# the source file, and the value is another dictionary with the following
+# keys:
+#
+# - signal: the token used in the marshaller prototype (mandatory)
+# - ctype: the C type for the marshaller argument (mandatory)
+# - getter: the function used to retrieve the argument from the GValue
+# array when invoking the callback (optional)
+# - promoted: the C type used by va_arg() to retrieve the argument from
+# the va_list when invoking the callback (optional, only used when
+# generating va_list marshallers)
+# - box: an array of two elements, containing the boxing and unboxing
+# functions for the given type (optional, only used when generating
+# va_list marshallers)
+# - static-check: a boolean value, if the given type should perform
+# a static type check before boxing or unboxing the argument (optional,
+# only used when generating va_list marshallers)
+# - takes-type: a boolean value, if the boxing and unboxing functions
+# for the given type require the type (optional, only used when
+# generating va_list marshallers)
+# - deprecated: whether the token has been deprecated (optional)
+# - replaced-by: the token used to replace a deprecated token (optional,
+# only used if deprecated is True)
+IN_ARGS = {
+ 'VOID': {
+ 'signal': 'VOID',
+ 'ctype': 'void',
+ },
+ 'BOOLEAN': {
+ 'signal': 'BOOLEAN',
+ 'ctype': 'gboolean',
+ 'getter': 'g_marshal_value_peek_boolean',
+ },
+ 'CHAR': {
+ 'signal': 'CHAR',
+ 'ctype': 'gchar',
+ 'promoted': 'gint',
+ 'getter': 'g_marshal_value_peek_char',
+ },
+ 'UCHAR': {
+ 'signal': 'UCHAR',
+ 'ctype': 'guchar',
+ 'promoted': 'guint',
+ 'getter': 'g_marshal_value_peek_uchar',
+ },
+ 'INT': {
+ 'signal': 'INT',
+ 'ctype': 'gint',
+ 'getter': 'g_marshal_value_peek_int',
+ },
+ 'UINT': {
+ 'signal': 'UINT',
+ 'ctype': 'guint',
+ 'getter': 'g_marshal_value_peek_uint',
+ },
+ 'LONG': {
+ 'signal': 'LONG',
+ 'ctype': 'glong',
+ 'getter': 'g_marshal_value_peek_long',
+ },
+ 'ULONG': {
+ 'signal': 'ULONG',
+ 'ctype': 'gulong',
+ 'getter': 'g_marshal_value_peek_ulong',
+ },
+ 'INT64': {
+ 'signal': 'INT64',
+ 'ctype': 'gint64',
+ 'getter': 'g_marshal_value_peek_int64',
+ },
+ 'UINT64': {
+ 'signal': 'UINT64',
+ 'ctype': 'guint64',
+ 'getter': 'g_marshal_value_peek_uint64',
+ },
+ 'ENUM': {
+ 'signal': 'ENUM',
+ 'ctype': 'gint',
+ 'getter': 'g_marshal_value_peek_enum',
+ },
+ 'FLAGS': {
+ 'signal': 'FLAGS',
+ 'ctype': 'guint',
+ 'getter': 'g_marshal_value_peek_flags',
+ },
+ 'FLOAT': {
+ 'signal': 'FLOAT',
+ 'ctype': 'gfloat',
+ 'promoted': 'gdouble',
+ 'getter': 'g_marshal_value_peek_float',
+ },
+ 'DOUBLE': {
+ 'signal': 'DOUBLE',
+ 'ctype': 'gdouble',
+ 'getter': 'g_marshal_value_peek_double',
+ },
+ 'STRING': {
+ 'signal': 'STRING',
+ 'ctype': 'gpointer',
+ 'getter': 'g_marshal_value_peek_string',
+ 'box': ['g_strdup', 'g_free'],
+ 'static-check': True,
+ },
+ 'PARAM': {
+ 'signal': 'PARAM',
+ 'ctype': 'gpointer',
+ 'getter': 'g_marshal_value_peek_param',
+ 'box': ['g_param_spec_ref', 'g_param_spec_unref'],
+ 'static-check': True,
+ },
+ 'BOXED': {
+ 'signal': 'BOXED',
+ 'ctype': 'gpointer',
+ 'getter': 'g_marshal_value_peek_boxed',
+ 'box': ['g_boxed_copy', 'g_boxed_free'],
+ 'static-check': True,
+ 'takes-type': True,
+ },
+ 'POINTER': {
+ 'signal': 'POINTER',
+ 'ctype': 'gpointer',
+ 'getter': 'g_marshal_value_peek_pointer',
+ },
+ 'OBJECT': {
+ 'signal': 'OBJECT',
+ 'ctype': 'gpointer',
+ 'getter': 'g_marshal_value_peek_object',
+ 'box': ['g_object_ref', 'g_object_unref'],
+ },
+ 'VARIANT': {
+ 'signal': 'VARIANT',
+ 'ctype': 'gpointer',
+ 'getter': 'g_marshal_value_peek_variant',
+ 'box': ['g_variant_ref_sink', 'g_variant_unref'],
+ 'static-check': True,
+ 'takes-type': False,
+ },
+
+ # Deprecated tokens
+ 'NONE': {
+ 'signal': 'VOID',
+ 'ctype': 'void',
+ 'deprecated': True,
+ 'replaced_by': 'VOID'
+ },
+ 'BOOL': {
+ 'signal': 'BOOLEAN',
+ 'ctype': 'gboolean',
+ 'getter': 'g_marshal_value_peek_boolean',
+ 'deprecated': True,
+ 'replaced_by': 'BOOLEAN'
+ }
+}
+
+
+# Marshaller return values, as a dictionary where the key is the token used
+# in the source file, and the value is another dictionary with the following
+# keys:
+#
+# - signal: the token used in the marshaller prototype (mandatory)
+# - ctype: the C type for the marshaller argument (mandatory)
+# - setter: the function used to set the return value of the callback
+# into a GValue (optional)
+# - deprecated: whether the token has been deprecated (optional)
+# - replaced-by: the token used to replace a deprecated token (optional,
+# only used if deprecated is True)
+OUT_ARGS = {
+ 'VOID': {
+ 'signal': 'VOID',
+ 'ctype': 'void',
+ },
+ 'BOOLEAN': {
+ 'signal': 'BOOLEAN',
+ 'ctype': 'gboolean',
+ 'setter': 'g_value_set_boolean',
+ },
+ 'CHAR': {
+ 'signal': 'CHAR',
+ 'ctype': 'gchar',
+ 'setter': 'g_value_set_char',
+ },
+ 'UCHAR': {
+ 'signal': 'UCHAR',
+ 'ctype': 'guchar',
+ 'setter': 'g_value_set_uchar',
+ },
+ 'INT': {
+ 'signal': 'INT',
+ 'ctype': 'gint',
+ 'setter': 'g_value_set_int',
+ },
+ 'UINT': {
+ 'signal': 'UINT',
+ 'ctype': 'guint',
+ 'setter': 'g_value_set_uint',
+ },
+ 'LONG': {
+ 'signal': 'LONG',
+ 'ctype': 'glong',
+ 'setter': 'g_value_set_long',
+ },
+ 'ULONG': {
+ 'signal': 'ULONG',
+ 'ctype': 'gulong',
+ 'setter': 'g_value_set_ulong',
+ },
+ 'INT64': {
+ 'signal': 'INT64',
+ 'ctype': 'gint64',
+ 'setter': 'g_value_set_int64',
+ },
+ 'UINT64': {
+ 'signal': 'UINT64',
+ 'ctype': 'guint64',
+ 'setter': 'g_value_set_uint64',
+ },
+ 'ENUM': {
+ 'signal': 'ENUM',
+ 'ctype': 'gint',
+ 'setter': 'g_value_set_enum',
+ },
+ 'FLAGS': {
+ 'signal': 'FLAGS',
+ 'ctype': 'guint',
+ 'setter': 'g_value_set_flags',
+ },
+ 'FLOAT': {
+ 'signal': 'FLOAT',
+ 'ctype': 'gfloat',
+ 'setter': 'g_value_set_float',
+ },
+ 'DOUBLE': {
+ 'signal': 'DOUBLE',
+ 'ctype': 'gdouble',
+ 'setter': 'g_value_set_double',
+ },
+ 'STRING': {
+ 'signal': 'STRING',
+ 'ctype': 'gchar*',
+ 'setter': 'g_value_take_string',
+ },
+ 'PARAM': {
+ 'signal': 'PARAM',
+ 'ctype': 'GParamSpec*',
+ 'setter': 'g_value_take_param',
+ },
+ 'BOXED': {
+ 'signal': 'BOXED',
+ 'ctype': 'gpointer',
+ 'setter': 'g_value_take_boxed',
+ },
+ 'POINTER': {
+ 'signal': 'POINTER',
+ 'ctype': 'gpointer',
+ 'setter': 'g_value_set_pointer',
+ },
+ 'OBJECT': {
+ 'signal': 'OBJECT',
+ 'ctype': 'GObject*',
+ 'setter': 'g_value_take_object',
+ },
+ 'VARIANT': {
+ 'signal': 'VARIANT',
+ 'ctype': 'GVariant*',
+ 'setter': 'g_value_take_variant',
+ },
+
+ # Deprecated tokens
+ 'NONE': {
+ 'signal': 'VOID',
+ 'ctype': 'void',
+ 'setter': None,
+ 'deprecated': True,
+ 'replaced_by': 'VOID',
+ },
+ 'BOOL': {
+ 'signal': 'BOOLEAN',
+ 'ctype': 'gboolean',
+ 'setter': 'g_value_set_boolean',
+ 'deprecated': True,
+ 'replaced_by': 'BOOLEAN',
+ },
+}
+
+
+def check_args(retval, params, fatal_warnings=False):
+ '''Check the @retval and @params tokens for invalid and deprecated symbols.'''
+ if retval not in OUT_ARGS:
+ print_error('Unknown return value type "{}"'.format(retval))
+
+ if OUT_ARGS[retval].get('deprecated', False):
+ replaced_by = OUT_ARGS[retval]['replaced_by']
+ print_warning(DEPRECATED_MSG_STR.format(retval, replaced_by), fatal_warnings)
+
+ for param in params:
+ if param not in IN_ARGS:
+ print_error('Unknown parameter type "{}"'.format(param))
+ else:
+ if IN_ARGS[param].get('deprecated', False):
+ replaced_by = IN_ARGS[param]['replaced_by']
+ print_warning(DEPRECATED_MSG_STR.format(param, replaced_by), fatal_warnings)
+
+
+def indent(text, level=0, fill=' '):
+ '''Indent @text by @level columns, using the @fill character'''
+ return ''.join([fill for x in range(level)]) + text
+
+
+# pylint: disable=too-few-public-methods
+class Visibility:
+ '''Symbol visibility options'''
+ NONE = 0
+ INTERNAL = 1
+ EXTERN = 2
+
+
+def generate_marshaller_name(prefix, retval, params, replace_deprecated=True):
+ '''Generate a marshaller name for the given @prefix, @retval, and @params.
+ If @replace_deprecated is True, the generated name will replace deprecated
+ tokens.'''
+ if replace_deprecated:
+ real_retval = OUT_ARGS[retval]['signal']
+ real_params = []
+ for param in params:
+ real_params.append(IN_ARGS[param]['signal'])
+ else:
+ real_retval = retval
+ real_params = params
+ return '{prefix}_{retval}__{args}'.format(prefix=prefix,
+ retval=real_retval,
+ args='_'.join(real_params))
+
+
+def generate_prototype(retval, params,
+ prefix='g_cclosure_user_marshal',
+ visibility=Visibility.NONE,
+ va_marshal=False):
+ '''Generate a marshaller declaration with the given @visibility. If @va_marshal
+ is True, the marshaller will use variadic arguments in place of a GValue array.'''
+ signature = []
+
+ if visibility == Visibility.INTERNAL:
+ signature += ['G_GNUC_INTERNAL']
+ elif visibility == Visibility.EXTERN:
+ signature += ['extern']
+
+ function_name = generate_marshaller_name(prefix, retval, params)
+
+ if not va_marshal:
+ signature += ['void ' + function_name + ' (GClosure *closure,']
+ width = len('void ') + len(function_name) + 2
+
+ signature += [indent('GValue *return_value,', level=width, fill=' ')]
+ signature += [indent('guint n_param_values,', level=width, fill=' ')]
+ signature += [indent('const GValue *param_values,', level=width, fill=' ')]
+ signature += [indent('gpointer invocation_hint,', level=width, fill=' ')]
+ signature += [indent('gpointer marshal_data);', level=width, fill=' ')]
+ else:
+ signature += ['void ' + function_name + 'v (GClosure *closure,']
+ width = len('void ') + len(function_name) + 3
+
+ signature += [indent('GValue *return_value,', level=width, fill=' ')]
+ signature += [indent('gpointer instance,', level=width, fill=' ')]
+ signature += [indent('va_list args,', level=width, fill=' ')]
+ signature += [indent('gpointer marshal_data,', level=width, fill=' ')]
+ signature += [indent('int n_params,', level=width, fill=' ')]
+ signature += [indent('GType *param_types);', level=width, fill=' ')]
+
+ return signature
+
+
+# pylint: disable=too-many-statements, too-many-locals, too-many-branches
+def generate_body(retval, params, prefix, va_marshal=False):
+ '''Generate a marshaller definition. If @va_marshal is True, the marshaller
+ will use va_list and variadic arguments in place of a GValue array.'''
+ retval_setter = OUT_ARGS[retval].get('setter', None)
+ # If there's no return value then we can mark the retval argument as unused
+ # and get a minor optimisation, as well as avoid a compiler warning
+ if not retval_setter:
+ unused = ' G_GNUC_UNUSED'
+ else:
+ unused = ''
+
+ body = ['void']
+
+ function_name = generate_marshaller_name(prefix, retval, params)
+
+ if not va_marshal:
+ body += [function_name + ' (GClosure *closure,']
+ width = len(function_name) + 2
+
+ body += [indent('GValue *return_value{},'.format(unused), level=width, fill=' ')]
+ body += [indent('guint n_param_values,', level=width, fill=' ')]
+ body += [indent('const GValue *param_values,', level=width, fill=' ')]
+ body += [indent('gpointer invocation_hint G_GNUC_UNUSED,', level=width, fill=' ')]
+ body += [indent('gpointer marshal_data)', level=width, fill=' ')]
+ else:
+ body += [function_name + 'v (GClosure *closure,']
+ width = len(function_name) + 3
+
+ body += [indent('GValue *return_value{},'.format(unused), level=width, fill=' ')]
+ body += [indent('gpointer instance,', level=width, fill=' ')]
+ body += [indent('va_list args,', level=width, fill=' ')]
+ body += [indent('gpointer marshal_data,', level=width, fill=' ')]
+ body += [indent('int n_params,', level=width, fill=' ')]
+ body += [indent('GType *param_types)', level=width, fill=' ')]
+
+ # Filter the arguments that have a getter
+ get_args = [x for x in params if IN_ARGS[x].get('getter', None) is not None]
+
+ body += ['{']
+
+ # Generate the type of the marshaller function
+ typedef_marshal = generate_marshaller_name('GMarshalFunc', retval, params)
+
+ typedef = ' typedef {ctype} (*{func_name}) ('.format(ctype=OUT_ARGS[retval]['ctype'],
+ func_name=typedef_marshal)
+ pad = len(typedef)
+ typedef += 'gpointer data1,'
+ body += [typedef]
+
+ for idx, in_arg in enumerate(get_args):
+ body += [indent('{} arg{:d},'.format(IN_ARGS[in_arg]['ctype'], idx + 1), level=pad)]
+
+ body += [indent('gpointer data2);', level=pad)]
+
+ # Variable declarations
+ body += [' GCClosure *cc = (GCClosure *) closure;']
+ body += [' gpointer data1, data2;']
+ body += [' {} callback;'.format(typedef_marshal)]
+
+ if retval_setter:
+ body += [' {} v_return;'.format(OUT_ARGS[retval]['ctype'])]
+
+ if va_marshal:
+ for idx, arg in enumerate(get_args):
+ body += [' {} arg{:d};'.format(IN_ARGS[arg]['ctype'], idx)]
+
+ if get_args:
+ body += [' va_list args_copy;']
+ body += ['']
+
+ body += [' va_copy (args_copy, args);']
+
+ for idx, arg in enumerate(get_args):
+ ctype = IN_ARGS[arg]['ctype']
+ promoted_ctype = IN_ARGS[arg].get('promoted', ctype)
+ body += [VA_ARG_STR.format(idx, ctype, promoted_ctype)]
+ if IN_ARGS[arg].get('box', None):
+ box_func = IN_ARGS[arg]['box'][0]
+ if IN_ARGS[arg].get('static-check', False):
+ static_check = STATIC_CHECK_STR.format(idx)
+ else:
+ static_check = ''
+ arg_check = 'arg{:d} != NULL'.format(idx)
+ body += [' if ({}{})'.format(static_check, arg_check)]
+ if IN_ARGS[arg].get('takes-type', False):
+ body += [BOX_TYPED_STR.format(idx=idx, box_func=box_func)]
+ else:
+ body += [BOX_UNTYPED_STR.format(idx=idx, box_func=box_func)]
+
+ body += [' va_end (args_copy);']
+
+ body += ['']
+
+ # Preconditions check
+ if retval_setter:
+ body += [' g_return_if_fail (return_value != NULL);']
+
+ if not va_marshal:
+ body += [' g_return_if_fail (n_param_values == {:d});'.format(len(get_args) + 1)]
+
+ body += ['']
+
+ # Marshal instance, data, and callback set up
+ body += [' if (G_CCLOSURE_SWAP_DATA (closure))']
+ body += [' {']
+ body += [' data1 = closure->data;']
+ if va_marshal:
+ body += [' data2 = instance;']
+ else:
+ body += [' data2 = g_value_peek_pointer (param_values + 0);']
+ body += [' }']
+ body += [' else']
+ body += [' {']
+ if va_marshal:
+ body += [' data1 = instance;']
+ else:
+ body += [' data1 = g_value_peek_pointer (param_values + 0);']
+ body += [' data2 = closure->data;']
+ body += [' }']
+ # pylint: disable=line-too-long
+ body += [' callback = ({}) (marshal_data ? marshal_data : cc->callback);'.format(typedef_marshal)]
+ body += ['']
+
+ # Marshal callback action
+ if retval_setter:
+ callback = ' {} callback ('.format(' v_return =')
+ else:
+ callback = ' callback ('
+
+ pad = len(callback)
+ body += [callback + 'data1,']
+
+ if va_marshal:
+ for idx, arg in enumerate(get_args):
+ body += [indent('arg{:d},'.format(idx), level=pad)]
+ else:
+ for idx, arg in enumerate(get_args):
+ arg_getter = IN_ARGS[arg]['getter']
+ body += [indent('{} (param_values + {:d}),'.format(arg_getter, idx + 1), level=pad)]
+
+ body += [indent('data2);', level=pad)]
+
+ if va_marshal:
+ boxed_args = [x for x in get_args if IN_ARGS[x].get('box', None) is not None]
+ if not boxed_args:
+ body += ['']
+ else:
+ for idx, arg in enumerate(get_args):
+ if not IN_ARGS[arg].get('box', None):
+ continue
+ unbox_func = IN_ARGS[arg]['box'][1]
+ if IN_ARGS[arg].get('static-check', False):
+ static_check = STATIC_CHECK_STR.format(idx)
+ else:
+ static_check = ''
+ arg_check = 'arg{:d} != NULL'.format(idx)
+ body += [' if ({}{})'.format(static_check, arg_check)]
+ if IN_ARGS[arg].get('takes-type', False):
+ body += [UNBOX_TYPED_STR.format(idx=idx, unbox_func=unbox_func)]
+ else:
+ body += [UNBOX_UNTYPED_STR.format(idx=idx, unbox_func=unbox_func)]
+
+ if retval_setter:
+ body += ['']
+ body += [' {} (return_value, v_return);'.format(retval_setter)]
+
+ body += ['}']
+
+ return body
+
+
+def generate_marshaller_alias(outfile, marshaller, real_marshaller,
+ include_va=False,
+ source_location=None):
+ '''Generate an alias between @marshaller and @real_marshaller, including
+ an optional alias for va_list marshallers'''
+ if source_location:
+ outfile.write('/* {} */\n'.format(source_location))
+
+ outfile.write('#define {}\t{}\n'.format(marshaller, real_marshaller))
+
+ if include_va:
+ outfile.write('#define {}v\t{}v\n'.format(marshaller, real_marshaller))
+
+ outfile.write('\n')
+
+
+def generate_marshallers_header(outfile, retval, params,
+ prefix='g_cclosure_user_marshal',
+ internal=False,
+ include_va=False, source_location=None):
+ '''Generate a declaration for a marshaller function, to be used in the header,
+ with the given @retval, @params, and @prefix. An optional va_list marshaller
+ for the same arguments is also generated. The generated buffer is written to
+ the @outfile stream object.'''
+ if source_location:
+ outfile.write('/* {} */\n'.format(source_location))
+
+ if internal:
+ visibility = Visibility.INTERNAL
+ else:
+ visibility = Visibility.EXTERN
+
+ signature = generate_prototype(retval, params, prefix, visibility, False)
+ if include_va:
+ signature += generate_prototype(retval, params, prefix, visibility, True)
+ signature += ['']
+
+ outfile.write('\n'.join(signature))
+ outfile.write('\n')
+
+
+def generate_marshallers_body(outfile, retval, params,
+ prefix='g_cclosure_user_marshal',
+ include_prototype=True,
+ internal=False,
+ include_va=False, source_location=None):
+ '''Generate a definition for a marshaller function, to be used in the source,
+ with the given @retval, @params, and @prefix. An optional va_list marshaller
+ for the same arguments is also generated. The generated buffer is written to
+ the @outfile stream object.'''
+ if source_location:
+ outfile.write('/* {} */\n'.format(source_location))
+
+ if include_prototype:
+ # Declaration visibility
+ if internal:
+ decl_visibility = Visibility.INTERNAL
+ else:
+ decl_visibility = Visibility.EXTERN
+ proto = ['/* Prototype for -Wmissing-prototypes */']
+ # Add C++ guards in case somebody compiles the generated code
+ # with a C++ compiler
+ proto += ['G_BEGIN_DECLS']
+ proto += generate_prototype(retval, params, prefix, decl_visibility, False)
+ proto += ['G_END_DECLS']
+ outfile.write('\n'.join(proto))
+ outfile.write('\n')
+
+ body = generate_body(retval, params, prefix, False)
+ outfile.write('\n'.join(body))
+ outfile.write('\n\n')
+
+ if include_va:
+ if include_prototype:
+ # Declaration visibility
+ if internal:
+ decl_visibility = Visibility.INTERNAL
+ else:
+ decl_visibility = Visibility.EXTERN
+ proto = ['/* Prototype for -Wmissing-prototypes */']
+ # Add C++ guards here as well
+ proto += ['G_BEGIN_DECLS']
+ proto += generate_prototype(retval, params, prefix, decl_visibility, True)
+ proto += ['G_END_DECLS']
+ outfile.write('\n'.join(proto))
+ outfile.write('\n')
+
+ body = generate_body(retval, params, prefix, True)
+ outfile.write('\n'.join(body))
+ outfile.write('\n\n')
+
+
+def parse_args():
+ arg_parser = argparse.ArgumentParser(description='Generate signal marshallers for GObject')
+ arg_parser.add_argument('--prefix', metavar='STRING',
+ default='g_cclosure_user_marshal',
+ help='Specify marshaller prefix')
+ arg_parser.add_argument('--output', metavar='FILE',
+ type=argparse.FileType('w'),
+ default=sys.stdout,
+ help='Write output into the specified file')
+ arg_parser.add_argument('--skip-source',
+ action='store_true',
+ help='Skip source location comments')
+ arg_parser.add_argument('--internal',
+ action='store_true',
+ help='Mark generated functions as internal')
+ arg_parser.add_argument('--valist-marshallers',
+ action='store_true',
+ help='Generate va_list marshallers')
+ arg_parser.add_argument('-v', '--version',
+ action='store_true',
+ dest='show_version',
+ help='Print version information, and exit')
+ arg_parser.add_argument('--g-fatal-warnings',
+ action='store_true',
+ dest='fatal_warnings',
+ help='Make warnings fatal')
+ arg_parser.add_argument('--include-header', metavar='HEADER', nargs='?',
+ action='append',
+ dest='include_headers',
+ help='Include the specified header in the body')
+ arg_parser.add_argument('--pragma-once',
+ action='store_true',
+ help='Use "pragma once" as the inclusion guard')
+ arg_parser.add_argument('-D',
+ action='append',
+ dest='cpp_defines',
+ default=[],
+ help='Pre-processor define')
+ arg_parser.add_argument('-U',
+ action='append',
+ dest='cpp_undefines',
+ default=[],
+ help='Pre-processor undefine')
+ arg_parser.add_argument('files', metavar='FILE', nargs='*',
+ type=argparse.FileType('r'),
+ help='Files with lists of marshallers to generate, ' +
+ 'or "-" for standard input')
+ arg_parser.add_argument('--prototypes',
+ action='store_true',
+ help='Generate the marshallers prototype in the C code')
+ arg_parser.add_argument('--header',
+ action='store_true',
+ help='Generate C headers')
+ arg_parser.add_argument('--body',
+ action='store_true',
+ help='Generate C code')
+
+ group = arg_parser.add_mutually_exclusive_group()
+ group.add_argument('--stdinc',
+ action='store_true',
+ dest='stdinc', default=True,
+ help='Include standard marshallers')
+ group.add_argument('--nostdinc',
+ action='store_false',
+ dest='stdinc', default=True,
+ help='Use standard marshallers')
+
+ group = arg_parser.add_mutually_exclusive_group()
+ group.add_argument('--quiet',
+ action='store_true',
+ help='Only print warnings and errors')
+ group.add_argument('--verbose',
+ action='store_true',
+ help='Be verbose, and include debugging information')
+
+ args = arg_parser.parse_args()
+
+ if args.show_version:
+ print(VERSION_STR)
+ sys.exit(0)
+
+ return args
+
+
+def generate(args):
+ # Backward compatibility hack; some projects use both arguments to
+ # generate the marshallers prototype in the C source, even though
+ # it's not really a supported use case. We keep this behaviour by
+ # forcing the --prototypes and --body arguments instead. We make this
+ # warning non-fatal even with --g-fatal-warnings, as it's a deprecation
+ compatibility_mode = False
+ if args.header and args.body:
+ print_warning('Using --header and --body at the same time is deprecated; ' +
+ 'use --body --prototypes instead', False)
+ args.prototypes = True
+ args.header = False
+ compatibility_mode = True
+
+ if args.header:
+ generate_header_preamble(args.output,
+ prefix=args.prefix,
+ std_includes=args.stdinc,
+ use_pragma=args.pragma_once)
+ elif args.body:
+ generate_body_preamble(args.output,
+ std_includes=args.stdinc,
+ include_headers=args.include_headers,
+ cpp_defines=args.cpp_defines,
+ cpp_undefines=args.cpp_undefines)
+
+ seen_marshallers = set()
+
+ for infile in args.files:
+ if not args.quiet:
+ print_info('Reading {}...'.format(infile.name))
+
+ line_count = 0
+ for line in infile:
+ line_count += 1
+
+ if line == '\n' or line.startswith('#'):
+ continue
+
+ matches = re.match(r'^([A-Z0-9]+)\s?:\s?([A-Z0-9,\s]+)$', line.strip())
+ if not matches or len(matches.groups()) != 2:
+ print_warning('Invalid entry: "{}"'.format(line.strip()), args.fatal_warnings)
+ continue
+
+ if not args.skip_source:
+ location = '{} ({}:{:d})'.format(line.strip(), infile.name, line_count)
+ else:
+ location = None
+
+ retval = matches.group(1).strip()
+ params = [x.strip() for x in matches.group(2).split(',')]
+ check_args(retval, params, args.fatal_warnings)
+
+ raw_marshaller = generate_marshaller_name(args.prefix, retval, params, False)
+ if raw_marshaller in seen_marshallers:
+ if args.verbose:
+ print_info('Skipping repeated marshaller {}'.format(line.strip()))
+ continue
+
+ if args.header:
+ if args.verbose:
+ print_info('Generating declaration for {}'.format(line.strip()))
+ generate_std_alias = False
+ if args.stdinc:
+ std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
+ if std_marshaller in GOBJECT_MARSHALLERS:
+ if args.verbose:
+ print_info('Skipping default marshaller {}'.format(line.strip()))
+ generate_std_alias = True
+
+ marshaller = generate_marshaller_name(args.prefix, retval, params)
+ if generate_std_alias:
+ generate_marshaller_alias(args.output, marshaller, std_marshaller,
+ source_location=location,
+ include_va=args.valist_marshallers)
+ else:
+ generate_marshallers_header(args.output, retval, params,
+ prefix=args.prefix,
+ internal=args.internal,
+ include_va=args.valist_marshallers,
+ source_location=location)
+ # If the marshaller is defined using a deprecated token, we want to maintain
+ # compatibility and generate an alias for the old name pointing to the new
+ # one
+ if marshaller != raw_marshaller:
+ if args.verbose:
+ print_info('Generating alias for deprecated tokens')
+ generate_marshaller_alias(args.output, raw_marshaller, marshaller,
+ include_va=args.valist_marshallers)
+ elif args.body:
+ if args.verbose:
+ print_info('Generating definition for {}'.format(line.strip()))
+ generate_std_alias = False
+ if args.stdinc:
+ std_marshaller = generate_marshaller_name(STD_PREFIX, retval, params)
+ if std_marshaller in GOBJECT_MARSHALLERS:
+ if args.verbose:
+ print_info('Skipping default marshaller {}'.format(line.strip()))
+ generate_std_alias = True
+ marshaller = generate_marshaller_name(args.prefix, retval, params)
+ if generate_std_alias:
+ # We need to generate the alias if we are in compatibility mode
+ if compatibility_mode:
+ generate_marshaller_alias(args.output, marshaller, std_marshaller,
+ source_location=location,
+ include_va=args.valist_marshallers)
+ else:
+ generate_marshallers_body(args.output, retval, params,
+ prefix=args.prefix,
+ internal=args.internal,
+ include_prototype=args.prototypes,
+ include_va=args.valist_marshallers,
+ source_location=location)
+ if compatibility_mode and marshaller != raw_marshaller:
+ if args.verbose:
+ print_info('Generating alias for deprecated tokens')
+ generate_marshaller_alias(args.output, raw_marshaller, marshaller,
+ include_va=args.valist_marshallers)
+
+ seen_marshallers.add(raw_marshaller)
+
+ if args.header:
+ generate_header_postamble(args.output, prefix=args.prefix, use_pragma=args.pragma_once)
+
+
+if __name__ == '__main__':
+ args = parse_args()
+
+ with args.output:
+ generate(args)
diff --git a/os/windows/gobject/glib-mkenums b/os/windows/gobject/glib-mkenums
new file mode 100644
index 000000000..f3214553b
--- /dev/null
+++ b/os/windows/gobject/glib-mkenums
@@ -0,0 +1,810 @@
+#!/usr/bin/env python3
+
+# If the code below looks horrible and unpythonic, do not panic.
+#
+# It is.
+#
+# This is a manual conversion from the original Perl script to
+# Python. Improvements are welcome.
+#
+from __future__ import print_function, unicode_literals
+
+import argparse
+import os
+import re
+import sys
+import tempfile
+import io
+import errno
+import codecs
+import locale
+
+# Non-english locale systems might complain to unrecognized character
+sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8')
+
+VERSION_STR = '''glib-mkenums version 2.79.0
+glib-mkenums comes with ABSOLUTELY NO WARRANTY.
+You may redistribute copies of glib-mkenums under the terms of
+the GNU General Public License which can be found in the
+GLib source package. Sources, examples and contact
+information are available at http://www.gtk.org'''
+
+# pylint: disable=too-few-public-methods
+class Color:
+ '''ANSI Terminal colors'''
+ GREEN = '\033[1;32m'
+ BLUE = '\033[1;34m'
+ YELLOW = '\033[1;33m'
+ RED = '\033[1;31m'
+ END = '\033[0m'
+
+
+def print_color(msg, color=Color.END, prefix='MESSAGE'):
+ '''Print a string with a color prefix'''
+ if os.isatty(sys.stderr.fileno()):
+ real_prefix = '{start}{prefix}{end}'.format(start=color, prefix=prefix, end=Color.END)
+ else:
+ real_prefix = prefix
+ print('{prefix}: {msg}'.format(prefix=real_prefix, msg=msg), file=sys.stderr)
+
+
+def print_error(msg):
+ '''Print an error, and terminate'''
+ print_color(msg, color=Color.RED, prefix='ERROR')
+ sys.exit(1)
+
+
+def print_warning(msg, fatal=False):
+ '''Print a warning, and optionally terminate'''
+ if fatal:
+ color = Color.RED
+ prefix = 'ERROR'
+ else:
+ color = Color.YELLOW
+ prefix = 'WARNING'
+ print_color(msg, color, prefix)
+ if fatal:
+ sys.exit(1)
+
+
+def print_info(msg):
+ '''Print a message'''
+ print_color(msg, color=Color.GREEN, prefix='INFO')
+
+
+def get_rspfile_args(rspfile):
+ '''
+ Response files are useful on Windows where there is a command-line character
+ limit of 8191 because when passing sources as arguments to glib-mkenums this
+ limit can be exceeded in large codebases.
+
+ There is no specification for response files and each tool that supports it
+ generally writes them out in slightly different ways, but some sources are:
+ https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files
+ https://docs.microsoft.com/en-us/windows/desktop/midl/the-response-file-command
+ '''
+ import shlex
+ if not os.path.isfile(rspfile):
+ sys.exit('Response file {!r} does not exist'.format(rspfile))
+ try:
+ with open(rspfile, 'r') as f:
+ cmdline = f.read()
+ except OSError as e:
+ sys.exit('Response file {!r} could not be read: {}'
+ .format(rspfile, e.strerror))
+ return shlex.split(cmdline)
+
+
+def write_output(output):
+ global output_stream
+ print(output, file=output_stream)
+
+
+# Python 2 defaults to ASCII in case stdout is redirected.
+# This should make it match Python 3, which uses the locale encoding.
+if sys.stdout.encoding is None:
+ output_stream = codecs.getwriter(
+ locale.getpreferredencoding())(sys.stdout)
+else:
+ output_stream = sys.stdout
+
+
+# Some source files aren't UTF-8 and the old perl version didn't care.
+# Replace invalid data with a replacement character to keep things working.
+# https://bugzilla.gnome.org/show_bug.cgi?id=785113#c20
+def replace_and_warn(err):
+ # 7 characters of context either side of the offending character
+ print_warning('UnicodeWarning: {} at {} ({})'.format(
+ err.reason, err.start,
+ err.object[err.start - 7:err.end + 7]))
+ return ('?', err.end)
+
+codecs.register_error('replace_and_warn', replace_and_warn)
+
+
+# glib-mkenums.py
+# Information about the current enumeration
+flags = None # Is enumeration a bitmask?
+option_underscore_name = '' # Overridden underscore variant of the enum name
+ # for example to fix the cases we don't get the
+ # mixed-case -> underscorized transform right.
+option_lowercase_name = '' # DEPRECATED. A lower case name to use as part
+ # of the *_get_type() function, instead of the
+ # one that we guess. For instance, when an enum
+ # uses abnormal capitalization and we can not
+ # guess where to put the underscores.
+option_since = '' # User provided version info for the enum.
+seenbitshift = 0 # Have we seen bitshift operators?
+seenprivate = False # Have we seen a private option?
+enum_prefix = None # Prefix for this enumeration
+enumname = '' # Name for this enumeration
+enumshort = '' # $enumname without prefix
+enumname_prefix = '' # prefix of $enumname
+enumindex = 0 # Global enum counter
+firstenum = 1 # Is this the first enumeration per file?
+entries = [] # [ name, val ] for each entry
+c_namespace = {} # C symbols namespace.
+
+output = '' # Filename to write result into
+
+def parse_trigraph(opts):
+ result = {}
+ for opt in re.findall(r'(?:[^\s,"]|"(?:\\.|[^"])*")+', opts):
+ opt = re.sub(r'^\s*', '', opt)
+ opt = re.sub(r'\s*$', '', opt)
+ m = re.search(r'(\w+)(?:=(.+))?', opt)
+ assert m is not None
+ groups = m.groups()
+ key = groups[0]
+ if len(groups) > 1:
+ val = groups[1]
+ else:
+ val = 1
+ result[key] = val.strip('"') if val is not None else None
+ return result
+
+def parse_entries(file, file_name):
+ global entries, enumindex, enumname, seenbitshift, seenprivate, flags
+ looking_for_name = False
+
+ while True:
+ line = file.readline()
+ if not line:
+ break
+
+ line = line.strip()
+
+ # read lines until we have no open comments
+ while re.search(r'/\*([^*]|\*(?!/))*$', line):
+ line += file.readline()
+
+ # strip comments w/o options
+ line = re.sub(r'''/\*(?!<)
+ ([^*]+|\*(?!/))*
+ \*/''', '', line, flags=re.X)
+
+ line = line.rstrip()
+
+ # skip empty lines
+ if len(line.strip()) == 0:
+ continue
+
+ if looking_for_name:
+ m = re.match(r'\s*(\w+)', line)
+ if m:
+ enumname = m.group(1)
+ return True
+
+ # Handle include files
+ m = re.match(r'\#include\s*<([^>]*)>', line)
+ if m:
+ newfilename = os.path.join("..", m.group(1))
+ newfile = io.open(newfilename, encoding="utf-8",
+ errors="replace_and_warn")
+
+ if not parse_entries(newfile, newfilename):
+ return False
+ else:
+ continue
+
+ m = re.match(r'\s*\}\s*(\w+)', line)
+ if m:
+ enumname = m.group(1)
+ enumindex += 1
+ return 1
+
+ m = re.match(r'\s*\}', line)
+ if m:
+ enumindex += 1
+ looking_for_name = True
+ continue
+
+ m = re.match(r'''\s*
+ (\w+)\s* # name
+ (\s+[A-Z]+_(?:AVAILABLE|DEPRECATED)_ENUMERATOR_IN_[0-9_]+(?:_FOR\s*\(\s*\w+\s*\))?\s*)? # availability
+ (?:=( # value
+ \s*\w+\s*\(.*\)\s* # macro with multiple args
+ | # OR
+ (?:[^,/]|/(?!\*))* # anything but a comma or comment
+ ))?,?\s*
+ (?:/\*< # options
+ (([^*]|\*(?!/))*)
+ >\s*\*/)?,?
+ \s*$''', line, flags=re.X)
+ if m:
+ groups = m.groups()
+ name = groups[0]
+ availability = None
+ value = None
+ options = None
+ if len(groups) > 1:
+ availability = groups[1]
+ if len(groups) > 2:
+ value = groups[2]
+ if len(groups) > 3:
+ options = groups[3]
+ if flags is None and value is not None and '<<' in value:
+ seenbitshift = 1
+
+ if options is not None:
+ options = parse_trigraph(options)
+ if 'skip' not in options:
+ entries.append((name, value, seenprivate, options.get('nick')))
+ else:
+ entries.append((name, value, seenprivate))
+ else:
+ m = re.match(r'''\s*
+ /\*< (([^*]|\*(?!/))*) >\s*\*/
+ \s*$''', line, flags=re.X)
+ if m:
+ options = m.groups()[0]
+ if options is not None:
+ options = parse_trigraph(options)
+ if 'private' in options:
+ seenprivate = True
+ continue
+ if 'public' in options:
+ seenprivate = False
+ continue
+ if re.match(r's*\#', line):
+ pass
+ else:
+ print_warning('Failed to parse "{}" in {}'.format(line, file_name))
+ return False
+
+help_epilog = '''Production text substitutions:
+ \u0040EnumName\u0040 PrefixTheXEnum
+ \u0040enum_name\u0040 prefix_the_xenum
+ \u0040ENUMNAME\u0040 PREFIX_THE_XENUM
+ \u0040ENUMSHORT\u0040 THE_XENUM
+ \u0040ENUMPREFIX\u0040 PREFIX
+ \u0040enumsince\u0040 the user-provided since value given
+ \u0040VALUENAME\u0040 PREFIX_THE_XVALUE
+ \u0040valuenick\u0040 the-xvalue
+ \u0040valuenum\u0040 the integer value (limited support, Since: 2.26)
+ \u0040type\u0040 either enum or flags
+ \u0040Type\u0040 either Enum or Flags
+ \u0040TYPE\u0040 either ENUM or FLAGS
+ \u0040filename\u0040 name of current input file
+ \u0040basename\u0040 base name of the current input file (Since: 2.22)
+'''
+
+
+# production variables:
+idprefix = "" # "G", "Gtk", etc
+symprefix = "" # "g", "gtk", etc, if not just lc($idprefix)
+fhead = "" # output file header
+fprod = "" # per input file production
+ftail = "" # output file trailer
+eprod = "" # per enum text (produced prior to value itarations)
+vhead = "" # value header, produced before iterating over enum values
+vprod = "" # value text, produced for each enum value
+vtail = "" # value tail, produced after iterating over enum values
+comment_tmpl = "" # comment template
+
+def read_template_file(file):
+ global idprefix, symprefix, fhead, fprod, ftail, eprod, vhead, vprod, vtail, comment_tmpl
+ tmpl = {'file-header': fhead,
+ 'file-production': fprod,
+ 'file-tail': ftail,
+ 'enumeration-production': eprod,
+ 'value-header': vhead,
+ 'value-production': vprod,
+ 'value-tail': vtail,
+ 'comment': comment_tmpl,
+ }
+ in_ = 'junk'
+
+ ifile = io.open(file, encoding="utf-8", errors="replace_and_warn")
+ for line in ifile:
+ m = re.match(r'\/\*\*\*\s+(BEGIN|END)\s+([\w-]+)\s+\*\*\*\/', line)
+ if m:
+ if in_ == 'junk' and m.group(1) == 'BEGIN' and m.group(2) in tmpl:
+ in_ = m.group(2)
+ continue
+ elif in_ == m.group(2) and m.group(1) == 'END' and m.group(2) in tmpl:
+ in_ = 'junk'
+ continue
+ else:
+ sys.exit("Malformed template file " + file)
+
+ if in_ != 'junk':
+ tmpl[in_] += line
+
+ if in_ != 'junk':
+ sys.exit("Malformed template file " + file)
+
+ fhead = tmpl['file-header']
+ fprod = tmpl['file-production']
+ ftail = tmpl['file-tail']
+ eprod = tmpl['enumeration-production']
+ vhead = tmpl['value-header']
+ vprod = tmpl['value-production']
+ vtail = tmpl['value-tail']
+ comment_tmpl = tmpl['comment']
+
+parser = argparse.ArgumentParser(epilog=help_epilog,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+
+parser.add_argument('--identifier-prefix', default='', dest='idprefix',
+ help='Identifier prefix')
+parser.add_argument('--symbol-prefix', default='', dest='symprefix',
+ help='Symbol prefix')
+parser.add_argument('--fhead', default=[], dest='fhead', action='append',
+ help='Output file header')
+parser.add_argument('--ftail', default=[], dest='ftail', action='append',
+ help='Output file footer')
+parser.add_argument('--fprod', default=[], dest='fprod', action='append',
+ help='Put out TEXT every time a new input file is being processed.')
+parser.add_argument('--eprod', default=[], dest='eprod', action='append',
+ help='Per enum text, produced prior to value iterations')
+parser.add_argument('--vhead', default=[], dest='vhead', action='append',
+ help='Value header, produced before iterating over enum values')
+parser.add_argument('--vprod', default=[], dest='vprod', action='append',
+ help='Value text, produced for each enum value.')
+parser.add_argument('--vtail', default=[], dest='vtail', action='append',
+ help='Value tail, produced after iterating over enum values')
+parser.add_argument('--comments', default='', dest='comment_tmpl',
+ help='Comment structure')
+parser.add_argument('--template', default='', dest='template',
+ help='Template file')
+parser.add_argument('--output', default=None, dest='output')
+parser.add_argument('--version', '-v', default=False, action='store_true', dest='version',
+ help='Print version information')
+parser.add_argument('args', nargs='*',
+ help='One or more input files, or a single argument @rspfile_path '
+ 'pointing to a file that contains the actual arguments')
+
+# Support reading an rspfile of the form @filename which contains the args
+# to be parsed
+if len(sys.argv) == 2 and sys.argv[1].startswith('@'):
+ args = get_rspfile_args(sys.argv[1][1:])
+else:
+ args = sys.argv[1:]
+
+options = parser.parse_args(args)
+
+if options.version:
+ print(VERSION_STR)
+ sys.exit(0)
+
+def unescape_cmdline_args(arg):
+ arg = arg.replace('\\n', '\n')
+ arg = arg.replace('\\r', '\r')
+ return arg.replace('\\t', '\t')
+
+if options.template != '':
+ read_template_file(options.template)
+
+idprefix += options.idprefix
+symprefix += options.symprefix
+
+# This is a hack to maintain some semblance of backward compatibility with
+# the old, Perl-based glib-mkenums. The old tool had an implicit ordering
+# on the arguments and templates; each argument was parsed in order, and
+# all the strings appended. This allowed developers to write:
+#
+# glib-mkenums \
+# --fhead ... \
+# --template a-template-file.c.in \
+# --ftail ...
+#
+# And have the fhead be prepended to the file-head stanza in the template,
+# as well as the ftail be appended to the file-tail stanza in the template.
+# Short of throwing away ArgumentParser and going over sys.argv[] element
+# by element, we can simulate that behaviour by ensuring some ordering in
+# how we build the template strings:
+#
+# - the head stanzas are always prepended to the template
+# - the prod stanzas are always appended to the template
+# - the tail stanzas are always appended to the template
+#
+# Within each instance of the command line argument, we append each value
+# to the array in the order in which it appears on the command line.
+fhead = ''.join([unescape_cmdline_args(x) for x in options.fhead]) + fhead
+vhead = ''.join([unescape_cmdline_args(x) for x in options.vhead]) + vhead
+
+fprod += ''.join([unescape_cmdline_args(x) for x in options.fprod])
+eprod += ''.join([unescape_cmdline_args(x) for x in options.eprod])
+vprod += ''.join([unescape_cmdline_args(x) for x in options.vprod])
+
+ftail = ftail + ''.join([unescape_cmdline_args(x) for x in options.ftail])
+vtail = vtail + ''.join([unescape_cmdline_args(x) for x in options.vtail])
+
+if options.comment_tmpl != '':
+ comment_tmpl = unescape_cmdline_args(options.comment_tmpl)
+elif comment_tmpl == "":
+ # default to C-style comments
+ comment_tmpl = "/* \u0040comment\u0040 */"
+
+output = options.output
+
+if output is not None:
+ (out_dir, out_fn) = os.path.split(options.output)
+ out_suffix = '_' + os.path.splitext(out_fn)[1]
+ if out_dir == '':
+ out_dir = '.'
+ fd, filename = tempfile.mkstemp(dir=out_dir)
+ os.close(fd)
+ tmpfile = io.open(filename, "w", encoding="utf-8")
+ output_stream = tmpfile
+else:
+ tmpfile = None
+
+# put auto-generation comment
+comment = comment_tmpl.replace('\u0040comment\u0040',
+ 'This file is generated by glib-mkenums, do '
+ 'not modify it. This code is licensed under '
+ 'the same license as the containing project. '
+ 'Note that it links to GLib, so must comply '
+ 'with the LGPL linking clauses.')
+write_output("\n" + comment + '\n')
+
+def replace_specials(prod):
+ prod = prod.replace(r'\\a', r'\a')
+ prod = prod.replace(r'\\b', r'\b')
+ prod = prod.replace(r'\\t', r'\t')
+ prod = prod.replace(r'\\n', r'\n')
+ prod = prod.replace(r'\\f', r'\f')
+ prod = prod.replace(r'\\r', r'\r')
+ prod = prod.rstrip()
+ return prod
+
+
+def warn_if_filename_basename_used(section, prod):
+ for substitution in ('\u0040filename\u0040',
+ '\u0040basename\u0040'):
+ if substitution in prod:
+ print_warning('{} used in {} section.'.format(substitution,
+ section))
+
+if len(fhead) > 0:
+ prod = fhead
+ warn_if_filename_basename_used('file-header', prod)
+ prod = replace_specials(prod)
+ write_output(prod)
+
+def process_file(curfilename):
+ global entries, flags, seenbitshift, seenprivate, enum_prefix, c_namespace
+ firstenum = True
+
+ try:
+ curfile = io.open(curfilename, encoding="utf-8",
+ errors="replace_and_warn")
+ except IOError as e:
+ if e.errno == errno.ENOENT:
+ print_warning('No file "{}" found.'.format(curfilename))
+ return
+ raise
+
+ while True:
+ line = curfile.readline()
+ if not line:
+ break
+
+ line = line.strip()
+
+ # read lines until we have no open comments
+ while re.search(r'/\*([^*]|\*(?!/))*$', line):
+ line += curfile.readline()
+
+ # strip comments w/o options
+ line = re.sub(r'''/\*(?!<)
+ ([^*]+|\*(?!/))*
+ \*/''', '', line)
+
+ # ignore forward declarations
+ if re.match(r'\s*typedef\s+enum.*;', line):
+ continue
+
+ m = re.match(r'''\s*typedef\s+enum\s*[_A-Za-z]*[_A-Za-z0-9]*\s*
+ ({)?\s*
+ (?:/\*<
+ (([^*]|\*(?!/))*)
+ >\s*\*/)?
+ \s*({)?''', line, flags=re.X)
+ if m:
+ groups = m.groups()
+ if len(groups) >= 2 and groups[1] is not None:
+ options = parse_trigraph(groups[1])
+ if 'skip' in options:
+ continue
+ enum_prefix = options.get('prefix', None)
+ flags = options.get('flags', None)
+ if 'flags' in options:
+ if flags is None:
+ flags = 1
+ else:
+ flags = int(flags)
+ option_lowercase_name = options.get('lowercase_name', None)
+ option_underscore_name = options.get('underscore_name', None)
+ option_since = options.get('since', None)
+ else:
+ enum_prefix = None
+ flags = None
+ option_lowercase_name = None
+ option_underscore_name = None
+ option_since = None
+
+ if option_lowercase_name is not None:
+ if option_underscore_name is not None:
+ print_warning("lowercase_name overridden with underscore_name")
+ option_lowercase_name = None
+ else:
+ print_warning("lowercase_name is deprecated, use underscore_name")
+
+ # Didn't have trailing '{' look on next lines
+ if groups[0] is None and (len(groups) < 4 or groups[3] is None):
+ while True:
+ line = curfile.readline()
+ if not line:
+ print_error("Syntax error when looking for opening { in enum")
+ if re.match(r'\s*\{', line):
+ break
+
+ seenbitshift = 0
+ seenprivate = False
+ entries = []
+
+ # Now parse the entries
+ parse_entries(curfile, curfilename)
+
+ # figure out if this was a flags or enums enumeration
+ if flags is None:
+ flags = seenbitshift
+
+ # Autogenerate a prefix
+ if enum_prefix is None:
+ for entry in entries:
+ if not entry[2] and (len(entry) < 4 or entry[3] is None):
+ name = entry[0]
+ if enum_prefix is not None:
+ enum_prefix = os.path.commonprefix([name, enum_prefix])
+ else:
+ enum_prefix = name
+ if enum_prefix is None:
+ enum_prefix = ""
+ else:
+ # Trim so that it ends in an underscore
+ enum_prefix = re.sub(r'_[^_]*$', '_', enum_prefix)
+ else:
+ # canonicalize user defined prefixes
+ enum_prefix = enum_prefix.upper()
+ enum_prefix = enum_prefix.replace('-', '_')
+ enum_prefix = re.sub(r'(.*)([^_])$', r'\1\2_', enum_prefix)
+
+ fixed_entries = []
+ for e in entries:
+ name = e[0]
+ num = e[1]
+ private = e[2]
+ if len(e) < 4 or e[3] is None:
+ nick = re.sub(r'^' + enum_prefix, '', name)
+ nick = nick.replace('_', '-').lower()
+ e = (name, num, private, nick)
+ fixed_entries.append(e)
+ entries = fixed_entries
+
+ # Spit out the output
+ if option_underscore_name is not None:
+ enumlong = option_underscore_name.upper()
+ enumsym = option_underscore_name.lower()
+ enumshort = re.sub(r'^[A-Z][A-Z0-9]*_', '', enumlong)
+
+ enumname_prefix = re.sub('_' + enumshort + '$', '', enumlong)
+ elif symprefix == '' and idprefix == '':
+ # enumname is e.g. GMatchType
+ enspace = re.sub(r'^([A-Z][a-z]*).*$', r'\1', enumname)
+
+ enumshort = re.sub(r'^[A-Z][a-z]*', '', enumname)
+ enumshort = re.sub(r'([^A-Z])([A-Z])', r'\1_\2', enumshort)
+ enumshort = re.sub(r'([A-Z][A-Z])([A-Z][0-9a-z])', r'\1_\2', enumshort)
+ enumshort = enumshort.upper()
+
+ enumname_prefix = re.sub(r'^([A-Z][a-z]*).*$', r'\1', enumname).upper()
+
+ enumlong = enspace.upper() + "_" + enumshort
+ enumsym = enspace.lower() + "_" + enumshort.lower()
+
+ if option_lowercase_name is not None:
+ enumsym = option_lowercase_name
+ else:
+ enumshort = enumname
+ if idprefix:
+ enumshort = re.sub(r'^' + idprefix, '', enumshort)
+ else:
+ enumshort = re.sub(r'/^[A-Z][a-z]*', '', enumshort)
+
+ enumshort = re.sub(r'([^A-Z])([A-Z])', r'\1_\2', enumshort)
+ enumshort = re.sub(r'([A-Z][A-Z])([A-Z][0-9a-z])', r'\1_\2', enumshort)
+ enumshort = enumshort.upper()
+
+ if symprefix:
+ enumname_prefix = symprefix.upper()
+ else:
+ enumname_prefix = idprefix.upper()
+
+ enumlong = enumname_prefix + "_" + enumshort
+ enumsym = enumlong.lower()
+
+ if option_since is not None:
+ enumsince = option_since
+ else:
+ enumsince = ""
+
+ if firstenum:
+ firstenum = False
+
+ if len(fprod) > 0:
+ prod = fprod
+ base = os.path.basename(curfilename)
+
+ prod = prod.replace('\u0040filename\u0040', curfilename)
+ prod = prod.replace('\u0040basename\u0040', base)
+ prod = replace_specials(prod)
+
+ write_output(prod)
+
+ if len(eprod) > 0:
+ prod = eprod
+
+ prod = prod.replace('\u0040enum_name\u0040', enumsym)
+ prod = prod.replace('\u0040EnumName\u0040', enumname)
+ prod = prod.replace('\u0040ENUMSHORT\u0040', enumshort)
+ prod = prod.replace('\u0040ENUMNAME\u0040', enumlong)
+ prod = prod.replace('\u0040ENUMPREFIX\u0040', enumname_prefix)
+ prod = prod.replace('\u0040enumsince\u0040', enumsince)
+ if flags:
+ prod = prod.replace('\u0040type\u0040', 'flags')
+ else:
+ prod = prod.replace('\u0040type\u0040', 'enum')
+ if flags:
+ prod = prod.replace('\u0040Type\u0040', 'Flags')
+ else:
+ prod = prod.replace('\u0040Type\u0040', 'Enum')
+ if flags:
+ prod = prod.replace('\u0040TYPE\u0040', 'FLAGS')
+ else:
+ prod = prod.replace('\u0040TYPE\u0040', 'ENUM')
+ prod = replace_specials(prod)
+ write_output(prod)
+
+ if len(vhead) > 0:
+ prod = vhead
+ prod = prod.replace('\u0040enum_name\u0040', enumsym)
+ prod = prod.replace('\u0040EnumName\u0040', enumname)
+ prod = prod.replace('\u0040ENUMSHORT\u0040', enumshort)
+ prod = prod.replace('\u0040ENUMNAME\u0040', enumlong)
+ prod = prod.replace('\u0040ENUMPREFIX\u0040', enumname_prefix)
+ prod = prod.replace('\u0040enumsince\u0040', enumsince)
+ if flags:
+ prod = prod.replace('\u0040type\u0040', 'flags')
+ else:
+ prod = prod.replace('\u0040type\u0040', 'enum')
+ if flags:
+ prod = prod.replace('\u0040Type\u0040', 'Flags')
+ else:
+ prod = prod.replace('\u0040Type\u0040', 'Enum')
+ if flags:
+ prod = prod.replace('\u0040TYPE\u0040', 'FLAGS')
+ else:
+ prod = prod.replace('\u0040TYPE\u0040', 'ENUM')
+ prod = replace_specials(prod)
+ write_output(prod)
+
+ if len(vprod) > 0:
+ prod = vprod
+ next_num = 0
+
+ prod = replace_specials(prod)
+ for name, num, private, nick in entries:
+ tmp_prod = prod
+
+ if '\u0040valuenum\u0040' in prod:
+ # only attempt to eval the value if it is requested
+ # this prevents us from throwing errors otherwise
+ if num is not None:
+ # use sandboxed evaluation as a reasonable
+ # approximation to C constant folding
+ inum = eval(num, {}, c_namespace)
+
+ # make sure it parsed to an integer
+ if not isinstance(inum, int):
+ sys.exit("Unable to parse enum value '%s'" % num)
+ num = inum
+ else:
+ num = next_num
+
+ c_namespace[name] = num
+ tmp_prod = tmp_prod.replace('\u0040valuenum\u0040', str(num))
+ next_num = int(num) + 1
+
+ if private:
+ continue
+
+ tmp_prod = tmp_prod.replace('\u0040VALUENAME\u0040', name)
+ tmp_prod = tmp_prod.replace('\u0040valuenick\u0040', nick)
+ if flags:
+ tmp_prod = tmp_prod.replace('\u0040type\u0040', 'flags')
+ else:
+ tmp_prod = tmp_prod.replace('\u0040type\u0040', 'enum')
+ if flags:
+ tmp_prod = tmp_prod.replace('\u0040Type\u0040', 'Flags')
+ else:
+ tmp_prod = tmp_prod.replace('\u0040Type\u0040', 'Enum')
+ if flags:
+ tmp_prod = tmp_prod.replace('\u0040TYPE\u0040', 'FLAGS')
+ else:
+ tmp_prod = tmp_prod.replace('\u0040TYPE\u0040', 'ENUM')
+ tmp_prod = tmp_prod.rstrip()
+
+ write_output(tmp_prod)
+
+ if len(vtail) > 0:
+ prod = vtail
+ prod = prod.replace('\u0040enum_name\u0040', enumsym)
+ prod = prod.replace('\u0040EnumName\u0040', enumname)
+ prod = prod.replace('\u0040ENUMSHORT\u0040', enumshort)
+ prod = prod.replace('\u0040ENUMNAME\u0040', enumlong)
+ prod = prod.replace('\u0040ENUMPREFIX\u0040', enumname_prefix)
+ prod = prod.replace('\u0040enumsince\u0040', enumsince)
+ if flags:
+ prod = prod.replace('\u0040type\u0040', 'flags')
+ else:
+ prod = prod.replace('\u0040type\u0040', 'enum')
+ if flags:
+ prod = prod.replace('\u0040Type\u0040', 'Flags')
+ else:
+ prod = prod.replace('\u0040Type\u0040', 'Enum')
+ if flags:
+ prod = prod.replace('\u0040TYPE\u0040', 'FLAGS')
+ else:
+ prod = prod.replace('\u0040TYPE\u0040', 'ENUM')
+ prod = replace_specials(prod)
+ write_output(prod)
+
+for fname in sorted(options.args):
+ process_file(fname)
+
+if len(ftail) > 0:
+ prod = ftail
+ warn_if_filename_basename_used('file-tail', prod)
+ prod = replace_specials(prod)
+ write_output(prod)
+
+# put auto-generation comment
+comment = comment_tmpl
+comment = comment.replace('\u0040comment\u0040', 'Generated data ends here')
+write_output("\n" + comment + "\n")
+
+if tmpfile is not None:
+ tmpfilename = tmpfile.name
+ tmpfile.close()
+
+ try:
+ os.unlink(options.output)
+ except OSError as error:
+ if error.errno != errno.ENOENT:
+ raise error
+
+ os.rename(tmpfilename, options.output)