ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GArgs.cpp
Revision: 2
Committed: Mon Mar 22 22:03:27 2010 UTC (9 years, 6 months ago) by gpertea
File size: 7464 byte(s)
Log Message:
added my gclib source files

Line User Rev File contents
1 gpertea 2 #include <stdlib.h>
2     #include <string.h>
3     #include "GArgs.h"
4     #include <ctype.h>
5    
6     #define TRACE 1
7    
8     #include "GBase.h"
9    
10     //GArgs::is_opt="1"; //just to have a non-NULL value for switch testing
11    
12    
13     GArgs::GArgs(int argc, char* const argv[], const char* format, bool nodigitopts) {
14     /* format is:
15     <letter>[:] for e.g. p:hT <- -p testing -ptesting -h -T
16     <string>= for e.g. PID=S= <- PID=50 S=3.5
17     This means that the = options, if present, must NEVER be given after
18     dashed switches (non-value) directly
19     */
20    
21     //parse format string first:
22     const char* fstr=format;
23     fmtcount=0;
24     count=0;
25     nonOptCount=0;
26     nonOptPos=0;
27     optPos=0;
28     errarg=0;
29     args=NULL;
30     fmt=NULL;
31     int fmtlen=strlen(format);
32     while (fstr-format < fmtlen ) {
33     int l=strcspn(fstr, ":=");
34     if (fstr[l]=='\0') { //end of string reached
35     //all previous chars are just switches:
36     GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
37     //store each switches
38     for (int i=0; i<l;i++) {
39     GCALLOC(fmt[fmtcount+i].opt, 2); //one char length
40     fmt[fmtcount+i].opt[0]=fstr[i];
41     fmt[fmtcount+i].type = 0;
42     }
43     fmtcount+=l;
44     break;
45     }
46     else {
47     if (fstr[l]==':') {
48     //fstr[l-1] is an argument, but all the previous are just switches
49     GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef));
50     //store each switches AND the option
51     for (int i=0; i<l;i++) {
52     GCALLOC(fmt[fmtcount+i].opt, 2); //one char length
53     fmt[fmtcount+i].opt[0]=fstr[i];
54     fmt[fmtcount+i].type = (i==l-1)?1:0;
55     }
56     fmtcount+=l;
57     }
58     else { // fstr[l]=='=' case!
59     //all these chars are one = style argument
60     GREALLOC(fmt, (fmtcount+1)*sizeof(fmtdef));
61     GMALLOC(fmt[fmtcount].opt, l+1);
62     strncpy(fmt[fmtcount].opt, fstr, l);
63     fmt[fmtcount].opt[l]='\0';
64     fmt[fmtcount].type=2;
65     fmtcount++;
66     }
67     fstr+=l+1;
68     }
69     }
70     //---- that was the parsing of the format string
71     //now parse the arguments based on given format specification
72     int p=1; //skip program name
73     int f=0;
74     //GMessage("argc=%d\n", argc);
75     while (p<argc) {
76     if (argv[p][0]=='-') { //dashed argument ?
77     int cpos=1;
78     char c=argv[p][cpos];
79     if (c==0 || (nodigitopts && isdigit(c))) {
80     //special case: plain argument '-' or negative number
81     GREALLOC(args, (count+1)*sizeof(argdata));
82     args[count].opt=NULL;
83     if (c==0) {
84     GCALLOC(args[count].value, 2);
85     args[count].value[0]='-';
86     }
87     else {
88     args[count].value=Gstrdup(argv[p]);
89     }
90     count++;
91     nonOptCount++;
92     }
93     else { //dashed argument or switch
94     COLLAPSED:
95     if ((f=validOpt(c))>=0) {
96     if (fmt[f].type==0) {//switch type
97     GREALLOC(args, (count+1)*sizeof(argdata));
98     GCALLOC(args[count].opt, 2);
99     args[count].opt[0]=c;
100     GCALLOC(args[count].value, 1);
101     count++;
102     // only switches can be grouped with some other switches or options
103     if (argv[p][cpos+1]!='\0') {
104     cpos++;
105     c=argv[p][cpos];
106     goto COLLAPSED;
107     }
108     }
109     else
110     if (fmt[f].type==1) { //dash argument
111     GREALLOC(args, (count+1)*sizeof(argdata));
112     GCALLOC(args[count].opt, 2);
113     args[count].opt[0]=c;
114     if (argv[p][cpos+1]=='\0') {
115     if (p+1<argc) { //value is the whole next argument
116     p++;
117     GMALLOC(args[count].value, strlen(argv[p])+1);
118     strcpy(args[count].value, argv[p]);
119     }
120     else {
121     errarg=p;
122     return;
123     }
124     }
125     else { //value immediately follows the dash-option
126     GMALLOC(args[count].value, strlen(argv[p])-cpos);
127     strcpy(args[count].value, (argv[p]+cpos+1));
128     //GMessage("args[%d].value = '%s'",count, args[count].value);
129     }
130     count++;
131     }
132     else {//inconsistent type
133     errarg=p;
134     return;
135     }
136     } //was validOpt
137     else { //option not found in format definition!
138     errarg=p;
139     return;
140     }
141     }
142     }
143     else {//not a dashed argument
144     char* e=strchr(argv[p],'=');
145     if (e!=NULL && strchr(format,'=')!=NULL && e!=argv[p] && *(e-1)!='\\') {
146     //this must be an '=' option
147     //yet the '=' char can be preceded by a '\' in order to not be parsed
148     //as a = option
149     char part[128];
150     strncpy(part, argv[p], e-argv[p]);
151     part[e-argv[p]]='\0';
152     if ((f=validOpt(part))>=0 && fmt[f].type==2) {
153     GREALLOC(args, (count+1)*sizeof(argdata));
154     args[count].opt=Gstrdup(part);
155     if (strlen(argv[p])-strlen(part)>0) {
156     GMALLOC(args[count].value, strlen(argv[p])-strlen(part)+1);
157     strcpy(args[count].value, e+1);
158     }
159     else {
160     args[count].value=NULL;
161     }
162     count++;
163     }
164     else { //error - format does not match this '=' argument
165     errarg=p;
166     return;
167     }
168     }
169     else { //it seems it's just a plain argument, like a filename, etc.
170     GREALLOC(args, (count+1)*sizeof(argdata));
171     args[count].opt=NULL; //it's not an option
172     args[count].value=Gstrdup(argv[p]);
173     count++;
174     nonOptCount++;
175     }
176     }
177     p++;//check next arg string
178     }
179     }
180    
181     GArgs::~GArgs() {
182     int i;
183     for (i=0; i<fmtcount; i++)
184     GFREE(fmt[i].opt);
185     GFREE(fmt);
186     for (i=0; i<count; i++) {
187     GFREE(args[i].opt);
188     GFREE(args[i].value);
189     }
190     GFREE(args);
191     }
192    
193     int GArgs::validOpt(char o) {
194     for (int i=0; i<fmtcount; i++)
195     if (fmt[i].opt[0]==o && fmt[i].opt[1]=='\0') return i;
196     return -1;
197     }
198    
199     int GArgs::validOpt(char* o) {
200     for (int i=0; i<fmtcount; i++)
201     if (strcmp(fmt[i].opt, o)==0) return i;
202     return -1;
203     }
204    
205     int GArgs::isError() { // returns the offending argv position or 0 if no error
206     return errarg;
207     }
208    
209     char* GArgs::getOpt(const char* o) { /* retrieve the value for option o
210     returns
211     NULL if option not given at all
212     !=NULL if boolean option was given
213     opt.value if value option was given
214     */
215     for (int i=0; i<count; i++)
216     if (args[i].opt!=NULL && strcmp(args[i].opt, o)==0)
217     return args[i].value;
218     return NULL;
219     }
220    
221     char* GArgs::getOpt(const char o) {
222     for (int i=0; i<count; i++)
223     if (args[i].opt!=NULL && args[i].opt[0]==o && args[i].opt[1]=='\0')
224     return args[i].value;
225     return NULL;
226     }
227    
228     int GArgs::startNonOpt(){ //reset iteration through non-dashed arguments
229     //returns the number of non-dashed arguments
230     nonOptPos=0;
231     return nonOptCount;
232     }
233    
234    
235     char* GArgs::nextNonOpt() { //get the next non-dashed argument
236     //or NULL if no more
237     for (int i=nonOptPos;i<count;i++)
238     if (args[i].opt==NULL) {
239     nonOptPos=i+1;
240     return args[i].value;
241     }
242     return NULL;
243     }
244    
245     int GArgs::startOpt(){ //reset iteration through non-dashed arguments
246     //returns the number of non-dashed arguments
247     optPos=0;
248     return count-nonOptCount;
249     }
250    
251    
252     char* GArgs::nextOpt() { //get the next non-dashed argument
253     //or NULL if no more
254     for (int i=optPos;i<count;i++)
255     if (args[i].opt!=NULL) {
256     optPos=i+1;
257     return args[i].opt;
258     }
259     return NULL;
260     }