ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GArgs.cpp
Revision: 16
Committed: Mon Jul 18 20:56:02 2011 UTC (7 years, 9 months ago) by gpertea
File size: 10606 byte(s)
Log Message:
sync with local source

Line File contents
1 #include "GBase.h"
2 #include "GArgs.h"
3 #include <ctype.h>
4
5 GArgs::GArgs(int argc, char* const argv[], const char* format, bool nodigitopts) {
6 /* format can be:
7 <string>{;|=} e.g. disable-test;PID=S= for --disable-test PID=50 (or --PID 50) S=3.5 etc.
8 <letter>[:] e.g. p:hT for -p testing (or -ptesting) -h -T
9 */
10 const char* fstr=format;
11 fmtcount=0;
12 count=0;
13 nonOptCount=0;
14 nonOptPos=0;
15 optPos=0;
16 errarg=0;
17 err_valmissing=false;
18 args=NULL;
19 fmt=NULL;
20 _argc=argc;
21 _argv=argv;
22 int fmtlen=strlen(format);
23 //---- first parse the format string
24 while (fstr-format < fmtlen ) {
25 int l=strcspn(fstr, ";=:");
26 if (fstr[l]==0) { //end of string reached
27 //all previous chars are just switches:
28 GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
29 //store each switch
30 for (int i=0; i<l;i++) {
31 fmt[fmtcount+i].longopt=NULL;
32 fmt[fmtcount+i].opt=fstr[i];
33 fmt[fmtcount+i].req_value = false;
34 fmt[fmtcount+i].code=fmtcount+i+1;
35 }
36 fmtcount+=l;
37 break;
38 }
39 else {
40 if (fstr[l]==':') {
41 //fstr[l-1] is an argument, but all the previous are just switches
42 GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
43 //store each switch AND the option
44 for (int i=0; i<l;i++) {
45 fmt[fmtcount+i].longopt=NULL; //one char length
46 fmt[fmtcount+i].opt=fstr[i];
47 fmt[fmtcount+i].req_value = (i==l-1);
48 fmt[fmtcount+i].code=fmtcount+i+1;
49 }
50 fmtcount+=l;
51 }
52 else { // fstr[l]=='=' or ';'
53 GREALLOC(fmt, (fmtcount+1)*sizeof(fmtdef));
54 fmt[fmtcount].longopt=Gstrdup(fstr, fstr+l-1);
55 fmt[fmtcount].opt=0;
56 fmt[fmtcount].req_value=(fstr[l]=='=');
57 fmt[fmtcount].code=fmtcount+1;
58 fmtcount++;
59 }
60 fstr+=l+1;
61 }
62 }
63 //-- now parse the arguments based on the given format specification
64 parseArgs(nodigitopts);
65 }
66
67 int GArgs::parseArgs(bool nodigitopts) {
68 int p=1; //skip program name
69 int f=0;
70 while (p<_argc) {
71 if (_argv[p][0]=='-' && (_argv[p][1]==0 || _argv[p][1]!='-')) {
72 //single-dash argument
73 int cpos=1;
74 char c=_argv[p][cpos];
75 if (c==0 || (nodigitopts && isdigit(c)) ||
76 (c=='.' && isdigit(_argv[p][cpos+1]))) {
77 //special case: plain argument '-' or just a negative number
78 GREALLOC(args, (count+1)*sizeof(argdata));
79 args[count].opt=NULL;
80 args[count].fmti=-1;
81 if (c==0) {
82 GCALLOC(args[count].value, 2);
83 args[count].value[0]='-';
84 }
85 else { //negative number given
86 args[count].value=Gstrdup(_argv[p]);
87 }
88 count++;
89 nonOptCount++;
90 }
91 else { //single-dash argument or switch
92 COLLAPSED:
93 if ((f=validShortOpt(c))>=0) {
94 GREALLOC(args, (count+1)*sizeof(argdata));
95 GCALLOC(args[count].opt, 2);
96 args[count].opt[0]=c;
97 args[count].fmti=f;
98 if (!fmt[f].req_value) {//switch type
99 GCALLOC(args[count].value,1);//so getOpt() functions would not return NULL
100 count++;
101 // only switches can be grouped with some other switches or options
102 if (_argv[p][cpos+1]!='\0') {
103 cpos++;
104 c=_argv[p][cpos];
105 goto COLLAPSED;
106 }
107 }
108 else {
109 //single-dash argument followed by a value
110 if (_argv[p][cpos+1]=='\0') {
111 if (p+1<_argc && _argv[p+1][0]!=0) { //value is the whole next argument
112 p++;
113 args[count].value=Gstrdup(_argv[p]);
114 }
115 else {
116 errarg=p;
117 err_valmissing=true;
118 return errarg;
119 }
120 }
121 else { //value immediately follows the dash-option
122 args[count].value=Gstrdup(_argv[p]+cpos+1);
123 }
124 count++;
125 }
126 } //was validShortOpt
127 else { //option not found in format definition!
128 errarg=p;
129 return errarg;
130 }
131 }
132 } //-single-dash
133 else {//not a single-dash argument
134 char* ap=_argv[p];
135 bool is_longopt=false;
136 if (*ap=='-' && ap[1]=='-') {
137 is_longopt=true;
138 ap+=2;
139 }
140 char* e=strchr(ap+1,'=');
141 while (e!=NULL && *(e-1)=='\\') e=strchr(e,'=');
142 if (e==NULL && is_longopt) {
143 e=ap;
144 while (*e!=0 && *e!=' ') e++;
145 //e will be on eos or next space
146 }
147 if (e!=NULL && e>ap) {
148 //this must be a long option
149 //e is on eos, space or '='
150 if ((f=validLongOpt(ap,e-1))>=0) {
151 GREALLOC(args, (count+1)*sizeof(argdata));
152 args[count].opt=Gstrdup(ap,e-1);
153 args[count].fmti=f;
154 if (fmt[f].req_value) {
155 if (*e==0) {
156 //value is the next argument
157 if (p+1<_argc && _argv[p+1][0]!=0) {
158 p++;
159 args[count].value=Gstrdup(_argv[p]);
160 }
161 else {
162 errarg=p;
163 err_valmissing=true;
164 return errarg;
165 }
166 }
167 else { //value is in the same argument
168 //while (*e!=0 && (*e==' ' || *e=='=')) e++;
169 if (*e=='=') e++;
170 if (*e==0) {
171 errarg=p;
172 err_valmissing=true;
173 return errarg;
174 }
175 args[count].value=Gstrdup(e);
176 }
177 } //value required
178 else { //no value expected
179 GCALLOC(args[count].value,1); //do not return NULL
180 }
181 count++;
182 }
183 else { //error - this long argument not recognized
184 errarg=p;
185 return errarg;
186 }
187 }
188 else { //just a plain non-option argument
189 if (e==ap) { //i.e. just "--"
190 errarg=p;
191 return errarg;
192 }
193 GREALLOC(args, (count+1)*sizeof(argdata));
194 args[count].opt=NULL; //it's not an option
195 args[count].value=Gstrdup(_argv[p]);
196 args[count].fmti=-1;
197 count++;
198 nonOptCount++;
199 }
200 }
201 p++;//check next arg string
202 } //while arguments
203 return errarg;
204 }
205
206 void GArgs::printError(FILE* fout, const char* usage, bool exitProgram) {
207 if (errarg==0) return;
208 if (usage) fprintf(fout, "%s\n", usage);
209 if (err_valmissing)
210 fprintf(fout, "Error: value required for option '%s'\n", _argv[errarg]);
211 else
212 fprintf(fout, "Error: invalid argument '%s'\n", _argv[errarg]);
213 if (exitProgram)
214 exit(1);
215 }
216
217 void GArgs::printError(const char* usage, bool exitProgram) {
218 printError(stderr, usage, exitProgram);
219 }
220
221 void GArgs::printCmdLine(FILE* fout) {
222 if (_argv==NULL) return;
223 for (int i=0;i<_argc;i++) {
224 fprintf(fout, "%s%c", _argv[i], (i==_argc-1)?'\n':' ');
225 }
226 }
227
228 GArgs::GArgs(int argc, char* const argv[], const GArgsDef fmtrecs[], bool nodigitopts) {
229 fmtcount=0;
230 count=0;
231 nonOptCount=0;
232 nonOptPos=0;
233 optPos=0;
234 errarg=0;
235 err_valmissing=false;
236 args=NULL;
237 fmt=NULL;
238 _argc=argc;
239 _argv=argv;
240 if (fmtrecs==NULL) return;
241
242 const GArgsDef* frec=fmtrecs;
243 while ((frec->longopt || frec->opt) && fmtcount<255) {
244 fmtcount++;
245 frec=&(fmtrecs[fmtcount]);
246 }
247 GCALLOC(fmt, fmtcount*sizeof(fmtdef));
248 for (int i=0;i<fmtcount;i++) {
249 fmt[i].longopt=Gstrdup(fmtrecs[i].longopt); //do we need to use Gstrdup here?
250 fmt[i].opt=fmtrecs[i].opt;
251 fmt[i].req_value=fmtrecs[i].req_value;
252 fmt[i].code=fmtrecs[i].code;
253 }
254 parseArgs(nodigitopts);
255 }
256
257
258 GArgs::~GArgs() {
259 int i;
260 for (i=0; i<fmtcount; i++)
261 GFREE(fmt[i].longopt);
262 GFREE(fmt);
263 for (i=0; i<count; i++) {
264 GFREE(args[i].opt);
265 GFREE(args[i].value);
266 }
267 GFREE(args);
268 }
269
270 int GArgs::validShortOpt(char o) {
271 for (int i=0; i<fmtcount; i++)
272 if (fmt[i].opt==o) return i;
273 return -1;
274 }
275
276 int GArgs::validLongOpt(char* o, char* to) {
277 char* pstr=Gstrdup(o,to);
278 for (int i=0; i<fmtcount; i++) {
279 if (fmt[i].longopt && strcmp(fmt[i].longopt, pstr)==0) {
280 GFREE(pstr);
281 return i;
282 }
283 }
284 GFREE(pstr);
285 return -1;
286 }
287
288 int GArgs::validOpt(int code) {
289 for (int i=0; i<fmtcount; i++)
290 if (fmt[i].code==code) return i;
291 return -1;
292 }
293
294
295 int GArgs::isError() { // returns the offending argv position or 0 if no error
296 return errarg;
297 }
298
299 char* GArgs::getOpt(const char* o) { /* retrieve the value for option o
300 returns
301 NULL if option not given at all
302 !=NULL if boolean option was given
303 opt.value if value option was given
304 */
305 for (int i=0; i<count; i++)
306 if (args[i].opt!=NULL && strcmp(args[i].opt, o)==0)
307 return args[i].value;
308 return NULL;
309 }
310
311 char* GArgs::getOpt(const char o) {
312 for (int i=0; i<count; i++)
313 if (args[i].opt!=NULL && args[i].opt[0]==o && args[i].opt[1]=='\0')
314 return args[i].value;
315 return NULL;
316 }
317
318 char* GArgs::getOpt(int c) {
319 for (int i=0; i<count; i++)
320 if (args[i].fmti>=0 && fmt[args[i].fmti].code==c)
321 return args[i].value;
322 return NULL;
323 }
324
325 char* GArgs::getOptName(int c) {
326 for (int i=0; i<count; i++)
327 if (args[i].fmti>=0 && fmt[args[i].fmti].code==c)
328 return args[i].opt;
329 return NULL;
330 }
331
332
333 int GArgs::startNonOpt(){ //reset iteration through non-option arguments
334 //returns the number of non-option arguments
335 nonOptPos=0;
336 return nonOptCount;
337 }
338
339
340 char* GArgs::nextNonOpt() { //get the next non-dashed argument
341 //or NULL if no more
342 for (int i=nonOptPos;i<count;i++)
343 if (args[i].opt==NULL) {
344 nonOptPos=i+1;
345 return args[i].value;
346 }
347 return NULL;
348 }
349
350 int GArgs::startOpt(){ //reset iteration through option arguments
351 //returns the number of option arguments
352 optPos=0;
353 return count-nonOptCount;
354 }
355
356
357 char* GArgs::nextOpt() { //get the next non-dashed argument
358 //or NULL if no more
359 for (int i=optPos;i<count;i++)
360 if (args[i].opt!=NULL) {
361 optPos=i+1;
362 return args[i].opt;
363 }
364 return NULL;
365 }
366
367 int GArgs::nextCode() { //get the next non-dashed argument
368 //or NULL if no more
369 for (int i=optPos;i<count;i++)
370 if (args[i].opt!=NULL && args[i].fmti>=0) {
371 optPos=i+1;
372 return fmt[args[i].fmti].code;
373 }
374 return 0; //must make sure that codes are > 0 for this to work properly
375 }