PageRenderTime 52ms CodeModel.GetById 17ms app.highlight 30ms RepoModel.GetById 0ms app.codeStats 1ms

/strigi-0.7.7/strigidaemon/bin/daemon/dbus/dbuscpp/makecode.pl

#
Perl | 468 lines | 461 code | 5 blank | 2 comment | 4 complexity | 8705c7df4a21c0c3b5270f0e818c6e09 MD5 | raw file
Possible License(s): LGPL-2.0
  1#! /usr/bin/perl -w
  2use strict;
  3use File::Basename;
  4
  5die "Usage: $0 [interfacename] [headerfile.h]\n"
  6    unless @ARGV == 2 || @ARGV == 3;
  7
  8# global variables
  9my $interfacename = $ARGV[0];
 10my $interfaceheader = $ARGV[1];
 11my $extrainclude;
 12if ($ARGV[2]) {
 13    $extrainclude = $ARGV[2];
 14}
 15
 16die "File $interfaceheader is not readable.\n" unless -r $interfaceheader;
 17
 18my $class;
 19my %functionsIn;
 20my %functionsOut;
 21my %responses;
 22my %signals;
 23my $classname;
 24my $constructorargs = "";
 25
 26open FILE, $interfaceheader or die "Can't open file: $!\n";
 27my @lines = <FILE>;
 28close FILE;
 29
 30my %typemapping = (
 31	"void" => "ignore",
 32	"void*" => "ignore",
 33	"char*" => "ignore",
 34	"std::string" => "s",
 35	"int32_t" => "i",
 36	"uint32_t" => "u",
 37	"bool" => "b",
 38	"std::vector<std::string>" => "as",
 39	"std::set<std::string>" => "as",
 40	"Hits" => "a(sdsssxxa{sas})",
 41	"std::map<std::string, std::string>" => "a{ss}",
 42	"std::vector<char>" => "ay",
 43	"std::multimap<int, std::string>" => "a(is)",
 44	"std::vector<std::pair<bool,std::string> >" => "a(bs)",
 45	"std::vector<std::pair<std::string, uint32_t> >" => "a(su)",
 46	"uint64_t" => "t",
 47	"Strigi::Variant" => "v",
 48	"std::vector<std::vector<Strigi::Variant> >" => "aav",
 49	"std::vector<int32_t>" => "ai",
 50	"std::vector<uint32_t>" => "au"
 51);
 52
 53sub splitArguments {
 54    my $s = shift;
 55    my @args = ();
 56    my $i = 0;
 57    my $b = 0;
 58    while ($i < length($s)) {
 59        my $c = substr($s, $i, 1);
 60        if ($c eq ',' && $b eq 0) {
 61            my $a = substr($s, 0, $i);
 62            push(@args, $a);
 63            $s = substr($s, $i+1);
 64            $i = -1;
 65        } elsif ($c eq '<') {
 66            $b++;
 67        } elsif ($c eq '>') {
 68            $b--;
 69        }
 70        $i++;
 71    }
 72    if (length($s)) {
 73        push(@args, $s);
 74    }
 75    return @args;
 76}
 77sub parseArguments {
 78    my $in = shift;
 79    my @args = splitArguments($in);
 80    my @a;
 81    foreach (@args) {
 82        if (m/^\s*(.*)$/) {
 83            $_ = $1;
 84        }
 85        if (m/^const\s+(.*)$/) {
 86            $_ = $1;
 87        }
 88        my $atype;
 89        my $aname;
 90        if (m/^(.+)\&?\s+\&?(\w+)$/) {
 91            $atype = $1;
 92            $aname = $2;
 93        } else {
 94            die "PARSE ERROR: '$_'";
 95        }
 96        $atype =~ s/\&?\s*\&?$//;
 97        die "Type $atype cannot be mapped." unless $typemapping{$atype};
 98        push(@a, $atype, $aname);
 99    }
100    return @a;
101}
102sub printFunctionDefinition {
103    my $name = shift;
104    print FH "void\n";
105    print FH "Private$classname\::$name(DBusMessage* msg, DBusConnection* conn) {\n";
106    print FH "    DBusMessageWriter writer(conn, msg);\n";
107    print FH "    try {\n";
108    print FH "        DBusMessageReader reader(msg);\n";
109    my $i = $functionsIn{$name};
110    my @a = parseArguments($i);
111    for ($i=1; $i < @a; $i+=2) {
112        print FH "        ".$a[$i-1]." ".$a[$i].";\n";
113    }
114    if (@a) {
115        print FH "        reader";
116        for ($i=1; $i < @a; $i+=2) {
117	    print FH " >> ".$a[$i];
118        }
119        print FH ";\n";
120    }
121    print FH "        if (!reader.isOk()) {\n";
122    print FH "            writer.setError(\"Invalid input.\");\n";
123    print FH "        } else if (!reader.atEnd()) {\n";
124    print FH "            writer.setError(\"Too many arguments.\");\n";
125    print FH "        } else {\n            ";
126    if (length($functionsOut{$name}) > 0 && $functionsOut{$name} ne "void") {
127        print FH "writer << ";
128    }
129    print FH "impl.$name(";
130    for ($i=1; $i < @a; $i+=2) {
131        print FH $a[$i];
132        if ($i < @a-2) {
133            print FH ",";
134        }
135    }
136    print FH ");\n";
137    print FH "        }\n";
138    print FH "    } catch (const std::exception& e) {\n";
139    print FH "        writer.setError(e.what());\n";
140    print FH "    } catch (...) {\n";
141    print FH "        writer.setError(\"\");\n";
142    print FH "    }\n";
143    print FH "}\n";
144}
145sub printASyncFunctionDefinition {
146    my $name = shift;
147    print FH "void\n";
148    print FH "Private$classname\::$name(DBusMessage* dbm, DBusConnection* conn) {\n";
149    print FH "    DBusMessageReader reader(dbm);\n";
150    my $i = $functionsIn{$name};
151    my @a = parseArguments($i);
152    for ($i=3; $i < @a; $i+=2) {
153        print FH "    ".$a[$i-1]." ".$a[$i].";\n";
154    }
155    if (@a) {
156        print FH "    reader";
157        for ($i=3; $i < @a; $i+=2) {
158	    print FH " >> ".$a[$i];
159        }
160        print FH ";\n";
161    }
162    print FH "    if (!reader.isOk()) {\n";
163    print FH "        DBusMessageWriter writer(conn, dbm);\n";
164    print FH "        writer.setError(\"Invalid input.\");\n";
165    print FH "    } else if (!reader.atEnd()) {\n";
166    print FH "        DBusMessageWriter writer(conn, dbm);\n";
167    print FH "        writer.setError(\"Too many arguments.\");\n";
168    print FH "    } else {\n";
169    print FH "        dbus_message_ref(dbm);\n";
170    print FH "        try {\n            ";
171    print FH "impl.$name(dbm, ";
172    for ($i=3; $i < @a; $i+=2) {
173        print FH $a[$i];
174        if ($i < @a-2) {
175            print FH ",";
176        }
177    }
178    print FH ");\n        } catch (const std::exception& e) {\n";
179    print FH "            DBusMessageWriter writer(conn, dbm);\n";
180    print FH "            writer.setError(e.what());\n";
181    print FH "            dbus_message_unref(dbm);\n";
182    print FH "        }\n";
183    print FH "    }\n";
184    print FH "}\n";
185}
186sub printIntrospectionXML {
187    my $name = shift;
188    my $i = $functionsIn{$name};
189    my @a = parseArguments($i);
190    print FH "    << \"    <method name='$name'>\\n\"\n";
191    for ($i=1; $i < @a; $i+=2) {
192        my $type = $a[$i-1];
193        $type =~ s/^\s*const\s*//;
194        $type = $typemapping{$a[$i-1]};
195        print FH "    << \"      <arg name='$a[$i]' type='$type' direction='in'/>\\n\"\n";
196    }
197    my $type = $functionsOut{$name};
198    $type =~ s/^\s*const\s*//;
199    if (length($type) > 0 && $type ne "void") {
200        my $outname = "out";
201        # try to find the name of the output variable
202        if ($type =~ m#\s*/\*\s*(\S+)\s*\*/\s*#) {
203            $outname = $1;
204            $type =~ s#\s*/\*\s*\S+\s*\*/\s*##g;
205        }
206        $type = $typemapping{$type};
207        print FH"    << \"      <arg name='$outname' type='$type' direction='out'/>\\n\"\n";
208    }
209    print FH "    << \"    </method>\\n\"\n";
210}
211sub printASyncIntrospectionXML {
212    my $name = shift;
213    my $i = $functionsIn{$name};
214    my @a = parseArguments($i);
215    print FH "    << \"    <method name='$name'>\\n\"\n";
216    for ($i=3; $i < @a; $i+=2) {
217        my $type = $typemapping{$a[$i-1]};
218        print FH "    << \"      <arg name='$a[$i]' type='$type' direction='in'/>\\n\"\n";
219    }
220    $i = $responses{$name."Response"};
221    @a = parseArguments($i);
222    die "Not enough arguments for ${name}Response." unless @a > 3;
223    for ($i=5; $i < @a; $i+=2) {
224        my $type = $typemapping{$a[$i-1]};
225        print FH "    << \"      <arg name='$a[$i]' type='$type' direction='out'/>\\n\"\n";
226    }
227    print FH "    << \"    </method>\\n\"\n";
228}
229sub printSignalIntrospectionXML {
230    my $name = shift;
231    my $i = $signals{$name};
232    my @a = parseArguments($i);
233    print FH "    << \"    <signal name='$name'>\\n\"\n";
234    for ($i=1; $i < @a; $i+=2) {
235        my $type = $typemapping{$a[$i-1]};
236        print FH "    << \"      <arg name='$a[$i]' type='$type'/>\\n\"\n";
237    }
238    print FH "    << \"    </signal>\\n\"\n";
239}
240
241# find the classname
242foreach (@lines) {
243    if (m/^class\s+(\w+)/) {
244        $class = $1;
245    }
246}
247die "No class found." unless defined $class;
248
249# parse the functions from the header file
250my @codelines;
251my $line = "";
252foreach (@lines) {
253    chomp;
254    s/\/\/.*//; # remove inline comments
255    $line .= " $_";
256    if ($line =~ m/[;}{]/) {
257        push @codelines, $line;
258        $line = "";
259    }
260}
261foreach (@codelines) {
262    # match function line
263    if (m/^\s*             # leading whitespace
264            (virtual\s+)?  # 1: optional 'virtual' keyword
265            (\S?.*)\s+       # 2: output argument
266            ~?(\w+)        # 3: function name
267            \(\s*(.*)\s*\) # 4: function arguments
268            (\s*=\s*0)?    # 5: pure virtual syntax
269            /x) {
270        my $out = $2;
271        my $name = $3;
272        my $in = $4;
273        my $null = $5;
274        # skip constructor, destructor and static functions
275        if ($name eq $class) {
276            if (defined $in) {
277                $in =~ s/^\s*//;   # remove leading space
278                $in =~ s/\s*$//;   # remove trailing space
279                $in =~ s/\).*//;   # remove chars after ')'
280                $in =~ s/=[^,]*//; # remove default arguments
281                if (length($in)) {
282                    $constructorargs = $in;
283                    #print "constructor $name '$in'\n";
284                }
285            }
286            next;
287        } elsif ($out =~ m/static/) {
288            next;
289        }
290        if ($out eq "void" && defined $null) {
291            if ($name =~ m/Response$/) {
292                # response
293                $responses{$name} = $in;
294            } else {
295                # signal
296                $signals{$name} = $in;
297            }
298        } else {
299            $functionsIn{$name} = $in;
300            $functionsOut{$name} = $out;
301            die "Function $name in $interfaceheader cannot be abstract."
302                unless !defined $5;
303        }
304    }
305}
306# check that all responses match
307foreach my $response (keys %responses) {
308    my $function = $response;
309    $function =~ s/Response$//;
310    my $out = $functionsOut{$function};
311    die "Function $function is not ok." unless $out eq "void";
312}
313# print the inherited class
314$classname = "DBus$class";
315my $headerfile = lc($classname).".h";
316my $cppfile = lc($classname).".cpp";
317my $relativeinterfaceheader = $interfaceheader;
318$relativeinterfaceheader =~ s#.*/src/daemon/##;
319
320open (FH, "> $headerfile") or die;
321print FH "// generated by makecode.pl\n";
322print FH "#ifndef ".uc($classname)."_H\n";
323print FH "#define ".uc($classname)."_H\n";
324print FH "#include \"$relativeinterfaceheader\"\n";
325print FH "#define DBUS_API_SUBJECT_TO_CHANGE 1\n";
326print FH "#include <dbus/dbus.h>\n";
327print FH "#include <exception>\n";
328print FH "#ifdef  __APPLE__ \n";
329print FH "#define uint64_t dbus_uint64_t\n";
330print FH "#endif\n";
331print FH "class DBusObjectInterface;\n";
332print FH "class $classname : public $class {\n";
333print FH "private:\n";
334print FH "    std::string object;\n";
335print FH "    DBusConnection* const conn;\n";
336print FH "    DBusObjectInterface* const iface;\n";
337foreach (keys %responses) {
338    print FH "    void $_(".$responses{$_}.");\n";
339}
340foreach (keys %signals) {
341    print FH "    void $_(".$signals{$_}.");\n";
342}
343print FH "public:\n";
344print FH "    $classname(const std::string& objectname, DBusConnection* c";
345if (length($constructorargs)) {
346    print FH ", $constructorargs";
347}
348print FH ");\n";
349print FH "    ~$classname();\n";
350print FH "    DBusObjectInterface* interface() { return iface; }\n";
351print FH "};\n";
352print FH "#endif\n";
353close(FH);
354
355open (FH, "> $cppfile") or die;
356print FH "// generated by makecode.pl\n";
357print FH "#include \"$headerfile\"\n";
358if (defined $extrainclude && length($extrainclude)) {
359    print FH "#include \"$extrainclude\"\n";
360}
361print FH "#include \"dbus/dbuscpp/dbusobjectinterface.h\"\n";
362print FH "#include \"dbus/dbuscpp/dbusmessagereader.h\"\n";
363print FH "#include \"dbus/dbuscpp/dbusmessagewriter.h\"\n";
364print FH "#include <sstream>\n";
365print FH "class Private$classname : public DBusObjectInterface {\n";
366print FH "private:\n";
367print FH "    $classname& impl;\n";
368print FH "    typedef void (Private$classname\::*handlerFunction)\n";
369print FH "        (DBusMessage* msg, DBusConnection* conn);\n";
370print FH "    std::map<std::string, handlerFunction> handlers;\n";
371print FH "    DBusHandlerResult handleCall(DBusConnection*c,DBusMessage* m);\n";
372print FH "    std::string getIntrospectionXML();\n";
373foreach (keys %functionsIn) {
374    print FH "    void $_(DBusMessage* msg, DBusConnection* conn);\n";
375}
376print FH "public:\n";
377print FH "    Private$classname($classname& i);\n";
378print FH "};\n";
379print FH "Private$classname\::Private$classname($classname& i)\n";
380print FH "        :DBusObjectInterface(\"$interfacename\"), impl(i) {\n";
381foreach (keys %functionsIn) {
382    print FH "    handlers[\"$_\"] = &Private$classname\::".$_.";\n";
383}
384print FH "}\n";
385print FH "DBusHandlerResult\n";
386print FH "Private$classname\::handleCall(DBusConnection*connection, DBusMessage* msg) {\n";
387print FH <<THEEND;
388    std::map<std::string, handlerFunction>::const_iterator h;
389    const char* i = getInterfaceName().c_str();
390    for (h = handlers.begin(); h != handlers.end(); ++h) {
391        if (dbus_message_is_method_call(msg, i, h->first.c_str())) {
392            (this->*h->second)(msg, connection);
393            return DBUS_HANDLER_RESULT_HANDLED;
394        }
395    }
396    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
397}
398THEEND
399print FH "std::string\n";
400print FH "Private$classname\::getIntrospectionXML() {\n";
401print FH "    std::ostringstream xml;\n";
402print FH "    xml << \"  <interface name='\"+getInterfaceName()+\"'>\\n\"\n";
403foreach (keys %functionsIn) {
404    if (defined $responses{$_."Response"}) {
405        printASyncIntrospectionXML($_);
406    } else {
407        printIntrospectionXML($_);
408    }
409}
410foreach (keys %signals) {
411    printSignalIntrospectionXML($_);
412}
413print FH "    << \"  </interface>\\n\";\n";
414print FH "    return xml.str();\n";
415print FH "}\n";
416foreach (keys %functionsIn) {
417    if (defined $responses{$_."Response"}) {
418        printASyncFunctionDefinition($_);
419    } else {
420        printFunctionDefinition($_);
421    }
422}
423print FH "$classname\::$classname(const std::string& on, DBusConnection* c";
424if (length($constructorargs)) {
425    print FH ", $constructorargs) \n";
426    print FH "        :$class(";
427    my @args = splitArguments($constructorargs);
428    for (my $i=0; $i<@args; ++$i) {
429        if ($i != 0) { print FH ","; }
430        my $arg = $args[$i];
431        $arg =~ s/.*\W(\w+)\s*$/$1/;
432        print FH $arg;
433    }
434    print FH "), ";
435} else {
436    print FH ")\n        :";
437}
438print FH "object(on), conn(c), iface(new Private$classname(*this)) {}\n";
439print FH "$classname\::~$classname() {\n";
440print FH "    delete iface;\n";
441print FH "}\n";
442foreach (keys %responses) {
443    print FH "void\n";
444    print FH "$classname\::$_(".$responses{$_}.") {\n";
445    print FH "    DBusMessage* m = static_cast<DBusMessage*>(msg);\n";
446    print FH "    DBusMessageWriter writer(conn, m);\n";
447    print FH "    writer";
448    my @args = parseArguments($responses{$_});
449    for (my $i=5; $i <= $#args; $i += 2) {
450        print FH " << ".$args[$i];
451    }
452    print FH ";\n";
453    print FH "    dbus_message_unref(m);\n";
454    print FH "}\n";
455}
456foreach (keys %signals) {
457    print FH "void\n";
458    print FH "$classname\::$_(".$signals{$_}.") {\n";
459    print FH "    DBusMessageWriter writer(conn, object.c_str(), \"$interfacename\", \"$_\");\n";
460    print FH "    writer";
461    my @args = parseArguments($signals{$_});
462    for (my $i=1; $i <= $#args; $i += 2) {
463        print FH " << ".$args[$i];
464    }
465    print FH ";\n";
466    print FH "}\n";
467}
468close (FH);