diff options
author | Robert <krzmbrzl@gmail.com> | 2020-09-12 14:23:26 +0300 |
---|---|---|
committer | Robert <krzmbrzl@gmail.com> | 2020-09-12 14:46:55 +0300 |
commit | 59263838a7dcc7c80edde8165b86114d593823bf (patch) | |
tree | a9af5f495a42b38887f2eaa550acccebd5d5e80c /scripts | |
parent | 0a53864d2084a9cd47fe6216914cccb7841b187c (diff) |
MAINT: Replaced mkwrapper.pl by python script
The old perl script was broken and therefore replaced with a more modern
and flexible Python script.
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/generateIceWrapper.py | 203 | ||||
-rwxr-xr-x | scripts/mkwrapper.pl | 142 |
2 files changed, 203 insertions, 142 deletions
diff --git a/scripts/generateIceWrapper.py b/scripts/generateIceWrapper.py new file mode 100755 index 000000000..83a687206 --- /dev/null +++ b/scripts/generateIceWrapper.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 + +# Copyright 2020 The Mumble Developers. All rights reserved. +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file at the root of the +# Mumble source tree or at <https://www.mumble.info/LICENSE>. + + +import argparse +import re +from datetime import datetime +import os + +def comment_remover(text): + def replacer(match): + s = match.group(0) + if s.startswith('/'): + return "" + else: + return s + pattern = re.compile( + r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + re.DOTALL | re.MULTILINE + ) + return re.sub(pattern, replacer, text) + +def fix_lineEnding(text): + # Convert from Windows to Unix + text = text.replace("\r\n", "\n") + # Convert from old Mac to Unix + text = text.replace("\r", "\n") + + return text + +def create_disclaimerComment(): + return "// This file was auto-generated by scripts/generateIceWrapper.py on " + datetime.now().strftime("%Y-%m-%d") + " -- DO NOT EDIT MANUALLY!\n" + +def generateFunction(className, functionName, wrapArgs, callArgs): + function = "void ::Murmur::" + className + "I::" + functionName + "_async(" + (", ".join(wrapArgs)) + ") {\n" + function += "\t// qWarning() << \"" + functionName + "\" << meta->mp.qsIceSecretRead.isNull() << meta->mp.qsIceSecretRead.isEmpty();\n" + function += "#ifndef ACCESS_" + className + "_" + functionName + "_ALL\n" + function += "#\tifdef ACCESS_" + className + "_" + functionName + "_READ\n" + function += "\tif (!meta->mp.qsIceSecretRead.isNull()) {\n" + function += "\t\tbool ok = !meta->mp.qsIceSecretRead.isEmpty();\n" + function += "#\telse\n" + function += "\tif (!meta->mp.qsIceSecretRead.isNull() || !meta->mp.qsIceSecretWrite.isNull()) {\n" + function += "\t\tbool ok = !meta->mp.qsIceSecretWrite.isEmpty();\n" + function += "#\tendif // ACCESS_" + className + "_" + functionName + "_READ\n" + function += "\t\t::Ice::Context::const_iterator i = current.ctx.find(\"secret\");\n" + function += "\t\tok = ok && (i != current.ctx.end());\n" + function += "\t\tif (ok) {\n" + function += "\t\t\tconst QString &secret = u8((*i).second);\n" + function += "#\tifdef ACCESS_" + className + "_" + functionName + "_READ\n" + function += "\t\t\tok = ((secret == meta->mp.qsIceSecretRead) || (secret == meta->mp.qsIceSecretWrite));\n" + function += "#\telse\n" + function += "\t\t\tok = (secret == meta->mp.qsIceSecretWrite);\n" + function += "#\tendif // ACCESS_" + className + "_" + functionName + "_READ\n" + function += "\t\t}\n" + function += "\n" + function += "\t\tif (!ok) {\n" + function += "\t\t\tcb->ice_exception(InvalidSecretException());\n" + function += "\t\t\treturn;\n" + function += "\t\t}\n" + function += "\t}\n" + function += "#endif // ACCESS_" + className + "_" + functionName + "_ALL\n" + function += "\n" + function += "\tExecEvent *ie = new ExecEvent(boost::bind(&impl_" + className + "_" + functionName + ", " + ", ".join(callArgs) + "));\n" + function += "\tQCoreApplication::instance()->postEvent(mi, ie);\n" + function += "}\n" + + return function + + +def main(): + parser = argparse.ArgumentParser(description="Generates the wrapper files needed for the ICE server-interface") + parser.add_argument("-i", "--ice-file", help="Path to the ICE specification file (*.ice)", metavar="PATH") + parser.add_argument("-g", "--generated-ice-header", help="Path to the header file that was generated by ICE", metavar="PATH") + parser.add_argument("-o", "--out-file", help="Path to the file to write the generated output to. If omitted, the content will be written to std::out", metavar="PATH") + parser.add_argument("-q", "--quiet", action="store_true", help="Don't display used file paths") + + args = parser.parse_args() + + scriptPath = os.path.realpath(__file__) + rootDir = os.path.dirname(os.path.dirname(scriptPath)) + + if args.ice_file is None: + # Try to figure out the path to the ice-file (Murmur.ice) + args.ice_file = os.path.join(rootDir, "src", "murmur", "Murmur.ice") + if args.generated_ice_header is None: + # Try to figure out path to the generated header file (in the build dir) + args.generated_ice_header = os.path.join(rootDir, "build", "src", "murmur", "Murmur.h") + + if not args.quiet: + print("Using ICE-file at \"%s\"" % args.ice_file) + print("Using ICE-generated header file at \"%s\"" % args.generated_ice_header) + + + iceSpec = fix_lineEnding(open(args.ice_file, "r").read()) + generatedIceHeader = fix_lineEnding(open(args.generated_ice_header, "r").read()) + + # remove comments from the iceSpec + iceSpec = comment_remover(iceSpec) + # Remove all tabs from iceSpec + iceSpec = iceSpec.replace("\t", "") + # Remove empty lines form iceSpec + iceSpec = iceSpec.replace("\n\n", "\n") + + # Escape all special characters so that iceSpec can be used in a std::string ctor + iceSpec = iceSpec.replace("\"", "\\\"") # quotes + iceSpec = iceSpec.replace("\n", "\\n") # newlines + + wrapperContent = create_disclaimerComment() + + # Include boost-bind as we'll need it later + wrapperContent += "\n#include <boost/bind/bind.hpp>\n\n" + + + className = "" + responseTypes = {} + for currentLine in generatedIceHeader.split("\n"): + currentLine = currentLine.strip() + + if not currentLine: + # Skip empty lines + continue + + # find class name + match = re.match("^class\s+AMD_(.+)\s+:\s+(?:public\svirtual|virtual\s+public)\s+::Ice(?:::AMDCallback|Util::Shared)", currentLine) + if match: + className = "AMD_" + match.group(1) + + match = re.match("virtual\s+void\s+ice_response\\((.*)\\)\s+=\s+0;", currentLine) + if match: + if not className: + raise RuntimeError("Expected a className to be found at this time") + match = re.match("virtual\s+void\s+(.+)_async\(const\s+(.+?)&\s*\w*,(.*)\s+const\s+::Ice::Current&", currentLine) + if match: + functionName = match.group(1) + objectName = match.group(2) + arguments = match.group(3) + + if functionName == "getSlice": + # getSlice is handled separately + continue + + targetClass = "Server" if "AMD_Server" in objectName else "Meta" + + wrapArgs = [] + callArgs = [] + argIndex = 0 + + wrapArgs.append("const %s &cb" % objectName) + callArgs.append("cb") + + if targetClass == "Server": + callArgs.append("QString::fromStdString(current.id.name).toInt()") + else: + callArgs.append("current.adapter") + + for currentArg in arguments.split(","): + if not currentArg: + # skip empty entries + continue + + parts = currentArg.split() + if len(parts) > 1: + lastPart = parts[len(parts) - 1] + + if not ":" in lastPart and not "&" in lastPart: + # Omit the last part as it is only a parameter name. We however want the parameters + # to be named p1, p2, ... which we'll do below + currentArg = " ".join(parts[:len(parts) - 1]) + + if len(currentArg.split()) == 1 and currentArg == "const": + # Failsafe in order for us to not only leave const as the type + # We have to include lastPart after all + currentArg += " " + lastPart + + argIndex += 1 + wrapArgs.append("%s p%d" % (currentArg, argIndex)) + callArgs.append("p%d" % argIndex) + + wrapArgs.append("const ::Ice::Current ¤t") + + wrapperContent += generateFunction(targetClass, functionName, wrapArgs, callArgs) + "\n" + + + wrapperContent += "void ::Murmur::MetaI::getSlice_async(const ::Murmur::AMD_Meta_getSlicePtr &cb, const Ice::Current&) {\n" + wrapperContent += "\tcb->ice_response(std::string(\"" + iceSpec + "\"));\n" + wrapperContent += "}\n" + + + if args.out_file is None: + # Write to std::out + print(wrapperContent) + else: + # Write to file + outFile = open(args.out_file, "w") + outFile.write(wrapperContent) + + + +main() diff --git a/scripts/mkwrapper.pl b/scripts/mkwrapper.pl deleted file mode 100755 index 3cf653f5c..000000000 --- a/scripts/mkwrapper.pl +++ /dev/null @@ -1,142 +0,0 @@ -#! /usr/bin/perl -# -# Copyright 2005-2020 The Mumble Developers. All rights reserved. -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file at the root of the -# Mumble source tree or at <https://www.mumble.info/LICENSE>. - -use warnings; -use strict; - -my $class; -my %return; -open(my $MI, "MurmurIce.cpp"); -my @mi = <$MI>; -close($MI); - -my $ice; -open(my $ICE, "Murmur.ice"); -my @ice=<$ICE>; -close($ICE); -$ice = join("", @ice); - -$ice =~ s/\/\*.+?\*\///gms; -$ice =~ s/^\t+//gm; -$ice =~ s/\n+/\n/gs; -$ice =~ s/^\n+//s; - -$ice =~ s/"/\\"/g; -$ice =~ s/\n/\\n/g; - -open(my $I, ">MurmurIceWrapper.cpp"); -open(my $B, ">BasicImpl.cpp"); - -for my $fh ($I, $B) { - print $fh qq' -// Auto-generated by scripts/mkwrapper.pl . Do not edit manually. - -'; -} - -open(my $MH, "murmur_ice/Murmur.h") or die "Could not open murmur_ice/Murmur.h"; - -sub func($$\@\@\@) { - my ($class, $func, $wrapargs, $callargs, $implargs) = @_; - - - print $I qq' -void ::Murmur::${class}I::${func}_async('. join(", ", @{$wrapargs}).qq') { - // qWarning() << "${func}" << meta->mp.qsIceSecretRead.isNull() << meta->mp.qsIceSecretRead.isEmpty(); -#ifndef ACCESS_${class}_${func}_ALL -#ifdef ACCESS_${class}_${func}_READ - if (! meta->mp.qsIceSecretRead.isNull()) { - bool ok = ! meta->mp.qsIceSecretRead.isEmpty(); -#else - if (! meta->mp.qsIceSecretRead.isNull() || ! meta->mp.qsIceSecretWrite.isNull()) { - bool ok = ! meta->mp.qsIceSecretWrite.isEmpty(); -#endif - ::Ice::Context::const_iterator i = current.ctx.find("secret"); - ok = ok && (i != current.ctx.end()); - if (ok) { - const QString &secret = u8((*i).second); -#ifdef ACCESS_${class}_${func}_READ - ok = ((secret == meta->mp.qsIceSecretRead) || (secret == meta->mp.qsIceSecretWrite)); -#else - ok = (secret == meta->mp.qsIceSecretWrite); -#endif - } - if (! ok) { - cb->ice_exception(InvalidSecretException()); - return; - } - } -#endif - ExecEvent *ie = new ExecEvent(boost::bind(&impl_${class}_$func, ' . join(", ", @${callargs}).qq')); - QCoreApplication::instance()->postEvent(mi, ie); -} -'; - - if( ! grep(/impl_${class}_$func/,@mi)) { - print $B "static void impl_${class}_$func(".join(", ", @${implargs}). ") {}\n"; - } -} - - -while(<$MH>) { - chomp(); - if (/^class AMD_(.+) : virtual public ::Ice(?:::AMDCallback|Util::Shared)/) { - $class = "AMD_".$1; - } - if (/virtual void ice_response\((.*)\) = 0;/) { - $return{$class}=$1; - } - if (/virtual void (.+)_async\(const (.+?)&,(.*) const ::Ice::Current&/) { - my $func=$1; - my $obj=$2; - my $args=$3; - - next if ($func eq "getSlice"); - - my $class="Meta"; - $class = "Server" if ($obj =~ /AMD_Server/); - - my @wrapargs; - my @callargs; - my @implargs; - my $pc=0; - push @wrapargs, "const $obj &cb"; - push @callargs, "cb"; - push @implargs, "const $obj cb"; - if ($class eq "Server") { - push @callargs, "QString::fromStdString(current.id.name).toInt()"; - push @implargs, "int server_id"; - } else { - push @callargs, "current.adapter"; - push @implargs, "const Ice::ObjectAdapterPtr adapter"; - } - foreach my $p (split(/,/,$args)) { - $pc++; - push @wrapargs, "$p p$pc"; - push @callargs, "p$pc"; - push @implargs, "$p p$pc"; - } -# if ($class eq "Server") { - push @wrapargs, "const ::Ice::Current ¤t"; -# } else { -# push @wrapargs, "const ::Ice::Current &"; -# } - - func($class,$func,@wrapargs,@callargs,@implargs); - } -} - -print $I qq' -void ::Murmur::MetaI::getSlice_async(const ::Murmur::AMD_Meta_getSlicePtr& cb, const Ice::Current&) { - cb->ice_response(std::string("$ice")); -} -'; - -close($MH); -close($I); -close($B); - |