]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/cmndline.cc
6b36325c7c71949e0905abedb45aa85db031feb4
[apt.git] / apt-pkg / contrib / cmndline.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: cmndline.cc,v 1.1 1998/09/22 05:30:26 jgg Exp $
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 /* */
22 CommandLine::CommandLine(Args *AList,Configuration *Conf) : ArgList(AList),
23 Conf(Conf), FileList(0)
24 {
25 }
26 /*}}}*/
27 // CommandLine::Parse - Main action member /*{{{*/
28 // ---------------------------------------------------------------------
29 /* */
30 bool CommandLine::Parse(int argc,const char **argv)
31 {
32 FileList = new const char *[argc];
33 const char **Files = FileList;
34 int I;
35 for (I = 1; I != argc; I++)
36 {
37 const char *Opt = argv[I];
38
39 // It is not an option
40 if (*Opt != '-')
41 {
42 *Files++ = Opt;
43 continue;
44 }
45
46 Opt++;
47
48 // Double dash signifies the end of option processing
49 if (*Opt == '-' && Opt[1] == 0)
50 break;
51
52 // Single dash is a short option
53 if (*Opt != '-')
54 {
55 // Iterate over each letter
56 while (*Opt != 0)
57 {
58 // Search for the option
59 Args *A;
60 for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++);
61 if (A->end() == true)
62 return _error->Error("Command line option '%c' [from %s] is not known.",*Opt,argv[I]);
63
64 if (HandleOpt(I,argc,argv,Opt,A) == false)
65 return false;
66 if (*Opt != 0)
67 Opt++;
68 }
69 continue;
70 }
71
72 Opt++;
73
74 // Match up to a = against the list
75 const char *OptEnd = Opt;
76 Args *A;
77 for (; *OptEnd != 0 && *OptEnd != '='; OptEnd++);
78 for (A = ArgList; A->end() == false &&
79 stringcasecmp(Opt,OptEnd,A->LongOpt) != 0; A++);
80
81 // Failed, look for a word after the first - (no-foo)
82 if (A->end() == true)
83 {
84 for (; Opt != OptEnd && *Opt != '-'; Opt++);
85
86 if (Opt == OptEnd)
87 return _error->Error("Command line option %s is not understood",argv[I]);
88 Opt++;
89
90 for (A = ArgList; A->end() == false &&
91 stringcasecmp(Opt,OptEnd,A->LongOpt) != 0; A++);
92
93 // Failed again..
94 if (A->end() == true && OptEnd - Opt != 1)
95 return _error->Error("Command line option %s is not understood",argv[I]);
96
97 // The option could be a single letter option prefixed by a no-..
98 for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++);
99
100 if (A->end() == true)
101 return _error->Error("Command line option %s is not understood",argv[I]);
102 }
103
104 // Deal with it.
105 OptEnd--;
106 if (HandleOpt(I,argc,argv,OptEnd,A) == false)
107 return false;
108 }
109
110 // Copy any remaining file names over
111 for (; I != argc; I++)
112 *Files++ = argv[I];
113 *Files = 0;
114
115 return true;
116 }
117 /*}}}*/
118 // CommandLine::HandleOpt - Handle a single option including all flags /*{{{*/
119 // ---------------------------------------------------------------------
120 /* This is a helper function for parser, it looks at a given argument
121 and looks for specific patterns in the string, it gets tokanized
122 -ruffly- like -*[yes|true|enable]-(o|longopt)[=][ ][argument] */
123 bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
124 const char *&Opt,Args *A)
125 {
126 const char *Argument = 0;
127 bool CertainArg = false;
128 int IncI = 0;
129
130 /* Determine the possible location of an option or 0 if their is
131 no option */
132 if (Opt[1] == 0 || (Opt[1] == '=' && Opt[2] == 0))
133 {
134 if (I + 1 < argc && argv[I+1][0] != '-')
135 Argument = argv[I+1];
136
137 // Equals was specified but we fell off the end!
138 if (Opt[1] == '=' && Argument == 0)
139 return _error->Error("Option %s requires an argument.",argv[I]);
140 if (Opt[1] == '=')
141 CertainArg = true;
142
143 IncI = 1;
144 }
145 else
146 {
147 if (Opt[1] == '=')
148 {
149 CertainArg = true;
150 Argument = Opt + 2;
151 }
152 else
153 Argument = Opt + 1;
154 }
155
156 // Option is an argument set
157 if ((A->Flags & HasArg) == HasArg)
158 {
159 if (Argument == 0)
160 return _error->Error("Option %s requires an argument.",argv[I]);
161 Opt += strlen(Opt);
162 I += IncI;
163
164 // Parse a configuration file
165 if ((A->Flags & ConfigFile) == ConfigFile)
166 return ReadConfigFile(*Conf,Argument);
167
168 Conf->Set(A->ConfName,Argument);
169 return true;
170 }
171
172 // Option is an integer level
173 if ((A->Flags & IntLevel) == IntLevel)
174 {
175 // There might be an argument
176 if (Argument != 0)
177 {
178 char *EndPtr;
179 unsigned long Value = strtol(Argument,&EndPtr,10);
180
181 // Conversion failed and the argument was specified with an =s
182 if (EndPtr == Argument && CertainArg == true)
183 return _error->Error("Option %s requires an integer argument, not '%s'",argv[I],Argument);
184
185 // Conversion was ok, set the value and return
186 if (EndPtr != Argument)
187 {
188 Conf->Set(A->ConfName,Value);
189 Opt += strlen(Opt);
190 I += IncI;
191 return true;
192 }
193 }
194
195 // Increase the level
196 Conf->Set(A->ConfName,Conf->FindI(A->ConfName)+1);
197 return true;
198 }
199
200 // Option is a boolean
201 int Sense = -1; // -1 is unspecified, 0 is yes 1 is no
202
203 // Look for an argument.
204 while (1)
205 {
206 // Look at preceeding text
207 char Buffer[300];
208 if (Argument == 0)
209 {
210 if (strlen(argv[I]) >= sizeof(Buffer))
211 return _error->Error("Option '%s' is too long",argv[I]);
212
213 const char *J = argv[I];
214 for (; *J != 0 && *J == '-'; J++);
215 const char *JEnd = J;
216 for (; *JEnd != 0 && *JEnd != '-'; JEnd++);
217 if (*JEnd != 0)
218 {
219 strncpy(Buffer,J,JEnd - J);
220 Buffer[JEnd - J] = 0;
221 Argument = Buffer;
222 CertainArg = true;
223 }
224 else
225 break;
226 }
227
228 // Check for positives
229 if (strcasecmp(Argument,"yes") == 0 ||
230 strcasecmp(Argument,"true") == 0 ||
231 strcasecmp(Argument,"with") == 0 ||
232 strcasecmp(Argument,"enable") == 0)
233 {
234 Sense = 1;
235
236 // Eat the argument
237 if (Argument != Buffer)
238 {
239 Opt += strlen(Opt);
240 I += IncI;
241 }
242 break;
243 }
244
245 // Check for negatives
246 if (strcasecmp(Argument,"no") == 0 ||
247 strcasecmp(Argument,"false") == 0 ||
248 strcasecmp(Argument,"without") == 0 ||
249 strcasecmp(Argument,"disable") == 0)
250 {
251 Sense = 0;
252
253 // Eat the argument
254 if (Argument != Buffer)
255 {
256 Opt += strlen(Opt);
257 I += IncI;
258 }
259 break;
260 }
261
262 if (CertainArg == true)
263 return _error->Error("Sense %s is not understood, try true or false.",Argument);
264
265 Argument = 0;
266 }
267
268 // Indeterminate sense depends on the flag
269 if (Sense == -1)
270 {
271 if ((A->Flags & InvBoolean) == InvBoolean)
272 Sense = 0;
273 else
274 Sense = 1;
275 }
276
277 Conf->Set(A->ConfName,Sense);
278 return true;
279 }
280 /*}}}*/