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 <qdir.h> 00034 #include <qfile.h> 00035 #include <qasciidict.h> 00036 #include <qstrlist.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 QAsciiDict<QCString>; 00057 template class QPtrList<KCmdLineArgs>; 00058 00059 class KCmdLineParsedOptions : public QAsciiDict<QCString> 00060 { 00061 public: 00062 KCmdLineParsedOptions() 00063 : QAsciiDict<QCString>( 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 QDataStream& save( QDataStream &s) const 00071 { return QGDict::write(s); } 00072 00073 QDataStream& load( QDataStream &s) 00074 { return QGDict::read(s); } 00075 00076 protected: 00077 virtual QDataStream& write( QDataStream &s, QPtrCollection::Item data) const 00078 { 00079 QCString *str = (QCString *) data; 00080 s << (*str); 00081 return s; 00082 } 00083 00084 virtual QDataStream& read( QDataStream &s, QPtrCollection::Item &item) 00085 { 00086 QCString *str = new QCString; 00087 s >> (*str); 00088 item = (void *)str; 00089 return s; 00090 } 00091 00092 }; 00093 00094 class KCmdLineParsedArgs : public QStrList 00095 { 00096 public: 00097 KCmdLineParsedArgs() 00098 : QStrList( true ) { } 00099 QDataStream& save( QDataStream &s) const 00100 { return QGList::write(s); } 00101 00102 QDataStream& load( QDataStream &s) 00103 { return QGList::read(s); } 00104 }; 00105 00106 00107 class KCmdLineArgsList: public QPtrList<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 QString KCmdLineArgs::cwd() 00195 { 00196 return QFile::decodeName(QCString(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( QDataStream &ds) 00239 { 00240 if (!parsed) 00241 parseAllArgs(); 00242 00243 // Remove Qt and KDE options. 00244 removeArgs("qt"); 00245 removeArgs("kde"); 00246 00247 QCString 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 << QCString(args->id); 00259 args->save(ds); 00260 } 00261 } 00262 00263 void 00264 KCmdLineArgs::loadAppArgs( QDataStream &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 QCString 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 QCString 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, QCString &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 QCString 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, QCString opt, int &i, bool _enabled, bool &moreOptions) 00430 { 00431 KCmdLineArgs *args = argsList->first(); 00432 const char *opt_name; 00433 const char *def; 00434 QCString 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 QCString 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, 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(QString::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(QString::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, argument); 00529 } 00530 else 00531 { 00532 args->setOption(opt, enabled); 00533 } 00534 } 00535 00536 void 00537 KCmdLineArgs::printQ(const QString &msg) 00538 { 00539 QCString 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( QString("Qt: %1\n").arg(qVersion())); 00597 printQ( QString("KDE: %1\n").arg(KDE_VERSION_STRING)); 00598 printQ( QString("%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 QValueList<KAboutPerson> authors = about->authors(); 00611 if ( !authors.isEmpty() ) { 00612 QString authorlist; 00613 for (QValueList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) { 00614 QString email; 00615 if ( !(*it).emailAddress().isEmpty() ) 00616 email = " <" + (*it).emailAddress() + ">"; 00617 authorlist += QString(" ") + (*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 ( QString(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() || about->bugAddress() == "submit@bugs.kde.org" ) 00629 printQ( i18n( "Please use http://bugs.kde.org to report bugs.\n" ) ); 00630 else { 00631 if( about->authors().count() == 1 && about->authors().first().emailAddress() == about->bugAddress() ) 00632 printQ( i18n( "Please report bugs to %1.\n" ).arg( about->authors().first().emailAddress() ) ); 00633 else 00634 printQ( i18n( "Please report bugs to %1.\n" ).arg(about->bugAddress()) ); 00635 } 00636 } 00637 else 00638 { 00639 printQ(about->customAuthorPlainText()); 00640 } 00641 } 00642 exit(0); 00643 } else { 00644 if ((option[0] == 'n') && (option[1] == 'o')) 00645 { 00646 option += 2; 00647 enabled = false; 00648 } 00649 findOption(orig, option, i, enabled, inOptions); 00650 } 00651 } 00652 else 00653 { 00654 // Check whether appOptions allows these arguments 00655 if (!allowArgs) 00656 { 00657 if (ignoreUnknown) 00658 continue; 00659 enable_i18n(); 00660 usage( i18n("Unexpected argument '%1'.").arg(QString::fromLocal8Bit(argv[i]))); 00661 } 00662 else 00663 { 00664 appOptions->addArgument(argv[i]); 00665 if (everythingAfterArgIsArgs) 00666 inOptions = false; 00667 } 00668 } 00669 } 00670 parsed = true; 00671 } 00672 00678 int * 00679 KCmdLineArgs::qt_argc() 00680 { 00681 if (!argsList) 00682 KApplication::addCmdLineOptions(); // Lazy bastards! 00683 00684 static int qt_argc = -1; 00685 if( qt_argc != -1 ) 00686 return &qt_argc; 00687 00688 KCmdLineArgs *args = parsedArgs("qt"); 00689 assert(args); // No qt options have been added! 00690 if (!argv) 00691 { 00692 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 00693 fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n"); 00694 00695 assert( 0 ); 00696 exit(255); 00697 } 00698 00699 assert(argc >= (args->count()+1)); 00700 qt_argc = args->count() +1; 00701 return &qt_argc; 00702 } 00703 00709 char *** 00710 KCmdLineArgs::qt_argv() 00711 { 00712 if (!argsList) 00713 KApplication::addCmdLineOptions(); // Lazy bastards! 00714 00715 static char** qt_argv; 00716 if( qt_argv != NULL ) 00717 return &qt_argv; 00718 00719 KCmdLineArgs *args = parsedArgs("qt"); 00720 assert(args); // No qt options have been added! 00721 if (!argv) 00722 { 00723 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 00724 fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n"); 00725 00726 assert( 0 ); 00727 exit(255); 00728 } 00729 00730 qt_argv = new char*[ args->count() + 2 ]; 00731 qt_argv[ 0 ] = qstrdup( appName()); 00732 int i = 0; 00733 for(; i < args->count(); i++) 00734 { 00735 qt_argv[i+1] = qstrdup((char *) args->arg(i)); 00736 } 00737 qt_argv[i+1] = 0; 00738 00739 return &qt_argv; 00740 } 00741 00742 void 00743 KCmdLineArgs::enable_i18n() 00744 { 00745 // called twice or too late 00746 if (KGlobal::_locale) 00747 return; 00748 00749 if (!KGlobal::_instance) { 00750 KInstance *instance = new KInstance(about); 00751 (void) instance->config(); 00752 // Don't delete instance! 00753 } 00754 } 00755 00756 void 00757 KCmdLineArgs::usage(const QString &error) 00758 { 00759 assert(KGlobal::_locale); 00760 QCString localError = error.local8Bit(); 00761 if (localError[error.length()-1] == '\n') 00762 localError = localError.left(error.length()-1); 00763 fprintf(stderr, "%s: %s\n", argv[0], localError.data()); 00764 00765 QString tmp = i18n("Use --help to get a list of available command line options."); 00766 localError = tmp.local8Bit(); 00767 fprintf(stderr, "%s: %s\n", argv[0], localError.data()); 00768 exit(254); 00769 } 00770 00771 void 00772 KCmdLineArgs::usage(const char *id) 00773 { 00774 enable_i18n(); 00775 assert(argsList != 0); // It's an error to call usage(...) without 00776 // having done addCmdLineOptions first! 00777 00778 QString optionFormatString = " %1 %2\n"; 00779 QString optionFormatStringDef = " %1 %2 [%3]\n"; 00780 QString optionHeaderString = i18n("\n%1:\n"); 00781 QString tmp; 00782 QString usage; 00783 00784 KCmdLineArgs *args = argsList->last(); 00785 00786 if (!(args->id) && (args->options) && 00787 (args->options->name) && (args->options->name[0] != '+')) 00788 { 00789 usage = i18n("[options] ")+usage; 00790 } 00791 00792 while(args) 00793 { 00794 if (args->name) 00795 { 00796 usage = i18n("[%1-options]").arg(args->name)+" "+usage; 00797 } 00798 args = argsList->prev(); 00799 } 00800 00801 KCmdLineArgs *appOptions = argsList->last(); 00802 if (!appOptions->id) 00803 { 00804 const KCmdLineOptions *option = appOptions->options; 00805 while(option && option->name) 00806 { 00807 if (option->name[0] == '+') 00808 usage = usage + (option->name+1) + " "; 00809 else if ( option->name[0] == '!' && option->name[1] == '+' ) 00810 usage = usage + (option->name+2) + " "; 00811 00812 option++; 00813 } 00814 } 00815 00816 printQ(i18n("Usage: %1 %2\n").arg(argv[0]).arg(usage)); 00817 printQ("\n"+about->shortDescription()+"\n"); 00818 00819 printQ(optionHeaderString.arg(i18n("Generic options"))); 00820 printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options"))); 00821 00822 args = argsList->first(); 00823 while(args) 00824 { 00825 if (args->name && args->id) 00826 { 00827 QString option = QString("--help-%1").arg(args->id); 00828 QString desc = i18n("Show %1 specific options").arg(args->name); 00829 00830 printQ(optionFormatString.arg(option, -25).arg(desc)); 00831 } 00832 args = argsList->next(); 00833 } 00834 00835 printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options"))); 00836 printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information"))); 00837 printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information"))); 00838 printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information"))); 00839 printQ(optionFormatString.arg("--", -25).arg(i18n("End of options"))); 00840 00841 args = argsList->first(); // Sets current to 1st. 00842 00843 bool showAll = id && (::qstrcmp(id, "all") == 0); 00844 00845 if (!showAll) 00846 { 00847 while(args) 00848 { 00849 if (!id && !args->id) break; 00850 if (id && (::qstrcmp(args->id, id) == 0)) break; 00851 args = argsList->next(); 00852 } 00853 } 00854 00855 while(args) 00856 { 00857 bool hasArgs = false; 00858 bool hasOptions = false; 00859 QString optionsHeader; 00860 if (args->name) 00861 optionsHeader = optionHeaderString.arg(i18n("%1 options").arg(QString::fromLatin1(args->name))); 00862 else 00863 optionsHeader = i18n("\nOptions:\n"); 00864 00865 while (args) 00866 { 00867 const KCmdLineOptions *option = args->options; 00868 QCString opt = ""; 00869 // 00870 while(option && option->name) 00871 { 00872 QString description; 00873 QString descriptionRest; 00874 QStringList dl; 00875 00876 // Option header 00877 if (option->name[0] == ':') 00878 { 00879 if (option->description) 00880 { 00881 optionsHeader = "\n"+i18n(option->description); 00882 if (!optionsHeader.endsWith("\n")) 00883 optionsHeader.append("\n"); 00884 hasOptions = false; 00885 } 00886 option++; 00887 continue; 00888 } 00889 00890 // Free-form comment 00891 if (option->name[0] == 0) 00892 { 00893 if (option->description) 00894 { 00895 QString tmp = "\n"+i18n(option->description); 00896 if (!tmp.endsWith("\n")) 00897 tmp.append("\n"); 00898 printQ(tmp); 00899 } 00900 option++; 00901 continue; 00902 } 00903 00904 // Options 00905 if (option->description) 00906 { 00907 description = i18n(option->description); 00908 dl = QStringList::split("\n", description, true); 00909 description = dl.first(); 00910 dl.remove( dl.begin() ); 00911 } 00912 QCString name = option->name; 00913 if (name[0] == '!') 00914 name = name.mid(1); 00915 00916 if (name[0] == '+') 00917 { 00918 if (!hasArgs) 00919 { 00920 printQ(i18n("\nArguments:\n")); 00921 hasArgs = true; 00922 } 00923 00924 name = name.mid(1); 00925 if ((name[0] == '[') && (name[name.length()-1] == ']')) 00926 name = name.mid(1, name.length()-2); 00927 printQ(optionFormatString.arg(name, -25) 00928 .arg(description)); 00929 } 00930 else 00931 { 00932 if (!hasOptions) 00933 { 00934 printQ(optionsHeader); 00935 hasOptions = true; 00936 } 00937 00938 if ((name.length() == 1) || (name[1] == ' ')) 00939 name = "-"+name; 00940 else 00941 name = "--"+name; 00942 if (!option->description) 00943 { 00944 opt = name + ", "; 00945 } 00946 else 00947 { 00948 opt = opt + name; 00949 if (!option->def) 00950 { 00951 printQ(optionFormatString.arg(opt, -25) 00952 .arg(description)); 00953 } 00954 else 00955 { 00956 printQ(optionFormatStringDef.arg(opt, -25) 00957 .arg(description).arg(option->def)); 00958 } 00959 opt = ""; 00960 } 00961 } 00962 for(QStringList::Iterator it = dl.begin(); 00963 it != dl.end(); 00964 ++it) 00965 { 00966 printQ(optionFormatString.arg("", -25).arg(*it)); 00967 } 00968 00969 option++; 00970 } 00971 args = argsList->next(); 00972 if (!args || args->name || !args->id) break; 00973 } 00974 if (!showAll) break; 00975 } 00976 00977 exit(254); 00978 } 00979 00980 // 00981 // Member functions 00982 // 00983 00989 KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions *_options, 00990 const char *_name, const char *_id) 00991 : options(_options), name(_name), id(_id) 00992 { 00993 parsedOptionList = 0; 00994 parsedArgList = 0; 00995 isQt = (::qstrcmp(id, "qt") == 0); 00996 } 00997 01001 KCmdLineArgs::~KCmdLineArgs() 01002 { 01003 delete parsedOptionList; 01004 delete parsedArgList; 01005 if (argsList) 01006 argsList->removeRef(this); 01007 } 01008 01009 void 01010 KCmdLineArgs::clear() 01011 { 01012 delete parsedArgList; 01013 parsedArgList = 0; 01014 delete parsedOptionList; 01015 parsedOptionList = 0; 01016 } 01017 01018 void 01019 KCmdLineArgs::reset() 01020 { 01021 if ( argsList ) { 01022 argsList->setAutoDelete( true ); 01023 argsList->clear(); 01024 delete argsList; 01025 argsList = 0; 01026 } 01027 parsed = false; 01028 } 01029 01030 void 01031 KCmdLineArgs::save( QDataStream &ds) const 01032 { 01033 uint count = 0; 01034 if (parsedOptionList) 01035 parsedOptionList->save( ds ); 01036 else 01037 ds << count; 01038 01039 if (parsedArgList) 01040 parsedArgList->save( ds ); 01041 else 01042 ds << count; 01043 } 01044 01045 void 01046 KCmdLineArgs::load( QDataStream &ds) 01047 { 01048 if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions; 01049 if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs; 01050 01051 parsedOptionList->load( ds ); 01052 parsedArgList->load( ds ); 01053 01054 if (parsedOptionList->count() == 0) 01055 { 01056 delete parsedOptionList; 01057 parsedOptionList = 0; 01058 } 01059 if (parsedArgList->count() == 0) 01060 { 01061 delete parsedArgList; 01062 parsedArgList = 0; 01063 } 01064 } 01065 01066 void 01067 KCmdLineArgs::setOption(const QCString &opt, bool enabled) 01068 { 01069 if (isQt) 01070 { 01071 // Qt does it own parsing. 01072 QCString arg = "-"; 01073 if( !enabled ) 01074 arg += "no"; 01075 arg += opt; 01076 addArgument(arg); 01077 } 01078 if (!parsedOptionList) { 01079 parsedOptionList = new KCmdLineParsedOptions; 01080 parsedOptionList->setAutoDelete(true); 01081 } 01082 01083 if (enabled) 01084 parsedOptionList->replace( opt, new QCString("t") ); 01085 else 01086 parsedOptionList->replace( opt, new QCString("f") ); 01087 } 01088 01089 void 01090 KCmdLineArgs::setOption(const QCString &opt, const char *value) 01091 { 01092 if (isQt) 01093 { 01094 // Qt does it's own parsing. 01095 QCString arg = "-"; 01096 arg += opt; 01097 addArgument(arg); 01098 addArgument(value); 01099 01100 #ifdef Q_WS_X11 01101 // Hack coming up! 01102 if (arg == "-display") 01103 { 01104 setenv(DISPLAY, value, true); 01105 } 01106 #endif 01107 } 01108 if (!parsedOptionList) { 01109 parsedOptionList = new KCmdLineParsedOptions; 01110 parsedOptionList->setAutoDelete(true); 01111 } 01112 01113 parsedOptionList->insert( opt, new QCString(value) ); 01114 } 01115 01116 QCString 01117 KCmdLineArgs::getOption(const char *_opt) const 01118 { 01119 QCString *value = 0; 01120 if (parsedOptionList) 01121 { 01122 value = parsedOptionList->find(_opt); 01123 } 01124 01125 if (value) 01126 return (*value); 01127 01128 // Look up the default. 01129 const char *opt_name; 01130 const char *def; 01131 bool dummy = true; 01132 QCString opt = _opt; 01133 int result = ::findOption( options, opt, opt_name, def, dummy) & ~4; 01134 01135 if (result != 3) 01136 { 01137 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 01138 fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n", 01139 _opt, _opt); 01140 fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n"); 01141 01142 assert( 0 ); 01143 exit(255); 01144 } 01145 return QCString(def); 01146 } 01147 01148 QCStringList 01149 KCmdLineArgs::getOptionList(const char *_opt) const 01150 { 01151 QCStringList result; 01152 if (!parsedOptionList) 01153 return result; 01154 01155 while(true) 01156 { 01157 QCString *value = parsedOptionList->take(_opt); 01158 if (!value) 01159 break; 01160 result.prepend(*value); 01161 delete value; 01162 } 01163 01164 // Reinsert items in dictionary 01165 // WABA: This is rather silly, but I don't want to add restrictions 01166 // to the API like "you can only call this function once". 01167 // I can't access all items without taking them out of the list. 01168 // So taking them out and then putting them back is the only way. 01169 for(QCStringList::ConstIterator it=result.begin(); 01170 it != result.end(); 01171 ++it) 01172 { 01173 parsedOptionList->insert(_opt, new QCString(*it)); 01174 } 01175 return result; 01176 } 01177 01178 bool 01179 KCmdLineArgs::isSet(const char *_opt) const 01180 { 01181 // Look up the default. 01182 const char *opt_name; 01183 const char *def; 01184 bool dummy = true; 01185 QCString opt = _opt; 01186 int result = ::findOption( options, opt, opt_name, def, dummy) & ~4; 01187 01188 if (result == 0) 01189 { 01190 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n"); 01191 fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n", 01192 _opt, _opt); 01193 fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n"); 01194 01195 assert( 0 ); 01196 exit(255); 01197 } 01198 01199 QCString *value = 0; 01200 if (parsedOptionList) 01201 { 01202 value = parsedOptionList->find(opt); 01203 } 01204 01205 if (value) 01206 { 01207 if (result == 3) 01208 return true; 01209 else 01210 return ((*value)[0] == 't'); 01211 } 01212 01213 if (result == 3) 01214 return false; // String option has 'false' as default. 01215 01216 // We return 'true' as default if the option was listed as '-nofork' 01217 // We return 'false' as default if the option was listed as '-fork' 01218 return (result == 2); 01219 } 01220 01221 int 01222 KCmdLineArgs::count() const 01223 { 01224 if (!parsedArgList) 01225 return 0; 01226 return parsedArgList->count(); 01227 } 01228 01229 const char * 01230 KCmdLineArgs::arg(int n) const 01231 { 01232 if (!parsedArgList || (n >= (int) parsedArgList->count())) 01233 { 01234 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n"); 01235 fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n", 01236 n); 01237 01238 assert( 0 ); 01239 exit(255); 01240 } 01241 01242 return parsedArgList->at(n); 01243 } 01244 01245 KURL 01246 KCmdLineArgs::url(int n) const 01247 { 01248 return makeURL( arg(n) ); 01249 } 01250 01251 KURL KCmdLineArgs::makeURL(const char *_urlArg) 01252 { 01253 const QString urlArg = QFile::decodeName(_urlArg); 01254 QFileInfo fileInfo(urlArg); 01255 if (!fileInfo.isRelative()) { // i.e. starts with '/', on unix 01256 KURL result; 01257 result.setPath(urlArg); 01258 return result; // Absolute path. 01259 } 01260 01261 if ( KURL::isRelativeURL(urlArg) || fileInfo.exists() ) { 01262 KURL result; 01263 result.setPath( cwd()+'/'+urlArg ); 01264 result.cleanPath(); 01265 return result; // Relative path 01266 } 01267 01268 return KURL(urlArg); // Argument is a URL 01269 } 01270 01271 void 01272 KCmdLineArgs::addArgument(const char *argument) 01273 { 01274 if (!parsedArgList) 01275 parsedArgList = new KCmdLineParsedArgs; 01276 01277 parsedArgList->append(argument); 01278 } 01279 01280 static const KCmdLineOptions kde_tempfile_option[] = 01281 { 01282 { "tempfile", I18N_NOOP("The files/URLs opened by the application will be deleted after use"), 0}, 01283 KCmdLineLastOption 01284 }; 01285 01286 void 01287 KCmdLineArgs::addTempFileOption() 01288 { 01289 KCmdLineArgs::addCmdLineOptions( kde_tempfile_option, "KDE-tempfile", "kde-tempfile" ); 01290 } 01291 01292 bool KCmdLineArgs::isTempFileSet() 01293 { 01294 KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" ); 01295 if ( args ) 01296 return args->isSet( "tempfile" ); 01297 return false; 01298 }