kcmdlineargs.cpp
00001 /* 00002 Copyright (C) 1999 Waldo Bastian <bastian@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include <config.h> 00020 00021 #include <sys/param.h> 00022 00023 #include <assert.h> 00024 #include <stdio.h> 00025 #include <stdlib.h> 00026 #include <string.h> 00027 #include <unistd.h> 00028 00029 #ifdef HAVE_LIMITS_H 00030 #include <limits.h> 00031 #endif 00032 00033 #include <tqdir.h> 00034 #include <tqfile.h> 00035 #include <tqasciidict.h> 00036 #include <tqstrlist.h> 00037 00038 #include "kcmdlineargs.h" 00039 #include <kaboutdata.h> 00040 #include <klocale.h> 00041 #include <kapplication.h> 00042 #include <kglobal.h> 00043 #include <kstringhandler.h> 00044 #include <kstaticdeleter.h> 00045 00046 #ifdef Q_WS_X11 00047 #define DISPLAY "DISPLAY" 00048 #elif defined(Q_WS_QWS) 00049 #define DISPLAY "QWS_DISPLAY" 00050 #endif 00051 00052 #ifdef Q_WS_WIN 00053 #include <win32_utils.h> 00054 #endif 00055 00056 template class TQAsciiDict<TQCString>; 00057 template class TQPtrList<KCmdLineArgs>; 00058 00059 class KCmdLineParsedOptions : public TQAsciiDict<TQCString> 00060 { 00061 public: 00062 KCmdLineParsedOptions() 00063 : TQAsciiDict<TQCString>( 7 ) { } 00064 00065 // WABA: Huh? 00066 // The compiler doesn't find KCmdLineParsedOptions::write(s) by itself ??? 00067 // WABA: No, because there is another write function that hides the 00068 // write function in the base class even though this function has a 00069 // different signature. (obscure C++ feature) 00070 TQDataStream& save( TQDataStream &s) const 00071 { return TQGDict::write(s); } 00072 00073 TQDataStream& load( TQDataStream &s) 00074 { return TQGDict::read(s); } 00075 00076 protected: 00077 virtual TQDataStream& write( TQDataStream &s, TQPtrCollection::Item data) const 00078 { 00079 TQCString *str = (TQCString *) data; 00080 s << (*str); 00081 return s; 00082 } 00083 00084 virtual TQDataStream& read( TQDataStream &s, TQPtrCollection::Item &item) 00085 { 00086 TQCString *str = new TQCString; 00087 s >> (*str); 00088 item = (void *)str; 00089 return s; 00090 } 00091 00092 }; 00093 00094 class KCmdLineParsedArgs : public TQStrList 00095 { 00096 public: 00097 KCmdLineParsedArgs() 00098 : TQStrList( true ) { } 00099 TQDataStream& save( TQDataStream &s) const 00100 { return TQGList::write(s); } 00101 00102 TQDataStream& load( TQDataStream &s) 00103 { return TQGList::read(s); } 00104 }; 00105 00106 00107 class KCmdLineArgsList: public TQPtrList<KCmdLineArgs> 00108 { 00109 public: 00110 KCmdLineArgsList() { } 00111 }; 00112 00113 KCmdLineArgsList *KCmdLineArgs::argsList = 0; 00114 int KCmdLineArgs::argc = 0; 00115 char **KCmdLineArgs::argv = 0; 00116 char *KCmdLineArgs::mCwd = 0; 00117 static KStaticDeleter <char> mCwdd; 00118 const KAboutData *KCmdLineArgs::about = 0; 00119 bool KCmdLineArgs::parsed = false; 00120 bool KCmdLineArgs::ignoreUnknown = false; 00121 00122 // 00123 // Static functions 00124 // 00125 00126 void 00127 KCmdLineArgs::init(int _argc, char **_argv, const char *_appname, const char* programName, 00128 const char *_description, const char *_version, bool noKApp) 00129 { 00130 init(_argc, _argv, 00131 new KAboutData(_appname, programName, _version, _description), 00132 noKApp); 00133 } 00134 00135 void 00136 KCmdLineArgs::init(int _argc, char **_argv, const char *_appname, 00137 const char *_description, const char *_version, bool noKApp) 00138 { 00139 init(_argc, _argv, 00140 new KAboutData(_appname, _appname, _version, _description), 00141 noKApp); 00142 } 00143 00144 void 00145 KCmdLineArgs::initIgnore(int _argc, char **_argv, const char *_appname ) 00146 { 00147 init(_argc, _argv, 00148 new KAboutData(_appname, _appname, "unknown", "KDE Application", false)); 00149 ignoreUnknown = true; 00150 } 00151 00152 void 00153 KCmdLineArgs::init(const KAboutData* ab) 00154 { 00155 char **_argv = (char **) malloc(sizeof(char *)); 00156 _argv[0] = (char *) ab->appName(); 00157 init(1,_argv,ab, true); 00158 } 00159 00160 00161 void 00162 KCmdLineArgs::init(int _argc, char **_argv, const KAboutData *_about, bool noKApp) 00163 { 00164 argc = _argc; 00165 argv = _argv; 00166 00167 if (!argv) 00168 { 00169 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 00170 fprintf(stderr, "Passing null-pointer to 'argv' is not allowed.\n\n"); 00171 00172 assert( 0 ); 00173 exit(255); 00174 } 00175 00176 // Strip path from argv[0] 00177 if (argc) { 00178 char *p = strrchr( argv[0], '/'); 00179 if (p) 00180 argv[0] = p+1; 00181 } 00182 00183 about = _about; 00184 parsed = false; 00185 mCwd = mCwdd.setObject(mCwd, new char [PATH_MAX+1], true); 00186 (void) getcwd(mCwd, PATH_MAX); 00187 #ifdef Q_WS_WIN 00188 win32_slashify(mCwd, PATH_MAX); 00189 #endif 00190 if (!noKApp) 00191 KApplication::addCmdLineOptions(); 00192 } 00193 00194 TQString KCmdLineArgs::cwd() 00195 { 00196 return TQFile::decodeName(TQCString(mCwd)); 00197 } 00198 00199 const char * KCmdLineArgs::appName() 00200 { 00201 if (!argc) return 0; 00202 return argv[0]; 00203 } 00204 00205 void 00206 KCmdLineArgs::addCmdLineOptions( const KCmdLineOptions *options, const char *name, 00207 const char *id, const char *afterId) 00208 { 00209 if (!argsList) 00210 argsList = new KCmdLineArgsList(); 00211 00212 int pos = argsList->count(); 00213 00214 if (pos && id && argsList->last() && !argsList->last()->name) 00215 pos--; 00216 00217 KCmdLineArgs *args; 00218 int i = 0; 00219 for(args = argsList->first(); args; args = argsList->next(), i++) 00220 { 00221 if (!id && !args->id) 00222 return; // Options already present. 00223 00224 if (id && args->id && (::qstrcmp(id, args->id) == 0)) 00225 return; // Options already present. 00226 00227 if (afterId && args->id && (::qstrcmp(afterId, args->id) == 0)) 00228 pos = i+1; 00229 } 00230 00231 assert( parsed == false ); // You must add _ALL_ cmd line options 00232 // before accessing the arguments! 00233 args = new KCmdLineArgs(options, name, id); 00234 argsList->insert(pos, args); 00235 } 00236 00237 void 00238 KCmdLineArgs::saveAppArgs( TQDataStream &ds) 00239 { 00240 if (!parsed) 00241 parseAllArgs(); 00242 00243 // Remove Qt and KDE options. 00244 removeArgs("qt"); 00245 removeArgs("kde"); 00246 00247 TQCString qCwd = mCwd; 00248 ds << qCwd; 00249 00250 uint count = argsList ? argsList->count() : 0; 00251 ds << count; 00252 00253 if (!count) return; 00254 00255 KCmdLineArgs *args; 00256 for(args = argsList->first(); args; args = argsList->next()) 00257 { 00258 ds << TQCString(args->id); 00259 args->save(ds); 00260 } 00261 } 00262 00263 void 00264 KCmdLineArgs::loadAppArgs( TQDataStream &ds) 00265 { 00266 parsed = true; // don't reparse argc/argv! 00267 00268 // Remove Qt and KDE options. 00269 removeArgs("qt"); 00270 removeArgs("kde"); 00271 00272 KCmdLineArgs *args; 00273 if ( argsList ) { 00274 for(args = argsList->first(); args; args = argsList->next()) 00275 { 00276 args->clear(); 00277 } 00278 } 00279 00280 if (ds.atEnd()) 00281 return; 00282 00283 TQCString qCwd; 00284 ds >> qCwd; 00285 delete [] mCwd; 00286 00287 mCwd = mCwdd.setObject(mCwd, new char[qCwd.length()+1], true); 00288 strncpy(mCwd, qCwd.data(), qCwd.length()+1); 00289 00290 uint count; 00291 ds >> count; 00292 00293 while(count--) 00294 { 00295 TQCString id; 00296 ds >> id; 00297 assert( argsList ); 00298 for(args = argsList->first(); args; args = argsList->next()) 00299 { 00300 if (args->id == id) 00301 { 00302 args->load(ds); 00303 break; 00304 } 00305 } 00306 } 00307 parsed = true; 00308 } 00309 00310 KCmdLineArgs *KCmdLineArgs::parsedArgs(const char *id) 00311 { 00312 KCmdLineArgs *args = argsList ? argsList->first() : 0; 00313 while(args) 00314 { 00315 if ((id && ::qstrcmp(args->id, id) == 0) || (!id && !args->id)) 00316 { 00317 if (!parsed) 00318 parseAllArgs(); 00319 return args; 00320 } 00321 args = argsList->next(); 00322 } 00323 00324 return args; 00325 } 00326 00327 void KCmdLineArgs::removeArgs(const char *id) 00328 { 00329 KCmdLineArgs *args = argsList ? argsList->first() : 0; 00330 while(args) 00331 { 00332 if (args->id && id && ::qstrcmp(args->id, id) == 0) 00333 { 00334 if (!parsed) 00335 parseAllArgs(); 00336 break; 00337 } 00338 args = argsList->next(); 00339 } 00340 00341 if (args) 00342 delete args; 00343 } 00344 00345 /* 00346 * @return: 00347 * 0 - option not found. 00348 * 1 - option found // -fork 00349 * 2 - inverse option found ('no') // -nofork 00350 * 3 - option + arg found // -fork now 00351 * 00352 * +4 - no more options follow // !fork 00353 */ 00354 static int 00355 findOption(const KCmdLineOptions *options, TQCString &opt, 00356 const char *&opt_name, const char *&def, bool &enabled) 00357 { 00358 int result; 00359 bool inverse; 00360 int len = opt.length(); 00361 while(options && options->name) 00362 { 00363 result = 0; 00364 inverse = false; 00365 opt_name = options->name; 00366 if ((opt_name[0] == ':') || (opt_name[0] == 0)) 00367 { 00368 options++; 00369 continue; 00370 } 00371 00372 if (opt_name[0] == '!') 00373 { 00374 opt_name++; 00375 result = 4; 00376 } 00377 if ((opt_name[0] == 'n') && (opt_name[1] == 'o')) 00378 { 00379 opt_name += 2; 00380 inverse = true; 00381 } 00382 if (strncmp(opt.data(), opt_name, len) == 0) 00383 { 00384 opt_name += len; 00385 if (!opt_name[0]) 00386 { 00387 if (inverse) 00388 return result+2; 00389 00390 if (!options->description) 00391 { 00392 options++; 00393 if (!options->name) 00394 return result+0; 00395 TQCString nextOption = options->name; 00396 int p = nextOption.find(' '); 00397 if (p > 0) 00398 nextOption = nextOption.left(p); 00399 if (nextOption[0] == '!') 00400 nextOption = nextOption.mid(1); 00401 if (strncmp(nextOption.data(), "no", 2) == 0) 00402 { 00403 nextOption = nextOption.mid(2); 00404 enabled = !enabled; 00405 } 00406 result = findOption(options, nextOption, opt_name, def, enabled); 00407 assert(result); 00408 opt = nextOption; 00409 return result; 00410 } 00411 00412 return 1; 00413 } 00414 if (opt_name[0] == ' ') 00415 { 00416 opt_name++; 00417 def = options->def; 00418 return result+3; 00419 } 00420 } 00421 00422 options++; 00423 } 00424 return 0; 00425 } 00426 00427 00428 void 00429 KCmdLineArgs::findOption(const char *_opt, TQCString opt, int &i, bool _enabled, bool &moreOptions) 00430 { 00431 KCmdLineArgs *args = argsList->first(); 00432 const char *opt_name; 00433 const char *def; 00434 TQCString argument; 00435 int j = opt.find('='); 00436 if (j != -1) 00437 { 00438 argument = opt.mid(j+1); 00439 opt = opt.left(j); 00440 } 00441 00442 bool enabled = true; 00443 int result = 0; 00444 while (args) 00445 { 00446 enabled = _enabled; 00447 result = ::findOption(args->options, opt, opt_name, def, enabled); 00448 if (result) break; 00449 args = argsList->next(); 00450 } 00451 if (!args && (_opt[0] == '-') && _opt[1] && (_opt[1] != '-')) 00452 { 00453 // Option not found check if it is a valid option 00454 // in the style of -Pprinter1 or ps -aux 00455 int p = 1; 00456 while (true) 00457 { 00458 TQCString singleCharOption = " "; 00459 singleCharOption[0] = _opt[p]; 00460 args = argsList->first(); 00461 while (args) 00462 { 00463 enabled = _enabled; 00464 result = ::findOption(args->options, singleCharOption, opt_name, def, enabled); 00465 if (result) break; 00466 args = argsList->next(); 00467 } 00468 if (!args) 00469 break; // Unknown argument 00470 00471 p++; 00472 if (result == 1) // Single option 00473 { 00474 args->setOption(singleCharOption, enabled); 00475 if (_opt[p]) 00476 continue; // Next option 00477 else 00478 return; // Finished 00479 } 00480 else if (result == 3) // This option takes an argument 00481 { 00482 if (argument.isEmpty()) 00483 { 00484 argument = _opt+p; 00485 } 00486 args->setOption(singleCharOption, (const char*)argument); 00487 return; 00488 } 00489 break; // Unknown argument 00490 } 00491 args = 0; 00492 result = 0; 00493 } 00494 00495 if (!args || !result) 00496 { 00497 if (ignoreUnknown) 00498 return; 00499 enable_i18n(); 00500 usage( i18n("Unknown option '%1'.").arg(TQString::fromLocal8Bit(_opt))); 00501 } 00502 00503 if ((result & 4) != 0) 00504 { 00505 result &= ~4; 00506 moreOptions = false; 00507 } 00508 00509 if (result == 3) // This option takes an argument 00510 { 00511 if (!enabled) 00512 { 00513 if (ignoreUnknown) 00514 return; 00515 enable_i18n(); 00516 usage( i18n("Unknown option '%1'.").arg(TQString::fromLocal8Bit(_opt))); 00517 } 00518 if (argument.isEmpty()) 00519 { 00520 i++; 00521 if (i >= argc) 00522 { 00523 enable_i18n(); 00524 usage( i18n("'%1' missing.").arg( opt_name)); 00525 } 00526 argument = argv[i]; 00527 } 00528 args->setOption(opt, (const char*)argument); 00529 } 00530 else 00531 { 00532 args->setOption(opt, enabled); 00533 } 00534 } 00535 00536 void 00537 KCmdLineArgs::printQ(const TQString &msg) 00538 { 00539 TQCString localMsg = msg.local8Bit(); 00540 fprintf(stdout, "%s", localMsg.data()); 00541 } 00542 00543 void 00544 KCmdLineArgs::parseAllArgs() 00545 { 00546 bool allowArgs = false; 00547 bool inOptions = true; 00548 bool everythingAfterArgIsArgs = false; 00549 KCmdLineArgs *appOptions = argsList->last(); 00550 if (!appOptions->id) 00551 { 00552 const KCmdLineOptions *option = appOptions->options; 00553 while(option && option->name) 00554 { 00555 if (option->name[0] == '+') 00556 allowArgs = true; 00557 if ( option->name[0] == '!' && option->name[1] == '+' ) 00558 { 00559 allowArgs = true; 00560 everythingAfterArgIsArgs = true; 00561 } 00562 option++; 00563 } 00564 } 00565 for(int i = 1; i < argc; i++) 00566 { 00567 if (!argv[i]) 00568 continue; 00569 00570 if ((argv[i][0] == '-') && argv[i][1] && inOptions) 00571 { 00572 bool enabled = true; 00573 const char *option = &argv[i][1]; 00574 const char *orig = argv[i]; 00575 if (option[0] == '-') 00576 { 00577 option++; 00578 argv[i]++; 00579 if (!option[0]) 00580 { 00581 inOptions = false; 00582 continue; 00583 } 00584 } 00585 if (::qstrcmp(option, "help") == 0) 00586 { 00587 usage(0); 00588 } 00589 else if (strncmp(option, "help-",5) == 0) 00590 { 00591 usage(option+5); 00592 } 00593 else if ( (::qstrcmp(option, "version") == 0) || 00594 (::qstrcmp(option, "v") == 0)) 00595 { 00596 printQ( TQString("Qt: %1\n").arg(qVersion())); 00597 printQ( TQString("KDE: %1\n").arg(KDE_VERSION_STRING)); 00598 printQ( TQString("%1: %2\n"). 00599 arg(about->programName()).arg(about->version())); 00600 exit(0); 00601 } else if ( (::qstrcmp(option, "license") == 0) ) 00602 { 00603 enable_i18n(); 00604 printQ( about->license() ); 00605 printQ( "\n" ); 00606 exit(0); 00607 } else if ( ::qstrcmp( option, "author") == 0 ) { 00608 enable_i18n(); 00609 if ( about ) { 00610 const TQValueList<KAboutPerson> authors = about->authors(); 00611 if ( !authors.isEmpty() ) { 00612 TQString authorlist; 00613 for (TQValueList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) { 00614 TQString email; 00615 if ( !(*it).emailAddress().isEmpty() ) 00616 email = " <" + (*it).emailAddress() + ">"; 00617 authorlist += TQString(" ") + (*it).name() + email + "\n"; 00618 } 00619 printQ( i18n("the 2nd argument is a list of name+address, one on each line","%1 was written by\n%2").arg ( TQString(about->programName()) ).arg( authorlist ) ); 00620 } 00621 } else { 00622 printQ( i18n("This application was written by somebody who wants to remain anonymous.") ); 00623 } 00624 if (about) 00625 { 00626 if (!about->customAuthorTextEnabled ()) 00627 { 00628 if (about->bugAddress().isEmpty() 00629 || about->bugAddress() == "submit@bugs.trinitydesktop.org" 00630 || about->bugAddress() == "http://bugs.trinitydesktop.org" ) 00631 printQ( i18n( "Please use http://bugs.trinitydesktop.org to report bugs.\n" ) ); 00632 else { 00633 if( about->authors().count() == 1 && about->authors().first().emailAddress() == about->bugAddress() ) 00634 printQ( i18n( "Please report bugs to %1.\n" ).arg( about->authors().first().emailAddress() ) ); 00635 else 00636 printQ( i18n( "Please report bugs to %1.\n" ).arg(about->bugAddress()) ); 00637 } 00638 } 00639 else 00640 { 00641 printQ(about->customAuthorPlainText()); 00642 } 00643 } 00644 exit(0); 00645 } else { 00646 if ((option[0] == 'n') && (option[1] == 'o')) 00647 { 00648 option += 2; 00649 enabled = false; 00650 } 00651 findOption(orig, option, i, enabled, inOptions); 00652 } 00653 } 00654 else 00655 { 00656 // Check whether appOptions allows these arguments 00657 if (!allowArgs) 00658 { 00659 if (ignoreUnknown) 00660 continue; 00661 enable_i18n(); 00662 usage( i18n("Unexpected argument '%1'.").arg(TQString::fromLocal8Bit(argv[i]))); 00663 } 00664 else 00665 { 00666 appOptions->addArgument(argv[i]); 00667 if (everythingAfterArgIsArgs) 00668 inOptions = false; 00669 } 00670 } 00671 } 00672 parsed = true; 00673 } 00674 00680 int * 00681 KCmdLineArgs::qt_argc() 00682 { 00683 if (!argsList) 00684 KApplication::addCmdLineOptions(); // Lazy bastards! 00685 00686 static int qt_argc = -1; 00687 if( qt_argc != -1 ) 00688 return &qt_argc; 00689 00690 KCmdLineArgs *args = parsedArgs("qt"); 00691 assert(args); // No qt options have been added! 00692 if (!argv) 00693 { 00694 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 00695 fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n"); 00696 00697 assert( 0 ); 00698 exit(255); 00699 } 00700 00701 assert(argc >= (args->count()+1)); 00702 qt_argc = args->count() +1; 00703 return &qt_argc; 00704 } 00705 00711 char *** 00712 KCmdLineArgs::qt_argv() 00713 { 00714 if (!argsList) 00715 KApplication::addCmdLineOptions(); // Lazy bastards! 00716 00717 static char** qt_argv; 00718 if( qt_argv != NULL ) 00719 return &qt_argv; 00720 00721 KCmdLineArgs *args = parsedArgs("qt"); 00722 assert(args); // No qt options have been added! 00723 if (!argv) 00724 { 00725 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 00726 fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n"); 00727 00728 assert( 0 ); 00729 exit(255); 00730 } 00731 00732 qt_argv = new char*[ args->count() + 2 ]; 00733 qt_argv[ 0 ] = qstrdup( appName()); 00734 int i = 0; 00735 for(; i < args->count(); i++) 00736 { 00737 qt_argv[i+1] = qstrdup((char *) args->arg(i)); 00738 } 00739 qt_argv[i+1] = 0; 00740 00741 return &qt_argv; 00742 } 00743 00744 void 00745 KCmdLineArgs::enable_i18n() 00746 { 00747 // called twice or too late 00748 if (KGlobal::_locale) 00749 return; 00750 00751 if (!KGlobal::_instance) { 00752 KInstance *instance = new KInstance(about); 00753 (void) instance->config(); 00754 // Don't delete instance! 00755 } 00756 } 00757 00758 void 00759 KCmdLineArgs::usage(const TQString &error) 00760 { 00761 assert(KGlobal::_locale); 00762 TQCString localError = error.local8Bit(); 00763 if (localError[error.length()-1] == '\n') 00764 localError = localError.left(error.length()-1); 00765 fprintf(stderr, "%s: %s\n", argv[0], localError.data()); 00766 00767 TQString tmp = i18n("Use --help to get a list of available command line options."); 00768 localError = tmp.local8Bit(); 00769 fprintf(stderr, "%s: %s\n", argv[0], localError.data()); 00770 exit(254); 00771 } 00772 00773 void 00774 KCmdLineArgs::usage(const char *id) 00775 { 00776 enable_i18n(); 00777 assert(argsList != 0); // It's an error to call usage(...) without 00778 // having done addCmdLineOptions first! 00779 00780 TQString optionFormatString = " %1 %2\n"; 00781 TQString optionFormatStringDef = " %1 %2 [%3]\n"; 00782 TQString optionHeaderString = i18n("\n%1:\n"); 00783 TQString tmp; 00784 TQString usage; 00785 00786 KCmdLineArgs *args = argsList->last(); 00787 00788 if (!(args->id) && (args->options) && 00789 (args->options->name) && (args->options->name[0] != '+')) 00790 { 00791 usage = i18n("[options] ")+usage; 00792 } 00793 00794 while(args) 00795 { 00796 if (args->name) 00797 { 00798 usage = i18n("[%1-options]").arg(args->name)+" "+usage; 00799 } 00800 args = argsList->prev(); 00801 } 00802 00803 KCmdLineArgs *appOptions = argsList->last(); 00804 if (!appOptions->id) 00805 { 00806 const KCmdLineOptions *option = appOptions->options; 00807 while(option && option->name) 00808 { 00809 if (option->name[0] == '+') 00810 usage = usage + (option->name+1) + " "; 00811 else if ( option->name[0] == '!' && option->name[1] == '+' ) 00812 usage = usage + (option->name+2) + " "; 00813 00814 option++; 00815 } 00816 } 00817 00818 printQ(i18n("Usage: %1 %2\n").arg(argv[0]).arg(usage)); 00819 printQ("\n"+about->shortDescription()+"\n"); 00820 00821 printQ(optionHeaderString.arg(i18n("Generic options"))); 00822 printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options"))); 00823 00824 args = argsList->first(); 00825 while(args) 00826 { 00827 if (args->name && args->id) 00828 { 00829 TQString option = TQString("--help-%1").arg(args->id); 00830 TQString desc = i18n("Show %1 specific options").arg(args->name); 00831 00832 printQ(optionFormatString.arg(option, -25).arg(desc)); 00833 } 00834 args = argsList->next(); 00835 } 00836 00837 printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options"))); 00838 printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information"))); 00839 printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information"))); 00840 printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information"))); 00841 printQ(optionFormatString.arg("--", -25).arg(i18n("End of options"))); 00842 00843 args = argsList->first(); // Sets current to 1st. 00844 00845 bool showAll = id && (::qstrcmp(id, "all") == 0); 00846 00847 if (!showAll) 00848 { 00849 while(args) 00850 { 00851 if (!id && !args->id) break; 00852 if (id && (::qstrcmp(args->id, id) == 0)) break; 00853 args = argsList->next(); 00854 } 00855 } 00856 00857 while(args) 00858 { 00859 bool hasArgs = false; 00860 bool hasOptions = false; 00861 TQString optionsHeader; 00862 if (args->name) 00863 optionsHeader = optionHeaderString.arg(i18n("%1 options").arg(TQString::fromLatin1(args->name))); 00864 else 00865 optionsHeader = i18n("\nOptions:\n"); 00866 00867 while (args) 00868 { 00869 const KCmdLineOptions *option = args->options; 00870 TQCString opt = ""; 00871 // 00872 while(option && option->name) 00873 { 00874 TQString description; 00875 TQString descriptionRest; 00876 TQStringList dl; 00877 00878 // Option header 00879 if (option->name[0] == ':') 00880 { 00881 if (option->description) 00882 { 00883 optionsHeader = "\n"+i18n(option->description); 00884 if (!optionsHeader.endsWith("\n")) 00885 optionsHeader.append("\n"); 00886 hasOptions = false; 00887 } 00888 option++; 00889 continue; 00890 } 00891 00892 // Free-form comment 00893 if (option->name[0] == 0) 00894 { 00895 if (option->description) 00896 { 00897 TQString tmp = "\n"+i18n(option->description); 00898 if (!tmp.endsWith("\n")) 00899 tmp.append("\n"); 00900 printQ(tmp); 00901 } 00902 option++; 00903 continue; 00904 } 00905 00906 // Options 00907 if (option->description) 00908 { 00909 description = i18n(option->description); 00910 dl = TQStringList::split("\n", description, true); 00911 description = dl.first(); 00912 dl.remove( dl.begin() ); 00913 } 00914 TQCString name = option->name; 00915 if (name[0] == '!') 00916 name = name.mid(1); 00917 00918 if (name[0] == '+') 00919 { 00920 if (!hasArgs) 00921 { 00922 printQ(i18n("\nArguments:\n")); 00923 hasArgs = true; 00924 } 00925 00926 name = name.mid(1); 00927 if ((name[0] == '[') && (name[name.length()-1] == ']')) 00928 name = name.mid(1, name.length()-2); 00929 printQ(optionFormatString.arg(QString(name), -25) 00930 .arg(description)); 00931 } 00932 else 00933 { 00934 if (!hasOptions) 00935 { 00936 printQ(optionsHeader); 00937 hasOptions = true; 00938 } 00939 00940 if ((name.length() == 1) || (name[1] == ' ')) 00941 name = "-"+name; 00942 else 00943 name = "--"+name; 00944 if (!option->description) 00945 { 00946 opt = name + ", "; 00947 } 00948 else 00949 { 00950 opt = opt + name; 00951 if (!option->def) 00952 { 00953 printQ(optionFormatString.arg(QString(opt), -25) 00954 .arg(description)); 00955 } 00956 else 00957 { 00958 printQ(optionFormatStringDef.arg(QString(opt), -25) 00959 .arg(description).arg(option->def)); 00960 } 00961 opt = ""; 00962 } 00963 } 00964 for(TQStringList::Iterator it = dl.begin(); 00965 it != dl.end(); 00966 ++it) 00967 { 00968 printQ(optionFormatString.arg("", -25).arg(*it)); 00969 } 00970 00971 option++; 00972 } 00973 args = argsList->next(); 00974 if (!args || args->name || !args->id) break; 00975 } 00976 if (!showAll) break; 00977 } 00978 00979 exit(254); 00980 } 00981 00982 // 00983 // Member functions 00984 // 00985 00991 KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions *_options, 00992 const char *_name, const char *_id) 00993 : options(_options), name(_name), id(_id) 00994 { 00995 parsedOptionList = 0; 00996 parsedArgList = 0; 00997 isQt = (::qstrcmp(id, "qt") == 0); 00998 } 00999 01003 KCmdLineArgs::~KCmdLineArgs() 01004 { 01005 delete parsedOptionList; 01006 delete parsedArgList; 01007 if (argsList) 01008 argsList->removeRef(this); 01009 } 01010 01011 void 01012 KCmdLineArgs::clear() 01013 { 01014 delete parsedArgList; 01015 parsedArgList = 0; 01016 delete parsedOptionList; 01017 parsedOptionList = 0; 01018 } 01019 01020 void 01021 KCmdLineArgs::reset() 01022 { 01023 if ( argsList ) { 01024 argsList->setAutoDelete( true ); 01025 argsList->clear(); 01026 delete argsList; 01027 argsList = 0; 01028 } 01029 parsed = false; 01030 } 01031 01032 void 01033 KCmdLineArgs::save( TQDataStream &ds) const 01034 { 01035 uint count = 0; 01036 if (parsedOptionList) 01037 parsedOptionList->save( ds ); 01038 else 01039 ds << count; 01040 01041 if (parsedArgList) 01042 parsedArgList->save( ds ); 01043 else 01044 ds << count; 01045 } 01046 01047 void 01048 KCmdLineArgs::load( TQDataStream &ds) 01049 { 01050 if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions; 01051 if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs; 01052 01053 parsedOptionList->load( ds ); 01054 parsedArgList->load( ds ); 01055 01056 if (parsedOptionList->count() == 0) 01057 { 01058 delete parsedOptionList; 01059 parsedOptionList = 0; 01060 } 01061 if (parsedArgList->count() == 0) 01062 { 01063 delete parsedArgList; 01064 parsedArgList = 0; 01065 } 01066 } 01067 01068 void 01069 KCmdLineArgs::setOption(const TQCString &opt, bool enabled) 01070 { 01071 if (isQt) 01072 { 01073 // Qt does it own parsing. 01074 TQCString arg = "-"; 01075 if( !enabled ) 01076 arg += "no"; 01077 arg += opt; 01078 addArgument(arg); 01079 } 01080 if (!parsedOptionList) { 01081 parsedOptionList = new KCmdLineParsedOptions; 01082 parsedOptionList->setAutoDelete(true); 01083 } 01084 01085 if (enabled) 01086 parsedOptionList->replace( opt, new TQCString("t") ); 01087 else 01088 parsedOptionList->replace( opt, new TQCString("f") ); 01089 } 01090 01091 void 01092 KCmdLineArgs::setOption(const TQCString &opt, const char *value) 01093 { 01094 if (isQt) 01095 { 01096 // Qt does it's own parsing. 01097 TQCString arg = "-"; 01098 arg += opt; 01099 addArgument(arg); 01100 addArgument(value); 01101 01102 #ifdef Q_WS_X11 01103 // Hack coming up! 01104 if (arg == "-display") 01105 { 01106 setenv(DISPLAY, value, true); 01107 } 01108 #endif 01109 } 01110 if (!parsedOptionList) { 01111 parsedOptionList = new KCmdLineParsedOptions; 01112 parsedOptionList->setAutoDelete(true); 01113 } 01114 01115 parsedOptionList->insert( opt, new TQCString(value) ); 01116 } 01117 01118 TQCString 01119 KCmdLineArgs::getOption(const char *_opt) const 01120 { 01121 TQCString *value = 0; 01122 if (parsedOptionList) 01123 { 01124 value = parsedOptionList->find(_opt); 01125 } 01126 01127 if (value) 01128 return (*value); 01129 01130 // Look up the default. 01131 const char *opt_name; 01132 const char *def; 01133 bool dummy = true; 01134 TQCString opt = _opt; 01135 int result = ::findOption( options, opt, opt_name, def, dummy) & ~4; 01136 01137 if (result != 3) 01138 { 01139 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 01140 fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n", 01141 _opt, _opt); 01142 fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n"); 01143 01144 assert( 0 ); 01145 exit(255); 01146 } 01147 return TQCString(def); 01148 } 01149 01150 QCStringList 01151 KCmdLineArgs::getOptionList(const char *_opt) const 01152 { 01153 QCStringList result; 01154 if (!parsedOptionList) 01155 return result; 01156 01157 while(true) 01158 { 01159 TQCString *value = parsedOptionList->take(_opt); 01160 if (!value) 01161 break; 01162 result.prepend(*value); 01163 delete value; 01164 } 01165 01166 // Reinsert items in dictionary 01167 // WABA: This is rather silly, but I don't want to add restrictions 01168 // to the API like "you can only call this function once". 01169 // I can't access all items without taking them out of the list. 01170 // So taking them out and then putting them back is the only way. 01171 for(QCStringList::ConstIterator it=result.begin(); 01172 it != result.end(); 01173 ++it) 01174 { 01175 parsedOptionList->insert(_opt, new TQCString(*it)); 01176 } 01177 return result; 01178 } 01179 01180 bool 01181 KCmdLineArgs::isSet(const char *_opt) const 01182 { 01183 // Look up the default. 01184 const char *opt_name; 01185 const char *def; 01186 bool dummy = true; 01187 TQCString opt = _opt; 01188 int result = ::findOption( options, opt, opt_name, def, dummy) & ~4; 01189 01190 if (result == 0) 01191 { 01192 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 01193 fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n", 01194 _opt, _opt); 01195 fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n"); 01196 01197 assert( 0 ); 01198 exit(255); 01199 } 01200 01201 TQCString *value = 0; 01202 if (parsedOptionList) 01203 { 01204 value = parsedOptionList->find(opt); 01205 } 01206 01207 if (value) 01208 { 01209 if (result == 3) 01210 return true; 01211 else 01212 return ((*value)[0] == 't'); 01213 } 01214 01215 if (result == 3) 01216 return false; // String option has 'false' as default. 01217 01218 // We return 'true' as default if the option was listed as '-nofork' 01219 // We return 'false' as default if the option was listed as '-fork' 01220 return (result == 2); 01221 } 01222 01223 int 01224 KCmdLineArgs::count() const 01225 { 01226 if (!parsedArgList) 01227 return 0; 01228 return parsedArgList->count(); 01229 } 01230 01231 const char * 01232 KCmdLineArgs::arg(int n) const 01233 { 01234 if (!parsedArgList || (n >= (int) parsedArgList->count())) 01235 { 01236 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n"); 01237 fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n", 01238 n); 01239 01240 assert( 0 ); 01241 exit(255); 01242 } 01243 01244 return parsedArgList->at(n); 01245 } 01246 01247 KURL 01248 KCmdLineArgs::url(int n) const 01249 { 01250 return makeURL( arg(n) ); 01251 } 01252 01253 KURL KCmdLineArgs::makeURL(const char *_urlArg) 01254 { 01255 const TQString urlArg = TQFile::decodeName(_urlArg); 01256 TQFileInfo fileInfo(urlArg); 01257 if (!fileInfo.isRelative()) { // i.e. starts with '/', on unix 01258 KURL result; 01259 result.setPath(urlArg); 01260 return result; // Absolute path. 01261 } 01262 01263 if ( KURL::isRelativeURL(urlArg) || fileInfo.exists() ) { 01264 KURL result; 01265 result.setPath( cwd()+'/'+urlArg ); 01266 result.cleanPath(); 01267 return result; // Relative path 01268 } 01269 01270 return KURL(urlArg); // Argument is a URL 01271 } 01272 01273 void 01274 KCmdLineArgs::addArgument(const char *argument) 01275 { 01276 if (!parsedArgList) 01277 parsedArgList = new KCmdLineParsedArgs; 01278 01279 parsedArgList->append(argument); 01280 } 01281 01282 static const KCmdLineOptions kde_tempfile_option[] = 01283 { 01284 { "tempfile", I18N_NOOP("The files/URLs opened by the application will be deleted after use"), 0}, 01285 KCmdLineLastOption 01286 }; 01287 01288 void 01289 KCmdLineArgs::addTempFileOption() 01290 { 01291 KCmdLineArgs::addCmdLineOptions( kde_tempfile_option, "KDE-tempfile", "kde-tempfile" ); 01292 } 01293 01294 bool KCmdLineArgs::isTempFileSet() 01295 { 01296 KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" ); 01297 if ( args ) 01298 return args->isSet( "tempfile" ); 01299 return false; 01300 }