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