/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);