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 (8 years, 4 months ago) by gpertea
File size: 10606 byte(s)
Log Message:
sync with local source

Line User Rev File contents
1 gpertea 16 #include "GBase.h"
2 gpertea 2 #include "GArgs.h"
3     #include <ctype.h>
4    
5     GArgs::GArgs(int argc, char* const argv[], const char* format, bool nodigitopts) {
6 gpertea 16 /* 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 gpertea 2 */
10     const char* fstr=format;
11     fmtcount=0;
12     count=0;
13     nonOptCount=0;
14     nonOptPos=0;
15     optPos=0;
16     errarg=0;
17 gpertea 16 err_valmissing=false;
18 gpertea 2 args=NULL;
19     fmt=NULL;
20 gpertea 16 _argc=argc;
21     _argv=argv;
22 gpertea 2 int fmtlen=strlen(format);
23 gpertea 16 //---- first parse the format string
24 gpertea 2 while (fstr-format < fmtlen ) {
25 gpertea 16 int l=strcspn(fstr, ";=:");
26     if (fstr[l]==0) { //end of string reached
27 gpertea 2 //all previous chars are just switches:
28     GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
29 gpertea 16 //store each switch
30 gpertea 2 for (int i=0; i<l;i++) {
31 gpertea 16 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 gpertea 2 }
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 gpertea 16 //store each switch AND the option
44 gpertea 2 for (int i=0; i<l;i++) {
45 gpertea 16 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 gpertea 2 }
50     fmtcount+=l;
51     }
52 gpertea 16 else { // fstr[l]=='=' or ';'
53 gpertea 2 GREALLOC(fmt, (fmtcount+1)*sizeof(fmtdef));
54 gpertea 16 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 gpertea 2 fmtcount++;
59     }
60     fstr+=l+1;
61     }
62     }
63 gpertea 16 //-- 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 gpertea 2 }
91 gpertea 16 else { //single-dash argument or switch
92     COLLAPSED:
93     if ((f=validShortOpt(c))>=0) {
94 gpertea 2 GREALLOC(args, (count+1)*sizeof(argdata));
95     GCALLOC(args[count].opt, 2);
96     args[count].opt[0]=c;
97 gpertea 16 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 gpertea 2 GREALLOC(args, (count+1)*sizeof(argdata));
152 gpertea 16 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 gpertea 2 count++;
182     }
183 gpertea 16 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 gpertea 2 }
193 gpertea 16 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 gpertea 2 }
201 gpertea 16 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 gpertea 2 }
226     }
227    
228 gpertea 16 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 gpertea 2 GArgs::~GArgs() {
259     int i;
260     for (i=0; i<fmtcount; i++)
261 gpertea 16 GFREE(fmt[i].longopt);
262 gpertea 2 GFREE(fmt);
263     for (i=0; i<count; i++) {
264     GFREE(args[i].opt);
265     GFREE(args[i].value);
266     }
267 gpertea 16 GFREE(args);
268 gpertea 2 }
269    
270 gpertea 16 int GArgs::validShortOpt(char o) {
271 gpertea 2 for (int i=0; i<fmtcount; i++)
272 gpertea 16 if (fmt[i].opt==o) return i;
273 gpertea 2 return -1;
274     }
275    
276 gpertea 16 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 gpertea 2 for (int i=0; i<fmtcount; i++)
290 gpertea 16 if (fmt[i].code==code) return i;
291 gpertea 2 return -1;
292     }
293    
294 gpertea 16
295 gpertea 2 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 gpertea 16 return NULL;
309 gpertea 2 }
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 gpertea 16 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 gpertea 2 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 gpertea 16 int GArgs::startOpt(){ //reset iteration through option arguments
351     //returns the number of option arguments
352 gpertea 2 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 gpertea 16
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     }