kcmdlineargs.cpp

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