]> git.saurik.com Git - apt.git/blame - apt-pkg/contrib/cmndline.cc
More CD support
[apt.git] / apt-pkg / contrib / cmndline.cc
CommitLineData
08e8f724
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
bc4af0b9 3// $Id: cmndline.cc,v 1.6 1998/11/25 23:54:22 jgg Exp $
08e8f724
AL
4/* ######################################################################
5
6 Command Line Class - Sophisticated command line parser
7
8 ##################################################################### */
9 /*}}}*/
10// Include files /*{{{*/
11#ifdef __GNUG__
12#pragma implementation "apt-pkg/cmndline.h"
13#endif
14#include <apt-pkg/cmndline.h>
15#include <apt-pkg/error.h>
16#include <strutl.h>
17 /*}}}*/
18
19// CommandLine::CommandLine - Constructor /*{{{*/
20// ---------------------------------------------------------------------
21/* */
22CommandLine::CommandLine(Args *AList,Configuration *Conf) : ArgList(AList),
23 Conf(Conf), FileList(0)
24{
e1b74f61
AL
25}
26 /*}}}*/
27// CommandLine::~CommandLine - Destructor /*{{{*/
28// ---------------------------------------------------------------------
29/* */
30CommandLine::~CommandLine()
31{
32 delete [] FileList;
08e8f724
AL
33}
34 /*}}}*/
35// CommandLine::Parse - Main action member /*{{{*/
36// ---------------------------------------------------------------------
37/* */
38bool CommandLine::Parse(int argc,const char **argv)
39{
e1b74f61 40 delete [] FileList;
08e8f724
AL
41 FileList = new const char *[argc];
42 const char **Files = FileList;
43 int I;
44 for (I = 1; I != argc; I++)
45 {
46 const char *Opt = argv[I];
47
48 // It is not an option
49 if (*Opt != '-')
50 {
51 *Files++ = Opt;
52 continue;
53 }
54
55 Opt++;
56
57 // Double dash signifies the end of option processing
58 if (*Opt == '-' && Opt[1] == 0)
59 break;
60
61 // Single dash is a short option
62 if (*Opt != '-')
63 {
64 // Iterate over each letter
65 while (*Opt != 0)
66 {
67 // Search for the option
68 Args *A;
69 for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++);
70 if (A->end() == true)
71 return _error->Error("Command line option '%c' [from %s] is not known.",*Opt,argv[I]);
72
73 if (HandleOpt(I,argc,argv,Opt,A) == false)
74 return false;
75 if (*Opt != 0)
76 Opt++;
77 }
78 continue;
79 }
80
81 Opt++;
82
83 // Match up to a = against the list
84 const char *OptEnd = Opt;
85 Args *A;
86 for (; *OptEnd != 0 && *OptEnd != '='; OptEnd++);
87 for (A = ArgList; A->end() == false &&
88 stringcasecmp(Opt,OptEnd,A->LongOpt) != 0; A++);
89
90 // Failed, look for a word after the first - (no-foo)
0d47bd08 91 bool PreceedMatch = false;
08e8f724
AL
92 if (A->end() == true)
93 {
94 for (; Opt != OptEnd && *Opt != '-'; Opt++);
95
96 if (Opt == OptEnd)
97 return _error->Error("Command line option %s is not understood",argv[I]);
98 Opt++;
0d47bd08 99 cout << Opt << endl;
08e8f724
AL
100
101 for (A = ArgList; A->end() == false &&
102 stringcasecmp(Opt,OptEnd,A->LongOpt) != 0; A++);
103
104 // Failed again..
105 if (A->end() == true && OptEnd - Opt != 1)
106 return _error->Error("Command line option %s is not understood",argv[I]);
0d47bd08 107
08e8f724 108 // The option could be a single letter option prefixed by a no-..
08e8f724 109 if (A->end() == true)
0d47bd08
AL
110 {
111 for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++);
112
113 if (A->end() == true)
114 return _error->Error("Command line option %s is not understood",argv[I]);
115 }
e1b74f61
AL
116
117 // The option is not boolean
118 if (A->IsBoolean() == false)
119 return _error->Error("Command line option %s is not boolean",argv[I]);
0d47bd08 120 PreceedMatch = true;
08e8f724
AL
121 }
122
123 // Deal with it.
124 OptEnd--;
0d47bd08 125 if (HandleOpt(I,argc,argv,OptEnd,A,PreceedMatch) == false)
08e8f724
AL
126 return false;
127 }
128
129 // Copy any remaining file names over
130 for (; I != argc; I++)
131 *Files++ = argv[I];
132 *Files = 0;
133
134 return true;
135}
136 /*}}}*/
137// CommandLine::HandleOpt - Handle a single option including all flags /*{{{*/
138// ---------------------------------------------------------------------
139/* This is a helper function for parser, it looks at a given argument
140 and looks for specific patterns in the string, it gets tokanized
141 -ruffly- like -*[yes|true|enable]-(o|longopt)[=][ ][argument] */
142bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
0d47bd08 143 const char *&Opt,Args *A,bool PreceedMatch)
08e8f724
AL
144{
145 const char *Argument = 0;
146 bool CertainArg = false;
147 int IncI = 0;
148
149 /* Determine the possible location of an option or 0 if their is
150 no option */
151 if (Opt[1] == 0 || (Opt[1] == '=' && Opt[2] == 0))
152 {
153 if (I + 1 < argc && argv[I+1][0] != '-')
154 Argument = argv[I+1];
155
156 // Equals was specified but we fell off the end!
157 if (Opt[1] == '=' && Argument == 0)
158 return _error->Error("Option %s requires an argument.",argv[I]);
159 if (Opt[1] == '=')
160 CertainArg = true;
161
162 IncI = 1;
163 }
164 else
165 {
166 if (Opt[1] == '=')
167 {
168 CertainArg = true;
169 Argument = Opt + 2;
170 }
171 else
172 Argument = Opt + 1;
173 }
0d47bd08 174
08e8f724
AL
175 // Option is an argument set
176 if ((A->Flags & HasArg) == HasArg)
177 {
178 if (Argument == 0)
179 return _error->Error("Option %s requires an argument.",argv[I]);
180 Opt += strlen(Opt);
181 I += IncI;
182
183 // Parse a configuration file
184 if ((A->Flags & ConfigFile) == ConfigFile)
185 return ReadConfigFile(*Conf,Argument);
e1b74f61
AL
186
187 // Arbitary item specification
188 if ((A->Flags & ArbItem) == ArbItem)
189 {
190 const char *J;
191 for (J = Argument; *J != 0 && *J != '='; J++);
192 if (*J == 0)
7e798dd7 193 return _error->Error("Option %s: Configuration item sepecification must have an =<val>.",argv[I]);
e1b74f61 194
7e798dd7
AL
195 // = is trailing
196 if (J[1] == 0)
197 {
198 if (I+1 >= argc)
199 return _error->Error("Option %s: Configuration item sepecification must have an =<val>.",argv[I]);
200 Conf->Set(string(Argument,J-Argument),string(argv[I++ +1]));
201 }
202 else
203 Conf->Set(string(Argument,J-Argument),string(J+1));
e1b74f61
AL
204
205 return true;
206 }
08e8f724
AL
207
208 Conf->Set(A->ConfName,Argument);
209 return true;
210 }
211
212 // Option is an integer level
213 if ((A->Flags & IntLevel) == IntLevel)
214 {
215 // There might be an argument
216 if (Argument != 0)
217 {
218 char *EndPtr;
219 unsigned long Value = strtol(Argument,&EndPtr,10);
220
221 // Conversion failed and the argument was specified with an =s
222 if (EndPtr == Argument && CertainArg == true)
223 return _error->Error("Option %s requires an integer argument, not '%s'",argv[I],Argument);
224
225 // Conversion was ok, set the value and return
226 if (EndPtr != Argument)
227 {
228 Conf->Set(A->ConfName,Value);
229 Opt += strlen(Opt);
230 I += IncI;
231 return true;
232 }
233 }
234
235 // Increase the level
236 Conf->Set(A->ConfName,Conf->FindI(A->ConfName)+1);
237 return true;
238 }
239
240 // Option is a boolean
241 int Sense = -1; // -1 is unspecified, 0 is yes 1 is no
242
243 // Look for an argument.
244 while (1)
245 {
246 // Look at preceeding text
247 char Buffer[300];
248 if (Argument == 0)
249 {
0d47bd08
AL
250 if (PreceedMatch == false)
251 break;
252
08e8f724
AL
253 if (strlen(argv[I]) >= sizeof(Buffer))
254 return _error->Error("Option '%s' is too long",argv[I]);
0d47bd08
AL
255
256 // Skip the leading dash
08e8f724
AL
257 const char *J = argv[I];
258 for (; *J != 0 && *J == '-'; J++);
0d47bd08 259
08e8f724
AL
260 const char *JEnd = J;
261 for (; *JEnd != 0 && *JEnd != '-'; JEnd++);
262 if (*JEnd != 0)
263 {
264 strncpy(Buffer,J,JEnd - J);
265 Buffer[JEnd - J] = 0;
266 Argument = Buffer;
267 CertainArg = true;
268 }
269 else
270 break;
271 }
272
3b5421b4
AL
273 // Check for boolean
274 Sense = StringToBool(Argument);
275 if (Sense >= 0)
08e8f724 276 {
08e8f724
AL
277 // Eat the argument
278 if (Argument != Buffer)
279 {
280 Opt += strlen(Opt);
281 I += IncI;
282 }
283 break;
284 }
285
08e8f724
AL
286 if (CertainArg == true)
287 return _error->Error("Sense %s is not understood, try true or false.",Argument);
288
289 Argument = 0;
290 }
291
292 // Indeterminate sense depends on the flag
293 if (Sense == -1)
294 {
295 if ((A->Flags & InvBoolean) == InvBoolean)
296 Sense = 0;
297 else
298 Sense = 1;
299 }
300
301 Conf->Set(A->ConfName,Sense);
302 return true;
303}
304 /*}}}*/
bc4af0b9 305// CommandLine::FileSize - Count the number of filenames /*{{{*/
e1b74f61
AL
306// ---------------------------------------------------------------------
307/* */
308unsigned int CommandLine::FileSize() const
309{
310 unsigned int Count = 0;
311 for (const char **I = FileList; I != 0 && *I != 0; I++)
312 Count++;
313 return Count;
314}
315 /*}}}*/
bc4af0b9
AL
316// CommandLine::DispatchArg - Do something with the first arg /*{{{*/
317// ---------------------------------------------------------------------
318/* */
319bool CommandLine::DispatchArg(Dispatch *Map)
320{
321 int I;
322 for (I = 0; Map[I].Match != 0; I++)
323 {
324 if (strcmp(FileList[0],Map[I].Match) == 0)
325 {
326 bool Res = Map[I].Handler(*this);
327 if (Res == false && _error->PendingError() == false)
328 _error->Error("Handler silently failed");
329 return Res;
330 }
331 }
332
333 // No matching name
334 if (Map[I].Match == 0)
335 _error->Error("Invalid operation %s",FileList[0]);
336 return false;
337}
338 /*}}}*/