00001 #ifndef COMMAND_LINE_IMPLEMENTATION_FILE
00002 #define COMMAND_LINE_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "command_line.h"
00019 #include "directory.h"
00020 #include "filename.h"
00021
00022 #include <basis/function.h>
00023 #include <basis/istring.h>
00024 #include <basis/log_base.h>
00025 #include <basis/mutex.h>
00026 #include <basis/portable.h>
00027 #include <basis/string_array.h>
00028 #include <data_struct/static_memory_gremlin.h>
00029 #include <textual/parser_bits.h>
00030
00031 #undef LOG
00032 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00033
00035
00036 command_parameter::command_parameter(parameter_types type)
00037 : _type(type), _text(new istring) {}
00038
00039 command_parameter::command_parameter(parameter_types type, const istring &text)
00040 : _type(type), _text(new istring(text)) {}
00041
00042 command_parameter::command_parameter(const command_parameter &to_copy)
00043 : object_base(), _type(VALUE), _text(new istring)
00044 { *this = to_copy; }
00045
00046 command_parameter::~command_parameter() { WHACK(_text); }
00047
00048 const istring &command_parameter::text() const { return *_text; }
00049
00050 void command_parameter::text(const istring &new_text) { *_text = new_text; }
00051
00052 command_parameter &command_parameter::operator =
00053 (const command_parameter &to_copy)
00054 {
00055 if (this == &to_copy) return *this;
00056 _type = to_copy._type;
00057 *_text = *to_copy._text;
00058 return *this;
00059 }
00060
00062
00063
00064
00065
00066
00067
00068 #if defined(_MSC_VER) || defined(__MINGW32__)
00069 static char option_prefixes[] = { '-', '/', '\0' };
00070 #elif defined(__UNIX__)
00071 static char option_prefixes[] = { '-', '\0' };
00072 #else
00073 #error "I don't know what kind of operating system this is."
00074 #endif
00075
00076 bool it_is_a_prefix_char(char to_test)
00077 {
00078 for (int i = 0; option_prefixes[i]; i++)
00079 if (to_test == option_prefixes[i]) return true;
00080 return false;
00081 }
00082
00084
00085 class internal_cmd_line_array_of_parms : public array<command_parameter> {};
00086
00088
00089 SAFE_STATIC_CONST(command_parameter, command_line::cmdline_blank_parm, )
00090
00091
00092 command_line::command_line(int argc, char *argv[])
00093 : _implementation(new internal_cmd_line_array_of_parms),
00094 _program_name(new filename(directory::absolute_path(argv[0])))
00095 {
00096 argv++;
00097
00098
00099 string_array string_list;
00100 while (--argc > 0) {
00101 istring to_store = argv[0];
00102 string_list += to_store;
00103 argv++;
00104 }
00105 parse_string_array(string_list);
00106 }
00107
00108 command_line::command_line(const istring &full_line)
00109 : _implementation(new internal_cmd_line_array_of_parms),
00110 _program_name(new filename)
00111 {
00112 istring accumulator;
00113 string_array string_list;
00114 bool in_quote = false;
00115
00116
00117
00118
00119 for (int i = 0; i < full_line.length(); i++) {
00120 char to_examine = full_line.get(i);
00121 if (to_examine == '"') {
00122
00123 if (!in_quote) {
00124 in_quote = true;
00125 continue;
00126 }
00127
00128
00129 in_quote = false;
00130 to_examine = ' ';
00131
00132 }
00133
00134 if (parser_bits::white_space(to_examine)) {
00135
00136 if (!in_quote && accumulator.t()) {
00137
00138 string_list += accumulator;
00139 accumulator = "";
00140 } else if (in_quote) {
00141
00142 accumulator += to_examine;
00143 }
00144 } else {
00145
00146 accumulator += to_examine;
00147 }
00148 }
00149 if (accumulator.t()) string_list += accumulator;
00150
00151
00152 *_program_name = directory::absolute_path(string_list[0]);
00153 string_list.zap(0, 0);
00154 parse_string_array(string_list);
00155 }
00156
00157 command_line::~command_line()
00158 {
00159 WHACK(_program_name);
00160 WHACK(_implementation);
00161 }
00162
00163 int command_line::entries() const { return _implementation->length(); }
00164
00165 filename command_line::program_name() const { return *_program_name; }
00166
00167 const command_parameter &command_line::get(int field) const
00168 {
00169 bounds_return(field, 0, entries() - 1, cmdline_blank_parm());
00170 return _implementation->get(field);
00171 }
00172
00173 void command_line::separate_command_line(const istring &cmd_line,
00174 istring &app, istring &parms)
00175 {
00176 char to_find = ' ';
00177 if (cmd_line[0] == '\"') to_find = '\"';
00178
00179
00180
00181
00182 int seek_posn = 1;
00183
00184 while (seek_posn < cmd_line.length()) {
00185
00186
00187
00188 int indy = cmd_line.find(to_find, seek_posn);
00189 if (negative(indy)) {
00190
00191
00192 app = cmd_line;
00193 break;
00194 } else {
00195
00196
00197 if (to_find == '\"') {
00198
00199 if (cmd_line[indy - 1] == '\\') {
00200
00201 seek_posn = indy + 1;
00202 continue;
00203 }
00204 app = cmd_line.substring(0, indy);
00205 parms = cmd_line.substring(indy + 2, cmd_line.end());
00206
00207 break;
00208 } else {
00209
00210 app = cmd_line.substring(0, indy - 1);
00211 parms = cmd_line.substring(indy + 1, cmd_line.end());
00212 break;
00213 }
00214 }
00215 }
00216 }
00217
00218 bool command_line::zap(int field)
00219 {
00220 bounds_return(field, 0, entries() - 1, false);
00221 _implementation->zap(field, field);
00222 return true;
00223 }
00224
00225
00226
00227 #define COMPLAIN_CMDS(s) \
00228 listo_cmds += "unknown"; \
00229 COMPLAIN(s)
00230
00231 string_array command_line::get_command_line()
00232 {
00233 FUNCDEF("get_command_line");
00234 string_array listo_cmds;
00235
00236
00237 istring temporary;
00238 #ifdef __UNIX__
00239 if (!__argc || !__argv) {
00240
00241 temporary = portable::get_cmdline_from_proc();
00242 } else {
00243
00244 for (int i = 0; i < __argc; i++) {
00245
00246 listo_cmds += __argv[i];
00247 }
00248
00249 return listo_cmds;
00250 }
00251 #elif defined(__WIN32__)
00252
00253 for (int i = 0; i < __argc; i++) {
00254
00255 listo_cmds += __argv[i];
00256 }
00257 return listo_cmds;
00258 #elif defined(EMBEDDED_BUILD)
00259 listo_cmds += "unknown";
00260 return listo_cmds;
00261 #else
00262 COMPLAIN_CMDS("this OS doesn't support getting the command line.");
00263 return listo_cmds;
00264 #endif
00265
00266
00267
00268
00269
00270
00271
00272
00273 int posn = 0;
00274 int last_posn = -1;
00275 while (posn < temporary.length()) {
00276 posn = temporary.find(' ', posn);
00277 if (non_negative(posn)) {
00278
00279 listo_cmds += temporary.substring(last_posn + 1, posn - 1);
00280
00281
00282 last_posn = posn;
00283 posn++;
00284 } else {
00285
00286
00287 if (last_posn < temporary.length() - 1) {
00288
00289
00290 listo_cmds += temporary.substring(last_posn + 1,
00291 temporary.length() - 1);
00292 }
00293 break;
00294 }
00295 }
00296
00297 return listo_cmds;
00298 }
00299
00300 istring command_line::text_form() const
00301 {
00302 istring to_return;
00303 const istring EOL = log_base::platform_ending();
00304 for (int i = 0; i < entries(); i++) {
00305 const command_parameter &curr = get(i);
00306 to_return += isprintf("%d: ", i + 1);
00307 switch (curr.type()) {
00308 case command_parameter::CHAR_FLAG:
00309 to_return += istring("<char flag> ") + curr.text() + EOL;
00310 break;
00311 case command_parameter::STRING_FLAG:
00312 to_return += istring("<string flag> ") + curr.text() + EOL;
00313 break;
00314 case command_parameter::VALUE:
00315 default:
00316 to_return += istring("<value> ") + curr.text() + EOL;
00317 break;
00318 }
00319 }
00320 return to_return;
00321 }
00322
00323 bool command_line::find(char option_character, int &index,
00324 bool case_sense) const
00325 {
00326 istring opt(option_character, 1);
00327 if (!case_sense) opt.to_lower();
00328 for (int i = index; i < entries(); i++) {
00329
00330 if (get(i).type() == command_parameter::CHAR_FLAG) {
00331 bool success = (!case_sense && get(i).text().iequals(opt))
00332 || (case_sense && (get(i).text() == opt));
00333 if (success) {
00334
00335 index = i;
00336 return true;
00337 }
00338 }
00339 }
00340 return false;
00341 }
00342
00343 bool command_line::find(const istring &option_string, int &index,
00344 bool case_sense) const
00345 {
00346 FUNCDEF("find");
00347 if (option_string.length() && (option_string[0] == '-') )
00348 LOG(istring("found option string with dash! string is: ") + option_string);
00349
00350 for (int i = index; i < entries(); i++) {
00351 if (get(i).type() == command_parameter::STRING_FLAG) {
00352 bool success = (!case_sense && get(i).text().iequals(option_string))
00353 || (case_sense && (get(i).text() == option_string));
00354 if (success) {
00355
00356 index = i;
00357 return true;
00358 }
00359 }
00360 }
00361 return false;
00362 }
00363
00364 bool command_line::get_value(char option_character, istring &value,
00365 bool case_sense) const
00366 {
00367 value = "";
00368 int posn = 0;
00369 if (!find(option_character, posn, case_sense)) return false;
00370
00371
00372 posn++;
00373 if (posn >= entries()) return false;
00374
00375
00376 command_parameter cp = get(posn);
00377 if (cp.type() != command_parameter::VALUE) return false;
00378
00379
00380 value = cp.text();
00381 return true;
00382 }
00383
00384 bool command_line::get_value(const istring &option_string, istring &value,
00385 bool case_sense) const
00386 {
00387 FUNCDEF("get_value");
00388 if (option_string.length() && (option_string[0] == '-') )
00389 LOG(istring("found option string with dash! string is: ") + option_string);
00390
00391 value = "";
00392 int posn = 0;
00393 if (!find(option_string, posn, case_sense)) return false;
00394
00395
00396 posn++;
00397 if (posn >= entries()) return false;
00398
00399
00400 command_parameter cp = get(posn);
00401 if (cp.type() != command_parameter::VALUE) return false;
00402
00403
00404 value = cp.text();
00405 return true;
00406 }
00407
00408 void command_line::parse_string_array(const string_array &to_parse)
00409 {
00410 bool still_looking_for_flags = true;
00411
00412 for (int i = 0; i < to_parse.length(); i++) {
00413
00414 int index = 0;
00415 char c = to_parse[i].get(index++);
00416
00417 if (still_looking_for_flags && it_is_a_prefix_char(c)) {
00418
00419 bool gnu_type_of_flag = false;
00420 if (it_is_a_prefix_char(to_parse[i].get(index))) {
00421
00422 index++;
00423 if ( (index >= to_parse[i].length())
00424 || parser_bits::white_space(to_parse[i].get(index))) {
00425
00426
00427
00428 still_looking_for_flags = false;
00429 continue;
00430 }
00431 gnu_type_of_flag = true;
00432 }
00433
00434
00435
00436 c = 1;
00437 istring gnu_accumulator;
00438 while (c) {
00439 if (!gnu_type_of_flag) {
00440
00441 c = to_parse[i].get(index++);
00442
00443 if (c) {
00444 command_parameter to_add(command_parameter::CHAR_FLAG, istring(c, 1));
00445 *_implementation += to_add;
00446 }
00447 } else {
00448
00449 c = to_parse[i].get(index++);
00450 if (c)
00451 gnu_accumulator += c;
00452 }
00453 }
00454 if (gnu_accumulator.t()) {
00455
00456 command_parameter to_add(command_parameter::STRING_FLAG,
00457 gnu_accumulator);
00458 *_implementation += to_add;
00459 }
00460 } else {
00461
00462 istring found = to_parse[i];
00463 command_parameter to_add(command_parameter::VALUE, found);
00464 *_implementation += to_add;
00465 }
00466 }
00467 }
00468
00469 istring command_line::gather(int &index) const
00470 {
00471 istring to_return;
00472 for (int i = index; i < entries(); i++) {
00473 if (get(i).type() == command_parameter::CHAR_FLAG) {
00474 index = i;
00475 return to_return;
00476 } else to_return += get(i).text();
00477 }
00478 index = entries() - 1;
00479 return to_return;
00480 }
00481
00482
00483 #endif //COMMAND_LINE_IMPLEMENTATION_FILE
00484