qtmobility/tools/vsexplorer/vsexplorer.cpp
changeset 1 2b40d63a9c3d
child 4 90517678cc4f
equal deleted inserted replaced
0:cfcbf08528c4 1:2b40d63a9c3d
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QApplication>
       
    43 #include <QObject>
       
    44 #include <QTextStream>
       
    45 #include <QFile>
       
    46 #include <QSocketNotifier>
       
    47 #include <cstdio>
       
    48 #include <cstdlib>
       
    49 #include <QMap>
       
    50 #include <QDir>
       
    51 #include <QStringList>
       
    52 #include <QSet>
       
    53 
       
    54 #include <qvaluespace.h>
       
    55 #include <qvaluespacesubscriber.h>
       
    56 #include <qvaluespacepublisher.h>
       
    57 
       
    58 #ifdef USE_READLINE
       
    59 #include <stdio.h>
       
    60 #include <readline/readline.h>
       
    61 #include <readline/history.h>
       
    62 #include <QThread>
       
    63 #include <QMutex>
       
    64 #include <QEvent>
       
    65 #include <QWaitCondition>
       
    66 #include <pthread.h>
       
    67 #endif
       
    68 
       
    69 #ifdef Q_OS_WIN
       
    70 #include <QThread>
       
    71 #endif
       
    72 
       
    73 QTM_USE_NAMESPACE
       
    74 
       
    75 static bool terminateRequested = false;
       
    76 
       
    77 class VSExplorer : public QObject
       
    78 {
       
    79 Q_OBJECT
       
    80 public:
       
    81     VSExplorer();
       
    82 
       
    83     void printError();
       
    84     void printHelp();
       
    85     void ls();
       
    86     void dump();
       
    87     void pwdCmd();
       
    88     void ls(const QString &abs, bool);
       
    89     void subscribe();
       
    90     void unsubscribe();
       
    91     void quit();
       
    92     void suppress();
       
    93     void listwatchers();
       
    94     void watch(const QString &);
       
    95     void unwatch(const QString &);
       
    96     void set(const QString &, const QString &);
       
    97     void clear(const QString &);
       
    98     void subscriptions();
       
    99 
       
   100     QString path() const
       
   101     {
       
   102         return pwd.path();
       
   103     }
       
   104 
       
   105 public slots:
       
   106     void processLine(const QString &);
       
   107 
       
   108 private slots:
       
   109     void contentsChanged();
       
   110     void interestChanged(const QString &attribute, bool interested);
       
   111 
       
   112 private:
       
   113     void lsPath(QValueSpaceSubscriber *, int = 0, bool = false);
       
   114 
       
   115     bool isSuppress;
       
   116     QValueSpaceSubscriber pwd;
       
   117     QValueSpacePublisher prov;
       
   118     QSet<QValueSpaceSubscriber *> subs;
       
   119     QSet<QValueSpacePublisher *> watchers;
       
   120 };
       
   121 static VSExplorer * vse = 0;
       
   122 
       
   123 class LineInput :
       
   124 #if defined(USE_READLINE) || defined(Q_OS_WIN)
       
   125     public QThread
       
   126 #else
       
   127     public QObject
       
   128 #endif
       
   129 {
       
   130     Q_OBJECT
       
   131 
       
   132 public:
       
   133     LineInput();
       
   134 
       
   135 signals:
       
   136     void line(const QString &);
       
   137 
       
   138 #if defined(USE_READLINE)
       
   139 protected:
       
   140     virtual bool event(QEvent *);
       
   141     virtual void run();
       
   142 
       
   143 private:
       
   144     QMutex mutex;
       
   145     QWaitCondition wait;
       
   146 #elif defined(Q_OS_WIN)
       
   147 protected:
       
   148     void run();
       
   149 
       
   150 private:
       
   151     QFile ts;
       
   152 #else
       
   153 private slots:
       
   154     void readyRead();
       
   155 
       
   156 private:
       
   157     QFile ts;
       
   158     QSocketNotifier *sock;
       
   159 #endif
       
   160 };
       
   161 
       
   162 VSExplorer::VSExplorer()
       
   163 : isSuppress(false), pwd("/"), prov("/")
       
   164 {
       
   165 }
       
   166 
       
   167 void VSExplorer::interestChanged(const QString &attribute, bool interested)
       
   168 {
       
   169     Q_ASSERT(sender());
       
   170 
       
   171     if (!isSuppress) {
       
   172         QValueSpacePublisher *obj = static_cast<QValueSpacePublisher *>(sender());
       
   173         fprintf(stdout, "\nInterest Changed: %s ... %s %d\n",
       
   174                 qPrintable(obj->path()), qPrintable(attribute), interested);
       
   175     }
       
   176 }
       
   177 
       
   178 static QString variantToString( const QVariant& var )
       
   179 {
       
   180     if ( var.type() == QVariant::StringList )
       
   181         return var.toStringList().join(", ");
       
   182     else
       
   183         return var.toString();
       
   184 }
       
   185 
       
   186 void VSExplorer::contentsChanged()
       
   187 {
       
   188     Q_ASSERT(sender());
       
   189 
       
   190     if(!isSuppress) {
       
   191         QValueSpaceSubscriber *subscriber = static_cast<QValueSpaceSubscriber *>(sender());
       
   192         fprintf(stdout, "\nChanged: %s\n", subscriber->path().toAscii().constData());
       
   193     }
       
   194 }
       
   195 
       
   196 void VSExplorer::printError()
       
   197 {
       
   198     fprintf(stdout, "Come again?\n");
       
   199     fflush(stdout);
       
   200 }
       
   201 
       
   202 void VSExplorer::printHelp()
       
   203 {
       
   204     fprintf(stdout, "help/?: Print this message\n");
       
   205     fprintf(stdout, "quit: Exit VSExplorer\n");
       
   206     fprintf(stdout, "ls: List contents of path\n");
       
   207     fprintf(stdout, "pwd: Print current working directory\n");
       
   208     fprintf(stdout, "subscribe: Subscribe to path\n");
       
   209     fprintf(stdout, "unsubscribe: Unsubscribe from path\n");
       
   210     fprintf(stdout, "suppress: Toggle suppression of publish messages\n");
       
   211     fprintf(stdout, "subscriptions: List current subscriptions\n");
       
   212     fprintf(stdout, "set <key> <value>: Set app layer<key> to <value>\n");
       
   213     fprintf(stdout, "clear <key>: Clear app layer <key>\n");
       
   214     fprintf(stdout, "cd <path>: Change working path\n");
       
   215     fprintf(stdout, "watch <path>: Add a watch for the path\n");
       
   216     fprintf(stdout, "unwatch <path>: Remove a watch for the path\n");
       
   217     fprintf(stdout, "watchers: List paths for which a watch is active\n");
       
   218     fflush(stdout);
       
   219 }
       
   220 
       
   221 void VSExplorer::ls()
       
   222 {
       
   223     lsPath(&pwd);
       
   224     fflush(stdout);
       
   225 }
       
   226 
       
   227 void VSExplorer::ls(const QString &abs, bool all)
       
   228 {
       
   229     QValueSpaceSubscriber subscriber(abs);
       
   230     lsPath(&subscriber, 0, all);
       
   231     fflush(stdout);
       
   232 }
       
   233 
       
   234 
       
   235 void VSExplorer::lsPath(QValueSpaceSubscriber * p, int indent, bool showHidden)
       
   236 {
       
   237     QStringList paths = p->subPaths();
       
   238 
       
   239     QVariant var = p->value();
       
   240     bool spaceRequired = false;
       
   241     if(!var.isNull()) {
       
   242         fprintf(stdout, "Value: '%s' (%s)\n",
       
   243                 variantToString(var).toAscii().constData(), var.typeName());
       
   244         spaceRequired = true;
       
   245     }
       
   246 
       
   247     foreach(QString path, paths) {
       
   248         if(!showHidden && path.startsWith("."))
       
   249             continue;
       
   250 
       
   251         if(spaceRequired) {
       
   252             fprintf(stdout, "\n");
       
   253             spaceRequired = false;
       
   254         }
       
   255         for(int ii = 0; ii < indent; ++ii) fprintf(stdout, "\t");
       
   256         fprintf(stdout, "%s/", path.toAscii().constData());
       
   257         QVariant value = p->value(path);
       
   258         if(!value.isNull()) {
       
   259             if(path.length() < 30) {
       
   260                 for(int ii = 0; ii < 30 - path.length(); ++ii)
       
   261                     fprintf(stdout, " ");
       
   262             } else {
       
   263                 fprintf(stdout, "    ");
       
   264             }
       
   265 
       
   266             fprintf(stdout, " '%s' (%s)",
       
   267                     variantToString(value).toAscii().constData(), value.typeName());
       
   268         }
       
   269         fprintf(stdout, "\n");
       
   270     }
       
   271 }
       
   272 
       
   273 void VSExplorer::listwatchers()
       
   274 {
       
   275     if(watchers.isEmpty()) {
       
   276         fprintf(stdout, "No watchers.\n");
       
   277     } else {
       
   278         fprintf(stdout, "Current watchers:\n");
       
   279         foreach (QValueSpacePublisher *obj, watchers)
       
   280             fprintf(stdout, "\t%s\n", obj->path().toAscii().constData());
       
   281     }
       
   282 
       
   283     fflush(stdout);
       
   284 }
       
   285 
       
   286 void VSExplorer::subscriptions()
       
   287 {
       
   288     if(subs.isEmpty()) {
       
   289         fprintf(stdout, "No subscriptions.\n");
       
   290     } else {
       
   291         fprintf(stdout, "Current subscriptions:\n");
       
   292 
       
   293         foreach (QValueSpaceSubscriber *subscriber, subs)
       
   294             fprintf(stdout, "\t%s\n", subscriber->path().toAscii().constData());
       
   295     }
       
   296 
       
   297     fflush(stdout);
       
   298 }
       
   299 
       
   300 void VSExplorer::subscribe()
       
   301 {
       
   302     QValueSpaceSubscriber *subscriber = new QValueSpaceSubscriber;
       
   303     subscriber->setPath(&pwd);
       
   304     QObject::connect(subscriber, SIGNAL(contentsChanged()),
       
   305                      this, SLOT(contentsChanged()));
       
   306     subs.insert(subscriber);
       
   307 
       
   308     fprintf(stdout, "OK\n");
       
   309     fflush(stdout);
       
   310 }
       
   311 
       
   312 void VSExplorer::unsubscribe()
       
   313 {
       
   314     foreach (QValueSpaceSubscriber *subscriber, subs) {
       
   315         if (subscriber->path() == pwd.path()) {
       
   316             subs.remove(subscriber);
       
   317             delete subscriber;
       
   318             fprintf(stdout, "OK\n");
       
   319             fflush(stdout);
       
   320             return;
       
   321         }
       
   322     }
       
   323 
       
   324     fprintf(stdout, "No subscription.\n");
       
   325     fflush(stdout);
       
   326 }
       
   327 
       
   328 void VSExplorer::quit()
       
   329 {
       
   330     fprintf(stdout, "Bye, bye.\n");
       
   331     fflush(stdout);
       
   332     terminateRequested = true;
       
   333 }
       
   334 
       
   335 void VSExplorer::watch(const QString &path)
       
   336 {
       
   337     foreach (QValueSpacePublisher *obj, watchers) {
       
   338         if (obj->path() == path)
       
   339             return;
       
   340     }
       
   341 
       
   342     QValueSpacePublisher * newObject = new QValueSpacePublisher(path);
       
   343     watchers.insert(newObject);
       
   344     QObject::connect(newObject, SIGNAL(interestChanged(QString,bool)),
       
   345                      this, SLOT(interestChanged(QString,bool)));
       
   346 }
       
   347 
       
   348 void VSExplorer::unwatch(const QString &path)
       
   349 {
       
   350     foreach (QValueSpacePublisher *obj, watchers) {
       
   351         if (obj->path() == path) {
       
   352             watchers.remove(obj);
       
   353             delete obj;
       
   354             return;
       
   355         }
       
   356     }
       
   357 }
       
   358 
       
   359 void VSExplorer::suppress()
       
   360 {
       
   361     if (isSuppress) {
       
   362         isSuppress = false;
       
   363         fprintf(stdout, "Suppression off.\n");
       
   364     } else {
       
   365         isSuppress = true;
       
   366         fprintf(stdout, "Suppression on.\n");
       
   367     }
       
   368     fflush(stdout);
       
   369 }
       
   370 
       
   371 void VSExplorer::set(const QString &name, const QString &value)
       
   372 {
       
   373     if('/' == *name.constData())
       
   374         prov.setValue(name, value);
       
   375     else if(pwd.path().endsWith("/"))
       
   376         prov.setValue(pwd.path() + name, value);
       
   377     else
       
   378         prov.setValue(pwd.path() + "/" + name, value);
       
   379 }
       
   380 
       
   381 void VSExplorer::clear(const QString &name)
       
   382 {
       
   383     if('/' == *name.constData())
       
   384         prov.resetValue(name);
       
   385     else if(pwd.path().endsWith("/"))
       
   386         prov.resetValue(pwd.path() + name);
       
   387     else
       
   388         prov.resetValue(pwd.path() + "/" + name);
       
   389 }
       
   390 
       
   391 void VSExplorer::processLine(const QString &line)
       
   392 {
       
   393     QStringList cmds = line.trimmed().split(' ');
       
   394 
       
   395     if(cmds.isEmpty()) {
       
   396         return;
       
   397     }
       
   398 
       
   399     const QString & cmd = cmds.at(0);
       
   400     if(cmd == "ls" && 1 == cmds.count()) {
       
   401         ls();
       
   402     } else if(cmd == "dump") {
       
   403         dump();
       
   404     } else if(cmd == "pwd") {
       
   405         pwdCmd();
       
   406     } else if(cmd == "ls" && 2 <= cmds.count()) {
       
   407         QStringList newCmds = cmds;
       
   408         newCmds.removeFirst();
       
   409         bool lsAll = false;
       
   410         if(newCmds.first() == "-a") {
       
   411             lsAll = true;
       
   412             newCmds.removeFirst();
       
   413         }
       
   414         QString newPath = newCmds.join(" ");
       
   415         if(newPath.startsWith("\"") && newPath.endsWith("\"")) {
       
   416             newPath = newPath.mid(1);
       
   417             newPath = newPath.left(newPath.length() - 1);
       
   418         }
       
   419         if(newPath.isEmpty()) {
       
   420             ls(pwd.path().toAscii(), lsAll);
       
   421         } else if(newPath.startsWith("/")) {
       
   422             ls(newPath.toAscii(), lsAll);
       
   423         } else {
       
   424             QString oldPath = pwd.path();
       
   425             if(!oldPath.endsWith("/"))
       
   426                 oldPath.append("/");
       
   427             oldPath.append(newPath);
       
   428             oldPath = QDir::cleanPath(oldPath);
       
   429             ls(oldPath.toAscii(), lsAll);
       
   430         }
       
   431 
       
   432     } else if(cmd == "cd" && 2 <= cmds.count()) {
       
   433         QStringList newCmds = cmds;
       
   434         newCmds.removeFirst();
       
   435         QString newPath = newCmds.join(" ");
       
   436         if(newPath.startsWith("\"") && newPath.endsWith("\"")) {
       
   437             newPath = newPath.mid(1);
       
   438             newPath = newPath.left(newPath.length() - 1);
       
   439         }
       
   440         if(newPath.startsWith("/")) {
       
   441             pwd.setPath(newPath);
       
   442         } else {
       
   443             QString oldPath = pwd.path();
       
   444             if(!oldPath.endsWith("/"))
       
   445                 oldPath.append("/");
       
   446             oldPath.append(newPath);
       
   447             oldPath = QDir::cleanPath(oldPath);
       
   448             pwd.setPath(oldPath);
       
   449         }
       
   450     } else if(cmd == "unwatch" && 2 <= cmds.count()) {
       
   451         QStringList newCmds = cmds;
       
   452         newCmds.removeFirst();
       
   453         QString newPath = newCmds.join(" ");
       
   454         QString finalPath;
       
   455         if(newPath.startsWith("\"") && newPath.endsWith("\"")) {
       
   456             newPath = newPath.mid(1);
       
   457             newPath = newPath.left(newPath.length() - 1);
       
   458         }
       
   459         if(newPath.startsWith("/")) {
       
   460             finalPath = QValueSpaceSubscriber(newPath).path();
       
   461         } else {
       
   462             QString oldPath = pwd.path();
       
   463             if(!oldPath.endsWith("/"))
       
   464                 oldPath.append("/");
       
   465             oldPath.append(newPath);
       
   466             oldPath = QDir::cleanPath(oldPath);
       
   467             finalPath = QValueSpaceSubscriber(oldPath).path();
       
   468         }
       
   469         unwatch(finalPath.toUtf8());
       
   470     } else if(cmd == "watch" && 2 <= cmds.count()) {
       
   471         QStringList newCmds = cmds;
       
   472         newCmds.removeFirst();
       
   473         QString newPath = newCmds.join(" ");
       
   474         QString finalPath;
       
   475         if(newPath.startsWith("\"") && newPath.endsWith("\"")) {
       
   476             newPath = newPath.mid(1);
       
   477             newPath = newPath.left(newPath.length() - 1);
       
   478         }
       
   479         if(newPath.startsWith("/")) {
       
   480             finalPath = QValueSpaceSubscriber(newPath).path();
       
   481         } else {
       
   482             QString oldPath = pwd.path();
       
   483             if(!oldPath.endsWith("/"))
       
   484                 oldPath.append("/");
       
   485             oldPath.append(newPath);
       
   486             oldPath = QDir::cleanPath(oldPath);
       
   487             finalPath = QValueSpaceSubscriber(oldPath).path();
       
   488         }
       
   489         watch(finalPath.toUtf8());
       
   490     } else if(cmd == "set" && 3 == cmds.count()) {
       
   491         set(cmds.at(1).trimmed(), cmds.at(2).trimmed());
       
   492     } else if(cmd == "clear" && 2 == cmds.count()) {
       
   493         clear(cmds.at(1).trimmed());
       
   494     } else if((cmd == "subscribe" || cmd == "sub") && 1 == cmds.count()) {
       
   495         subscribe();
       
   496     } else if((cmd == "unsubscribe" || cmd == "unsub") && 1 == cmds.count()) {
       
   497         unsubscribe();
       
   498     } else if((cmd == "?" || cmd == "help") && 1 == cmds.count()) {
       
   499         printHelp();
       
   500     } else if((cmd == "quit" || cmd == "exit") && 1 == cmds.count()) {
       
   501         quit();
       
   502     } else if((cmd == "suppress") && 1 == cmds.count()) {
       
   503         suppress();
       
   504     } else if((cmd == "watchers") && 1 == cmds.count()) {
       
   505         listwatchers();
       
   506     } else if((cmd == "subscriptions") && 1 == cmds.count()) {
       
   507         subscriptions();
       
   508     } else if(cmd == "") {
       
   509     } else {
       
   510         printError();
       
   511     }
       
   512 }
       
   513 
       
   514 #ifdef USE_READLINE
       
   515 extern "C" {
       
   516     char * item_generator(const char * text, int num);
       
   517     char * command_generator(const char * text, int num);
       
   518     char ** item_completion(const char * text, int start, int end);
       
   519 }
       
   520 #endif
       
   521 
       
   522 LineInput::LineInput()
       
   523 {
       
   524 #if defined(USE_READLINE)
       
   525     rl_completion_append_character = '\0';
       
   526     rl_attempted_completion_function = item_completion;
       
   527     rl_completer_quote_characters = "\"";
       
   528     rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&(";
       
   529     rl_filename_quote_characters = " ";
       
   530     QObject::connect(this, SIGNAL(finished()), qApp, SLOT(quit()));
       
   531     QObject::connect(this, SIGNAL(terminated()), qApp, SLOT(quit()));
       
   532     start();
       
   533 #elif defined(Q_OS_WIN)
       
   534     ts.open(stdin, QIODevice::ReadOnly);
       
   535     QObject::connect(this, SIGNAL(finished()), qApp, SLOT(quit()));
       
   536     QObject::connect(this, SIGNAL(terminated()), qApp, SLOT(quit()));
       
   537     start();
       
   538 
       
   539     fprintf(stdout, "%s > ", vse->path().constData());
       
   540     fflush(stdout);
       
   541 #else
       
   542     ts.open(stdin, QIODevice::ReadOnly);
       
   543     sock = new QSocketNotifier(ts.handle(), QSocketNotifier::Read, this);
       
   544     QObject::connect(sock, SIGNAL(activated(int)), this, SLOT(readyRead()));
       
   545 
       
   546     fprintf(stdout, "%s > ", qPrintable(vse->path()));
       
   547     fflush(stdout);
       
   548 #endif
       
   549 }
       
   550 
       
   551 #if !defined(USE_READLINE) && !defined(Q_OS_WIN)
       
   552 void LineInput::readyRead()
       
   553 {
       
   554     QByteArray line = ts.readLine();
       
   555 
       
   556     emit this->line(QString::fromLocal8Bit(line));
       
   557 
       
   558     if(terminateRequested)
       
   559         exit(0);
       
   560 
       
   561     fprintf(stdout, "%s > ", qPrintable(vse->path()));
       
   562     fflush(stdout);
       
   563 }
       
   564 #endif
       
   565 
       
   566 #ifdef USE_READLINE
       
   567 #define TEXTEVENTTYPE (QEvent::User + 10)
       
   568 struct TextEvent : public QEvent
       
   569 {
       
   570     TextEvent(char *line)
       
   571         : QEvent((QEvent::Type)TEXTEVENTTYPE), data(line) {}
       
   572 
       
   573     char * data;
       
   574 };
       
   575 
       
   576 bool LineInput::event(QEvent *e)
       
   577 {
       
   578     if(e->type() == TEXTEVENTTYPE) {
       
   579         TextEvent * te = static_cast<TextEvent *>(e);
       
   580         emit line(te->data);
       
   581         free(te->data);
       
   582 
       
   583         mutex.lock();
       
   584         wait.wakeAll();
       
   585         mutex.unlock();
       
   586 
       
   587         return true;
       
   588     } else {
       
   589         return QThread::event(e);
       
   590     }
       
   591 }
       
   592 
       
   593 char ** item_completion(const char * text, int start, int end)
       
   594 {
       
   595     char ** matches = (char **)NULL;
       
   596     const char * non_space = text;
       
   597     while(*non_space == ' ') ++non_space;
       
   598 
       
   599 
       
   600     if(start == non_space - text)
       
   601         matches = rl_completion_matches(text, command_generator);
       
   602     else
       
   603         matches = rl_completion_matches(text, item_generator);
       
   604 
       
   605     rl_attempted_completion_over = 1;
       
   606     return (matches);
       
   607 }
       
   608 
       
   609 char * command_generator(const char * t, int num)
       
   610 {
       
   611     static QList<QByteArray> children;
       
   612 
       
   613     if(0 == num) {
       
   614         children.clear();
       
   615 
       
   616         // Command
       
   617         static const char * commands[] = { "help ",
       
   618                                            "quit ",
       
   619                                            "pwd ",
       
   620                                            "ls ",
       
   621                                            "subscribe ",
       
   622                                            "unsubscribe ",
       
   623                                            "suppress ",
       
   624                                            "subscriptions ",
       
   625                                            "set ",
       
   626                                            "clear ",
       
   627                                            "cd " };
       
   628 
       
   629         for(unsigned int ii = 0; ii < sizeof(commands) / sizeof(char *); ++ii)
       
   630             if(0 == ::strncmp(commands[ii], t, strlen(t)))
       
   631                 children.append(commands[ii]);
       
   632     }
       
   633 
       
   634     if(children.isEmpty())
       
   635         return 0;
       
   636 
       
   637     char * rv = (char *)malloc(children.at(0).length() + 1);
       
   638     ::memcpy(rv, children.at(0).constData(), children.at(0).length() + 1);
       
   639     children.removeFirst();
       
   640 
       
   641     return rv;
       
   642 }
       
   643 
       
   644 char * item_generator(const char * t, int num)
       
   645 {
       
   646     static QStringList children;
       
   647 
       
   648     rl_filename_completion_desired = 1;
       
   649     rl_filename_quoting_desired = 1;
       
   650     if(0 == num) {
       
   651 
       
   652         children.clear();
       
   653 
       
   654         // Path
       
   655         QString text = QString::fromLocal8Bit(t);
       
   656         QString textExt;
       
   657         QString textBase;
       
   658 
       
   659         int last = text.lastIndexOf('/');
       
   660         if(-1 == last) {
       
   661             textExt = text;
       
   662         } else {
       
   663             textBase = text.left(last);
       
   664             textExt = text.mid(last + 1);
       
   665         }
       
   666 
       
   667         QString vsBase;
       
   668 
       
   669         if(*textBase.constData() != '/') {
       
   670             QString in = vse->path();
       
   671             if(!in.endsWith("/"))
       
   672                 vsBase = in + "/" + textBase;
       
   673             else
       
   674                 vsBase = in + textBase;
       
   675         } else {
       
   676             vsBase = textBase;
       
   677         }
       
   678 
       
   679         QValueSpaceSubscriber subscriber(vsBase);
       
   680 
       
   681         QStringList schildren = subscriber.subPaths();
       
   682 
       
   683         foreach(QString child, schildren) {
       
   684             if(child.startsWith(textExt)) {
       
   685                 QString completion;
       
   686                 completion.append(textBase);
       
   687                 if(!completion.isEmpty())
       
   688                     completion.append("/");
       
   689                 completion.append(child.toAscii());
       
   690                 completion.append("/");
       
   691                 children.append(completion);
       
   692             }
       
   693         }
       
   694     }
       
   695 
       
   696     if(children.isEmpty())
       
   697         return 0;
       
   698 
       
   699     QByteArray child = children.takeFirst().toLocal8Bit();
       
   700     char *rv = (char *)malloc(child.length() + 1);
       
   701     ::memcpy(rv, child.constData(), child.length() + 1);
       
   702 
       
   703     return rv;
       
   704 }
       
   705 
       
   706 
       
   707 void LineInput::run()
       
   708 {
       
   709     while(true) {
       
   710         /* Get a line from the user. */
       
   711         mutex.lock();
       
   712         QString prompt = vse->path();
       
   713         prompt.append(" > ");
       
   714         mutex.unlock();
       
   715         char *line_read = readline (prompt.toLocal8Bit().constData());
       
   716 
       
   717         /* If the line has any text in it,
       
   718            save it on the history. */
       
   719         if (line_read && *line_read)
       
   720             add_history (line_read);
       
   721 
       
   722         mutex.lock();
       
   723         TextEvent * e = new TextEvent(line_read);
       
   724         QApplication::postEvent(this, e);
       
   725         wait.wait(&mutex);
       
   726         if(terminateRequested) {
       
   727             mutex.unlock();
       
   728             return;
       
   729         } else {
       
   730             mutex.unlock();
       
   731         }
       
   732     }
       
   733 }
       
   734 #endif
       
   735 
       
   736 #ifdef Q_OS_WIN
       
   737 void LineInput::run()
       
   738 {
       
   739     while (!terminateRequested) {
       
   740         fprintf(stdout, "%s > ", vse->path().constData());
       
   741         fflush(stdout);
       
   742 
       
   743         QByteArray l = ts.readLine();
       
   744         emit line(QString::fromLocal8Bit(l.constData(), l.length()));
       
   745     }
       
   746 }
       
   747 
       
   748 #endif
       
   749 
       
   750 void usage(char * app)
       
   751 {
       
   752     fprintf(stderr, "Usage: %s [-s] [-d]\n", app);
       
   753     fprintf(stderr, "   -s     a valuespace manager instance is created\n");
       
   754     fprintf(stderr, "   -d     the tree content is dumped to command line\n");
       
   755     exit(-1);
       
   756 }
       
   757 
       
   758 void dodump(QValueSpaceSubscriber *subscriber)
       
   759 {
       
   760     foreach (const QString &child, subscriber->subPaths()) {
       
   761         if (child.isEmpty())
       
   762             continue;
       
   763 
       
   764         QValueSpaceSubscriber subItem;
       
   765         subItem.setPath(subscriber);
       
   766         subItem.cd(child);
       
   767         dodump(&subItem);
       
   768     }
       
   769 
       
   770     QVariant var = subscriber->value();
       
   771     fprintf(stdout, "%s '%s' %s\n",
       
   772             subscriber->path().toAscii().constData(),
       
   773             variantToString(var).toAscii().constData(),
       
   774             var.typeName());
       
   775 }
       
   776 
       
   777 void VSExplorer::dump()
       
   778 {
       
   779     QValueSpaceSubscriber subscriber;
       
   780     subscriber.setPath(&pwd);
       
   781     dodump(&subscriber);
       
   782     fflush(stdout);
       
   783 }
       
   784 
       
   785 void VSExplorer::pwdCmd()
       
   786 {
       
   787     fprintf(stdout, "Working directory: %s\n", pwd.path().toLatin1().constData());
       
   788     fflush(stdout);
       
   789 }
       
   790 
       
   791 
       
   792 int main(int argc, char ** argv)
       
   793 {
       
   794     QApplication app(argc, argv, true);
       
   795 
       
   796     bool manager = false;
       
   797     bool dump = false;
       
   798     for(int ii = 1; ii < argc; ++ii) {
       
   799         if(0 == ::strcmp(argv[ii], "-s"))
       
   800             manager = true;
       
   801         else if(0 == ::strcmp(argv[ii], "-d"))
       
   802             dump = true;
       
   803         else
       
   804             usage(argv[0]);
       
   805     }
       
   806 
       
   807     if(manager)
       
   808         QValueSpace::initValueSpaceServer();
       
   809 
       
   810     if(dump) {
       
   811         QValueSpaceSubscriber subscriber("/");
       
   812         dodump(&subscriber);
       
   813         return 0;
       
   814     } else {
       
   815         vse = new VSExplorer;
       
   816         LineInput li;
       
   817 
       
   818 
       
   819 #ifdef Q_OS_WIN
       
   820         QObject::connect(&li, SIGNAL(line(QString)),
       
   821                          vse, SLOT(processLine(QString)), Qt::BlockingQueuedConnection);
       
   822 #else
       
   823         QObject::connect(&li, SIGNAL(line(QString)),
       
   824                          vse, SLOT(processLine(QString)));
       
   825 #endif
       
   826 
       
   827         int rv = app.exec();
       
   828         delete vse;
       
   829         return rv;
       
   830     }
       
   831 }
       
   832 
       
   833 #include "vsexplorer.moc"