kdecore Library API Documentation

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