Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

370 lines
11 KiB

  1. #---------------------------------------------------------------------
  2. package Getp;
  3. # (c) 2000 Microsoft Corporation. All rights reserved.
  4. #
  5. # Version: 1.00 (01-14-2000) : Basic function implement
  6. # 1.01 (01-17-2000) : Use -tag to define the function
  7. # 1.02 (02-01-2000) : Fix $self problem => Complete Object Oriented
  8. # 1.03 (05-02-2000) : Provide -? and -x:xxx parameters & fix path value problem
  9. # 1.04 (05-04-2000) : Provide getparams, getparamsEnv function & remove $class
  10. # 2.00 (08-01-2000) : Provide enterprise of getparams; use Getopt::Mix and support '?', ':', '+' and '*'
  11. #---------------------------------------------------------------------
  12. # $VERSION = '1.04';
  13. require 5.003;
  14. use Getopt::Mixed 1.006 "nextOption";
  15. require Exporter;
  16. @ISA = qw(Exporter);
  17. my $gp_RealSyntax;
  18. sub GetParams {
  19. # push ARGV, because the Getopt::Mixed only works for ARGV
  20. my @ARGs = @_;
  21. my @ARGV_BAK=@ARGV;
  22. # Store the parameters
  23. my (@Parameter, @necessary, @optional) = ();
  24. # Separator;
  25. my $Separator;
  26. my %emptyhash;
  27. my $gp_hptr = \%emptyhash;
  28. my ($gp_tempvalue, $gp_preoption);
  29. my ($gp_opt, $gp_pretty, $gp_val)=();
  30. my (@gp_Unsolve, %plus_sign, %star_sign, %question_mark, %colon_mark)=();
  31. @ARGV=();
  32. ################################ Parse GetParams's arguments
  33. # 1. Prepare the parameters for Getopt::Mixed
  34. for (@ARGs) {
  35. if ((/^[\-\/]\?/||/[\-\/]{1,2}help/i) && ($Separator eq "")) {
  36. exit &Usage;
  37. }
  38. if (/^[\-\/]{1,2}([^\-\/\:\=]+)(:)?/) {
  39. push(@Parameter, _set_opt_to_pretty($1));
  40. push(@Parameter, $') if (defined $2);
  41. } else {
  42. push(@Parameter, $_);
  43. }
  44. if (($Parameter[$#Parameter-1]=~/-p(arameter)?/) && ($Separator eq "")) {
  45. $Separator = $#Parameter;
  46. }
  47. }
  48. &Getopt::Mixed::abortMsg("Parameter -p does not defined!!") if ($Separator eq "");
  49. # 2. Call Getopt::Mixed to set up getparams syntax
  50. @ARGV = @Parameter[0..$Separator];
  51. Getopt::Mixed::init( qw(
  52. n=s necessary>n
  53. o=s optional>o
  54. h=s hash>h
  55. p=s
  56. parameter>p
  57. ));
  58. # 3. Fetch one by one record to get its value
  59. while (($gp_opt, $gp_val, $gp_pretty) = nextOption()) {
  60. if (($gp_opt=~/^n(ecessary)?/i)||($gp_opt=~/^o(ptional)?/i)) {
  61. if ($gp_val!~/\s/) { # Will remove after we do not need compatible with old one
  62. while ($gp_val=~/(\w)(:)?/g) {
  63. my ($opt,$col)=($1, $2);
  64. $gp_RealSyntax .= $opt . ((defined $col)?"=s ":" ");
  65. ($gp_opt=~/n/)?push(@necessary, $opt):push(@optional,$opt);
  66. }
  67. } else { # This works for long / singal(which use space delimited the parameters)
  68. $_ = " $gp_val "; # for easy to match:)
  69. s/ / /g;
  70. s/\s(\w+)(\:*)?\?+[\+\*]/ $1$2\* /; # ::??* => ::*
  71. s/\s(\w+)(\:*)\:\*\s/ $1$2\+ /; # ::* => :+
  72. s/\s(\w+)(\:+)?(\?+)?(\+)?\s/ # :+ => :
  73. $colon_mark{$1}=length($2) if (length($2) ne 0);
  74. $question_mark{$1}=length($3) if (length($3) ne 0); # for with parameter and without parameter
  75. length($2)?" $1\:$4 ":" $1$4 ";/ge;
  76. s/\s(\w+)\:?\+\s/$plus_sign{$1}=-1;" $1\: "/ge; # + => 1,2,3,...
  77. s/\s(\w+)\*\s/$star_sign{$1}=-1;" $1 "/ge; # * => 0,1,2,...
  78. while (/\s(\w+)(:)?\s/g) {
  79. my ($opt,$col)=($1, $2);
  80. $gp_RealSyntax .= $opt . ((defined $col)?"=s ":" ");
  81. ($gp_opt=~/n/)?push(@necessary, $opt):push(@optional,$opt);
  82. }
  83. while (/\s(\w+\>\w+)\s/g) {
  84. $gp_RealSyntax .= "$1 ";
  85. }
  86. }
  87. } elsif ($gp_opt=~/h/i) {
  88. $gp_hptr=$gp_val;
  89. } elsif ($gp_opt=~/p/i) {
  90. @{$gp_hptr}{@necessary,@optional}=(ref $gp_val)?@{$gp_val}:split(/\s+/, $gp_val);
  91. $gp_tempvalue=(ref $gp_val)?@{$gp_val}:split(/\s+/, $gp_val);
  92. } else {
  93. push @gp_Unsolve, $gp_opt, $gp_val;
  94. }
  95. }
  96. # 4. Finish my syntax part
  97. Getopt::Mixed::cleanup();
  98. # Verify syntax match with parameters
  99. &Getopt::Mixed::abortMsg("Parameter does not match with options!!") if ((scalar keys %$gp_hptr) ne $gp_tempvalue);
  100. ###################################### Parse User's arguments
  101. # 1. Prepare its arguments
  102. @ARGV=(@gp_Unsolve, @Parameter[$Separator+1 .. $#Parameter]);
  103. @gp_Unsolve=();
  104. undef $Separator;
  105. # 2. Make sure user does not specify help
  106. for (@ARGV) {
  107. if (/^[\-\/]\?/||/[\-\/]{1,2}help/i) {
  108. ${$gp_hptr}{'-?'}=HELP;
  109. $HELP=1;
  110. push( @EXPORT, "\$HELP" );
  111. return;
  112. }
  113. }
  114. # 3. Now, we set user defined syntax
  115. Getopt::Mixed::init($gp_RealSyntax);
  116. # Make sure we fetch in order
  117. $Getopt::Mixed::order = $Getopt::Mixed::RETURN_IN_ORDER;
  118. # Set up customized option finder
  119. $Getopt::Mixed::badOption = \&OptimizeCombination;
  120. # 4. Fetch each option and store it into the variable
  121. while (($gp_opt, $gp_val, $gp_pretty) = nextOption()) {
  122. # Count / Set option
  123. if ($gp_opt eq "") {
  124. if ((exists $plus_sign{$gp_preoption}) || (exists $star_sign{$gp_preoption})) {
  125. $gp_opt = $gp_preoption;
  126. } elsif ((exists $question_mark{$gp_preoption}) && ($question_mark{$gp_preoption} > 0)) {
  127. $gp_opt = $gp_preoption;
  128. $question_mark{$gp_preoption}-- if ($gp_val ne "");
  129. } elsif ((exists $colon_mark{$gp_preoption}) && ($colon_mark{$gp_preoption} > 0)) {
  130. $gp_opt = $gp_preoption;
  131. $colon_mark{$gp_preoption}--;
  132. }
  133. } else {
  134. if ((exists $colon_mark{$gp_opt}) && ($colon_mark{$gp_opt} > 0)) {
  135. $colon_mark{$gp_opt}--;
  136. } elsif ((exists $question_mark{$gp_opt}) && ($question_mark{$gp_opt} > 0)) {
  137. $question_mark{$gp_opt}-- if ($gp_val ne "");
  138. } elsif (((exists $colon_mark{$gp_opt}) ||
  139. (exists $question_mark{$gp_opt})) &&
  140. (!exists $plus_sign{$gp_opt}) &&
  141. (!exists $star_sign{$gp_opt})) {
  142. &Getopt::Mixed::abortMsg("Extra parameter for ($gp_opt)");
  143. }
  144. }
  145. # This is for debugger
  146. # print "gp_opt => $gp_opt, gp_val => $gp_val gp_preoption = $gp_preoption\n";
  147. # Store the option value to gp_hptr or gp_Unsolve
  148. if (exists ${$gp_hptr}{$gp_opt}) {
  149. if (defined ${${$gp_hptr}{$gp_opt}}) {
  150. if (!defined $gp_val) {
  151. if (${${$gp_hptr}{$gp_opt}}=~/^\d+$/ ) { # should be option
  152. ${${$gp_hptr}{$gp_opt}}++;
  153. } else {
  154. # should be another option continue. Meet this point when format is '??'
  155. next;
  156. }
  157. } elsif (ref ${${$gp_hptr}{$gp_opt}}) { # should be an array
  158. push @{${${$gp_hptr}{$gp_opt}}}, $gp_val; # store to an array directly if exist
  159. } else {
  160. ${${$gp_hptr}{$gp_opt}} = [${${$gp_hptr}{$gp_opt}}, $gp_val]; # create an array automatically
  161. }
  162. } else {
  163. $gp_val = 1 if (!defined $gp_val);
  164. ${${$gp_hptr}{$gp_opt}} = $gp_val;
  165. }
  166. push( @EXPORT, "\$${$gp_hptr}{$gp_opt}" ) if (!ref ${$gp_hptr}{$gp_opt}); # Call by name
  167. } else {
  168. push @gp_Unsolve, $gp_opt if ($gp_opt ne "");
  169. push @gp_Unsolve, $gp_val if ($gp_val ne "");
  170. }
  171. $gp_preoption = $gp_opt;
  172. }
  173. # 5. Finish user's syntax
  174. Getopt::Mixed::cleanup();
  175. # Keep Unsolved
  176. push @gp_Unsolve, @ARGV;
  177. # 6. Special process for star_sign & question mark (=> remove the dummy first 1)
  178. for (keys %star_sign, keys %question_mark) {
  179. if ((ref ${${$gp_hptr}{$_}}) && (${${${$gp_hptr}{$_}}}[0] eq 1)) {
  180. shift @{${${$gp_hptr}{$_}}};
  181. ${${$gp_hptr}{$_}} = ${${${$gp_hptr}{$_}}}[0] if (@{${${$gp_hptr}{$_}}} eq 1);
  182. }
  183. }
  184. # 7. Special check for limited elements
  185. map({
  186. &Getopt::Mixed::abortMsg("Option '$_' does not contain enough elements")
  187. if ((defined ${${$gp_hptr}{$_}}) && ($colon_mark{$_} != 0))
  188. } keys %colon_mark);
  189. # 8. Verify necessary parameters are set
  190. @necessary = map({(!defined ${${$gp_hptr}{$_}})?$_:() } @necessary);
  191. &Getopt::Mixed::abortMsg("Parameter(s) (" . join(",", @necessary) . ") is(are) necessary!!") if(@necessary ne 0);
  192. # Store the ARGV back
  193. @ARGV=@ARGV_BAK;
  194. # 9. Export to its parent
  195. if(@EXPORT) {
  196. local $Exporter::ExportLevel = 1; #Export the value to its parent-parent (because its parent is sub {&Process($self,@_)}
  197. import Getp;
  198. }
  199. # Return gp_Unsolved parameters
  200. return (wantarray)?@gp_Unsolve:join(" ",@gp_Unsolve);
  201. }
  202. sub OptimizeCombination {
  203. my($pos, $pretty, $mylist)=@_;
  204. my ($ctr)=(0);
  205. # Get all possible list
  206. my @list = matchme(_get_opt_from_pretty($pretty), split(/=s\s+|\s+/,$gp_RealSyntax));
  207. # Remove incorrect syntax
  208. for (split(/\s+/, $gp_RealSyntax)) {
  209. next if (!/(.+)=s/);
  210. $pattern = $1;
  211. for ($ctr=0;$ctr < @list;) {
  212. ($list[$ctr]=~/^$pattern\s|\s$pattern\s/)? splice(@list, $ctr, 1) : $ctr++;
  213. }
  214. }
  215. $ctr = 0; # initial for only one element in @list
  216. # Find out which one is you specified
  217. if (@list eq 0) {
  218. &Getopt::Mixed::abortMsg("Argument $pretty is not able to figure out");
  219. return;
  220. } elsif (@list > 1) {
  221. if (eval("\$0!~/" . __PACKAGE__ . "\\.pm\$/i")) { # Only asking if not command line
  222. do {
  223. for ($ctr=0;$ctr < @list;++$ctr) {
  224. printf("%d : %s\n", $ctr+1, $list[$ctr]);
  225. }
  226. print "Select one for $gp_val meaning is : ";
  227. $ctr = <STDIN>;
  228. } while($ctr < 1 || $ctr > @list);
  229. $ctr--;
  230. } else {
  231. &Getopt::Mixed::abortMsg("Choose combination is not support in command line!");
  232. }
  233. }
  234. # Create pretty list
  235. @list= map({&_set_opt_to_pretty($_)} split(/\s+/, $list[$ctr]));
  236. splice(@ARGV, $pos, 0, @list);
  237. $pretty = $ARGV[0];
  238. return _get_opt_from_pretty($pretty), undef, shift @ARGV;
  239. }
  240. sub matchme {
  241. my($match,@items)=@_;
  242. my @matches=();
  243. for my $item (@items) {
  244. if ($match=~/^$item(.+)/) {
  245. push @matches, map({"$item $_"} matchme($1, @items));
  246. } elsif ($match=~/^$item$/) {
  247. push @matches, $item;
  248. }
  249. }
  250. return @matches;
  251. }
  252. # pretty is mean '-a', gp_opt is mean 'a'
  253. sub _get_opt_from_pretty {
  254. my ($pretty)=shift;
  255. $pretty=~s/^--?//;
  256. return $pretty;
  257. }
  258. sub _set_opt_to_pretty {
  259. my ($opt)=shift;
  260. return (length($opt)==1)?"-$opt":"--$opt";
  261. }
  262. sub Usage {
  263. print <<USAGE
  264. $0 - Get option
  265. =====================================================================
  266. Syntax:
  267. $0 [-n[ecessary] <necessary>] [-o[ptional] <optional>]
  268. [-h[ash] hash] <-p[arameter] <paramlist>|-?>
  269. Parameters:
  270. necessary : necessary parameter, seperate by space, and can add colon
  271. (:) if has parameter. Such as "ser: cli:". It also can
  272. be alias which use '>' for assign to another defined
  273. option. Such as "server>ser client>cli".
  274. optional : optional parameter, seperate by space, and can add colon
  275. (:) if has parameter. Such as "c p l:". It also can be
  276. alias wich use '>' for assign to another defined option.
  277. Such as "check>c powerless>p lang>l".
  278. hash : an address. Only use for Perl program calls. Such as
  279. \\\%myhash.
  280. paramlist : A list contains the names or variable's address (only
  281. for perl program) for store the real value. Such as
  282. "server client check powerless lang". You also can do
  283. [\\\$server \\\$client \\\$check \\\$powerless \\\$lang]
  284. in Perl calls
  285. Remark:
  286. ':' : limited one parameter
  287. Examples:
  288. 1. Accept -cZ as -c -Z, -f as -full, and -s sourcepath for necessary
  289. $0 -n "s:" -o "c Z f full>f" -p "sourcepath opt_c opt_z full" %*
  290. 2. Accept -copy f1 [f2], -move f1 f2, -del f1 [...] -tab [...]
  291. $0 -o "copy:? move:: del+ tab*" -p "copyarg movearg delarg tab"
  292. 3. Accept -f [file] -f [file1] [file2]
  293. $0 -n "f* " -p "file" %*
  294. USAGE
  295. }
  296. if (eval("\$0=~/" . __PACKAGE__ . "\\.pm\$/i")) {
  297. my %myvar;
  298. my $list = GetParams('-h' => \%myvar, (0==@ARGV)?"-?":@ARGV);
  299. map({print "set " . $myvar{$_} . "=" . ((ref ${$myvar{$_}})?join(" ",@{${$myvar{$_}}}):${$myvar{$_}}) . "\n" if (defined ${$myvar{$_}}) } keys %myvar);
  300. print "set __Unsolve__=$list\n";
  301. }
  302. 1;