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