PageRenderTime 97ms CodeModel.GetById 24ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 1ms

/parsing/options.d

http://github.com/wilkie/djehuty
D | 479 lines | 395 code | 53 blank | 31 comment | 122 complexity | 20999452578447cdf63024a16cccabed MD5 | raw file
  1/*
  2 * options.d
  3 *
  4 * This module implements a mechanism to read in command line options.
  5 *
  6 * Author: Dave Wilkinson
  7 * Originated: September 28th, 2009
  8 *
  9 */
 10
 11module parsing.options;
 12
 13import core.util;
 14import core.string;
 15import core.definitions;
 16import core.arguments;
 17import core.main;
 18
 19public import _ConsoleIO = io.console;
 20
 21template BuildArgumentRetrieval(T) {
 22	//pragma(msg, T.stringof);
 23	static if (is(T == char)) {
 24		const char[] BuildArgumentRetrieval = `(param)[0];`;
 25	}
 26	else static if (IsSigned!(T)) {
 27		const char[] BuildArgumentRetrieval = `cast(` ~ T.stringof ~ `)param.toInt();`;
 28	}
 29	else {
 30		const char[] BuildArgumentRetrieval = `param;`;
 31	}
 32}
 33
 34template BuildArgumentRetrieve(uint argidx, uint idx, list...) {
 35	static if (idx >= list.length) {
 36		const char[] BuildArgumentRetrieve = ``;
 37	}
 38	else static if (list[idx].stringof[0] != '"') {
 39		const char[] BuildArgumentRetrieve = `param = getParameter();`
 40			~ "\n\t\t\t\t"
 41			~ `if (param is null) { onError(token); return; } `
 42			~ "\n\t\t\t\t"
 43			~ list[idx].stringof ~ ` arg` ~ argidx.stringof[0..$-1] ~ ` = `
 44			~ BuildArgumentRetrieval!(list[idx])
 45			~ "\n\t\t\t\t"
 46			~ BuildArgumentRetrieve!(argidx+1,idx+2, list);
 47	}
 48	else {
 49		// no more parameters
 50		const char[] BuildArgumentRetrieve = ``;
 51	}
 52}
 53
 54template BuildOpParams(uint argidx, uint idx, list...) {
 55	static if (idx >= list.length) {
 56		const char[] BuildOpParams = ``;
 57	}
 58	else static if (argidx == 0) {
 59		static if (list[idx].stringof[0] != '"') {
 60			const char[] BuildOpParams = `arg0` ~ BuildOpParams!(argidx+1, idx+2, list);
 61		}
 62		else {
 63			const char[] BuildOpParams = ``;
 64		}
 65	}
 66	else {
 67		static if (list[idx].stringof[0] != '"') {
 68			const char[] BuildOpParams = `, arg` ~ argidx.stringof[0..$-1] ~ BuildOpParams!(argidx+1, idx+2, list);
 69		}
 70		else {
 71			const char[] BuildOpParams = ``;
 72		}
 73	}
 74}
 75
 76template RebuildOpName(char[] name, uint idx = 0) {
 77	static if (idx >= name.length || name == "" || name[idx] == ',' || name[idx] == ' ') {
 78		const char[] RebuildOpName = Capitalize!(name[0..idx]);
 79	}
 80	else static if (name[idx] == '-') {
 81		const char[] RebuildOpName = Capitalize!(name[0..idx]) ~ RebuildOpName!(name[idx+1..$], 0);
 82	}
 83	else {
 84		const char[] RebuildOpName = RebuildOpName!(name, idx + 1);
 85	}
 86}
 87
 88template BuildOpName(uint idx, list...) {
 89	const char[] BuildOpName = `on` ~ RebuildOpName!(list[idx]) ~ `(` ~ BuildOpParams!(0, idx+2, list) ~ `);`;
 90}
 91
 92template BuildCaseList(char[] optionstring, uint pos = 0) {
 93	static if (pos >= optionstring.length) {
 94		const char[] BuildCaseList = `case ` ~ "`" ~ optionstring ~ "`" ~ `:
 95				`;
 96	}
 97	else static if (optionstring[pos] == ',' || optionstring[pos] == ' ') {
 98		static if (Trim!(optionstring[0..pos]) == "") {
 99			const char[] BuildCaseList = BuildCaseList!(optionstring[pos+1..$], 0);
100		}
101		else {
102			const char[] BuildCaseList = `case ` ~ "`" ~ Trim!(optionstring[0..pos]) ~ "`" ~ `:
103			` ~ BuildCaseList!(optionstring[pos+1..$], 0);
104		}
105	}
106	else {
107		const char[] BuildCaseList = BuildCaseList!(optionstring, pos + 1);
108	}
109}
110
111template BuildArgumentItem(uint idx, list...) {
112	static if (idx >= list.length) {
113		const char[] BuildArgumentItem = ``;
114	}
115	else static if (list[idx].stringof[0] == '"') {
116		//pragma(msg, idx.stringof ~ "::" ~ list[idx].stringof);
117		const char[] BuildArgumentItem =
118				BuildCaseList!(list[idx])
119				~ BuildArgumentRetrieve!(0, idx+2, list)
120				~ BuildOpName!(idx, list)
121				~ "\n\t\t\t\t" ~ `break;
122
123			` ~ BuildArgumentItem!(idx+2, list);
124	}
125	else {
126		const char[] BuildArgumentItem = "" ~ BuildArgumentItem!(idx+2, list);
127	}
128}
129
130// assumptions: 'token' is a string to check
131template BuildArgumentParser(list...) {
132	const char[] BuildArgumentParser = `
133		switch(token) {
134			` ~ BuildArgumentItem!(0, list) ~ `
135			default:
136				// no option found
137				tokenFound = false;
138				break;
139		}
140	`;
141}
142
143template BuildUsagestring(char[] name, uint idx = 0) {
144	static if (idx >= name.length) {
145		const char[] BuildUsagestring = Trim!(name[0..idx]);
146	}
147	else static if (name[idx] == ',') {
148		const char[] BuildUsagestring = Trim!(name[0..idx]) ~ ", -" ~ BuildUsagestring!(name[idx+1..$], 0);
149	}
150	else {
151		const char[] BuildUsagestring = BuildUsagestring!(name, idx + 1);
152	}
153}
154
155template BuildUsageParameterList(uint idx, list...) {
156	static if (idx >= list.length) {
157		const char[] BuildUsageParameterList = ` `;
158	}
159	else static if (list[idx].stringof[0] == '"') {
160		const char[] BuildUsageParameterList = ` `;
161	}
162	else {
163		static if (list[idx].stringof == "char[]") {
164			// {string} is prettier, imho
165			const char[] BuildUsageParameterList = ` {string}` ~ BuildUsageParameterList!(idx+2, list);
166		}
167		else {
168			const char[] BuildUsageParameterList = ` {` ~ list[idx].stringof ~ `}` ~ BuildUsageParameterList!(idx+2, list);
169		}
170	}
171}
172
173template BuildUsageParameterPretty(char[] foo) {
174	const char[] BuildUsageParameterPretty = "           "[0..(11 - foo.length)] ~ foo;
175}
176
177template BuildUsageParameterDescList(uint idx, list...) {
178	static if (idx >= list.length) {
179		const char[] BuildUsageParameterDescList = ``;
180	}
181	else static if (list[idx].stringof[0] == '"') {
182		const char[] BuildUsageParameterDescList = ``;
183	}
184	else {
185		static if (list[idx].stringof == "char[]") {
186			// {string} is prettier, imho
187			const char[] BuildUsageParameterDescList = ` ` ~ BuildUsageParameterPretty!(`{string}`) ~ ` - ` ~ list[idx+1] ~ `\n` ~ BuildUsageParameterDescList!(idx+2, list);
188		}
189		else {
190			const char[] BuildUsageParameterDescList = ` ` ~ BuildUsageParameterPretty!(`{` ~ list[idx].stringof ~ `}`) ~ ` - ` ~ list[idx+1] ~ `\n` ~ BuildUsageParameterDescList!(idx+2, list);
191		}
192	}
193}
194
195template BuildUsageDesc(uint idx, list...) {
196	static if (idx >= list.length) {
197		const char[] BuildUsageDesc = ``;
198	}
199	else {
200		const char[] BuildUsageDesc = `_ConsoleIO.Console.putln("-` ~ BuildUsagestring!(list[idx]) ~ BuildUsageParameterList!(idx + 2, list) ~ `: ` ~ list[idx+1] ~ `");
201				_ConsoleIO.Console.putln("` ~ BuildUsageParameterDescList!(idx + 2, list) ~ `");
202			`;
203	}
204}
205
206template BuildUsageItem(uint idx, list...) {
207	static if (idx >= list.length) {
208		const char[] BuildUsageItem = ``;
209	}
210	else static if (list[idx].stringof[0] == '"') {
211		const char[] BuildUsageItem =
212				BuildCaseList!(list[idx])
213				~ BuildUsageDesc!(idx, list)
214				~ "\n\t\t\t\t" ~ `break;
215
216			` ~ BuildUsageItem!(idx+2, list);
217	}
218	else {
219		const char[] BuildUsageItem = "" ~ BuildUsageItem!(idx+2, list);
220	}
221}
222
223// Assumes 'option' contains the option to view
224template BuildUsagePrinter(list...) {
225	const char[] BuildUsagePrinter = `
226		switch(option) {
227			` ~ BuildUsageItem!(0, list) ~ `
228			default:
229				// no option
230				break;
231		}
232	`;
233}
234
235template BuildOpSimpleName(char[] name, uint idx = 0) {
236	static if (idx >= name.length) {
237		const char[] BuildOpSimpleName = Trim!(name[0..idx]);
238	}
239	else static if (name[idx] == ',') {
240		const char[] BuildOpSimpleName = Trim!(name[0..idx]);
241	}
242	else {
243		const char[] BuildOpSimpleName = BuildOpSimpleName!(name, idx + 1);
244	}
245}
246
247template BuildOpSortableName(char[] name, uint pos = 0) {
248	static if (pos >= name.length) {
249		const char[] BuildOpSortableName = ` ` ~ BuildOpSimpleName!(name);
250	}
251	else static if (name[pos] == '-') {
252		const char[] BuildOpSortableName = BuildOpSortableName!(name, pos + 1);
253	}
254	else {
255		const char[] BuildOpSortableName = name[pos..$] ~ ` ` ~ BuildOpSimpleName!(name);
256	}
257}
258
259template BuildOptionArray(uint idx, list...) {
260	static if (idx >= list.length) {
261		const char[] BuildOptionArray = ``;
262	}
263	else static if (list[idx].stringof[0] == '"') {
264		const char[] BuildOptionArray = `"` ~ BuildOpSortableName!(list[idx]) ~ `",
265			` ~ BuildOptionArray!(idx + 2, list);
266	}
267	else {
268		const char[] BuildOptionArray = BuildOptionArray!(idx + 2, list);
269	}
270}
271
272template BuildUsagePrinterAllDescPretty(char[] foo) {
273	static if (foo.length >= 40) {
274		const char[] BuildUsagePrinterAllDescPretty = foo;
275	}
276	else {
277		const char[] BuildUsagePrinterAllDescPretty = foo ~ "                                        "[0..35 - foo.length] ;
278	}
279}
280
281template BuildUsagePrinterAllDesc(uint idx, list...) {
282	static if (idx >= list.length) {
283		const char[] BuildUsagePrinterAllDesc = ``;
284	}
285	else static if (list[idx].stringof[0] == '"') {
286		const char[] BuildUsagePrinterAllDesc = `_ConsoleIO.Console.putln(" ` 
287				~ BuildUsagePrinterAllDescPretty!(Trim!(list[idx] ~ BuildUsageParameterList!(idx+2, list)))
288				~ ` - `
289				~ list[idx + 1]
290				~ `");`;
291	}
292	else {
293		const char[] BuildUsagePrinterAllDesc = "" ~ BuildUsagePrinterAllDesc!(idx+2, list);
294	}
295}
296
297template BuildUsagePrinterAllItem(uint idx, list...) {
298	static if (idx >= list.length) {
299		const char[] BuildUsagePrinterAllItem = ``;
300	}
301	else static if (list[idx].stringof[0] == '"') {
302		const char[] BuildUsagePrinterAllItem =
303				BuildCaseList!(list[idx])
304				~ BuildUsagePrinterAllDesc!(idx, list)
305				~ "\n\t\t\t\t" ~ `break;
306
307			` ~ BuildUsagePrinterAllItem!(idx+2, list);
308	}
309	else {
310		const char[] BuildUsagePrinterAllItem = "" ~ BuildUsagePrinterAllItem!(idx+2, list);
311	}
312}
313
314template BuildUsagePrinterAll(list...) {
315	const char[] BuildUsagePrinterAll = `
316		string[] options = [
317			` ~ Trim!(BuildOptionArray!(0, list))[0..$-1] ~ `
318		];
319
320		options.sort;
321
322		foreach(_opt; options) {
323			string _str = _opt.dup;
324			int pos = _str.findReverse(" ");
325			string option = _str[pos+1.._str.length];
326
327			switch (option) {
328			` ~ BuildUsagePrinterAllItem!(0, list) ~ `
329			default:
330				break;
331			}
332		}
333	`;
334}
335
336abstract class OptionParser {
337	this() {
338		parse();
339	}
340
341	void parse() {
342	}
343
344	void showUsage() {
345	}
346
347	void printUsage(string option) {
348	}
349
350	void onError(string option) {
351		// Default handler will print out the correct usage of the
352		// option and exit
353
354		_ConsoleIO.Console.putln("Error in syntax for option: -", option);
355		_ConsoleIO.Console.putln();
356		printUsage(option);
357		Djehuty.application.exit(0);
358	}
359}
360
361template Options(list...) {
362
363	// print out list of options
364	override string toString() {
365		return "";
366	}
367
368	override void showUsage() {
369
370		// Traditional header
371
372		_ConsoleIO.Console.putln("OVERVIEW: Application Name - Version - 0.0.0");
373		_ConsoleIO.Console.putln();
374		_ConsoleIO.Console.putln("USAGE: foo ");
375		_ConsoleIO.Console.putln();
376		_ConsoleIO.Console.putln("OPTIONS:");
377
378		// Followed by an alphabetical listing of options and their usage
379
380		//pragma(msg,BuildUsagePrinterAll!(list));
381		mixin(BuildUsagePrinterAll!(list));
382	}
383
384	override void printUsage(string option) {
385		char[] token;
386		//pragma(msg,BuildUsagePrinter!(list));
387		mixin(BuildUsagePrinter!(list));
388	}
389
390	override void parse() {
391		Arguments args = Arguments.instance;
392	//	_ConsoleIO.Console.putln(args.length);
393	//	foreach(var; args) {
394	//		_ConsoleIO.Console.putln(var);
395	//	}
396		char[] token;
397		string param;
398
399		for (uint i; i < args.length; ) {
400			string arg;
401
402			void pullArgument() {
403				arg = args.peekAt(i);
404				i++;
405			}
406
407			pullArgument();
408
409			if (arg[0] == '-') {
410				// it is an option
411				for (uint c = 1; c < arg.length; c++) {
412
413					string getParameter() {
414						string ret;
415						if (arg is null) {
416							return null;
417						}
418
419						if (c >= arg.length - 1) {
420							pullArgument();
421							ret = arg;
422						}
423						else {
424							ret = arg.substring(c+1);
425						}
426
427						if (ret !is null && ret.length > 0 && (ret[0] == '"' || ret[0] == '\'')) {
428							char lookingFor = ret[0];
429							// we have to look for the end of the string argument
430							while (!(ret[ret.length - 1] == lookingFor && (ret.length == 1 || ret[ret.length - 2] != '\\'))) {
431								pullArgument();
432								if (arg is null) {
433									onError(token);
434									return null;
435								}
436								ret ~= " ";
437								ret ~= arg;
438							}
439
440							// Replace escaped characters
441							char[] findStr = `\` ~ [lookingFor];
442							int pos = ret.find(findStr);
443							while (pos != -1) {
444								ret = (ret[0..pos] ~ [lookingFor] ~ ret[pos+2..ret.length]);
445								pos = ret.find(findStr, pos+1);
446							}
447							// good
448							ret = ret.substring(1, ret.length - 2);
449						}
450
451						if (arg !is null) {
452							c = arg.length;
453						}
454						return ret;
455					}
456
457					dchar chr = arg[c];
458
459					if (token.length == 0 && chr == '-' && c != 1) {
460						// incorrect
461						onError(token);
462						return;
463					}
464					token ~= chr;
465					bool tokenFound = true;
466
467					//pragma(msg,BuildArgumentParser!(list));
468
469					mixin(BuildArgumentParser!(list));
470
471					if (tokenFound) {
472						// interpretate and return the arguments
473						token = "";
474					}
475				}
476			}
477		}
478	}
479}