4
* Copyright (C) 2003 Enrico Zini <enrico@debian.org>
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#include "CommandlineParser.h"
22
#include <tagcoll/stringf.h>
29
using namespace stringf;
31
string CommandlineParser::WordWrapper::get(unsigned int width) throw ()
33
if (cursor >= s.size())
36
// Find the last work break before `width'
37
unsigned int brk = cursor;
38
for (unsigned int j = cursor; j < s.size() && j < cursor + width; j++)
44
} else if (!isspace(s[j]) && (j + 1 == s.size() || isspace(s[j + 1])))
53
res = string(s, cursor, string::npos);
56
res = string(s, cursor, brk - cursor);
58
while (cursor < s.size() && isspace(s[cursor]))
65
string CommandlineParser::WordWrapper::get(unsigned int width) throw ()
71
while (k > 0 && k + i < s.size() && !isspace(s[i + k]))
82
int CommandlineParser::option::intVal() const throw ()
84
return atoi(_value.c_str());
87
const CommandlineParser::option& CommandlineParser::get(const string& name) const throw ()
89
map<string, int>::const_iterator i = byname.find(name);
90
if (i == byname.end())
92
fprintf(stderr, "Program error: requested info about nonexistant commandline option \"%.*s\".\nAvailable: \n", PFSTR(name));
93
for (i = byname.begin(); i != byname.end(); i++)
94
fprintf(stderr, " \"%.*s\"\n", PFSTR(i->first));
96
assert (i != byname.end());
97
const option& o = options[i->second];
101
void CommandlineParser::add(const string& name, char shortopt, const string& longopt, const
102
string& help, const string& valname, bool val_optional) throw ()
104
options.push_back(option(name, shortopt, longopt, help, valname, val_optional));
106
shortopts.insert(pair<char, int>(shortopt, options.size() - 1));
108
longopts.insert(pair<string, int>(longopt, options.size() - 1));
109
byname.insert(pair<string, int>(name, options.size() - 1));
112
void CommandlineParser::printHelp() throw ()
114
char* columns = getenv("COLUMNS");
115
int width = columns ? atoi(columns) : 80;
116
unsigned int summax = 0;
117
vector<string> summaries;
119
// Print the first usage line
120
fprintf(stderr, "Usage: %.*s %.*s\n",
121
PFSTR(argv0), PFSTR(cmdline_summary));
123
// Prepare switch summaries and compute their maximum width
124
for (unsigned int i = 0; i < options.size(); i++)
127
if (options[i]._shortopt)
128
s += string("-") + options[i]._shortopt;
129
if (options[i]._longopt.size())
133
s += "--" + options[i]._longopt;
135
if (options[i]._valname.size())
137
string vname = options[i]._val_optional ?
138
"[" + options[i]._valname + "]"
139
: options[i]._valname;
140
if (options[i]._longopt.size())
145
if (s.size() > summax)
147
summaries.push_back(s);
151
for (unsigned int i = 0; i < options.size(); i++)
153
WordWrapper ww(options[i]._help);
155
string h = ww.get(width - summax - 4);
156
fprintf(stderr, " %-*.*s %.*s\n",
157
summax, summax, summaries[i].c_str(), PFSTR(h));
161
string h = ww.get(width - summax - 4);
162
fprintf(stderr, " %-*.*s %.*s\n",
163
summax, summax, "", PFSTR(h));
169
fprintf(stderr, "%.*s\n", PFSTR(description));
171
WordWrapper ww(description);
174
string h = ww.get(width);
175
fprintf(stderr, "%.*s\n", PFSTR(h));
180
bool CommandlineParser::parseLongOption(const string& name, const string& value)
184
map<string, int>::iterator o = longopts.find(name);
185
if (o == longopts.end())
187
fprintf(stderr, "Unknown option name: %.*s\n", PFSTR(name));
190
options[o->second]._defined = true;
192
if (options[o->second]._valname.size())
195
options[o->second]._value = value;
196
else if (!options[o->second]._val_optional)
198
fprintf(stderr, "Option %.*s requires the %.*s argument\n",
199
PFSTR(name), PFSTR(options[o->second]._valname));
206
bool CommandlineParser::parseShortOption(char opt, const string& value)
210
map<char, int>::iterator o = shortopts.find(opt);
211
if (o == shortopts.end())
213
fprintf(stderr, "Unknown option: `%c'\n", opt);
216
options[o->second]._defined = true;
218
if (options[o->second]._valname.size())
221
options[o->second]._value = value;
222
else if (!options[o->second]._val_optional)
224
fprintf(stderr, "Option `%c' requires the %.*s argument\n",
225
opt, PFSTR(options[o->second]._valname));
232
bool CommandlineParser::parse(int& argc, const char**& argv) throw ()
236
bool parses_opts = true;
238
for (int i = 1; i < argc; i++)
240
if (parses_opts && argv[i][0] == '-' && argv[i][1] != 0)
242
if (argv[i][1] == '-')
245
// -- option terminator
250
string optName = string(argv[i], 2, string::npos);
251
unsigned int eqsign = optName.find('=');
252
if (eqsign == string::npos)
255
if (!parseLongOption(optName))
259
if (!parseLongOption(optName.substr(0, eqsign),
260
optName.substr(eqsign + 1)))
270
// Unpacked short option, might have an argument
271
char opt = argv[i][1];
272
map<char, int>::iterator o = shortopts.find(opt);
273
if (o == shortopts.end())
275
fprintf(stderr, "Unknown option: `%c'\n", opt);
278
if (options[o->second]._valname.size())
281
if (argv[i + 1] && argv[i + 1][0] != '-')
283
// Is followed by an argument
285
if (!parseShortOption(opt, argv[i]))
288
// Is not followed by an argument
289
if (!parseShortOption(opt))
292
// Does not accept arguments
293
if (!parseShortOption(opt))
296
// Packed short options
297
for (const char* s = argv[i] + 1; *s; s++)
298
if (!parseShortOption(*s))
305
// Not a switch: keep it in the new argv
307
argv[nargc] = argv[i];
316
// vim:set ts=4 sw=4: