drv_proxy_gen.pl 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!/usr/bin/perl
  2. #
  3. # mbsync - mailbox synchronizer
  4. # Copyright (C) 2017 Oswald Buddenhagen <ossi@users.sf.net>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. # As a special exception, mbsync may be linked with the OpenSSL library,
  20. # despite that library's more restrictive license.
  21. #
  22. use strict;
  23. use warnings;
  24. die("Usage: $0 driver.h drv_proxy.c drv_proxy.inc\n")
  25. if ($#ARGV != 2);
  26. my ($in_header, $in_source, $out_source) = @ARGV;
  27. my %templates;
  28. my %defines;
  29. my %excluded;
  30. my %special;
  31. open(my $ins, $in_source) or die("Cannot open $in_source: $!\n");
  32. my $template;
  33. my $define;
  34. my $conts;
  35. while (<$ins>) {
  36. if ($template) {
  37. if (/^\/\/\# END$/) {
  38. $templates{$template} = $conts;
  39. $template = undef;
  40. } else {
  41. $conts .= $_;
  42. }
  43. } elsif ($define) {
  44. if (/^\/\/\# END$/) {
  45. $defines{$define} = $conts;
  46. $define = undef;
  47. } else {
  48. ($_ eq "\n") or s/^\t// or die("DEFINE content is not indented: $_");
  49. $conts .= $_;
  50. }
  51. } else {
  52. if (/^\/\/\# TEMPLATE (\w+)$/) {
  53. $template = $1;
  54. $conts = "";
  55. } elsif (/^\/\/\# DEFINE (\w+)$/) {
  56. $define = $1;
  57. $conts = "";
  58. } elsif (/^\/\/\# DEFINE (\w+) (.*)$/) {
  59. $defines{$1} = $2;
  60. } elsif (/^\/\/\# UNDEFINE (\w+)$/) {
  61. $defines{$1} = "";
  62. } elsif (/^\/\/\# EXCLUDE (\w+)$/) {
  63. $excluded{$1} = 1;
  64. } elsif (/^\/\/\# SPECIAL (\w+)$/) {
  65. $special{$1} = 1;
  66. }
  67. }
  68. }
  69. close($ins);
  70. open(my $inh, $in_header) or die("Cannot open $in_header: $!\n");
  71. my $sts = 0;
  72. my $cont = "";
  73. while (<$inh>) {
  74. if ($sts == 0) {
  75. if (/^struct driver \{$/) {
  76. $sts = 1;
  77. }
  78. } elsif ($sts == 1) {
  79. if (/^\};$/) {
  80. $sts = 0;
  81. } else {
  82. $cont .= $_;
  83. }
  84. }
  85. }
  86. close($inh);
  87. $cont =~ s,\n, ,g;
  88. $cont =~ s,/\*.*?\*/, ,g;
  89. $cont =~ s,\h+, ,g;
  90. my @ptypes = map { s,^ ,,r } split(/;/, $cont);
  91. pop @ptypes; # last one is empty
  92. my @cmd_table;
  93. sub make_args($)
  94. {
  95. $_ = shift;
  96. s/(?:^|(?<=, ))(?:const )?\w+ \*?//g;
  97. return $_;
  98. }
  99. sub type_to_format($)
  100. {
  101. $_ = shift;
  102. s/xint /\%\#x/g;
  103. s/uint /\%u/g;
  104. s/int /\%d/g;
  105. s/const char \*/\%s/g;
  106. return $_;
  107. }
  108. sub make_format($)
  109. {
  110. $_ = type_to_format(shift);
  111. s/, (\%\#?.)(\w+)/, $2=$1/g;
  112. return $_;
  113. }
  114. sub indent($$)
  115. {
  116. my ($str, $indent) = @_;
  117. return $str =~ s,^(?=.),$indent,smgr;
  118. }
  119. open(my $outh, ">".$out_source) or die("Cannot create $out_source: $!\n");
  120. for (@ptypes) {
  121. /^([\w* ]+)\(\*(\w+)\)\( (.*) \)$/ or die("Cannot parse prototype '$_'\n");
  122. my ($cmd_type, $cmd_name, $cmd_args) = ($1, $2, $3);
  123. if (defined($excluded{$cmd_name})) {
  124. push @cmd_table, "NULL";
  125. next;
  126. }
  127. push @cmd_table, "proxy_$cmd_name";
  128. next if (defined($special{$cmd_name}));
  129. my %replace;
  130. $replace{'name'} = $cmd_name;
  131. $replace{'type'} = $cmd_type;
  132. $cmd_args =~ s/^store_t \*ctx// or die("Arguments '$cmd_args' don't start with 'store_t *ctx'\n");
  133. if ($cmd_name =~ /^get_/) {
  134. $template = "GETTER";
  135. $replace{'fmt'} = type_to_format($cmd_type);
  136. } else {
  137. if ($cmd_type eq "void " && $cmd_args =~ s/, void \(\*cb\)\( (.*)void \*aux \), void \*aux$//) {
  138. my $cmd_cb_args = $1;
  139. if (length($cmd_cb_args)) {
  140. $replace{'decl_cb_args'} = $cmd_cb_args;
  141. my $r_cmd_cb_args = $cmd_cb_args;
  142. $r_cmd_cb_args =~ s/^int sts, // or die("Callback arguments of $cmd_name don't start with sts.\n");
  143. $replace{'decl_cb_state'} = $r_cmd_cb_args =~ s/, /\;\n/gr;
  144. my $pass_cb_args = make_args($cmd_cb_args);
  145. $replace{'save_cb_args'} = $pass_cb_args =~ s/([^,]+), /cmd->$1 = $1\;\n/gr;
  146. $pass_cb_args =~ s/([^, ]+)/cmd->$1/g;
  147. $replace{'pass_cb_args'} = $pass_cb_args;
  148. $replace{'print_pass_cb_args'} = $pass_cb_args =~ s/(.*), $/, $1/r;
  149. $replace{'print_fmt_cb_args'} = make_format($cmd_cb_args =~ s/(.*), $/, $1/r);
  150. $replace{'gen_cmd_t'} = "gen_sts_cmd_t";
  151. $replace{'GEN_CMD'} = "GEN_STS_CMD\n";
  152. $replace{'gen_cmd'} = "&cmd->gen.gen";
  153. } else {
  154. $replace{'gen_cmd_t'} = "gen_cmd_t";
  155. $replace{'GEN_CMD'} = "GEN_CMD\n";
  156. $replace{'gen_cmd'} = "&cmd->gen";
  157. }
  158. $replace{'checked'} //= '0';
  159. $template = "CALLBACK";
  160. } elsif ($cmd_type eq "void ") {
  161. $template = "REGULAR_VOID";
  162. } else {
  163. $template = "REGULAR";
  164. $replace{'fmt'} = type_to_format($cmd_type);
  165. }
  166. $replace{'decl_args'} = $cmd_args;
  167. $replace{'print_pass_args'} = $replace{'pass_args'} = make_args($cmd_args);
  168. $replace{'print_fmt_args'} = make_format($cmd_args);
  169. }
  170. for (keys %defines) {
  171. $replace{$1} = delete $defines{$_} if (/^${cmd_name}_(.*)$/);
  172. }
  173. my %used;
  174. my $text = $templates{$template};
  175. $text =~ s/^(\h*)\@(\w+)\@\n/$used{$2} = 1; indent($replace{$2} \/\/ "", $1)/smeg;
  176. $text =~ s/\@(\w+)\@/$used{$1} = 1; $replace{$1} \/\/ ""/eg;
  177. print $outh $text."\n";
  178. my @not_used = grep { !defined($used{$_}) } keys %replace;
  179. die("Fatal: unconsumed replacements in $cmd_name: ".join(" ", @not_used)."\n") if (@not_used);
  180. }
  181. die("Fatal: unconsumed DEFINEs: ".join(" ", keys %defines)."\n") if (%defines);
  182. print $outh "struct driver proxy_driver = {\n".join("", map { "\t$_,\n" } @cmd_table)."};\n";
  183. close $outh;