Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
480 lines (419 sloc) 12.1 KB
/*
* options.d
*
* This module implements a mechanism to read in command line options.
*
* Author: Dave Wilkinson
* Originated: September 28th, 2009
*
*/
module parsing.options;
import core.util;
import core.string;
import core.definitions;
import core.arguments;
import core.main;
public import _ConsoleIO = io.console;
template BuildArgumentRetrieval(T) {
//pragma(msg, T.stringof);
static if (is(T == char)) {
const char[] BuildArgumentRetrieval = `(param)[0];`;
}
else static if (IsSigned!(T)) {
const char[] BuildArgumentRetrieval = `cast(` ~ T.stringof ~ `)param.toInt();`;
}
else {
const char[] BuildArgumentRetrieval = `param;`;
}
}
template BuildArgumentRetrieve(uint argidx, uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildArgumentRetrieve = ``;
}
else static if (list[idx].stringof[0] != '"') {
const char[] BuildArgumentRetrieve = `param = getParameter();`
~ "\n\t\t\t\t"
~ `if (param is null) { onError(token); return; } `
~ "\n\t\t\t\t"
~ list[idx].stringof ~ ` arg` ~ argidx.stringof[0..$-1] ~ ` = `
~ BuildArgumentRetrieval!(list[idx])
~ "\n\t\t\t\t"
~ BuildArgumentRetrieve!(argidx+1,idx+2, list);
}
else {
// no more parameters
const char[] BuildArgumentRetrieve = ``;
}
}
template BuildOpParams(uint argidx, uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildOpParams = ``;
}
else static if (argidx == 0) {
static if (list[idx].stringof[0] != '"') {
const char[] BuildOpParams = `arg0` ~ BuildOpParams!(argidx+1, idx+2, list);
}
else {
const char[] BuildOpParams = ``;
}
}
else {
static if (list[idx].stringof[0] != '"') {
const char[] BuildOpParams = `, arg` ~ argidx.stringof[0..$-1] ~ BuildOpParams!(argidx+1, idx+2, list);
}
else {
const char[] BuildOpParams = ``;
}
}
}
template RebuildOpName(char[] name, uint idx = 0) {
static if (idx >= name.length || name == "" || name[idx] == ',' || name[idx] == ' ') {
const char[] RebuildOpName = Capitalize!(name[0..idx]);
}
else static if (name[idx] == '-') {
const char[] RebuildOpName = Capitalize!(name[0..idx]) ~ RebuildOpName!(name[idx+1..$], 0);
}
else {
const char[] RebuildOpName = RebuildOpName!(name, idx + 1);
}
}
template BuildOpName(uint idx, list...) {
const char[] BuildOpName = `on` ~ RebuildOpName!(list[idx]) ~ `(` ~ BuildOpParams!(0, idx+2, list) ~ `);`;
}
template BuildCaseList(char[] optionstring, uint pos = 0) {
static if (pos >= optionstring.length) {
const char[] BuildCaseList = `case ` ~ "`" ~ optionstring ~ "`" ~ `:
`;
}
else static if (optionstring[pos] == ',' || optionstring[pos] == ' ') {
static if (Trim!(optionstring[0..pos]) == "") {
const char[] BuildCaseList = BuildCaseList!(optionstring[pos+1..$], 0);
}
else {
const char[] BuildCaseList = `case ` ~ "`" ~ Trim!(optionstring[0..pos]) ~ "`" ~ `:
` ~ BuildCaseList!(optionstring[pos+1..$], 0);
}
}
else {
const char[] BuildCaseList = BuildCaseList!(optionstring, pos + 1);
}
}
template BuildArgumentItem(uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildArgumentItem = ``;
}
else static if (list[idx].stringof[0] == '"') {
//pragma(msg, idx.stringof ~ "::" ~ list[idx].stringof);
const char[] BuildArgumentItem =
BuildCaseList!(list[idx])
~ BuildArgumentRetrieve!(0, idx+2, list)
~ BuildOpName!(idx, list)
~ "\n\t\t\t\t" ~ `break;
` ~ BuildArgumentItem!(idx+2, list);
}
else {
const char[] BuildArgumentItem = "" ~ BuildArgumentItem!(idx+2, list);
}
}
// assumptions: 'token' is a string to check
template BuildArgumentParser(list...) {
const char[] BuildArgumentParser = `
switch(token) {
` ~ BuildArgumentItem!(0, list) ~ `
default:
// no option found
tokenFound = false;
break;
}
`;
}
template BuildUsagestring(char[] name, uint idx = 0) {
static if (idx >= name.length) {
const char[] BuildUsagestring = Trim!(name[0..idx]);
}
else static if (name[idx] == ',') {
const char[] BuildUsagestring = Trim!(name[0..idx]) ~ ", -" ~ BuildUsagestring!(name[idx+1..$], 0);
}
else {
const char[] BuildUsagestring = BuildUsagestring!(name, idx + 1);
}
}
template BuildUsageParameterList(uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildUsageParameterList = ` `;
}
else static if (list[idx].stringof[0] == '"') {
const char[] BuildUsageParameterList = ` `;
}
else {
static if (list[idx].stringof == "char[]") {
// {string} is prettier, imho
const char[] BuildUsageParameterList = ` {string}` ~ BuildUsageParameterList!(idx+2, list);
}
else {
const char[] BuildUsageParameterList = ` {` ~ list[idx].stringof ~ `}` ~ BuildUsageParameterList!(idx+2, list);
}
}
}
template BuildUsageParameterPretty(char[] foo) {
const char[] BuildUsageParameterPretty = " "[0..(11 - foo.length)] ~ foo;
}
template BuildUsageParameterDescList(uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildUsageParameterDescList = ``;
}
else static if (list[idx].stringof[0] == '"') {
const char[] BuildUsageParameterDescList = ``;
}
else {
static if (list[idx].stringof == "char[]") {
// {string} is prettier, imho
const char[] BuildUsageParameterDescList = ` ` ~ BuildUsageParameterPretty!(`{string}`) ~ ` - ` ~ list[idx+1] ~ `\n` ~ BuildUsageParameterDescList!(idx+2, list);
}
else {
const char[] BuildUsageParameterDescList = ` ` ~ BuildUsageParameterPretty!(`{` ~ list[idx].stringof ~ `}`) ~ ` - ` ~ list[idx+1] ~ `\n` ~ BuildUsageParameterDescList!(idx+2, list);
}
}
}
template BuildUsageDesc(uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildUsageDesc = ``;
}
else {
const char[] BuildUsageDesc = `_ConsoleIO.Console.putln("-` ~ BuildUsagestring!(list[idx]) ~ BuildUsageParameterList!(idx + 2, list) ~ `: ` ~ list[idx+1] ~ `");
_ConsoleIO.Console.putln("` ~ BuildUsageParameterDescList!(idx + 2, list) ~ `");
`;
}
}
template BuildUsageItem(uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildUsageItem = ``;
}
else static if (list[idx].stringof[0] == '"') {
const char[] BuildUsageItem =
BuildCaseList!(list[idx])
~ BuildUsageDesc!(idx, list)
~ "\n\t\t\t\t" ~ `break;
` ~ BuildUsageItem!(idx+2, list);
}
else {
const char[] BuildUsageItem = "" ~ BuildUsageItem!(idx+2, list);
}
}
// Assumes 'option' contains the option to view
template BuildUsagePrinter(list...) {
const char[] BuildUsagePrinter = `
switch(option) {
` ~ BuildUsageItem!(0, list) ~ `
default:
// no option
break;
}
`;
}
template BuildOpSimpleName(char[] name, uint idx = 0) {
static if (idx >= name.length) {
const char[] BuildOpSimpleName = Trim!(name[0..idx]);
}
else static if (name[idx] == ',') {
const char[] BuildOpSimpleName = Trim!(name[0..idx]);
}
else {
const char[] BuildOpSimpleName = BuildOpSimpleName!(name, idx + 1);
}
}
template BuildOpSortableName(char[] name, uint pos = 0) {
static if (pos >= name.length) {
const char[] BuildOpSortableName = ` ` ~ BuildOpSimpleName!(name);
}
else static if (name[pos] == '-') {
const char[] BuildOpSortableName = BuildOpSortableName!(name, pos + 1);
}
else {
const char[] BuildOpSortableName = name[pos..$] ~ ` ` ~ BuildOpSimpleName!(name);
}
}
template BuildOptionArray(uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildOptionArray = ``;
}
else static if (list[idx].stringof[0] == '"') {
const char[] BuildOptionArray = `"` ~ BuildOpSortableName!(list[idx]) ~ `",
` ~ BuildOptionArray!(idx + 2, list);
}
else {
const char[] BuildOptionArray = BuildOptionArray!(idx + 2, list);
}
}
template BuildUsagePrinterAllDescPretty(char[] foo) {
static if (foo.length >= 40) {
const char[] BuildUsagePrinterAllDescPretty = foo;
}
else {
const char[] BuildUsagePrinterAllDescPretty = foo ~ " "[0..35 - foo.length] ;
}
}
template BuildUsagePrinterAllDesc(uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildUsagePrinterAllDesc = ``;
}
else static if (list[idx].stringof[0] == '"') {
const char[] BuildUsagePrinterAllDesc = `_ConsoleIO.Console.putln(" `
~ BuildUsagePrinterAllDescPretty!(Trim!(list[idx] ~ BuildUsageParameterList!(idx+2, list)))
~ ` - `
~ list[idx + 1]
~ `");`;
}
else {
const char[] BuildUsagePrinterAllDesc = "" ~ BuildUsagePrinterAllDesc!(idx+2, list);
}
}
template BuildUsagePrinterAllItem(uint idx, list...) {
static if (idx >= list.length) {
const char[] BuildUsagePrinterAllItem = ``;
}
else static if (list[idx].stringof[0] == '"') {
const char[] BuildUsagePrinterAllItem =
BuildCaseList!(list[idx])
~ BuildUsagePrinterAllDesc!(idx, list)
~ "\n\t\t\t\t" ~ `break;
` ~ BuildUsagePrinterAllItem!(idx+2, list);
}
else {
const char[] BuildUsagePrinterAllItem = "" ~ BuildUsagePrinterAllItem!(idx+2, list);
}
}
template BuildUsagePrinterAll(list...) {
const char[] BuildUsagePrinterAll = `
string[] options = [
` ~ Trim!(BuildOptionArray!(0, list))[0..$-1] ~ `
];
options.sort;
foreach(_opt; options) {
string _str = _opt.dup;
int pos = _str.findReverse(" ");
string option = _str[pos+1.._str.length];
switch (option) {
` ~ BuildUsagePrinterAllItem!(0, list) ~ `
default:
break;
}
}
`;
}
abstract class OptionParser {
this() {
parse();
}
void parse() {
}
void showUsage() {
}
void printUsage(string option) {
}
void onError(string option) {
// Default handler will print out the correct usage of the
// option and exit
_ConsoleIO.Console.putln("Error in syntax for option: -", option);
_ConsoleIO.Console.putln();
printUsage(option);
Djehuty.application.exit(0);
}
}
template Options(list...) {
// print out list of options
override string toString() {
return "";
}
override void showUsage() {
// Traditional header
_ConsoleIO.Console.putln("OVERVIEW: Application Name - Version - 0.0.0");
_ConsoleIO.Console.putln();
_ConsoleIO.Console.putln("USAGE: foo ");
_ConsoleIO.Console.putln();
_ConsoleIO.Console.putln("OPTIONS:");
// Followed by an alphabetical listing of options and their usage
//pragma(msg,BuildUsagePrinterAll!(list));
mixin(BuildUsagePrinterAll!(list));
}
override void printUsage(string option) {
char[] token;
//pragma(msg,BuildUsagePrinter!(list));
mixin(BuildUsagePrinter!(list));
}
override void parse() {
Arguments args = Arguments.instance;
// _ConsoleIO.Console.putln(args.length);
// foreach(var; args) {
// _ConsoleIO.Console.putln(var);
// }
char[] token;
string param;
for (uint i; i < args.length; ) {
string arg;
void pullArgument() {
arg = args.peekAt(i);
i++;
}
pullArgument();
if (arg[0] == '-') {
// it is an option
for (uint c = 1; c < arg.length; c++) {
string getParameter() {
string ret;
if (arg is null) {
return null;
}
if (c >= arg.length - 1) {
pullArgument();
ret = arg;
}
else {
ret = arg.substring(c+1);
}
if (ret !is null && ret.length > 0 && (ret[0] == '"' || ret[0] == '\'')) {
char lookingFor = ret[0];
// we have to look for the end of the string argument
while (!(ret[ret.length - 1] == lookingFor && (ret.length == 1 || ret[ret.length - 2] != '\\'))) {
pullArgument();
if (arg is null) {
onError(token);
return null;
}
ret ~= " ";
ret ~= arg;
}
// Replace escaped characters
char[] findStr = `\` ~ [lookingFor];
int pos = ret.find(findStr);
while (pos != -1) {
ret = (ret[0..pos] ~ [lookingFor] ~ ret[pos+2..ret.length]);
pos = ret.find(findStr, pos+1);
}
// good
ret = ret.substring(1, ret.length - 2);
}
if (arg !is null) {
c = arg.length;
}
return ret;
}
dchar chr = arg[c];
if (token.length == 0 && chr == '-' && c != 1) {
// incorrect
onError(token);
return;
}
token ~= chr;
bool tokenFound = true;
//pragma(msg,BuildArgumentParser!(list));
mixin(BuildArgumentParser!(list));
if (tokenFound) {
// interpretate and return the arguments
token = "";
}
}
}
}
}
}