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          if (!about->bugAddress().isEmpty())
00602          {
00603             QString bugReporting = i18n( "Please use http://bugs.kde.org to report bugs, do not mail the authors directly.\n" );
00604         if (about->bugAddress() != "submit@bugs.kde.org")
00605             bugReporting.replace("http://bugs.kde.org", about->bugAddress());
00606         printQ(bugReporting);
00607          }
00608          exit(0);
00609          } else {
00610            if ((option[0] == 'n') && (option[1] == 'o'))
00611            {
00612               option += 2;
00613               enabled = false;
00614            }
00615            findOption(orig, option, i, enabled, inOptions);
00616          }
00617       }
00618       else
00619       {
00620          // Check whether appOptions allows these arguments
00621          if (!allowArgs)
00622          {
00623             if (ignoreUnknown)
00624                continue;
00625             enable_i18n();
00626             usage( i18n("Unexpected argument '%1'.").arg( argv[i]));
00627          }
00628          else
00629          {
00630             appOptions->addArgument(argv[i]);
00631             if (everythingAfterArgIsArgs)
00632                 inOptions = false;
00633          }
00634       }
00635    }
00636    parsed = true;
00637 }
00638 
00644 int *
00645 KCmdLineArgs::qt_argc()
00646 {
00647    if (!argsList)
00648       KApplication::addCmdLineOptions(); // Lazy bastards!
00649 
00650    KCmdLineArgs *args = parsedArgs("qt");
00651 
00652    assert(args); // No qt options have been added!
00653    if (!argv)
00654    {
00655       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
00656       fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
00657 
00658       assert( 0 );
00659       exit(255);
00660    }
00661 
00662    assert(argc >= (args->count()+1));
00663    argc = args->count() +1;
00664    return &argc;
00665 }
00666 
00672 char ***
00673 KCmdLineArgs::qt_argv()
00674 {
00675    if (!argsList)
00676       KApplication::addCmdLineOptions(); // Lazy bastards!
00677 
00678    KCmdLineArgs *args = parsedArgs("qt");
00679    assert(args); // No qt options have been added!
00680    if (!argv)
00681    {
00682       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
00683       fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
00684 
00685       assert( 0 );
00686       exit(255);
00687    }
00688 
00689    int i = 0;
00690    for(; i < args->count(); i++)
00691    {
00692       argv[i+1] = (char *) args->arg(i);
00693    }
00694    argv[i+1] = 0;
00695 
00696    return &argv;
00697 }
00698 
00699 void
00700 KCmdLineArgs::enable_i18n()
00701 {
00702     // called twice or too late
00703     if (KGlobal::_locale)
00704         return;
00705 
00706     if (!KGlobal::_instance) {
00707     KInstance *instance = new KInstance(about);
00708     (void) instance->config();
00709     // Don't delete instance!
00710     }
00711 }
00712 
00713 void
00714 KCmdLineArgs::usage(const QString &error)
00715 {
00716     assert(KGlobal::_locale);
00717     QCString localError = error.local8Bit();
00718     if (localError[error.length()-1] == '\n')
00719     localError = localError.left(error.length()-1);
00720     fprintf(stderr, "%s: %s\n", argv[0], localError.data());
00721 
00722     QString tmp = i18n("Use --help to get a list of available command line options.");
00723     localError = tmp.local8Bit();
00724     fprintf(stderr, "%s: %s\n", argv[0], localError.data());
00725     exit(254);
00726 }
00727 
00728 void
00729 KCmdLineArgs::usage(const char *id)
00730 {
00731    enable_i18n();
00732    assert(argsList != 0); // It's an error to call usage(...) without
00733                           // having done addCmdLineOptions first!
00734 
00735    QString optionFormatString       = "  %1 %2\n";
00736    QString optionFormatStringDef    = "  %1 %2 [%3]\n";
00737    QString optionHeaderString = i18n("\n%1:\n");
00738    QString tmp;
00739    QString usage;
00740 
00741    KCmdLineArgs *args = argsList->last();
00742 
00743    if (!(args->id) && (args->options) &&
00744        (args->options->name) && (args->options->name[0] != '+'))
00745    {
00746       usage = i18n("[options] ")+usage;
00747    }
00748 
00749    while(args)
00750    {
00751       if (args->name)
00752       {
00753          usage = QString(i18n("[%1-options]")).arg(args->name)+" "+usage;
00754       }
00755       args = argsList->prev();
00756    }
00757 
00758    KCmdLineArgs *appOptions = argsList->last();
00759    if (!appOptions->id)
00760    {
00761      const KCmdLineOptions *option = appOptions->options;
00762      while(option && option->name)
00763      {
00764        if (option->name[0] == '+')
00765           usage = usage + (option->name+1) + " ";
00766        else if ( option->name[0] == '!' && option->name[1] == '+' )
00767           usage = usage + (option->name+2) + " ";
00768 
00769        option++;
00770      }
00771    }
00772 
00773    printQ(i18n("Usage: %1 %2\n").arg(argv[0]).arg(usage));
00774    printQ("\n"+about->shortDescription()+"\n");
00775 
00776    printQ(optionHeaderString.arg(i18n("Generic options")));
00777    printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options")));
00778 
00779    args = argsList->first();
00780    while(args)
00781    {
00782       if (args->name && args->id)
00783       {
00784          QString option = QString("--help-%1").arg(args->id);
00785          QString desc = i18n("Show %1 specific options").arg(args->name);
00786 
00787          printQ(optionFormatString.arg(option, -25).arg(desc));
00788       }
00789       args = argsList->next();
00790    }
00791 
00792    printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options")));
00793    printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information")));
00794    printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information")));
00795    printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information")));
00796    printQ(optionFormatString.arg("--", -25).arg(i18n("End of options")));
00797 
00798    args = argsList->first(); // Sets current to 1st.
00799 
00800    bool showAll = id && (::qstrcmp(id, "all") == 0);
00801 
00802    if (!showAll)
00803    {
00804      while(args)
00805      {
00806        if (!id && !args->id) break;
00807        if (id && (::qstrcmp(args->id, id) == 0)) break;
00808        args = argsList->next();
00809      }
00810    }
00811 
00812    while(args)
00813    {
00814      bool hasArgs = false;
00815      bool hasOptions = false;
00816      while (args)
00817      {
00818        const KCmdLineOptions *option = args->options;
00819        QCString opt = "";
00820 //
00821        while(option && option->name)
00822        {
00823          QString description;
00824          QString descriptionRest;
00825          QStringList dl;
00826          if (option->description)
00827          {
00828             description = i18n(option->description);
00829             dl = QStringList::split("\n", description, true);
00830             description = dl.first();
00831             dl.remove( dl.begin() );
00832          }
00833          QCString name = option->name;
00834          if (name[0] == '!')
00835              name = name.mid(1);
00836 
00837          if (name[0] == '+')
00838          {
00839             if (!hasArgs)
00840             {
00841                printQ(i18n("\nArguments:\n"));
00842                hasArgs = true;
00843             }
00844 
00845             name = name.mid(1);
00846             if ((name[0] == '[') && (name[name.length()-1] == ']'))
00847            name = name.mid(1, name.length()-2);
00848             printQ(optionFormatString.arg(name, -25)
00849          .arg(description));
00850          }
00851          else
00852          {
00853             if (!hasOptions)
00854             {
00855                if (!args->name)
00856                   printQ(i18n("\nOptions:\n"));
00857                else if (args->name)
00858                   printQ(optionHeaderString.arg(i18n("%1 options").arg(QString::fromLatin1(args->name))));
00859                hasOptions = true;
00860             }
00861 
00862             if ((name.length() == 1) || (name[1] == ' '))
00863                name = "-"+name;
00864             else
00865                name = "--"+name;
00866             if (!option->description)
00867             {
00868                opt = name + ", ";
00869             }
00870             else
00871             {
00872                opt = opt + name;
00873                if (!option->def)
00874                {
00875                   printQ(optionFormatString.arg(opt, -25)
00876                          .arg(description));
00877                }
00878                else
00879                {
00880                   printQ(optionFormatStringDef.arg(opt, -25)
00881                          .arg(description).arg(option->def));
00882                }
00883                opt = "";
00884             }
00885          }
00886          for(QStringList::Iterator it = dl.begin();
00887              it != dl.end();
00888              it++)
00889          {
00890             printQ(optionFormatString.arg("", -25).arg(*it));
00891          }
00892 
00893          option++;
00894        }
00895        args = argsList->next();
00896        if (!args || args->name || !args->id) break;
00897      }
00898      if (!showAll) break;
00899    }
00900 
00901    exit(254);
00902 }
00903 
00904 //
00905 // Member functions
00906 //
00907 
00913 KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions *_options,
00914                             const char *_name, const char *_id)
00915   : options(_options), name(_name), id(_id)
00916 {
00917   parsedOptionList = 0;
00918   parsedArgList = 0;
00919   isQt = (::qstrcmp(id, "qt") == 0);
00920 }
00921 
00925 KCmdLineArgs::~KCmdLineArgs()
00926 {
00927   delete parsedOptionList;
00928   delete parsedArgList;
00929   if (argsList)
00930   {
00931      argsList->removeRef(this);
00932      if (argsList->count() == 0)
00933      {
00934         delete argsList;
00935         argsList = 0;
00936      }
00937   }
00938 }
00939 
00940 void
00941 KCmdLineArgs::clear()
00942 {
00943    delete parsedArgList;
00944    parsedArgList = 0;
00945    delete parsedOptionList;
00946    parsedOptionList = 0;
00947 }
00948 
00949 void
00950 KCmdLineArgs::save( QDataStream &ds) const
00951 {
00952    uint count = 0;
00953    if (parsedOptionList)
00954       parsedOptionList->save( ds );
00955    else
00956       ds << count;
00957 
00958    if (parsedArgList)
00959       parsedArgList->save( ds );
00960    else
00961       ds << count;
00962 }
00963 
00964 void
00965 KCmdLineArgs::load( QDataStream &ds)
00966 {
00967    if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions;
00968    if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs;
00969 
00970    parsedOptionList->load( ds );
00971    parsedArgList->load( ds );
00972 
00973    if (parsedOptionList->count() == 0)
00974    {
00975       delete parsedOptionList;
00976       parsedOptionList = 0;
00977    }
00978    if (parsedArgList->count() == 0)
00979    {
00980       delete parsedArgList;
00981       parsedArgList = 0;
00982    }
00983 }
00984 
00985 void
00986 KCmdLineArgs::setOption(const QCString &opt, bool enabled)
00987 {
00988    if (isQt)
00989    {
00990       // Qt does it own parsing.
00991       QCString arg = "-";
00992       if( !enabled )
00993           arg += "no";
00994       arg += opt;
00995       addArgument(arg);
00996    }
00997    if (!parsedOptionList) {
00998     parsedOptionList = new KCmdLineParsedOptions;
00999     parsedOptionList->setAutoDelete(true);
01000    }
01001 
01002    if (enabled)
01003       parsedOptionList->replace( opt, new QCString("t") );
01004    else
01005       parsedOptionList->replace( opt, new QCString("f") );
01006 }
01007 
01008 void
01009 KCmdLineArgs::setOption(const QCString &opt, const char *value)
01010 {
01011    if (isQt)
01012    {
01013       // Qt does it's own parsing.
01014       QCString arg = "-";
01015       arg += opt;
01016       addArgument(arg);
01017       addArgument(value);
01018 
01019       // Hack coming up!
01020       if (arg == "-display")
01021       {
01022          setenv(DISPLAY, value, true);
01023       }
01024    }
01025    if (!parsedOptionList) {
01026     parsedOptionList = new KCmdLineParsedOptions;
01027     parsedOptionList->setAutoDelete(true);
01028    }
01029 
01030    parsedOptionList->insert( opt, new QCString(value) );
01031 }
01032 
01033 QCString
01034 KCmdLineArgs::getOption(const char *_opt) const
01035 {
01036    QCString *value = 0;
01037    if (parsedOptionList)
01038    {
01039       value = parsedOptionList->find(_opt);
01040    }
01041 
01042    if (value)
01043       return (*value);
01044 
01045    // Look up the default.
01046    const char *opt_name;
01047    const char *def;
01048    bool dummy = true;
01049    QCString opt = _opt;
01050    int result = ::findOption( options, opt, opt_name, def, dummy) & ~4;
01051 
01052    if (result != 3)
01053    {
01054       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01055       fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n",
01056                       _opt, _opt);
01057       fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
01058 
01059       assert( 0 );
01060       exit(255);
01061    }
01062    return QCString(def);
01063 }
01064 
01065 QCStringList
01066 KCmdLineArgs::getOptionList(const char *_opt) const
01067 {
01068    QCStringList result;
01069    if (!parsedOptionList)
01070       return result;
01071 
01072    while(true)
01073    {
01074       QCString *value = parsedOptionList->take(_opt);
01075       if (!value)
01076          break;
01077       result.prepend(*value);
01078       delete value;
01079    }
01080 
01081    // Reinsert items in dictionary
01082    // WABA: This is rather silly, but I don't want to add restrictions
01083    // to the API like "you can only call this function once".
01084    // I can't access all items without taking them out of the list.
01085    // So taking them out and then putting them back is the only way.
01086    for(QCStringList::ConstIterator it=result.begin();
01087        it != result.end();
01088        ++it)
01089    {
01090       parsedOptionList->insert(_opt, new QCString(*it));
01091    }
01092    return result;
01093 }
01094 
01095 bool
01096 KCmdLineArgs::isSet(const char *_opt) const
01097 {
01098    // Look up the default.
01099    const char *opt_name;
01100    const char *def;
01101    bool dummy = true;
01102    QCString opt = _opt;
01103    int result = ::findOption( options, opt, opt_name, def, dummy) & ~4;
01104 
01105    if (result == 0)
01106    {
01107       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01108       fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
01109                       _opt, _opt);
01110       fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
01111 
01112       assert( 0 );
01113       exit(255);
01114    }
01115 
01116    QCString *value = 0;
01117    if (parsedOptionList)
01118    {
01119       value = parsedOptionList->find(opt);
01120    }
01121 
01122    if (value)
01123    {
01124       if (result == 3)
01125          return true;
01126       else
01127          return ((*value)[0] == 't');
01128    }
01129 
01130    if (result == 3)
01131       return false; // String option has 'false' as default.
01132 
01133    // We return 'true' as default if the option was listed as '-nofork'
01134    // We return 'false' as default if the option was listed as '-fork'
01135    return (result == 2);
01136 }
01137 
01138 int
01139 KCmdLineArgs::count() const
01140 {
01141    if (!parsedArgList)
01142       return 0;
01143    return parsedArgList->count();
01144 }
01145 
01146 const char *
01147 KCmdLineArgs::arg(int n) const
01148 {
01149    if (!parsedArgList || (n >= (int) parsedArgList->count()))
01150    {
01151       fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n");
01152       fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n",
01153                       n);
01154 
01155       assert( 0 );
01156       exit(255);
01157    }
01158 
01159    return parsedArgList->at(n);
01160 }
01161 
01162 KURL
01163 KCmdLineArgs::url(int n) const
01164 {
01165    return makeURL( arg(n) );
01166 }
01167 
01168 KURL KCmdLineArgs::makeURL( const char *urlArg )
01169 {
01170    if (*urlArg == '/')
01171    {
01172       KURL result;
01173       result.setPath(QFile::decodeName( urlArg));
01174       return result; // Absolute path.
01175    }
01176 
01177    if ( !KURL::isRelativeURL( QString::fromLocal8Bit(urlArg) ) )
01178      return KURL(QString::fromLocal8Bit(urlArg)); // Argument is a URL
01179 
01180    KURL result;
01181    result.setPath( cwd()+"/"+QFile::decodeName( urlArg ));
01182    result.cleanPath();
01183    return result;  // Relative path
01184 }
01185 
01186 void
01187 KCmdLineArgs::addArgument(const char *argument)
01188 {
01189    if (!parsedArgList)
01190       parsedArgList = new KCmdLineParsedArgs;
01191 
01192    parsedArgList->append(argument);
01193 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:14:46 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001