annotate dang/OptParse.d @ 1:2168f4cb73f1

First push
author johnsen@johnsen-desktop
date Fri, 18 Apr 2008 02:01:38 +0200
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
1 /*
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
2 Copyright (c) 2007 Kirk McDonald
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
3
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
5 this software and associated documentation files (the "Software"), to deal in
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
6 the Software without restriction, including without limitation the rights to
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
8 of the Software, and to permit persons to whom the Software is furnished to do
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
9 so, subject to the following conditions:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
10
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
11 The above copyright notice and this permission notice shall be included in all
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
12 copies or substantial portions of the Software.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
13
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
20 SOFTWARE.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
21 */
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
22 /**
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
23 * Command-line option parsing, in the style of Python's optparse.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
24 *
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
25 * Refer to the complete docs for more information.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
26 */
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
27 module dang.OptParse;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
28
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
29 import tango.io.Stdout;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
30 import tango.text.Util : locate, locatePrior;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
31 import tango.text.Ascii : toUpper;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
32 import tango.stdc.stdlib : exit, EXIT_FAILURE, EXIT_SUCCESS;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
33 import tango.text.convert.Integer : parse, toInt, toString = toString;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
34 import tango.text.convert.Utf : toString, toString32;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
35
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
36 /*
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
37 Options may be in two forms: long and short. Short options start with a single
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
38 dash and are one letter long. Long options start with two dashes and may
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
39 consist of any number of characters (so long as they don't start with a dash,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
40 though they may contain dashes). Options are case-sensitive.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
41
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
42 Short options may be combined. The following are equivalent:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
43
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
44 $ myapp -a -b -c
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
45 $ myapp -abc
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
46 $ myapp -ab -c
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
47
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
48 If -f and --file are aliases of the same option, which accepts an argument,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
49 the following are equivalent:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
50
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
51 $ myapp -f somefile.txt
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
52 $ myapp -fsomefile.txt
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
53 $ myapp --file somefile.txt
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
54 $ myapp --file=somefile.txt
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
55
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
56 The following are also valid:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
57
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
58 $ myapp -abcf somefile.txt
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
59 $ myapp -abcfsomefile.txt
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
60 $ myapp -abc --file somefile.txt
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
61
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
62 If an option occurs multiple times, the last one is the one recorded:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
63
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
64 $ myapp -f somefile.txt --file otherfile.txt
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
65
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
66 Matches 'otherfile.txt'.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
67 */
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
68
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
69 bool startswith(char[] s, char[] start) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
70 if (s.length < start.length) return false;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
71 return s[0 .. start.length] == start;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
72 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
73 bool endswith(char[] s, char[] end) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
74 if (s.length < end.length) return false;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
75 return s[$ - end.length .. $] == end;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
76 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
77
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
78 /// Thrown if client code tries to set up an improper option.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
79 class OptionError : Exception {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
80 this(char[] msg) { super(msg); }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
81 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
82 // Thrown if client code tries to extract the wrong type from an option.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
83 class OptionTypeError : Exception {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
84 this(char[] msg) { super(msg); }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
85 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
86
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
87 /++
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
88 This class represents the results after parsing the command-line.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
89 +/
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
90 class Options {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
91 char[][][char[]] opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
92 int[char[]] counted_opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
93 /// By default, leftover arguments are placed in this array.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
94 char[][] args;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
95
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
96 /// Retrieves the results of the Store and StoreConst actions.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
97 char[] opIndex(char[] opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
98 char[][]* o = opt in opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
99 if (o) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
100 return (*o)[0];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
101 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
102 return "";
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
103 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
104 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
105 /// Retrieves the results of the Store action, when the type is Integer.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
106 int value(char[] opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
107 char[][]* o = opt in opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
108 if (o) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
109 return toInt((*o)[0]);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
110 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
111 return 0;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
112 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
113 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
114 /// Retrieves the results of the Append and AppendConst actions.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
115 char[][] list(char[] opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
116 char[][]* o = opt in opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
117 if (o) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
118 return *o;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
119 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
120 return null;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
121 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
122 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
123 /// Retrieves the results of the Append action, when the type is Integer.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
124 int[] valueList(char[] opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
125 char[][]* o = opt in opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
126 int[] l;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
127 if (o) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
128 l.length = (*o).length;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
129 foreach (i, s; *o) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
130 l[i] = toInt(s);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
131 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
132 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
133 return l;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
134 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
135 /// Retrieves the results of the Count action.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
136 int count(char[] opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
137 int* c = opt in counted_opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
138 if (c) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
139 return *c;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
140 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
141 return 0;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
142 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
143 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
144 /// Retrieves the results of the SetTrue and SetFalse actions.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
145 bool flag(char[] opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
146 char[][]* o = opt in opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
147 if (o) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
148 return (*o)[0] == "1";
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
149 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
150 return false;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
151 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
152 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
153 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
154
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
155 // Options, args, this opt's index in args, name[, arg]
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
156 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
157 alias void delegate(Options, inout char[][], inout int, char[], char[]) OptionCallbackFancyArg;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
158 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
159 alias void delegate(Options, inout char[][], inout int, char[], int) OptionCallbackFancyInt;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
160 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
161 alias void delegate(Options, inout char[][], inout int, char[]) OptionCallbackFancy;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
162
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
163 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
164 alias void delegate(char[]) OptionCallbackArg;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
165 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
166 alias void delegate(int) OptionCallbackInt;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
167 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
168 alias void delegate() OptionCallback;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
169
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
170 /*
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
171 Actions:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
172 * Store: name
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
173 * StoreConst: name, const_value
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
174 * Append: name
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
175 * AppendConst: name, const_value
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
176 * Count: name
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
177 * CallbackArg: dga
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
178 * CallbackVoid: dg
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
179 */
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
180 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
181 enum Action { /+++/Store, /+++/StoreConst, /+++/Append, /+++/AppendConst, /+++/Count, /+++/SetTrue, /+++/SetFalse, /+++/Callback, /+++/CallbackFancy, /+++/Help /+++/}
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
182 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
183 enum ArgType { /+++/None, /+++/String, /+++/Integer /+++/}
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
184
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
185 ArgType defaultType(Action action) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
186 switch (action) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
187 case Action.Store, Action.Append, Action.Callback, Action.CallbackFancy:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
188 return ArgType.String;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
189 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
190 default:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
191 return ArgType.None;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
192 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
193 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
194 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
195
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
196 /++
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
197 This class represents a single command-line option.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
198 +/
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
199 class Option {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
200 char[][] shortopts, longopts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
201 Action action;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
202 ArgType type;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
203 char[] name, argname;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
204 char[] const_value;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
205
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
206 char[] default_string;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
207 int default_value;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
208 bool default_flag, has_default;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
209
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
210 OptionCallbackArg callback;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
211 OptionCallbackInt int_callback;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
212 OptionCallback void_callback;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
213
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
214 OptionCallbackFancyArg fancy_callback;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
215 OptionCallbackFancyInt fancy_int_callback;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
216 OptionCallbackFancy fancy_void_callback;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
217 char[] helptext;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
218 this(
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
219 char[][] shorts, char[][] longs, ArgType type,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
220 Action act, char[] name, char[] const_value,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
221 OptionCallbackArg dga, OptionCallback dg,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
222 OptionCallbackInt dgi,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
223 OptionCallbackFancyArg fdga,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
224 OptionCallbackFancyInt fdgi,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
225 OptionCallbackFancy fdg
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
226 ) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
227 this.shortopts = shorts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
228 this.longopts = longs;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
229 this.action = act;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
230 this.type = type;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
231 this.name = name;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
232 this.argname = toUpper(name.dup);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
233 this.default_string = "";
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
234 this.default_value = 0;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
235 this.default_flag = false;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
236
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
237 // Perform sanity checks.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
238 assert (name !is null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
239 switch (act) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
240 case Action.Store, Action.Append:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
241 assert(type != ArgType.None);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
242 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
243 case Action.StoreConst, Action.AppendConst:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
244 assert(type == ArgType.None);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
245 assert(const_value !is null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
246 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
247 case Action.Callback:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
248 //assert(type != ArgType.None);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
249 switch (type) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
250 case ArgType.String:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
251 assert(dga !is null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
252 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
253 case ArgType.Integer:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
254 assert(dgi !is null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
255 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
256 case ArgType.None:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
257 assert(dg !is null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
258 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
259 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
260 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
261 case Action.CallbackFancy:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
262 switch (type) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
263 case ArgType.String:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
264 assert(fdga !is null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
265 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
266 case ArgType.Integer:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
267 assert(fdgi !is null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
268 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
269 case ArgType.None:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
270 assert(fdg !is null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
271 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
272 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
273 default:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
274 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
275 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
276 this.const_value = const_value;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
277 this.callback = dga;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
278 this.int_callback = dgi;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
279 this.void_callback = dg;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
280 this.fancy_callback = fdga;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
281 this.fancy_int_callback = fdgi;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
282 this.fancy_void_callback = fdg;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
283 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
284 char[] toString() {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
285 int optCount = this.shortopts.length + this.longopts.length;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
286 char[] result;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
287 bool printed_arg = false;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
288 foreach(i, opt; this.shortopts ~ this.longopts) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
289 result ~= opt;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
290 if (i < optCount-1) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
291 result ~= ", ";
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
292 } else if (this.hasArg()) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
293 result ~= "=" ~ toUpper(this.argname.dup);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
294 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
295 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
296 return result;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
297 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
298 //enum Action { Store, StoreConst, Append, AppendConst, Count, SetTrue, SetFalse, Callback, CallbackFancy, Help }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
299 void issue_default(Options results) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
300 // Only set the default if the option doesn't already have a value.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
301 char[][]* val = this.name in results.opts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
302 switch (this.action) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
303 case Action.Store, Action.Append:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
304 if (val !is null) return;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
305 if (this.type == ArgType.String) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
306 results.opts[name] = [default_string];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
307 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
308 results.opts[name] = [.toString(default_value)];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
309 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
310 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
311 case Action.StoreConst, Action.AppendConst:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
312 if (val !is null) return;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
313 results.opts[name] = [default_string];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
314 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
315 case Action.SetTrue, Action.SetFalse:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
316 if (val !is null) return;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
317 if (default_flag) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
318 results.opts[name] = ["1"];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
319 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
320 results.opts[name] = ["0"];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
321 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
322 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
323 default:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
324 return;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
325 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
326 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
327 // Does whatever this option is supposed to do.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
328 void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
329 int i;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
330 if (this.type == ArgType.Integer) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
331 // Verify that it's an int.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
332 i = parser.toOptInt(arg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
333 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
334 switch (this.action) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
335 case Action.Store:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
336 results.opts[name] = [arg];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
337 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
338 case Action.Append:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
339 results.opts[name] ~= arg;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
340 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
341 case Action.StoreConst:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
342 assert(arg is null, "Got unexpected argument for '"~name~"' option.");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
343 results.opts[name] = [const_value];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
344 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
345 case Action.AppendConst:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
346 assert(arg is null, "Got unexpected argument for '"~name~"' option.");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
347 results.opts[name] ~= const_value;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
348 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
349 case Action.Count:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
350 assert(arg is null, "Got unexpected argument for '"~name~"' option.");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
351 ++results.counted_opts[name];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
352 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
353 case Action.SetTrue:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
354 results.opts[name] = ["1"];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
355 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
356 case Action.SetFalse:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
357 results.opts[name] = ["0"];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
358 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
359 case Action.Callback:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
360 switch (type) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
361 case ArgType.String:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
362 callback(arg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
363 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
364 case ArgType.Integer:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
365 int_callback(i);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
366 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
367 case ArgType.None:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
368 void_callback();
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
369 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
370 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
371 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
372 case Action.CallbackFancy:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
373 switch (type) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
374 case ArgType.String:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
375 fancy_callback(results, args, idx, name, arg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
376 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
377 case ArgType.Integer:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
378 fancy_int_callback(results, args, idx, name, i);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
379 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
380 case ArgType.None:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
381 fancy_void_callback(results, args, idx, name);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
382 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
383 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
384 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
385 case Action.Help:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
386 parser.helpText();
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
387 exit(EXIT_SUCCESS);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
388 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
389 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
390 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
391 /// Returns whether this option accepts an argument.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
392 bool hasArg() {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
393 return this.type != ArgType.None;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
394 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
395 /// Sets the help text for this option.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
396 Option help(char[] help) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
397 this.helptext = help;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
398 return this;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
399 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
400 /// Sets the name of this option's argument, if it has one.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
401 Option argName(char[] argname) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
402 this.argname = argname;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
403 return this;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
404 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
405 Option def(char[] val) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
406 if (
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
407 (this.type != ArgType.String || (this.action != Action.Store && this.action != Action.Append)) &&
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
408 this.action != Action.StoreConst && this.action != Action.AppendConst
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
409 )
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
410 throw new OptionError("Cannot specify string default for non-string option '"~this.name~"'");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
411 this.has_default = true;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
412 this.default_string = val;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
413 return this;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
414 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
415 Option def(int val) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
416 if (this.type != ArgType.Integer || (this.action != Action.Store && this.action != Action.Append))
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
417 throw new OptionError("Cannot specify integer default for non-integer option '"~this.name~"'");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
418 this.has_default = true;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
419 this.default_value = val;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
420 return this;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
421 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
422 Option def(bool val) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
423 if (this.action != Action.SetTrue && this.action != Action.SetFalse)
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
424 throw new OptionError("Cannot specify boolean default for non-flag option '"~this.name~"'");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
425 this.has_default = true;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
426 this.default_flag = val;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
427 return this;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
428 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
429 // Returns true if the passed option string matches this option.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
430 bool matches(char[] _arg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
431 dchar[] arg = toString32(_arg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
432 if (
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
433 arg.length < 2 ||
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
434 arg.length == 2 && (arg[0] != '-' || arg[1] == '-') ||
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
435 arg.length > 2 && (arg[0 .. 2] != "--" || arg[2] == '-')
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
436 ) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
437 return false;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
438 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
439 if (arg.length == 2) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
440 foreach (opt; shortopts) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
441 if (_arg == opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
442 return true;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
443 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
444 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
445 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
446 foreach (opt; longopts) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
447 if (_arg == opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
448 return true;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
449 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
450 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
451 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
452 return false;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
453 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
454 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
455
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
456 /++
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
457 This class is used to define a set of options, and parse the command-line
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
458 arguments.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
459 +/
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
460 class OptionParser {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
461 OptionCallbackArg leftover_cb;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
462 /// An array of all of the options known by this parser.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
463 Option[] options;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
464 char[] name, desc;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
465 /// The description of the programs arguments, as used in the Help action.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
466 char[] argdesc;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
467 private void delegate(char[]) error_callback;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
468
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
469 this(char[] desc="") {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
470 this.name = "";
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
471 this.desc = desc;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
472 this.argdesc = "[options] args...";
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
473 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
474
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
475 /// Sets a callback, to override the default error behavior.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
476 void setErrorCallback(void delegate(char[]) dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
477 error_callback = dg;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
478 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
479 void unknownOptError(char[] opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
480 error("Unknown argument '"~opt~"'");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
481 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
482 void expectedArgError(char[] opt) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
483 error("'"~opt~"' option expects an argument.");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
484 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
485 /// Displays an error message and terminates the program.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
486 void error(char[] err) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
487 if (error_callback !is null) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
488 error_callback(err);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
489 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
490 this.helpText();
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
491 Stdout.formatln(err);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
492 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
493 exit(EXIT_FAILURE);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
494 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
495 int toOptInt(char[] s) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
496 int i;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
497 uint ate;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
498 i = .parse(s, 10u, &ate);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
499 if (ate != s.length)
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
500 error("Could not convert '"~s~"' to an integer.");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
501 return i;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
502 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
503
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
504 /// Displays useful "help" information about the program's options.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
505 void helpText() {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
506 int optWidth;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
507 char[][] optStrs;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
508 typedef char spacechar = ' ';
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
509 spacechar[] padding;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
510 // Calculate the maximum width of the option lists.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
511 foreach(i, opt; options) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
512 optStrs ~= opt.toString();
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
513 if (optStrs[i].length > optWidth) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
514 optWidth = optStrs[i].length;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
515 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
516 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
517 Stdout.formatln("Usage: {0} {1}", this.name, this.argdesc);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
518 if (this.desc !is null && this.desc != "") Stdout.formatln(this.desc);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
519 Stdout.formatln("\nOptions:");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
520 foreach(i, opt; options) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
521 padding.length = optWidth - optStrs[i].length;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
522 Stdout.formatln(" {0}{1} {2}", optStrs[i], cast(char[])padding, opt.helptext);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
523 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
524 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
525
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
526 // Checks the passed arg against all the options in the parser.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
527 // Returns null if no match is found.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
528 Option matches(char[] arg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
529 foreach(o; options) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
530 if (o.matches(arg)) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
531 return o;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
532 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
533 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
534 return null;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
535 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
536 char[] getBaseName(char[] path) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
537 version(Windows) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
538 char delimiter = '\\';
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
539 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
540 char delimiter = '/';
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
541 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
542 uint idx = locatePrior(path, delimiter);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
543 if (idx == path.length) return path;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
544 return path[idx+1 .. $];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
545 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
546 char[] getProgramName(char[] path) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
547 version(Windows) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
548 // (Unicode note: ".exe" only contains 4 code units, so this slice
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
549 // should Just Work.) (Although it remains to be seen how robust
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
550 // this code actually is.)
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
551 //Stdout.formatln(path);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
552 //assert(path[$-4 .. $] == ".exe");
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
553 //path = path[0 .. $-4];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
554 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
555 return getBaseName(path);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
556 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
557 /// Parses the passed command-line arguments and returns the results.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
558 Options parse(char[][] args) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
559 this.name = getProgramName(args[0]);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
560 args = args[1 .. $];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
561 Options options = new Options;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
562 /*
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
563 The issue is this:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
564
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
565 $ myapp -abc
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
566
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
567 This might be three short opts, or one or two opts, the last of which
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
568 accepts an argument. In the three-opt case, we want to get:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
569
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
570 $ myapp -a -b -c
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
571
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
572 In the one-opt case, we want:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
573
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
574 $ myapp -a bc
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
575
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
576 In the two-opt case, we want:
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
577
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
578 $ myapp -a -b c
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
579
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
580 We also want to parse apart "--file=somefile" into "--file somefile"
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
581 */
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
582 char[] opt, newopt, arg;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
583 dchar[] opt32;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
584 int idx;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
585 Option match;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
586
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
587 for (int i=0; i<args.length; ++i) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
588 opt = args[i];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
589 // -- ends the option list, the remainder is dumped into args
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
590 if (opt == "--") {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
591 if (this.leftover_cb !is null) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
592 foreach(a; args[i+1 .. $]) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
593 this.leftover_cb(a);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
594 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
595 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
596 options.args ~= args[i+1 .. $];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
597 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
598 i = args.length;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
599 } else if (opt.startswith("--")) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
600 idx = locate(opt, '=');
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
601 if (idx != opt.length) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
602 newopt = opt[0 .. idx];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
603 // Stitch out the old arg, stitch in the newopt, arg pair.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
604 // (Unicode note: idx+1 works, since we know '=' is a
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
605 // single code unit.)
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
606 args = args[0 .. i] ~ [newopt, opt[idx+1 .. $]] ~ args[i+1 .. $];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
607 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
608 newopt = opt;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
609 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
610 match = matches(newopt);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
611 if (match is null) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
612 unknownOptError(newopt);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
613 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
614 if (match.hasArg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
615 if (i == args.length-1) expectedArgError(match.name);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
616 arg = args[i+1];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
617 ++i;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
618 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
619 arg = null;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
620 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
621 match.performAction(this, options, args, i, arg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
622 } else if (opt.startswith("-")) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
623 if (opt.length >= 2) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
624 opt32 = toString32(opt[1 .. $]);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
625 foreach (j, c; opt32) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
626 newopt = .toString("-" ~ [c]);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
627 match = matches(newopt);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
628 if (match is null) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
629 unknownOptError(newopt);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
630 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
631 if (match.hasArg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
632 // This is the last char in the group, look to the
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
633 // next element of args for the arg.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
634 if (j == opt32.length-1) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
635 if (i == args.length-1) expectedArgError(match.name);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
636 arg = args[i+1];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
637 ++i;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
638 // Otherwise, consume the rest of this group for
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
639 // the arg.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
640 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
641 arg = .toString(opt32[j+1 .. $]);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
642 match.performAction(this, options, args, i, arg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
643 break;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
644 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
645 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
646 arg = null;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
647 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
648 match.performAction(this, options, args, i, arg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
649 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
650 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
651 unknownOptError(opt);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
652 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
653 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
654 if (this.leftover_cb is null) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
655 options.args ~= opt;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
656 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
657 this.leftover_cb(opt);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
658 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
659 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
660 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
661 foreach (o; this.options) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
662 o.issue_default(options);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
663 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
664 return options;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
665 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
666
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
667 /++
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
668 Overrides the default behavior of leftover arguments, calling this callback
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
669 with them instead of adding them an array.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
670 +/
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
671 void leftoverCallback(OptionCallbackArg dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
672 this.leftover_cb = dg;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
673 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
674 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
675 Option addOption(Option option) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
676 this.options ~= option;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
677 return option;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
678 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
679 // options action name type const_value dga dgv dgi fdga fdgi fdg
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
680 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
681 Option addOption(char[][] options ...) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
682 return addOption(options, Action.Store, null, defaultType(Action.Store), null, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
683 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
684 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
685 Option addOption(char[][] options, char[] name) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
686 return addOption(options, Action.Store, name, defaultType(Action.Store), null, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
687 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
688 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
689 Option addOption(char[][] options, Action action) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
690 return addOption(options, action, null, defaultType(action), null, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
691 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
692 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
693 Option addOption(char[][] options, ArgType type) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
694 return addOption(options, Action.Store, null, type, null, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
695 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
696 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
697 Option addOption(char[][] options, Action action, ArgType type) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
698 return addOption(options, action, null, type, null, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
699 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
700 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
701 Option addOption(char[][] options, char[] name, Action action) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
702 return addOption(options, action, name, defaultType(action), null, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
703 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
704 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
705 Option addOption(char[][] options, char[] name, Action action, ArgType type) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
706 return addOption(options, action, name, type, null, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
707 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
708 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
709 Option addOption(char[][] options, Action action, char[] const_value) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
710 return addOption(options, action, null, defaultType(action), const_value, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
711 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
712 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
713 Option addOption(char[][] options, char[] name, char[] const_value) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
714 return addOption(options, Action.StoreConst, name, defaultType(Action.Store), const_value, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
715 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
716 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
717 Option addOption(char[][] options, char[] name, Action action, char[] const_value) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
718 return addOption(options, action, name, defaultType(action), const_value, null, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
719 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
720 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
721 Option addOption(char[][] options, OptionCallbackArg dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
722 return addOption(options, Action.Callback, null, ArgType.String, null, dg, null, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
723 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
724 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
725 Option addOption(char[][] options, OptionCallback dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
726 return addOption(options, Action.Callback, null, ArgType.None, null, null, dg, null, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
727 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
728 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
729 Option addOption(char[][] options, OptionCallbackInt dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
730 return addOption(options, Action.Callback, null, ArgType.Integer, null, null, null, dg, null, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
731 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
732 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
733 Option addOption(char[][] options, OptionCallbackFancyArg dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
734 return addOption(options, Action.CallbackFancy, null, ArgType.String, null, null, null, null, dg, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
735 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
736 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
737 Option addOption(char[][] options, OptionCallbackFancy dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
738 return addOption(options, Action.CallbackFancy, null, ArgType.None, null, null, null, null, null, null, dg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
739 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
740 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
741 Option addOption(char[][] options, OptionCallbackFancyInt dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
742 return addOption(options, Action.CallbackFancy, null, ArgType.Integer, null, null, null, null, null, dg, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
743 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
744 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
745 Option addOption(char[][] options, char[] name, OptionCallbackFancyArg dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
746 return addOption(options, Action.CallbackFancy, name, ArgType.String, null, null, null, null, dg, null, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
747 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
748 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
749 Option addOption(char[][] options, char[] name, OptionCallbackFancy dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
750 return addOption(options, Action.CallbackFancy, name, ArgType.None, null, null, null, null, null, null, dg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
751 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
752 ///
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
753 Option addOption(char[][] options, char[] name, OptionCallbackFancyInt dg) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
754 return addOption(options, Action.CallbackFancy, name, ArgType.Integer, null, null, null, null, null, dg, null);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
755 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
756 // Although users certainly /can/ call this, all those overloads are there
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
757 // for a reason.
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
758 Option addOption(
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
759 char[][] options,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
760 Action action, char[] name, ArgType type, char[] const_value,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
761 OptionCallbackArg callback, OptionCallback vcall,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
762 OptionCallbackInt icall,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
763 OptionCallbackFancyArg fdga,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
764 OptionCallbackFancyInt fdgi,
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
765 OptionCallbackFancy fdg
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
766 ) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
767 char[][] shortopts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
768 char[][] longopts;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
769 dchar[] opt;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
770 Option option;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
771 foreach (_opt; options) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
772 // (Unicode note: We convert to dchar[] so the length checks work
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
773 // out in the event of a short opt with a >127 character.)
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
774 opt = toString32(_opt);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
775 if (opt.length < 2) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
776 throw new OptionError(
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
777 "invalid option string '" ~ _opt ~ "': must be at least two characters long"
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
778 );
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
779 } else if (opt.length > 2) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
780 if (opt[0 .. 2] != "--" || opt[2] == '-')
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
781 throw new OptionError(
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
782 "invalid long option string '" ~ _opt ~ "': must start with --, followed by non-dash"
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
783 );
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
784 longopts ~= _opt;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
785 } else {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
786 if (opt[0] != '-' || opt[1] == '-')
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
787 throw new OptionError(
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
788 "invalid short option string '" ~ _opt ~ "': must be of the form -x, where x is non-dash"
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
789 );
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
790 shortopts ~= _opt;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
791 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
792 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
793 if (name is null) {
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
794 // (Unicode note: We know '-' is a single code unit, so these
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
795 // slices are okay.)
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
796 if (longopts.length > 0)
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
797 name = longopts[0][2 .. $];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
798 else if (shortopts.length > 0)
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
799 name = shortopts[0][1 .. 2];
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
800 else
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
801 throw new OptionError(
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
802 "No options provided to addOption!"
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
803 );
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
804 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
805 option = new Option(shortopts, longopts, type, action, name, const_value, callback, vcall, icall, fdga, fdgi, fdg);
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
806 this.options ~= option;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
807 return option;
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
808 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
809 }
2168f4cb73f1 First push
johnsen@johnsen-desktop
parents:
diff changeset
810