aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/unit++/optmap.cc
blob: 9e65d8497c94655e17e5a2f9226e5a483821e416 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright (C) 2001 Claus Dr�by
// Terms of use are in the file COPYING
#include <iostream>
#include <cstdlib>
#include "optmap.h"

using namespace std;
using namespace options_utils;

optmap::optmap(const char* usage)
: i(1), prog("program"), tail(usage)
{
}

optmap::~optmap()
{
	for (group_t::iterator p = group.begin(); p != group.end(); ++p)
		delete p->first;
}
optmap& optmap::add(const char* c, cmd* h)
{
	if (cmds.find(c) != cmds.end())
		throw invalid_argument(string("duplicated option: ")+c);
	cmds[c] = h;
	if (group[h].size() == 0)
		gvec.push_back(h);
	group[h].push_back(c);
	return *this;
}

optmap& optmap::alias(const char* new_opt, const char* old_opt)
{
	cmd* h = cmds[old_opt];
	if (!h)
		throw invalid_argument(string("no alias: ")+old_opt);
	return add(new_opt, h);
}
bool optmap::parse(int c, const char** v)
{
	argc = c;
	argv = v;
	prog = argv[0];
	for (; i < argc; ++i) {
		multichar = false;
		const char* s = argv[i];
		size_t l = strlen(s);
		if (*s != '-' || l == 1)
			return true;
		if (s[1] == '-') {
			if (l == 2) { // end of options marker `--'
				++i;
				return true;
			}
			if (!do_cmd(s+2))
				return false;
		} else {
			char cmd[2];
			cmd[1] = '\0';
			multichar = l > 2;
			first_multi = true;
			for (const char* p = s+1; *p; ++p) {
				cmd[0] = *p;
				if (!do_cmd(cmd))
					return false;;
				first_multi = false;
				if (!multichar) // get_arg used it
					break;
			}
		}
	}
	return true;
}

const char* optmap::get_arg()
{
	if (multichar) {
		if (!first_multi) {
			cerr << "internal option requires argument " << argv[i] << endl;
			return 0;
		}
		multichar = false;
		return argv[i]+2;
	}
	return i < argc - 1 ? argv[++i] : 0;
}

void optmap::usage(bool abort)
{
	cerr << "usage: " << prog;
	for (gvec_t::iterator p = gvec.begin(); p != gvec.end(); ++p) {
		cmd* h = *p;
		vector<string>& v(group[h]);
		string arg = h->arg();
		bool need_par = arg.size() > 0 && v.size() > 1;
		bool first = true;
		cerr << " [";
		if (need_par)
			cerr << "(";
		for (vector<string>::iterator s = v.begin(); s != v.end(); ++s) {
			cerr << (first ? " " : " | ") << (s->size() != 1 ? "--":"-") << *s;
			first = false;
		}
		if (need_par)
			cerr << ")";
		if (arg.size())
			cerr << ' ' << arg;
		cerr << " ]";
	}
	cerr << (tail.size() ? " " : "") << tail << endl;
	if (abort)
		exit(1);
}

bool optmap::do_cmd(const string& opt)
{
	cmd* c = cmds[opt];
	if (!c) {
		cerr << "unknown option: " << opt << endl;
		return false;
	}
	return c->do_cmd(this);
}

bool opt_int::do_cmd(optmap* om)
{
	const char* arg = om->get_arg();
	if (!arg)
		return false;
	char* end;
	int v = strtol(arg, &end, 10);
	if (*end) {
		cerr << "failed to parse int argument: " << arg << endl;
		return false;
	}
	val = v;
	return true;
}
bool opt_string::do_cmd(optmap* om)
{
	const char* arg = om->get_arg();
	if (!arg)
		return false;
	val = arg;
	return true;
}