~ubuntu-branches/ubuntu/vivid/debtags/vivid-proposed

« back to all changes in this revision

Viewing changes to tools/CommandlineParser.cc

  • Committer: Bazaar Package Importer
  • Author(s): Enrico Zini
  • Date: 2006-03-18 20:31:47 UTC
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20060318203147-d9uzdeong5f5nk14
Tags: 1.5.5
* Added dumpavail command.
* Don't rebuild the database on install: apt-index-watcher does it instead.
  Closes: #357103.
* Compiles with g++ 4.1.  Closes: #357360.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Command line parser
3
 
 *
4
 
 * Copyright (C) 2003  Enrico Zini <enrico@debian.org>
5
 
 *
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.
10
 
 *
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.
15
 
 *
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
19
 
 */
20
 
 
21
 
#include "CommandlineParser.h"
22
 
#include <tagcoll/stringf.h>
23
 
#include <assert.h>
24
 
#include <ctype.h>
25
 
#include <stdlib.h>
26
 
#include <stdio.h>
27
 
 
28
 
using namespace std;
29
 
using namespace stringf;
30
 
 
31
 
string CommandlineParser::WordWrapper::get(unsigned int width) throw ()
32
 
{
33
 
        if (cursor >= s.size())
34
 
                return "";
35
 
        
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++)
39
 
        {
40
 
                if (s[j] == '\n')
41
 
                {
42
 
                        brk = j;
43
 
                        break;
44
 
                } else if (!isspace(s[j]) && (j + 1 == s.size() || isspace(s[j + 1])))
45
 
                        brk = j + 1;
46
 
        }
47
 
        if (brk == cursor)
48
 
                brk = cursor + width;
49
 
        
50
 
        string res;
51
 
        if (brk >= s.size())
52
 
        {
53
 
                res = string(s, cursor, string::npos);
54
 
                cursor = s.size();
55
 
        } else {
56
 
                res = string(s, cursor, brk - cursor);
57
 
                cursor = brk;
58
 
                while (cursor < s.size() && isspace(s[cursor]))
59
 
                        cursor++;
60
 
        }
61
 
        return res;
62
 
}
63
 
 
64
 
/*
65
 
string CommandlineParser::WordWrapper::get(unsigned int width) throw ()
66
 
{
67
 
        if (i >= s.size())
68
 
                return "";
69
 
        
70
 
        int k = width;
71
 
        while (k > 0 && k + i < s.size() && !isspace(s[i + k]))
72
 
                k--;
73
 
        if (k == 0)
74
 
                k = width;
75
 
 
76
 
        string res(s, i, k);
77
 
        i += k;
78
 
        return res;
79
 
}
80
 
*/
81
 
 
82
 
int CommandlineParser::option::intVal() const throw ()
83
 
{
84
 
        return atoi(_value.c_str());
85
 
}
86
 
 
87
 
const CommandlineParser::option& CommandlineParser::get(const string& name) const throw ()
88
 
{
89
 
        map<string, int>::const_iterator i = byname.find(name);
90
 
        if (i == byname.end())
91
 
        {
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));
95
 
        }
96
 
        assert (i != byname.end());
97
 
        const option& o = options[i->second];
98
 
        return o;
99
 
}
100
 
 
101
 
void CommandlineParser::add(const string& name, char shortopt, const string& longopt, const
102
 
                string& help, const string& valname, bool val_optional) throw ()
103
 
{
104
 
        options.push_back(option(name, shortopt, longopt, help, valname, val_optional));
105
 
        if (shortopt)
106
 
                shortopts.insert(pair<char, int>(shortopt, options.size() - 1));
107
 
        if (longopt.size())
108
 
                longopts.insert(pair<string, int>(longopt, options.size() - 1));
109
 
        byname.insert(pair<string, int>(name, options.size() - 1));
110
 
}
111
 
 
112
 
void CommandlineParser::printHelp() throw ()
113
 
{
114
 
        char* columns = getenv("COLUMNS");
115
 
        int width = columns ? atoi(columns) : 80;
116
 
        unsigned int summax = 0;
117
 
        vector<string> summaries;
118
 
 
119
 
        // Print the first usage line
120
 
        fprintf(stderr, "Usage: %.*s %.*s\n",
121
 
                        PFSTR(argv0), PFSTR(cmdline_summary));
122
 
        
123
 
        // Prepare switch summaries and compute their maximum width
124
 
        for (unsigned int i = 0; i < options.size(); i++)
125
 
        {
126
 
                string s;
127
 
                if (options[i]._shortopt)
128
 
                        s += string("-") + options[i]._shortopt;
129
 
                if (options[i]._longopt.size())
130
 
                {
131
 
                        if (s.size())
132
 
                                s += ", ";
133
 
                        s += "--" + options[i]._longopt;
134
 
                }
135
 
                if (options[i]._valname.size())
136
 
                {
137
 
                        string vname = options[i]._val_optional ?
138
 
                                                        "[" + options[i]._valname + "]"
139
 
                                                        : options[i]._valname;
140
 
                        if (options[i]._longopt.size())
141
 
                                s += "=" + vname;
142
 
                        else
143
 
                                s += " " + vname;
144
 
                }
145
 
                if (s.size() > summax)
146
 
                        summax = s.size();
147
 
                summaries.push_back(s);
148
 
        }
149
 
 
150
 
        // Print the help
151
 
        for (unsigned int i = 0; i < options.size(); i++)
152
 
        {
153
 
                WordWrapper ww(options[i]._help);
154
 
 
155
 
                string h = ww.get(width - summax - 4);
156
 
                fprintf(stderr, "  %-*.*s  %.*s\n",
157
 
                                        summax, summax, summaries[i].c_str(), PFSTR(h));
158
 
 
159
 
                while (ww.hasData())
160
 
                {
161
 
                        string h = ww.get(width - summax - 4);
162
 
                        fprintf(stderr, "  %-*.*s  %.*s\n",
163
 
                                        summax, summax, "", PFSTR(h));
164
 
                }
165
 
        }
166
 
 
167
 
        fputc('\n', stderr);
168
 
 
169
 
        fprintf(stderr, "%.*s\n", PFSTR(description));
170
 
        /*
171
 
        WordWrapper ww(description);
172
 
        while (ww.hasData())
173
 
        {
174
 
                string h = ww.get(width);
175
 
                fprintf(stderr, "%.*s\n", PFSTR(h));
176
 
        }
177
 
        */
178
 
}
179
 
 
180
 
bool CommandlineParser::parseLongOption(const string& name, const string& value)
181
 
        throw ()
182
 
{
183
 
        // Have argument
184
 
        map<string, int>::iterator o = longopts.find(name);
185
 
        if (o == longopts.end())
186
 
        {
187
 
                fprintf(stderr, "Unknown option name: %.*s\n", PFSTR(name));
188
 
                return false;
189
 
        }
190
 
        options[o->second]._defined = true;
191
 
        
192
 
        if (options[o->second]._valname.size())
193
 
        {
194
 
                if (value.size())
195
 
                        options[o->second]._value = value;
196
 
                else if (!options[o->second]._val_optional)
197
 
                {
198
 
                        fprintf(stderr, "Option %.*s requires the %.*s argument\n",
199
 
                                        PFSTR(name), PFSTR(options[o->second]._valname));
200
 
                        return false;
201
 
                }
202
 
        }
203
 
        return true;
204
 
}
205
 
 
206
 
bool CommandlineParser::parseShortOption(char opt, const string& value)
207
 
        throw ()
208
 
{
209
 
        // Have argument
210
 
        map<char, int>::iterator o = shortopts.find(opt);
211
 
        if (o == shortopts.end())
212
 
        {
213
 
                fprintf(stderr, "Unknown option: `%c'\n", opt);
214
 
                return false;
215
 
        }
216
 
        options[o->second]._defined = true;
217
 
 
218
 
        if (options[o->second]._valname.size())
219
 
        {
220
 
                if (value.size())
221
 
                        options[o->second]._value = value;
222
 
                else if (!options[o->second]._val_optional)
223
 
                {
224
 
                        fprintf(stderr, "Option `%c' requires the %.*s argument\n",
225
 
                                        opt, PFSTR(options[o->second]._valname));
226
 
                        return false;
227
 
                }
228
 
        }
229
 
        return true;
230
 
}
231
 
 
232
 
bool CommandlineParser::parse(int& argc, const char**& argv) throw ()
233
 
{
234
 
        int nargc = 1;
235
 
        bool success = true;
236
 
        bool parses_opts = true;
237
 
 
238
 
        for (int i = 1; i < argc; i++)
239
 
        {
240
 
                if (parses_opts && argv[i][0] == '-' && argv[i][1] != 0)
241
 
                {
242
 
                        if (argv[i][1] == '-')
243
 
                        {
244
 
                                if (argv[i][2] == 0)
245
 
                                        // -- option terminator
246
 
                                        parses_opts = false;
247
 
                                else
248
 
                                {
249
 
                                        // Long option
250
 
                                        string optName = string(argv[i], 2, string::npos);
251
 
                                        unsigned int eqsign = optName.find('=');
252
 
                                        if (eqsign == string::npos)
253
 
                                        {
254
 
                                                // No argument
255
 
                                                if (!parseLongOption(optName))
256
 
                                                        success = false;
257
 
                                        } else {
258
 
                                                // With argument
259
 
                                                if (!parseLongOption(optName.substr(0, eqsign),
260
 
                                                                        optName.substr(eqsign + 1)))
261
 
                                                        success = false;
262
 
                                        }
263
 
                                }
264
 
                        }
265
 
                        else
266
 
                        {
267
 
                                // Short option(s)
268
 
                                if (argv[i][2] == 0)
269
 
                                {
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())
274
 
                                        {
275
 
                                                fprintf(stderr, "Unknown option: `%c'\n", opt);
276
 
                                                return false;
277
 
                                        }
278
 
                                        if (options[o->second]._valname.size())
279
 
                                        {
280
 
                                                // Accepts arguments
281
 
                                                if (argv[i + 1] && argv[i + 1][0] != '-')
282
 
                                                {
283
 
                                                        // Is followed by an argument
284
 
                                                        i++;
285
 
                                                        if (!parseShortOption(opt, argv[i]))
286
 
                                                                success = false;
287
 
                                                } else
288
 
                                                        // Is not followed by an argument
289
 
                                                        if (!parseShortOption(opt))
290
 
                                                                success = false;
291
 
                                        } else
292
 
                                                // Does not accept arguments
293
 
                                                if (!parseShortOption(opt))
294
 
                                                        success = false;
295
 
                                } else {
296
 
                                        // Packed short options
297
 
                                        for (const char* s = argv[i] + 1; *s; s++)
298
 
                                                if (!parseShortOption(*s))
299
 
                                                        success = false;
300
 
                                }
301
 
                        }
302
 
                }
303
 
                else
304
 
                {
305
 
                        // Not a switch: keep it in the new argv
306
 
                        if (i != nargc)
307
 
                                argv[nargc] = argv[i];
308
 
                        nargc++;
309
 
                }       
310
 
        }
311
 
        argc = nargc;
312
 
        argv[nargc] = 0;
313
 
        return success;
314
 
}
315
 
 
316
 
// vim:set ts=4 sw=4: