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