00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <sstream>
00038
00039 #include "cmdline_parser.hh"
00040
00041 CmdLineParser::CmdLineAtom::operator string () const
00042 {
00043 string s;
00044 string args;
00045
00046 switch (tag)
00047 {
00048 case k_string: args = " <string>"; break;
00049 case k_bool: args = " [=yes|no|true|false]"; break;
00050 case k_int: args = " <integer>"; break;
00051 case k_float: args = " <float>"; break;
00052 default: ASSERT(0, "bad cmd line atom tag");
00053 }
00054
00055 if ((sOpt != "") && (lOpt != "")) s = "-" + sOpt + " | --" + lOpt;
00056 else
00057 if (sOpt != "") s = "-" + sOpt;
00058 else s = "--" + lOpt;
00059
00060 s += args;
00061
00062 if (multi)
00063 if (optional) s = "(" + s + ")*";
00064 else s = "(" + s + ")+";
00065 else
00066 if (optional) s = "[" + s + "]";
00067 else if ((sOpt != "") && (lOpt != "")) s = "(" + s + ")";
00068
00069 return s;
00070 }
00071
00072 #define COLS 80
00073 #define TS 30
00074 ostream& CmdLineParser::CmdLineAtom::dumpDescription (ostream &os) const
00075 {
00076 string syn = (string) *this;
00077 int c = syn.length();
00078 int i = 0;
00079
00080 os << syn; c %= COLS;
00081
00082 int aux = c + 5;
00083 while (c++ < max(TS, aux)) os << ' ';
00084
00085 for (int i = 0; i < description.length(); )
00086 {
00087 int wb = min(description.find(' ', i + 1), description.length());
00088 if (c + wb - i > COLS)
00089 {
00090 os << endl;
00091 for (c = 0; c++ < TS; os << ' ');
00092 }
00093 c += wb - i;
00094 while (i < wb) os << description[i++];
00095 }
00096 return os;
00097 }
00098
00099
00100 int CmdLineParser::parse (int argc, char *argv[])
00101 throw (CmdLineParseException)
00102 {
00103
00104
00105 for (int i = 0; i < argc; i++)
00106 pr["invocation"] << argv[i];
00107
00108 for (int i = 0; i < argc; i++)
00109 {
00110 string s = argv[i];
00111
00112 if (s[0] != '-') return i;
00113 if (s == "--") return i + 1;
00114
00115 bool isLong = s[1] == '-';
00116 int c = isLong ? 2 : 1;
00117 string opt;
00118 int n;
00119 while ((s[c] != '=') && (c < s.length())) opt += s[c++];
00120
00121 for (n = 0; n < desc.size(); n++)
00122 {
00123 if ((isLong && (opt == desc[n].lOpt)) ||
00124 (!isLong && (opt == desc[n].sOpt)))
00125 {
00126 switch (desc[n].tag) {
00127 case CmdLineAtom::k_string:
00128 {
00129 string val;
00130 if (c + 1 < s.length()) val.assign(s, c + 1, s.length() - c - 1);
00131 else if (i + 1 < argc) val = argv[++i];
00132 else throw CmdLineParseException("string argument expected after option \"" + opt + "\"");
00133 if (desc[n].multi) pr[desc[n].prop] << val;
00134 else pr[desc[n].prop] = val;
00135 }
00136 break;
00137 case CmdLineAtom::k_bool:
00138 {
00139 string val;
00140 bool bval;
00141
00142 if (c + 1 < s.length()) val.assign(s, c + 1, s.length() - c - 1);
00143 else if ((i + 1 < argc) && (argv[i + 1][0] != '-')) val = argv[++i];
00144 else val = "yes";
00145
00146 if ((val == "yes") || (val == "true") ||
00147 (val == "YES") || (val == "TRUE")) bval = true;
00148 else if ((val == "no") || (val == "false") ||
00149 (val == "NO") || (val == "FALSE")) bval = false;
00150 else throw CmdLineParseException("value of boolean option \"" + opt + "\" must be one of yes/no/false/true");
00151 if (desc[n].multi) pr[desc[n].prop] << bval;
00152 else pr[desc[n].prop] = bval;
00153 }
00154 break;
00155 case CmdLineAtom::k_int:
00156 {
00157 string val;
00158 int ival;
00159
00160 if (c + 1 < s.length()) val.assign(s, c + 1, s.length() - c - 1);
00161 else if (i + 1 < argc) val = argv[++i];
00162 else throw CmdLineParseException("integer value expected after option \"" + opt + "\"");
00163
00164 if (!(istringstream(val) >> ival))
00165 throw CmdLineParseException("bad integer argument for option \"" + opt + "\"");
00166 if (desc[n].multi) pr[desc[n].prop] << ival;
00167 else pr[desc[n].prop] = ival;
00168 }
00169 break;
00170 case CmdLineAtom::k_float:
00171 {
00172 string val;
00173 float fval;
00174
00175 if (c + 1 < s.length()) val.assign(s, c + 1, s.length() - c - 1);
00176 else if (i + 1 < argc) val = argv[++i];
00177 else throw CmdLineParseException("integer value expected after option \"" + opt + "\"");
00178
00179 if (!(istringstream(val) >> fval))
00180 throw CmdLineParseException("bad floating point argument for option \"" + opt + "\"");
00181 if (desc[n].multi) pr[desc[n].prop] << fval;
00182 else pr[desc[n].prop] = fval;
00183 }
00184 break;
00185 }
00186 break;
00187 }
00188 }
00189
00190 if (n == desc.size())
00191 throw CmdLineParseException("unknown option \"" + opt + "\"");
00192 }
00193 }
00194
00195
00196 void CmdLineParser::printUsage (ostream &os)
00197 {
00198 os << "Usage: " << endl << progName << ' ';
00199 for (int i = 0; i < desc.size(); i++)
00200 os << (string) desc[i] << ' ';
00201
00202 os << endl << endl << "Options: " << endl << endl;
00203
00204 for (int i = 0; i < desc.size(); i++) {
00205 desc[i].dumpDescription(os);
00206 os << endl << endl;
00207 }
00208
00209 os << endl << endl;
00210 }