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    // Remove Qt and KDE options.
00267    removeArgs("qt");
00268    removeArgs("kde");
00269 
00270    KCmdLineArgs *args;
00271    if ( argsList ) {
00272       for(args = argsList->first(); args; args = argsList->next())
00273       {
00274          args->clear();
00275       }
00276    }
00277 
00278    if (ds.atEnd())
00279       return;
00280 
00281    QCString qCwd;
00282    ds >> qCwd;
00283    delete [] mCwd;
00284 
00285    mCwd = mCwdd.setObject(mCwd, new char[qCwd.length()+1], true);
00286    strncpy(mCwd, qCwd.data(), qCwd.length()+1);
00287 
00288    uint count;
00289    ds >> count;
00290 
00291    while(count--)
00292    {
00293      QCString id;
00294      ds >> id;
00295      assert( argsList );
00296      for(args = argsList->first(); args; args = argsList->next())
00297      {
00298        if (args->id  == id)
00299        {
00300           args->load(ds);
00301           break;
00302        }
00303      }
00304    }
00305    parsed = true;
00306 }
00307 
00308 KCmdLineArgs *KCmdLineArgs::parsedArgs(const char *id)
00309 {
00310    KCmdLineArgs *args = argsList ? argsList->first() : 0;
00311    while(args)
00312    {
00313       if ((id && ::qstrcmp(args->id, id) == 0) || (!id && !args->id))
00314       {
00315           if (!parsed)
00316              parseAllArgs();
00317           return args;
00318       }
00319       args = argsList->next();
00320    }
00321 
00322    return args;
00323 }
00324 
00325 void KCmdLineArgs::removeArgs(const char *id)
00326 {
00327    KCmdLineArgs *args = argsList ? argsList->first() : 0;
00328    while(args)
00329    {
00330       if (args->id && id && ::qstrcmp(args->id, id) == 0)
00331       {
00332           if (!parsed)
00333              parseAllArgs();
00334           break;
00335       }
00336       args = argsList->next();
00337    }
00338 
00339    if (args)
00340       delete args;
00341 }
00342 
00343 /*
00344  * @return:
00345  *  0 - option not found.
00346  *  1 - option found      // -fork
00347  *  2 - inverse option found ('no') // -nofork
00348  *  3 - option + arg found    // -fork now
00349  *
00350  *  +4 - no more options follow         // !fork
00351  */
00352 static int
00353 findOption(const KCmdLineOptions *options, QCString &opt,
00354            const char *&opt_name, const char *&def, bool &enabled)
00355 {
00356    int result;
00357    bool inverse;
00358    int len = opt.length();
00359    while(options && options->name)
00360    {
00361       result = 0;
00362       inverse = false;
00363       opt_name = options->name;
00364       if ((opt_name[0] == ':') || (opt_name[0] == 0))
00365       {
00366          options++;
00367          continue;
00368       }
00369 
00370       if (opt_name[0] == '!')
00371       {
00372          opt_name++;
00373          result = 4;
00374       }
00375       if ((opt_name[0] == 'n') && (opt_name[1] == 'o'))
00376       {
00377          opt_name += 2;
00378          inverse = true;
00379       }
00380       if (strncmp(opt.data(), opt_name, len) == 0)
00381       {
00382          opt_name += len;
00383          if (!opt_name[0])
00384          {
00385             if (inverse)
00386                return result+2;
00387 
00388             if (!options->description)
00389             {
00390                options++;
00391                if (!options->name)
00392                   return result+0;
00393                QCString nextOption = options->name;
00394                int p = nextOption.find(' ');
00395                if (p > 0)
00396                   nextOption = nextOption.left(p);
00397                if (strncmp(nextOption.data(), "no", 2) == 0)
00398                {
00399                   nextOption = nextOption.mid(2);
00400                   enabled = !enabled;
00401                }
00402                result = findOption(options, nextOption, opt_name, def, enabled);
00403                assert(result);
00404                opt = nextOption;
00405                return result;
00406             }
00407 
00408             return 1;
00409          }
00410          if (opt_name[0] == ' ')
00411          {
00412             opt_name++;
00413             def = options->def;
00414             return result+3;
00415          }
00416       }
00417 
00418       options++;
00419    }
00420    return 0;
00421 }
00422 
00423 
00424 void
00425 KCmdLineArgs::findOption(const char *_opt, QCString opt, int &i, bool _enabled, bool &moreOptions)
00426 {
00427    KCmdLineArgs *args = argsList->first();
00428    const char *opt_name;
00429    const char *def;
00430    QCString argument;
00431    int j = opt.find('=');
00432    if (j != -1)
00433    {
00434       argument = opt.mid(j+1);
00435       opt = opt.left(j);
00436    }
00437 
00438    bool enabled = true;
00439    int result = 0;
00440    while (args)
00441    {
00442       enabled = _enabled;
00443       result = ::findOption(args->options, opt, opt_name, def, enabled);
00444       if (result) break;
00445       args = argsList->next();
00446    }
00447    if (!args && (_opt[0] == '-') && _opt[1] && (_opt[1] != '-'))
00448    {
00449       // Option not found check if it is a valid option
00450       // in the style of -Pprinter1 or ps -aux
00451       int p = 1;
00452       while (true)
00453       {
00454          QCString singleCharOption = " ";
00455          singleCharOption[0] = _opt[p];
00456          args = argsList->first();
00457          while (args)
00458          {
00459             enabled = _enabled;
00460             result = ::findOption(args->options, singleCharOption, opt_name, def, enabled);
00461             if (result) break;
00462             args = argsList->next();
00463          }
00464          if (!args)
00465             break; // Unknown argument
00466 
00467          p++;
00468          if (result == 1) // Single option
00469          {
00470             args->setOption(singleCharOption, enabled);
00471             if (_opt[p])
00472                continue; // Next option
00473             else
00474                return; // Finished
00475          }
00476          else if (result == 3) // This option takes an argument
00477          {
00478             if (argument.isEmpty())
00479             {
00480                argument = _opt+p;
00481             }
00482             args->setOption(singleCharOption, argument);
00483             return;
00484          }
00485          break; // Unknown argument
00486       }
00487       args = 0;
00488       result = 0;
00489    }
00490 
00491    if (!args || !result)
00492    {
00493       if (ignoreUnknown)
00494          return;
00495       enable_i18n();
00496       usage( i18n("Unknown option '%1'.").arg(QString::fromLocal8Bit(_opt)));
00497    }
00498 
00499    if ((result & 4) != 0)
00500    {
00501       result &= ~4;
00502       moreOptions = false;
00503    }
00504 
00505    if (result == 3) // This option takes an argument
00506    {
00507       if (!enabled)
00508       {
00509          if (ignoreUnknown)
00510             return;
00511          enable_i18n();
00512          usage( i18n("Unknown option '%1'.").arg(QString::fromLocal8Bit(_opt)));
00513       }
00514       if (argument.isEmpty())
00515       {
00516          i++;
00517          if (i >= argc)
00518          {
00519             enable_i18n();
00520             usage( i18n("'%1' missing.").arg( opt_name));
00521          }
00522          argument = argv[i];
00523       }
00524       args->setOption(opt, argument);
00525    }
00526    else
00527    {
00528       args->setOption(opt, enabled);
00529    }
00530 }
00531 
00532 void
00533 KCmdLineArgs::printQ(const QString &msg)
00534 {
00535    QCString localMsg = msg.local8Bit();
00536    fprintf(stdout, "%s", localMsg.data());
00537 }
00538 
00539 void
00540 KCmdLineArgs::parseAllArgs()
00541 {
00542    bool allowArgs = false;
00543    bool inOptions = true;
00544    bool everythingAfterArgIsArgs = false;
00545    KCmdLineArgs *appOptions = argsList->last();
00546    if (!appOptions->id)
00547    {
00548      const KCmdLineOptions *option = appOptions->options;
00549      while(option && option->name)
00550      {
00551        if (option->name[0] == '+')
00552            allowArgs = true;
00553        if ( option->name[0] == '!' && option->name[1] == '+' )
00554        {
00555            allowArgs = true;
00556            everythingAfterArgIsArgs = true;
00557        }
00558        option++;
00559      }
00560    }
00561    for(int i = 1; i < argc; i++)
00562    {
00563       if (!argv[i])
00564          continue;
00565 
00566       if ((argv[i][0] == '-') && argv[i][1] && inOptions)
00567       {
00568          bool enabled = true;
00569          const char *option = &argv[i][1];
00570          const char *orig = argv[i];
00571          if (option[0] == '-')
00572          {
00573             option++;
00574             argv[i]++;
00575             if (!option[0])
00576             {
00577                inOptions = false;
00578                continue;
00579             }
00580          }
00581          if (::qstrcmp(option, "help") == 0)
00582          {
00583             usage(0);
00584          }
00585          else if (strncmp(option, "help-",5) == 0)
00586          {
00587             usage(option+5);
00588          }
00589          else if ( (::qstrcmp(option, "version") == 0) ||
00590                    (::qstrcmp(option, "v") == 0))
00591          {
00592             printQ( QString("Qt: %1\n").arg(qVersion()));
00593             printQ( QString("KDE: %1\n").arg(KDE_VERSION_STRING));
00594             printQ( QString("%1: %2\n").
00595       arg(about->programName()).arg(about->version()));
00596             exit(0);
00597          } else if ( (::qstrcmp(option, "license") == 0) )
00598          {
00599             enable_i18n();
00600             printQ( about->license() );
00601             printQ( "\n" );
00602             exit(0);
00603          } else if ( ::qstrcmp( option, "author") == 0 ) {
00604              enable_i18n();
00605        if ( about ) {
00606          const QValueList<KAboutPerson> authors = about->authors();
00607          if ( !authors.isEmpty() ) {
00608            QString authorlist;
00609            for (QValueList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) {
00610              QString email;
00611              if ( !(*it).emailAddress().isEmpty() )
00612                email = " <" + (*it).emailAddress() + ">";
00613              authorlist += QString("    ") + (*it).name() + email + "\n";
00614            }
00615            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 ) );
00616          }
00617        } else {
00618          printQ( i18n("This application was written by somebody who wants to remain anonymous.") );
00619        }
00620        if (about)
00621        {
00622          if (!about->customAuthorTextEnabled ())
00623          {
00624            if (about->bugAddress().isEmpty() || about->bugAddress() == "submit@bugs.kde.org" )
00625              printQ( i18n( "Please use http://bugs.kde.org to report bugs.\n" ) );
00626            else {
00627              if( about->authors().count() == 1 && about->authors().first().emailAddress() == about->bugAddress() )
00628                printQ( i18n( "Please report bugs to %1.\n" ).arg( about->authors().first().emailAddress() ) );
00629              else
00630                printQ( i18n( "Please report bugs to %1.\n" ).arg(about->bugAddress()) );
00631            }
00632          }
00633          else
00634          {
00635            printQ(about->customAuthorPlainText());
00636          }
00637        }
00638        exit(0);
00639          } else {
00640            if ((option[0] == 'n') && (option[1] == 'o'))
00641            {
00642               option += 2;
00643               enabled = false;
00644            }
00645            findOption(orig, option, i, enabled, inOptions);
00646          }
00647       }
00648       else
00649       {
00650          // Check whether appOptions allows these arguments
00651          if (!allowArgs)
00652          {
00653             if (ignoreUnknown)
00654                continue;
00655             enable_i18n();
00656             usage( i18n("Unexpected argument '%1'.").arg(QString::fromLocal8Bit(argv[i])));
00657          }
00658          else
00659          {
00660             appOptions->addArgument(argv[i]);
00661             if (everythingAfterArgIsArgs)
00662                 inOptions = false;
00663          }
00664       }
00665    }
00666    parsed = true;
00667 }
00668 
00674 int *
00675 KCmdLineArgs::qt_argc()
00676 {
00677    if (!argsList)
00678       KApplication::addCmdLineOptions(); // Lazy bastards!
00679 
00680    static int qt_argc = -1;
00681    if( qt_argc != -1 )
00682       return &qt_argc;
00683 
00684    KCmdLineArgs *args = parsedArgs("qt");
00685    assert(args); // No qt options have been added!
00686    if (!argv)
00687    {
00688       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
00689       fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
00690 
00691       assert( 0 );
00692       exit(255);
00693    }
00694 
00695    assert(argc >= (args->count()+1));
00696    qt_argc = args->count() +1;
00697    return &qt_argc;
00698 }
00699 
00705 char ***
00706 KCmdLineArgs::qt_argv()
00707 {
00708    if (!argsList)
00709       KApplication::addCmdLineOptions(); // Lazy bastards!
00710 
00711    static char** qt_argv;
00712    if( qt_argv != NULL )
00713       return &qt_argv;
00714 
00715    KCmdLineArgs *args = parsedArgs("qt");
00716    assert(args); // No qt options have been added!
00717    if (!argv)
00718    {
00719       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
00720       fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
00721 
00722       assert( 0 );
00723       exit(255);
00724    }
00725 
00726    qt_argv = new char*[ args->count() + 2 ];
00727    qt_argv[ 0 ] = qstrdup( appName());
00728    int i = 0;
00729    for(; i < args->count(); i++)
00730    {
00731       qt_argv[i+1] = qstrdup((char *) args->arg(i));
00732    }
00733    qt_argv[i+1] = 0;
00734 
00735    return &qt_argv;
00736 }
00737 
00738 void
00739 KCmdLineArgs::enable_i18n()
00740 {
00741     // called twice or too late
00742     if (KGlobal::_locale)
00743       return;
00744 
00745     if (!KGlobal::_instance) {
00746   KInstance *instance = new KInstance(about);
00747   (void) instance->config();
00748   // Don't delete instance!
00749     }
00750 }
00751 
00752 void
00753 KCmdLineArgs::usage(const QString &error)
00754 {
00755     assert(KGlobal::_locale);
00756     QCString localError = error.local8Bit();
00757     if (localError[error.length()-1] == '\n')
00758   localError = localError.left(error.length()-1);
00759     fprintf(stderr, "%s: %s\n", argv[0], localError.data());
00760 
00761     QString tmp = i18n("Use --help to get a list of available command line options.");
00762     localError = tmp.local8Bit();
00763     fprintf(stderr, "%s: %s\n", argv[0], localError.data());
00764     exit(254);
00765 }
00766 
00767 void
00768 KCmdLineArgs::usage(const char *id)
00769 {
00770    enable_i18n();
00771    assert(argsList != 0); // It's an error to call usage(...) without
00772                           // having done addCmdLineOptions first!
00773 
00774    QString optionFormatString   = "  %1 %2\n";
00775    QString optionFormatStringDef  = "  %1 %2 [%3]\n";
00776    QString optionHeaderString = i18n("\n%1:\n");
00777    QString tmp;
00778    QString usage;
00779 
00780    KCmdLineArgs *args = argsList->last();
00781 
00782    if (!(args->id) && (args->options) &&
00783        (args->options->name) && (args->options->name[0] != '+'))
00784    {
00785       usage = i18n("[options] ")+usage;
00786    }
00787 
00788    while(args)
00789    {
00790       if (args->name)
00791       {
00792          usage = i18n("[%1-options]").arg(args->name)+" "+usage;
00793       }
00794       args = argsList->prev();
00795    }
00796 
00797    KCmdLineArgs *appOptions = argsList->last();
00798    if (!appOptions->id)
00799    {
00800      const KCmdLineOptions *option = appOptions->options;
00801      while(option && option->name)
00802      {
00803        if (option->name[0] == '+')
00804           usage = usage + (option->name+1) + " ";
00805        else if ( option->name[0] == '!' && option->name[1] == '+' )
00806           usage = usage + (option->name+2) + " ";
00807 
00808        option++;
00809      }
00810    }
00811 
00812    printQ(i18n("Usage: %1 %2\n").arg(argv[0]).arg(usage));
00813    printQ("\n"+about->shortDescription()+"\n");
00814 
00815    printQ(optionHeaderString.arg(i18n("Generic options")));
00816    printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options")));
00817 
00818    args = argsList->first();
00819    while(args)
00820    {
00821       if (args->name && args->id)
00822       {
00823          QString option = QString("--help-%1").arg(args->id);
00824          QString desc = i18n("Show %1 specific options").arg(args->name);
00825 
00826          printQ(optionFormatString.arg(option, -25).arg(desc));
00827       }
00828       args = argsList->next();
00829    }
00830 
00831    printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options")));
00832    printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information")));
00833    printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information")));
00834    printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information")));
00835    printQ(optionFormatString.arg("--", -25).arg(i18n("End of options")));
00836 
00837    args = argsList->first(); // Sets current to 1st.
00838 
00839    bool showAll = id && (::qstrcmp(id, "all") == 0);
00840 
00841    if (!showAll)
00842    {
00843      while(args)
00844      {
00845        if (!id && !args->id) break;
00846        if (id && (::qstrcmp(args->id, id) == 0)) break;
00847        args = argsList->next();
00848      }
00849    }
00850 
00851    while(args)
00852    {
00853      bool hasArgs = false;
00854      bool hasOptions = false;
00855      QString optionsHeader;
00856      if (args->name)
00857         optionsHeader = optionHeaderString.arg(i18n("%1 options").arg(QString::fromLatin1(args->name)));
00858      else
00859         optionsHeader = i18n("\nOptions:\n");
00860 
00861      while (args)
00862      {
00863        const KCmdLineOptions *option = args->options;
00864        QCString opt = "";
00865 //
00866        while(option && option->name)
00867        {
00868          QString description;
00869          QString descriptionRest;
00870          QStringList dl;
00871 
00872          // Option header
00873          if (option->name[0] == ':')
00874          {
00875             if (option->description)
00876             {
00877                optionsHeader = "\n"+i18n(option->description);
00878                if (!optionsHeader.endsWith("\n"))
00879                   optionsHeader.append("\n");
00880                hasOptions = false;
00881             }
00882             option++;
00883             continue;
00884          }
00885 
00886          // Free-form comment
00887          if (option->name[0] == 0)
00888          {
00889             if (option->description)
00890             {
00891                QString tmp = "\n"+i18n(option->description);
00892                if (!tmp.endsWith("\n"))
00893                   tmp.append("\n");
00894                printQ(tmp);
00895             }
00896             option++;
00897             continue;
00898          }
00899 
00900          // Options
00901          if (option->description)
00902          {
00903             description = i18n(option->description);
00904             dl = QStringList::split("\n", description, true);
00905             description = dl.first();
00906             dl.remove( dl.begin() );
00907          }
00908          QCString name = option->name;
00909          if (name[0] == '!')
00910              name = name.mid(1);
00911 
00912          if (name[0] == '+')
00913          {
00914             if (!hasArgs)
00915             {
00916                printQ(i18n("\nArguments:\n"));
00917                hasArgs = true;
00918             }
00919 
00920             name = name.mid(1);
00921             if ((name[0] == '[') && (name[name.length()-1] == ']'))
00922          name = name.mid(1, name.length()-2);
00923             printQ(optionFormatString.arg(name, -25)
00924      .arg(description));
00925          }
00926          else
00927          {
00928             if (!hasOptions)
00929             {
00930                printQ(optionsHeader);
00931                hasOptions = true;
00932             }
00933 
00934             if ((name.length() == 1) || (name[1] == ' '))
00935                name = "-"+name;
00936             else
00937                name = "--"+name;
00938             if (!option->description)
00939             {
00940                opt = name + ", ";
00941             }
00942             else
00943             {
00944                opt = opt + name;
00945                if (!option->def)
00946                {
00947                   printQ(optionFormatString.arg(opt, -25)
00948                          .arg(description));
00949                }
00950                else
00951                {
00952                   printQ(optionFormatStringDef.arg(opt, -25)
00953                          .arg(description).arg(option->def));
00954                }
00955                opt = "";
00956             }
00957          }
00958          for(QStringList::Iterator it = dl.begin();
00959              it != dl.end();
00960              ++it)
00961          {
00962             printQ(optionFormatString.arg("", -25).arg(*it));
00963          }
00964 
00965          option++;
00966        }
00967        args = argsList->next();
00968        if (!args || args->name || !args->id) break;
00969      }
00970      if (!showAll) break;
00971    }
00972 
00973    exit(254);
00974 }
00975 
00976 //
00977 // Member functions
00978 //
00979 
00985 KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions *_options,
00986                             const char *_name, const char *_id)
00987   : options(_options), name(_name), id(_id)
00988 {
00989   parsedOptionList = 0;
00990   parsedArgList = 0;
00991   isQt = (::qstrcmp(id, "qt") == 0);
00992 }
00993 
00997 KCmdLineArgs::~KCmdLineArgs()
00998 {
00999   delete parsedOptionList;
01000   delete parsedArgList;
01001   if (argsList)
01002      argsList->removeRef(this);
01003 }
01004 
01005 void
01006 KCmdLineArgs::clear()
01007 {
01008    delete parsedArgList;
01009    parsedArgList = 0;
01010    delete parsedOptionList;
01011    parsedOptionList = 0;
01012 }
01013 
01014 void
01015 KCmdLineArgs::reset()
01016 {
01017    if ( argsList ) {
01018       argsList->setAutoDelete( true );
01019       argsList->clear();
01020       delete argsList;
01021       argsList = 0;
01022    }
01023    parsed = false;
01024 }
01025 
01026 void
01027 KCmdLineArgs::save( QDataStream &ds) const
01028 {
01029    uint count = 0;
01030    if (parsedOptionList)
01031       parsedOptionList->save( ds );
01032    else
01033       ds << count;
01034 
01035    if (parsedArgList)
01036       parsedArgList->save( ds );
01037    else
01038       ds << count;
01039 }
01040 
01041 void
01042 KCmdLineArgs::load( QDataStream &ds)
01043 {
01044    if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions;
01045    if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs;
01046 
01047    parsedOptionList->load( ds );
01048    parsedArgList->load( ds );
01049 
01050    if (parsedOptionList->count() == 0)
01051    {
01052       delete parsedOptionList;
01053       parsedOptionList = 0;
01054    }
01055    if (parsedArgList->count() == 0)
01056    {
01057       delete parsedArgList;
01058       parsedArgList = 0;
01059    }
01060 }
01061 
01062 void
01063 KCmdLineArgs::setOption(const QCString &opt, bool enabled)
01064 {
01065    if (isQt)
01066    {
01067       // Qt does it own parsing.
01068       QCString arg = "-";
01069       if( !enabled )
01070           arg += "no";
01071       arg += opt;
01072       addArgument(arg);
01073    }
01074    if (!parsedOptionList) {
01075   parsedOptionList = new KCmdLineParsedOptions;
01076   parsedOptionList->setAutoDelete(true);
01077    }
01078 
01079    if (enabled)
01080       parsedOptionList->replace( opt, new QCString("t") );
01081    else
01082       parsedOptionList->replace( opt, new QCString("f") );
01083 }
01084 
01085 void
01086 KCmdLineArgs::setOption(const QCString &opt, const char *value)
01087 {
01088    if (isQt)
01089    {
01090       // Qt does it's own parsing.
01091       QCString arg = "-";
01092       arg += opt;
01093       addArgument(arg);
01094       addArgument(value);
01095 
01096 #ifdef Q_WS_X11
01097       // Hack coming up!
01098       if (arg == "-display")
01099       {
01100          setenv(DISPLAY, value, true);
01101       }
01102 #endif
01103    }
01104    if (!parsedOptionList) {
01105   parsedOptionList = new KCmdLineParsedOptions;
01106   parsedOptionList->setAutoDelete(true);
01107    }
01108 
01109    parsedOptionList->insert( opt, new QCString(value) );
01110 }
01111 
01112 QCString
01113 KCmdLineArgs::getOption(const char *_opt) const
01114 {
01115    QCString *value = 0;
01116    if (parsedOptionList)
01117    {
01118       value = parsedOptionList->find(_opt);
01119    }
01120 
01121    if (value)
01122       return (*value);
01123 
01124    // Look up the default.
01125    const char *opt_name;
01126    const char *def;
01127    bool dummy = true;
01128    QCString opt = _opt;
01129    int result = ::findOption( options, opt, opt_name, def, dummy) & ~4;
01130 
01131    if (result != 3)
01132    {
01133       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01134       fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n",
01135                       _opt, _opt);
01136       fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
01137 
01138       assert( 0 );
01139       exit(255);
01140    }
01141    return QCString(def);
01142 }
01143 
01144 QCStringList
01145 KCmdLineArgs::getOptionList(const char *_opt) const
01146 {
01147    QCStringList result;
01148    if (!parsedOptionList)
01149       return result;
01150 
01151    while(true)
01152    {
01153       QCString *value = parsedOptionList->take(_opt);
01154       if (!value)
01155          break;
01156       result.prepend(*value);
01157       delete value;
01158    }
01159 
01160    // Reinsert items in dictionary
01161    // WABA: This is rather silly, but I don't want to add restrictions
01162    // to the API like "you can only call this function once".
01163    // I can't access all items without taking them out of the list.
01164    // So taking them out and then putting them back is the only way.
01165    for(QCStringList::ConstIterator it=result.begin();
01166        it != result.end();
01167        ++it)
01168    {
01169       parsedOptionList->insert(_opt, new QCString(*it));
01170    }
01171    return result;
01172 }
01173 
01174 bool
01175 KCmdLineArgs::isSet(const char *_opt) const
01176 {
01177    // Look up the default.
01178    const char *opt_name;
01179    const char *def;
01180    bool dummy = true;
01181    QCString opt = _opt;
01182    int result = ::findOption( options, opt, opt_name, def, dummy) & ~4;
01183 
01184    if (result == 0)
01185    {
01186       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01187       fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
01188                       _opt, _opt);
01189       fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
01190 
01191       assert( 0 );
01192       exit(255);
01193    }
01194 
01195    QCString *value = 0;
01196    if (parsedOptionList)
01197    {
01198       value = parsedOptionList->find(opt);
01199    }
01200 
01201    if (value)
01202    {
01203       if (result == 3)
01204          return true;
01205       else
01206          return ((*value)[0] == 't');
01207    }
01208 
01209    if (result == 3)
01210       return false; // String option has 'false' as default.
01211 
01212    // We return 'true' as default if the option was listed as '-nofork'
01213    // We return 'false' as default if the option was listed as '-fork'
01214    return (result == 2);
01215 }
01216 
01217 int
01218 KCmdLineArgs::count() const
01219 {
01220    if (!parsedArgList)
01221       return 0;
01222    return parsedArgList->count();
01223 }
01224 
01225 const char *
01226 KCmdLineArgs::arg(int n) const
01227 {
01228    if (!parsedArgList || (n >= (int) parsedArgList->count()))
01229    {
01230       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n");
01231       fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n",
01232                       n);
01233 
01234       assert( 0 );
01235       exit(255);
01236    }
01237 
01238    return parsedArgList->at(n);
01239 }
01240 
01241 KURL
01242 KCmdLineArgs::url(int n) const
01243 {
01244    return makeURL( arg(n) );
01245 }
01246 
01247 KURL KCmdLineArgs::makeURL(const char *_urlArg)
01248 {
01249    QString urlArg = QFile::decodeName(_urlArg);
01250    if (!QDir::isRelativePath(urlArg))
01251    {
01252       KURL result;
01253       result.setPath(urlArg);
01254       return result; // Absolute path.
01255    }
01256 
01257    if ( !KURL::isRelativeURL(urlArg) )
01258      return KURL(urlArg); // Argument is a URL
01259 
01260    KURL result;
01261    result.setPath( cwd()+"/"+urlArg );
01262    result.cleanPath();
01263    return result;  // Relative path
01264 }
01265 
01266 void
01267 KCmdLineArgs::addArgument(const char *argument)
01268 {
01269    if (!parsedArgList)
01270       parsedArgList = new KCmdLineParsedArgs;
01271 
01272    parsedArgList->append(argument);
01273 }
01274 
01275 static const KCmdLineOptions kde_tempfile_option[] =
01276 {
01277    { "tempfile",       I18N_NOOP("The files/URLs opened by the application will be deleted after use"), 0},
01278    KCmdLineLastOption
01279 };
01280 
01281 void
01282 KCmdLineArgs::addTempFileOption()
01283 {
01284     KCmdLineArgs::addCmdLineOptions( kde_tempfile_option, "KDE-tempfile", "kde-tempfile" );
01285 }
01286 
01287 bool KCmdLineArgs::isTempFileSet()
01288 {
01289     KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" );
01290     if ( args )
01291         return args->isSet( "tempfile" );
01292     return false;
01293 }
KDE Home | KDE Accessibility Home | Description of Access Keys