1 /**
2  * Copyright: Copyright (c) 2010-211 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Aug 15, 2010
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dvm.util.OptionParser;
8 
9 import tango.text.Arguments;
10 import tango.text.convert.Format;
11 import tango.io.Stdout;
12 
13 import mambo.core._;
14 import mambo.util.Traits;
15 
16 import dvm.dvm.Options;
17 import dvm.dvm.Exceptions;
18 
19 class OptionParser
20 {
21     string banner;
22 //    string[] separator;
23 
24     private
25     {
26         alias Format format;
27         Arguments arguments;
28         void delegate (string[] args) argsDg;
29         string helpText;
30         Option[] options;
31     }
32 
33     this ()
34     {
35         arguments = new Arguments;
36     }
37 
38     OptionParser separator (string[] args ...)
39     {
40         foreach (arg ; args)
41             buildHelpText(arg);
42 
43         return this;
44     }
45 
46     OptionParser on (char shortOption, string longOption, string helpText, void delegate () dg)
47     {
48         arguments(longOption).aliased(shortOption).help(helpText).bind(dg);
49         buildHelpText(shortOption, longOption, helpText);
50 
51         return this;
52     }
53 
54     OptionParser on (string longOption, string helpText, void delegate () dg)
55     {
56         arguments(longOption).help(helpText).bind(dg);
57         buildHelpText(longOption, helpText);
58 
59         return this;
60     }
61 
62     OptionParser on (char shortOption, string longOption, string helpText, void delegate (string) dg)
63     {
64         arguments(longOption).aliased(shortOption).help(helpText).params(1).bind(cast(const(char)[] delegate (const(char)[])) dg);
65         buildHelpText(shortOption, longOption, helpText);
66 
67         return this;
68     }
69 
70     OptionParser on (string longOption, string helpText, void delegate (string) dg)
71     {
72         arguments(longOption).help(helpText).params(1).bind(cast(const(char)[] delegate (const(char)[])) dg);
73         buildHelpText(longOption, helpText);
74 
75         return this;
76     }
77 
78     OptionParser on (void delegate (string[]) dg)
79     {
80         argsDg = dg;
81         return this;
82     }
83 
84     OptionParser parse (string input, bool sloppy = false)
85     {
86         if (!arguments.parse(input, sloppy))
87             throw new InvalidOptionException(arguments.errors(&stderr.layout.sprint).assumeUnique, __FILE__, __LINE__);
88 
89         handleArgs(cast(string[]) arguments(null).assigned);
90 
91         return this;
92     }
93 
94     OptionParser parse (string[] input, bool sloppy = false)
95     {
96         if (!arguments.parse(input, sloppy))
97             throw new InvalidOptionException(arguments.errors(&stderr.layout.sprint).assumeUnique, __FILE__, __LINE__);
98 
99         handleArgs(cast(string[]) arguments(null).assigned);
100 
101         return this;
102     }
103 
104     override string toString ()
105     {
106         return format("{}\n{}", banner, buildHelpText).assumeUnique;
107     }
108 
109     private void handleArgs (string[] args)
110     {
111         if (argsDg) argsDg(args);
112     }
113 
114     private void buildHelpText (char shortOption, string longOption, string helpText)
115     {
116         options ~= Option(shortOption, longOption, helpText);
117     }
118 
119     private void buildHelpText (string option, string helpText)
120     {
121         buildHelpText(char.init, option, helpText);
122     }
123 
124     private void buildHelpText (string str)
125     {
126         buildHelpText("", str);
127     }
128 
129     private string buildHelpText ()
130     {
131         string help;
132         auto len = lengthOfLongestOption;
133         auto indentation = Options.instance.indentation;
134         auto numberOfIndentations = Options.instance.numberOfIndentations;
135 
136         foreach (option ; options)
137         {
138             if (option.longOption.length == 0 && option.shortOption == char.init)
139                 help ~= format("{}\n", option.helpText);
140 
141             else if (option.shortOption == char.init)
142                 help ~= format("{}--{}{}{}{}\n",
143                             indentation ~ indentation,
144                             option.longOption,
145                             " ".repeat(len - option.longOption.length),
146                             indentation.repeat(numberOfIndentations),
147                             option.helpText);
148 
149             else
150                 help ~= format("{}-{}, --{}{}{}{}\n",
151                             indentation,
152                             option.shortOption,
153                             option.longOption,
154                             " ".repeat(len - option.longOption.length),
155                             indentation.repeat(numberOfIndentations),
156                             option.helpText);
157         }
158 
159         return help;
160     }
161 
162     private size_t lengthOfLongestOption ()
163     {
164         size_t len;
165 
166         foreach (option ; options)
167             if (option.longOption.length > len)
168                 len = option.longOption.length;
169 
170         return len;
171     }
172 }
173 
174 private:
175 
176 struct Option
177 {
178     char shortOption;
179     string longOption;
180     string helpText;
181 }