source: orange/source/orange/getarg.cpp @ 6963:13450016cefe

Revision 6963:13450016cefe, 9.8 KB checked in by ales_erjavec <ales.erjavec@…>, 4 years ago (diff)
  • Fixed a problem with compiling orange on Mac for python2.7 (conflict between isspace, isupper ... defined in <localefwd> and <ctypes.h>. Fixed by moving #include <iostream> and simmilar includes before other includes or removing it if not necessary).
Line 
1/*
2    This file is part of Orange.
3   
4    Copyright 1996-2010 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <iostream>
22#include <fstream>
23#include "getarg.hpp"
24#include "stladdon.hpp"
25#include "errors.hpp"
26#include <stdio.h>
27
28
29TProgArguments::TProgArguments() :
30allowSpaces(false)
31{}
32
33/*  A constructor which is given a list of possible options and standard C-like fields with
34    number of arguments and an array of char * pointers to arguments. If rupUnrec=true, unrecognized
35    options are reported. */
36TProgArguments::TProgArguments(const string &poss_options, int argc, char *argv[], bool repUnrec, bool parenth, bool anallowSpaces)
37  : possibleOptions(), options(), unrecognized(), direct(), allowSpaces(anallowSpaces)
38{ findPossibleOptions(poss_options);
39  vector<string> optionsList;
40
41  if (argc>1)
42    if (parenth) {
43      string cline(argv[1]);
44      for(int i=2; i<argc; ) {
45        string as(argv[i++]);
46        if (as.find(' ')==string::npos) cline+=' '+as;
47        else cline+=" \""+as+"\"";
48      }
49      string2atoms(cline, optionsList);
50    }
51    else
52      while(--argc) optionsList.push_back(*(++argv));
53
54  defile(optionsList);
55  process(optionsList);
56
57  if (repUnrec) reportUnrecognized();
58}
59
60
61/*  A constructor which is given a list of possible options. Arguments are given in as a string which
62    is processed (divided into atoms) by constructor. If rupUnrec=true, unrecognized options are reported. */
63TProgArguments::TProgArguments(const string &poss_options, const string &line, bool repUnrec, bool anallowSpaces)
64 : possibleOptions(), options(), unrecognized(), direct(), allowSpaces(anallowSpaces)
65{ findPossibleOptions(poss_options);
66  vector<string> optionsList;
67  string2atoms(line, optionsList);
68  defile(optionsList);
69  process(optionsList);
70
71  if (repUnrec) reportUnrecognized();
72}
73
74
75/*  Processes the string which specifies possible options (the first parameter to constructors)
76    and stores the results into possibleOptions field. poss_options consists of options' names, divided
77    by blanks. If option's name is immediately followed by a colon, option has parameters. For example,
78    string 'help f: m: u' specifies options 'help' and 'u' which have no parameters and 'f' and 'm' which
79    have (one) parameter. */
80void TProgArguments::findPossibleOptions(const string &poss_options)
81{
82  string ops;
83  string::const_iterator chi=poss_options.begin();
84  for(;;) {
85    if (chi==poss_options.end()) {
86      possibleOptions[ops] = false;
87      break;
88    }
89
90    else if ((*chi==':') || (*chi==' ')) {
91      char &po=possibleOptions[ops];
92      po=(*chi==':') ? 1 : 0;
93      while((++chi!=poss_options.end()) && (*chi==':')) po++;
94      while((chi!=poss_options.end()) && (*chi==' ')) chi++;
95      if (chi==poss_options.end()) break;
96      ops= *(chi++);
97    }
98
99    else ops+= *(chi++);
100  }
101}
102
103
104/* Processes the list of options (as rewritten from argv or line parameter to the constructor). */
105void TProgArguments::process(const vector<string> &optionsList)
106{ for(vector<string>::const_iterator si(optionsList.begin()), se(optionsList.end()); si!=se; )
107    if ((*si)[0]=='-') {
108      string option((*(si++)).c_str()+1);
109      if (possibleOptions.find(option)==possibleOptions.end())
110         unrecognized.insert(pair<string, string>(option, ((si==optionsList.end()) || ((*si)[0]=='-')) ? string("") : *(si++)));
111      else if (possibleOptions[option])
112        if (si==optionsList.end())
113          raiseError("missing parameter for option '%s'", option.c_str());
114        else
115          options.insert(pair<string, string>(option, *(si++)));  // for now, it takes only one option
116      else options.insert(pair<string, string>(option, ""));
117    }
118    else {
119      string::const_iterator ei((*si).begin()), ee((*si).end());
120      for(; (ei!=ee) && (*ei!='='); ei++);
121      if (ei==ee) direct.push_back(*(si++));
122      else {
123        string option((*si).begin(), ei), par(ei+1, (*si).end());
124        if (allowSpaces) {
125            while((++si != se) && (si->find("=") == string::npos)) {
126                par += " "+*si;
127            }
128        }
129        else {
130            si++;
131        }
132        if (possibleOptions.find(option)==possibleOptions.end())
133          unrecognized.insert(pair<string, string>(option, par));
134        else if (possibleOptions[option]) options.insert(pair<string, string>(option, par));
135        else
136          raiseError("option '%s' expects no arguments", option.c_str());
137      }
138    }
139}
140
141
142// Outputs the unrecognized arguments (the 'unrecognized' field)
143void TProgArguments::reportUnrecognized() const
144{ if (unrecognized.size())
145    raiseError("unrecognized option '%s'", (*unrecognized.begin()).first.c_str());
146}
147
148
149// Returns 'true' if argument par is in 'options' list
150bool TProgArguments::exists(const string &par) const
151{ return (options.find(par)!=options.end()); }
152
153
154// Returns the first value of the given parameter (there can be other...)
155string TProgArguments::operator[](const string &par) const
156{ TMultiStringParameters::const_iterator oi=options.find(par);
157  if (oi==options.end())
158    raiseError("parameter '%s' not found", par.c_str());
159  return (*oi).second;
160}
161
162
163
164bool readAnAtom(char *&curr, string &atom)
165{
166  for(;*curr && (*curr<=' ');curr++); // skip whitespace
167  if (!*curr) return false;
168
169  char *start=curr;
170
171  if (*curr=='"') {
172    for(curr++; (*curr!='"') && (*curr!=10) && (*curr!=13)  && *curr; curr++);
173    atom=string(++start, curr);
174    if (*curr++!='"')
175      raiseErrorWho("string2atoms", "newline in string '%s'", atom.c_str());
176  }
177  else if (*curr=='(') {
178    int parnths=1;
179    for(curr++; parnths && *curr && (*curr!=10) && (*curr!=13); curr++)
180      if (*curr=='(') parnths++;
181      else if (*curr==')') parnths--;
182    if (parnths)
183      raiseErrorWho("string2atoms", "to many ('s in '%s'", string(start, curr).c_str());
184
185    atom=string(++start, (curr++)-1);
186  }
187  else {
188    while(*(++curr)>' ');
189    atom=string(start, curr);
190  }
191  return true;
192}
193
194
195/*  Converts a string to a list of atoms. Atoms are separated by spaces and/or tabs while string
196    can also be finished by null, linefeed or cariage return characters. */
197int string2atoms(const string &line, vector<string> &atoms)
198{
199  if ((line[0]=='"') && (line[line.length()-1]=='"')) {
200    char buff[1024], *curr=buff;
201
202    for(int i=1, llen = line.length(); i+1<llen;)
203      if (line[i]=='"') {
204        *(curr++)='"';
205        if (line[++i]=='"') i++; // skips if there's another
206      }
207      else *(curr++)=line[i++];
208    *curr=0;
209    curr=buff;
210
211    string atom;
212    while(readAnAtom(curr, atom))
213      atoms.push_back(atom);
214  }
215  else {
216    char cline[1024];
217    strcpy(cline, line.c_str());
218    char *curr=cline;
219    string atom;
220    while(readAnAtom(curr, atom))
221      atoms.push_back(atom);
222  }
223
224  return atoms.size();
225}
226
227
228string firstAtom(const string &line)
229{ string first, others;
230  firstAndOthers(line, first, others);
231  return first;
232}
233
234string butFirstAtom(const string &line)
235{ string first, others;
236  firstAndOthers(line, first, others);
237  return others;
238}
239
240
241void firstAndOthers(const string &line, string &first, string &others)
242{ // skip whitespace before first
243  string::const_iterator curr(line.begin()), cue(line.end());
244  for(; (curr!=cue) && (*curr<=' '); curr++);
245
246  // find the end of first
247  string::const_iterator fbeg=curr;
248  for(; (curr!=cue) && (*curr>' '); curr++);
249  first=string(fbeg, curr);
250
251  // skip the whitespace before others
252  for(; (curr!=cue) && (*curr<=' '); curr++);
253  others=string(curr, cue);
254}
255
256
257string getSLine(istream &str)
258{ char line[1024];
259  str.getline(line, 1024);
260  if (str.gcount()==1024-1)
261    raiseError("line too long");
262  return line;
263}
264
265
266void defile(vector<string> &options)
267{ bool changed;
268  do {
269    changed=false;
270    vector<string> reoptions=options;
271    options.clear();
272    ITERATE(vector<string>, oi, reoptions) {
273      if ((*oi)[0]=='@') {
274        string::iterator be((*oi).end());
275        do --be; while ((*be!=':') && (*be!='@'));
276        if (*be=='@') {
277          ifstream pstr(string(be+1, (*oi).end()).c_str());
278          if (!pstr.is_open() || pstr.fail() || pstr.eof())
279            raiseError("invalid parameter file");
280          while (!pstr.fail() && !pstr.eof()) {
281            string nl=getSLine(pstr);
282            if (nl.length()) options.push_back(string(nl.begin(), nl.end()));
283          }
284        }
285        else {
286          string filename((*oi).begin()+1, be), lineNos(be+1, (*oi).end());
287          int lineNo=atoi(lineNos.c_str());
288          if (!lineNo)
289            raiseError("Invalid line number (%s) for parameter file %s.", lineNos.c_str(), filename.c_str());
290          ifstream pstr(filename.c_str());
291          if (!pstr.is_open() || pstr.fail() || pstr.eof())
292            raiseError("Invalid parameter file (%s).", (*oi).c_str());
293          while(--lineNo) {
294            getSLine(pstr);
295            if (pstr.fail() || pstr.eof())
296              raiseError("can't read parameter file %s to line %s", filename.c_str(), lineNos.c_str());
297          }
298          string nl=getSLine(pstr);
299          if (nl[0]=='=') options.push_back(string(nl.begin()+1, nl.end()));
300          else {
301            vector<string> ns;
302            string2atoms(nl, ns);
303            ITERATE(vector<string>, ni, ns) options.push_back(*ni);
304          }
305        }
306        changed=true;
307      }
308      else options.push_back(*oi);
309    }
310  } while (changed);
311}
312
313
Note: See TracBrowser for help on using the repository browser.