options.pm 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. #
  2. # Copyright 1999, 2000, 2001 Patrik Stridvall
  3. #
  4. # This library is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU Lesser General Public
  6. # License as published by the Free Software Foundation; either
  7. # version 2.1 of the License, or (at your option) any later version.
  8. #
  9. # This library is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. # Lesser General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Lesser General Public
  15. # License along with this library; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. #
  18. package options;
  19. use strict;
  20. use warnings 'all';
  21. use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  22. require Exporter;
  23. @ISA = qw(Exporter);
  24. @EXPORT = qw();
  25. @EXPORT_OK = qw($options parse_comma_list parse_value);
  26. use vars qw($options);
  27. use output qw($output);
  28. sub parse_comma_list($$) {
  29. my $prefix = shift;
  30. my $value = shift;
  31. if(defined($prefix) && $prefix eq "no") {
  32. return { active => 0, filter => 0, hash => {} };
  33. } elsif(defined($value)) {
  34. my %names;
  35. for my $name (split /,/, $value) {
  36. $names{$name} = 1;
  37. }
  38. return { active => 1, filter => 1, hash => \%names };
  39. } else {
  40. return { active => 1, filter => 0, hash => {} };
  41. }
  42. }
  43. sub parse_value($$) {
  44. my $prefix = shift;
  45. my $value = shift;
  46. return $value;
  47. }
  48. package _options;
  49. use strict;
  50. use warnings 'all';
  51. use output qw($output);
  52. sub options_set($$);
  53. sub new($$$$) {
  54. my $proto = shift;
  55. my $class = ref($proto) || $proto;
  56. my $self = {};
  57. bless ($self, $class);
  58. my $options_long = \%{$self->{_OPTIONS_LONG}};
  59. my $options_short = \%{$self->{_OPTIONS_SHORT}};
  60. my $options_usage = \${$self->{_OPTIONS_USAGE}};
  61. my $refoptions_long = shift;
  62. my $refoptions_short = shift;
  63. $$options_usage = shift;
  64. %$options_long = %{$refoptions_long};
  65. %$options_short = %{$refoptions_short};
  66. $self->options_set("default");
  67. my $arguments = \@{$self->{_ARGUMENTS}};
  68. @$arguments = ();
  69. my $end_of_options = 0;
  70. while(defined($_ = shift @ARGV)) {
  71. if(/^--$/) {
  72. $end_of_options = 1;
  73. next;
  74. } elsif($end_of_options) {
  75. # Nothing
  76. } elsif(/^--(all|none)$/) {
  77. $self->options_set("$1");
  78. next;
  79. } elsif(/^-([^=]*)(=(.*))?$/) {
  80. my $name;
  81. my $value;
  82. if(defined($2)) {
  83. $name = $1;
  84. $value = $3;
  85. } else {
  86. $name = $1;
  87. }
  88. if($name =~ /^([^-].*)$/) {
  89. $name = $$options_short{$1};
  90. } else {
  91. $name =~ s/^-(.*)$/$1/;
  92. }
  93. my $prefix;
  94. if(defined($name) && $name =~ /^no-(.*)$/) {
  95. $name = $1;
  96. $prefix = "no";
  97. if(defined($value)) {
  98. $output->write("options with prefix 'no' can't take parameters\n");
  99. return undef;
  100. }
  101. }
  102. my $option;
  103. if(defined($name)) {
  104. $option = $$options_long{$name};
  105. }
  106. if(defined($option)) {
  107. my $key = $$option{key};
  108. my $parser = $$option{parser};
  109. my $refvalue = \${$self->{$key}};
  110. my @parents = ();
  111. if(defined($$option{parent})) {
  112. if(ref($$option{parent}) eq "ARRAY") {
  113. @parents = @{$$option{parent}};
  114. } else {
  115. @parents = $$option{parent};
  116. }
  117. }
  118. if(defined($parser)) {
  119. if(!defined($value)) {
  120. $value = shift @ARGV;
  121. }
  122. $$refvalue = &$parser($prefix,$value);
  123. } else {
  124. if(defined($value)) {
  125. $$refvalue = $value;
  126. } elsif(!defined($prefix)) {
  127. $$refvalue = 1;
  128. } else {
  129. $$refvalue = 0;
  130. }
  131. }
  132. if((ref($$refvalue) eq "HASH" && $$refvalue->{active}) || $$refvalue) {
  133. while($#parents >= 0) {
  134. my @old_parents = @parents;
  135. @parents = ();
  136. foreach my $parent (@old_parents) {
  137. my $parentkey = $$options_long{$parent}{key};
  138. my $refparentvalue = \${$self->{$parentkey}};
  139. $$refparentvalue = 1;
  140. if(defined($$options_long{$parent}{parent})) {
  141. if(ref($$options_long{$parent}{parent}) eq "ARRAY") {
  142. push @parents, @{$$options_long{$parent}{parent}};
  143. } else {
  144. push @parents, $$options_long{$parent}{parent};
  145. }
  146. }
  147. }
  148. }
  149. }
  150. next;
  151. }
  152. }
  153. if(!$end_of_options && /^-(.*)$/) {
  154. $output->write("unknown option: $_\n");
  155. $output->write($$options_usage);
  156. exit 1;
  157. } else {
  158. push @$arguments, $_;
  159. }
  160. }
  161. if($self->help) {
  162. $output->write($$options_usage);
  163. $self->show_help;
  164. exit 0;
  165. }
  166. return $self;
  167. }
  168. sub DESTROY {
  169. }
  170. sub parse_files($) {
  171. my $self = shift;
  172. my $arguments = \@{$self->{_ARGUMENTS}};
  173. my $directories = \@{$self->{_DIRECTORIES}};
  174. my $c_files = \@{$self->{_C_FILES}};
  175. my $h_files = \@{$self->{_H_FILES}};
  176. my $error = 0;
  177. my @files = ();
  178. foreach (@$arguments) {
  179. if(!-e $_) {
  180. $output->write("$_: no such file or directory\n");
  181. $error = 1;
  182. } else {
  183. push @files, $_;
  184. }
  185. }
  186. if($error) {
  187. exit 1;
  188. }
  189. my @paths = ();
  190. my @c_files = ();
  191. my @h_files = ();
  192. foreach my $file (@files) {
  193. if($file =~ /\.c$/) {
  194. push @c_files, $file;
  195. } elsif($file =~ /\.h$/) {
  196. push @h_files, $file;
  197. } else {
  198. push @paths, $file;
  199. }
  200. }
  201. if($#c_files == -1 && $#h_files == -1 && $#paths == -1 && -d ".git")
  202. {
  203. @$c_files = sort split /\0/, `git ls-files -z \\*.c`;
  204. @$h_files = sort split /\0/, `git ls-files -z \\*.h`;
  205. }
  206. else
  207. {
  208. if($#c_files == -1 && $#h_files == -1 && $#paths == -1)
  209. {
  210. @paths = ".";
  211. }
  212. if($#paths != -1 || $#c_files != -1) {
  213. my $c_command = "find " . join(" ", @paths, @c_files) . " -name \\*.c";
  214. my %found;
  215. @$c_files = sort(map {
  216. s/^\.\/(.*)$/$1/;
  217. if(defined($found{$_})) {
  218. ();
  219. } else {
  220. $found{$_}++;
  221. $_;
  222. }
  223. } split(/\n/, `$c_command`));
  224. }
  225. if($#paths != -1 || $#h_files != -1) {
  226. my $h_command = "find " . join(" ", @paths, @h_files) . " -name \\*.h";
  227. my %found;
  228. @$h_files = sort(map {
  229. s/^\.\/(.*)$/$1/;
  230. if(defined($found{$_})) {
  231. ();
  232. } else {
  233. $found{$_}++;
  234. $_;
  235. }
  236. } split(/\n/, `$h_command`));
  237. }
  238. }
  239. my %dirs;
  240. foreach my $file (@$c_files, @$h_files) {
  241. my $dir = $file;
  242. $dir =~ s%/?[^/]+$%%;
  243. if(!$dir) { $dir = "."; }
  244. $dirs{$dir}++
  245. }
  246. @$directories = sort(keys(%dirs));
  247. }
  248. sub options_set($$) {
  249. my $self = shift;
  250. my $options_long = \%{$self->{_OPTIONS_LONG}};
  251. my $options_short = \%{$self->{_OPTIONS_SHORT}};
  252. local $_ = shift;
  253. for my $name (sort(keys(%$options_long))) {
  254. my $option = $$options_long{$name};
  255. my $key = uc($name);
  256. $key =~ tr/-/_/;
  257. $$option{key} = $key;
  258. my $refvalue = \${$self->{$key}};
  259. if(/^default$/) {
  260. $$refvalue = $$option{default};
  261. } elsif(/^all$/) {
  262. if($name !~ /^(?:help|debug|verbose|module)$/) {
  263. if(ref($$refvalue) ne "HASH") {
  264. $$refvalue = 1;
  265. } else {
  266. $$refvalue = { active => 1, filter => 0, hash => {} };
  267. }
  268. }
  269. } elsif(/^none$/) {
  270. if($name !~ /^(?:help|debug|verbose|module)$/) {
  271. if(ref($$refvalue) ne "HASH") {
  272. $$refvalue = 0;
  273. } else {
  274. $$refvalue = { active => 0, filter => 0, hash => {} };
  275. }
  276. }
  277. }
  278. }
  279. }
  280. sub show_help($) {
  281. my $self = shift;
  282. my $options_long = \%{$self->{_OPTIONS_LONG}};
  283. my $options_short = \%{$self->{_OPTIONS_SHORT}};
  284. my $maxname = 0;
  285. for my $name (sort(keys(%$options_long))) {
  286. if(length($name) > $maxname) {
  287. $maxname = length($name);
  288. }
  289. }
  290. for my $name (sort(keys(%$options_long))) {
  291. my $option = $$options_long{$name};
  292. my $description = $$option{description};
  293. my $parser = $$option{parser};
  294. my $current = ${$self->{$$option{key}}};
  295. my $value = $current;
  296. my $command;
  297. if(!defined $parser) {
  298. if($value) {
  299. $command = "--no-$name";
  300. } else {
  301. $command = "--$name";
  302. }
  303. } else {
  304. if(ref($value) eq "HASH" && $value->{active}) {
  305. $command = "--[no-]$name\[=<value>]";
  306. } else {
  307. $command = "--$name\[=<value>]";
  308. }
  309. }
  310. $output->write($command);
  311. $output->write(" " x (($maxname - length($name) + 17) - (length($command) - length($name) + 1)));
  312. if(!defined $parser) {
  313. if($value) {
  314. $output->write("Disable ");
  315. } else {
  316. $output->write("Enable ");
  317. }
  318. } else {
  319. if(ref($value) eq "HASH")
  320. {
  321. if ($value->{active}) {
  322. $output->write("(Disable) ");
  323. } else {
  324. $output->write("Enable ");
  325. }
  326. }
  327. }
  328. $output->write("$description\n");
  329. }
  330. }
  331. sub AUTOLOAD {
  332. my $self = shift;
  333. my $name = $_options::AUTOLOAD;
  334. $name =~ s/^.*::(.[^:]*)$/\U$1/;
  335. my $refvalue = $self->{$name};
  336. if(!defined($refvalue)) {
  337. die "<internal>: options.pm: member $name does not exist\n";
  338. }
  339. if(ref($$refvalue) ne "HASH") {
  340. return $$refvalue;
  341. } else {
  342. return $$refvalue->{active};
  343. }
  344. }
  345. sub arguments($) {
  346. my $self = shift;
  347. my $arguments = \@{$self->{_ARGUMENTS}};
  348. return @$arguments;
  349. }
  350. sub c_files($) {
  351. my $self = shift;
  352. my $c_files = \@{$self->{_C_FILES}};
  353. if(!@$c_files) {
  354. $self->parse_files;
  355. }
  356. return @$c_files;
  357. }
  358. sub h_files($) {
  359. my $self = shift;
  360. my $h_files = \@{$self->{_H_FILES}};
  361. if(!@$h_files) {
  362. $self->parse_files;
  363. }
  364. return @$h_files;
  365. }
  366. sub directories($) {
  367. my $self = shift;
  368. my $directories = \@{$self->{_DIRECTORIES}};
  369. if(!@$directories) {
  370. $self->parse_files;
  371. }
  372. return @$directories;
  373. }
  374. 1;