PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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