]> git.lyx.org Git - lyx.git/blobdiff - src/client/client.cpp
Account for old versions of Pygments
[lyx.git] / src / client / client.cpp
index ec375f05397cb53a3653156364f6ef08989b3aab..023e73e96b44e45facfb9af06232bd0164a0287b 100644 (file)
@@ -3,8 +3,8 @@
  * This file is part of LyX, the document processor.
  * Licence details can be found in the file COPYING.
  *
- * \author João Luis M. Assirati
- * \author Lars Gullik Bjønnes
+ * \author João Luis M. Assirati
+ * \author Lars Gullik Bjønnes
  *
  * Full author contact details are available in file CREDITS.
  */
 
 #include <config.h>
 
-#include "debug.h"
+#include "support/ConsoleApplication.h"
+#include "support/debug.h"
 #include "support/FileName.h"
-#include "support/unicode.h"
+#include "support/FileNameList.h"
 #include "support/lstrings.h"
-
-#include <boost/filesystem/operations.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/scoped_ptr.hpp>
+#include "support/Messages.h"
+#include "support/unicode.h"
+#include "support/unique_ptr.h"
 
 // getpid(), getppid()
 #ifdef HAVE_SYS_TYPES_H
 // fcntl()
 #include <fcntl.h>
 
+// strerror()
+#include <string.h>
+
 #include <cerrno>
+#include <cstdio>
 #include <cstdlib>
+#include <exception>
 #include <string>
 #include <vector>
 #include <map>
 #include <iostream>
 
 
+using namespace std;
+using namespace lyx::support;
+
 namespace lyx {
 
-using support::FileName;
-using support::prefixIs;
+// Dummy verbose support
+bool verbose = false;
+
+// Dummy LyXRC support
+struct LyXRC {
+       string icon_set;
+} lyxrc;
 
-using ::boost::scoped_ptr;
-namespace fs = ::boost::filesystem;
+// Keep the linker happy on Windows
+void lyx_exit(int)
+{}
 
-using std::string;
-using std::vector;
-using std::cout;
-using std::cerr;
-using std::cin;
-using std::endl;
+// Dummy language support
+Messages const & getGuiMessages()
+{
+       static Messages lyx_messages;
+
+       return lyx_messages;
+}
+
+
+Messages const & getMessages(string const &)
+{
+       return getGuiMessages();
+}
 
 
 namespace support {
 
 string itoa(unsigned int i)
 {
-       return ::boost::lexical_cast<string>(i);
+       char buf[20];
+       sprintf(buf, "%d", i);
+       return buf;
 }
 
 
 /// Returns the absolute pathnames of all lyx local sockets in
 /// file system encoding.
 /// Parts stolen from lyx::support::DirList().
-vector<fs::path> lyxSockets(string const & dir, string const & pid)
+FileNameList lyxSockets(string const & dir, string const & pid)
 {
-       vector<fs::path> dirlist;
+       FileNameList dirlist;
 
-       fs::path dirpath(dir);
+       FileName dirpath(dir + "/");
 
-       if (!fs::exists(dirpath) || !fs::is_directory(dirpath)) {
+       if (!dirpath.exists() || !dirpath.isDirectory()) {
                lyxerr << dir << " does not exist or is not a directory."
                       << endl;
                return dirlist;
        }
 
-       fs::directory_iterator beg((fs::path(dir)));
-       fs::directory_iterator end;
+       FileNameList dirs = dirpath.dirList("");
+       FileNameList::const_iterator it = dirs.begin();
+       FileNameList::const_iterator end = dirs.end();
 
-       for (; beg != end; ++beg) {
-               if (prefixIs(beg->leaf(), "lyx_tmpdir" + pid)) {
-                       fs::path lyxsocket = beg->path() / "lyxsocket";
-                       if (fs::exists(lyxsocket)) {
-                               dirlist.push_back(lyxsocket);
-                       }
-               }
+       for (; it != end; ++it) {
+               if (!it->isDirectory())
+                       continue;
+               string const tmpdir = it->absFileName();
+               if (!contains(tmpdir, "lyx_tmpdir" + pid))
+                       continue;
+
+               FileName lyxsocket(tmpdir + "/lyxsocket");
+               if (lyxsocket.exists())
+                       dirlist.push_back(lyxsocket);
        }
 
        return dirlist;
@@ -141,7 +168,7 @@ int connect(FileName const & name)
        if (::connect(fd,
                      reinterpret_cast<struct sockaddr *>(&addr),
                      sizeof(addr)) == -1) {
-               cerr << "lyxclient: Could not connect to socket " << name.absFilename()
+               cerr << "lyxclient: Could not connect to socket " << name.absFileName()
                     << ": " << strerror(errno) << endl;
                ::close(fd);
                return -1;
@@ -161,7 +188,12 @@ int connect(FileName const & name)
 
 
 
-// Class IOWatch ------------------------------------------------------------
+/////////////////////////////////////////////////////////////////////
+//
+// IOWatch
+//
+/////////////////////////////////////////////////////////////////////
+
 class IOWatch {
 public:
        IOWatch();
@@ -213,13 +245,19 @@ bool IOWatch::wait()
 }
 
 
-bool IOWatch::isset(int fd) {
+bool IOWatch::isset(int fd)
+{
        return FD_ISSET(fd, &act);
 }
-// ~Class IOWatch ------------------------------------------------------------
 
 
-// Class LyXDataSocket -------------------------------------------------------
+
+/////////////////////////////////////////////////////////////////////
+//
+// LyXDataSocket
+//
+/////////////////////////////////////////////////////////////////////
+
 // Modified LyXDataSocket class for use with the client
 class LyXDataSocket {
 public:
@@ -245,7 +283,7 @@ private:
 
 LyXDataSocket::LyXDataSocket(FileName const & address)
 {
-       if ((fd_ = support::socktools::connect(address)) == -1) {
+       if ((fd_ = socktools::connect(address)) == -1) {
                connected_ = false;
        } else {
                connected_ = true;
@@ -274,7 +312,7 @@ bool LyXDataSocket::connected() const
 // Returns true if there was a complete line to input
 // A line is of the form <key>:<value>
 //   A line not of this form will not be passed
-// The line read is splitted and stored in 'key' and 'value'
+// The line read is split and stored in 'key' and 'value'
 bool LyXDataSocket::readln(string & line)
 {
        int const charbuf_size = 100;
@@ -327,15 +365,19 @@ void LyXDataSocket::writeln(string const & line)
                connected_ = false;
        }
 }
-// ~Class LyXDataSocket -------------------------------------------------------
 
 
-// Class CmdLineParser -------------------------------------------------------
+/////////////////////////////////////////////////////////////////////
+//
+// CmdLineParser
+//
+/////////////////////////////////////////////////////////////////////
+
 class CmdLineParser {
 public:
        typedef int (*optfunc)(vector<docstring> const & args);
-       std::map<string, optfunc> helper;
-       std::map<string, bool> isset;
+       map<string, optfunc> helper;
+       map<string, bool> isset;
        bool parse(int, char * []);
        vector<char *> nonopt;
 };
@@ -385,38 +427,55 @@ bool CmdLineParser::parse(int argc, char * argv[])
 
 namespace cmdline {
 
+docstring mainTmp(from_ascii("/tmp"));
+
+
+class StopException : public exception
+{
+public:
+       StopException(int status) : status_(status) {}
+       int status() const { return status_; }
+private:
+       int status_;
+};
+
+
 void usage()
 {
-       cerr << "Usage: lyxclient [options]" << endl
-            << "Options are:" << endl
-            << "  -a address    set address of the lyx socket" << endl
-            << "  -t directory  set system temporary directory" << endl
-            << "  -p pid        select a running lyx by pid" << endl
-            << "  -c command    send a single command and quit" << endl
-            << "  -g file row   send a command to go to file and row" << endl
-            << "  -n name       set client name" << endl
-            << "  -h name       display this help end exit" << endl
-            << "If -a is not used, lyxclient will use the arguments of -t and -p to look for" << endl
-            << "a running lyx. If -t is not set, 'directory' defaults to /tmp. If -p is set," << endl
-            << "lyxclient will connect only to a lyx with the specified pid. Options -c and -g" << endl
-            << "cannot be set simultaneoulsly. If no -c or -g options are given, lyxclient" << endl
-            << "will read commands from standard input and disconnect when command read is BYE:"
-            << endl;
+       cerr <<
+               "Usage: lyxclient [options]\n"
+         "Options are:\n"
+         "  -a address    set address of the lyx socket\n"
+         "  -t directory  set system temporary directory (for detecting sockets)\n"
+         "  -p pid        select a running lyx by pidi\n"
+         "  -c command    send a single command and quit (LYXCMD prefix needed)\n"
+         "  -g file row   send a command to go to file and row\n"
+         "  -n name       set client name\n"
+         "  -h name       display this help end exit\n"
+         "If -a is not used, lyxclient will use the arguments of -t and -p to look for\n"
+         "a running lyx. If -t is not set, 'directory' defaults to the system directory. If -p is set,\n"
+         "lyxclient will connect only to a lyx with the specified pid. Options -c and -g\n"
+         "cannot be set simultaneoulsly. If no -c or -g options are given, lyxclient\n"
+         "will read commands from standard input and disconnect when command read is BYE:\n"
+         "\n"
+         "System directory is: " << to_utf8(cmdline::mainTmp)
+          << endl;
 }
 
 
 int h(vector<docstring> const &)
 {
        usage();
-       exit(0);
+       throw StopException(EXIT_SUCCESS);
 }
 
 
-docstring clientName(from_ascii(support::itoa(::getppid()) + ">" + support::itoa(::getpid())));
+docstring clientName =
+       from_ascii(itoa(::getppid()) + ">" + itoa(::getpid()));
 
 int n(vector<docstring> const & arg)
 {
-       if (arg.size() < 1) {
+       if (arg.empty()) {
                cerr << "lyxclient: The option -n requires 1 argument."
                     << endl;
                return -1;
@@ -431,7 +490,7 @@ docstring singleCommand;
 
 int c(vector<docstring> const & arg)
 {
-       if (arg.size() < 1) {
+       if (arg.empty()) {
                cerr << "lyxclient: The option -c requires 1 argument."
                     << endl;
                return -1;
@@ -448,9 +507,11 @@ int g(vector<docstring> const & arg)
                     << endl;
                return -1;
        }
-       singleCommand = "LYXCMD:server-goto-file-row "
-               + arg[0] + ' '
-               + arg[1];
+       singleCommand = "LYXCMD:command-sequence "
+               "server-goto-file-row "
+                       + arg[0] + ' '
+                       + arg[1] + "; " +
+               "lyx-activate";
        return 2;
 }
 
@@ -461,7 +522,7 @@ docstring serverAddress;
 
 int a(vector<docstring> const & arg)
 {
-       if (arg.size() < 1) {
+       if (arg.empty()) {
                cerr << "lyxclient: The option -a requires 1 argument."
                     << endl;
                return -1;
@@ -472,12 +533,11 @@ int a(vector<docstring> const & arg)
 }
 
 
-docstring mainTmp(from_ascii("/tmp"));
 
 
 int t(vector<docstring> const & arg)
 {
-       if (arg.size() < 1) {
+       if (arg.empty()) {
                cerr << "lyxclient: The option -t requires 1 argument."
                     << endl;
                return -1;
@@ -492,7 +552,7 @@ string serverPid; // Init to empty string
 
 int p(vector<docstring> const & arg)
 {
-       if (arg.size() < 1) {
+       if (arg.empty()) {
                cerr << "lyxclient: The option -p requires 1 argument."
                     << endl;
                return -1;
@@ -504,18 +564,46 @@ int p(vector<docstring> const & arg)
 
 } // namespace cmdline
 
-} // namespace lyx
+/// The main application class
+class LyXClientApp : public ConsoleApplication
+{
+public:
+       LyXClientApp(int & argc, char * argv[])
+               : ConsoleApplication("client" PROGRAM_SUFFIX, argc, argv),
+                 argc_(argc), argv_(argv)
+       {
+       }
+       void doExec()
+       {
+               try {
+                       int const exit_status = run();
+                       exit(exit_status);
+               }
+               catch (cmdline::StopException & e) {
+                       exit(e.status());
+               }
+       }
+private:
+       int run();
+       int & argc_;
+       char ** argv_;
+};
 
 
-int main(int argc, char * argv[])
+int LyXClientApp::run()
 {
-       using namespace lyx;
-       lyxerr.rdbuf(cerr.rdbuf());
+       // qt changes this, and our numeric conversions require the C locale
+       setlocale(LC_NUMERIC, "C");
 
+       // Set defaults
        char const * const lyxsocket = getenv("LYXSOCKET");
        if (lyxsocket)
                cmdline::serverAddress = from_local8bit(lyxsocket);
 
+       // Default temporary
+       cmdline::mainTmp = FileName::tempPath().absoluteFilePath();
+
+       // Command line builder
        CmdLineParser args;
        args.helper["-h"] = cmdline::h;
        args.helper["-c"] = cmdline::c;
@@ -526,14 +614,14 @@ int main(int argc, char * argv[])
        args.helper["-p"] = cmdline::p;
 
        // Command line failure conditions:
-       if ((!args.parse(argc, argv))
+       if ((!args.parse(argc_, argv_))
           || (args.isset["-c"] && args.isset["-g"])
           || (args.isset["-a"] && args.isset["-p"])) {
                cmdline::usage();
-               return 1;
+               return EXIT_FAILURE;
        }
 
-       scoped_ptr<LyXDataSocket> server;
+       unique_ptr<LyXDataSocket> server;
 
        if (!cmdline::serverAddress.empty()) {
                server.reset(new LyXDataSocket(FileName(to_utf8(cmdline::serverAddress))));
@@ -545,23 +633,23 @@ int main(int argc, char * argv[])
        } else {
                // We have to look for an address.
                // serverPid can be empty.
-               vector<fs::path> addrs = support::lyxSockets(to_filesystem8bit(cmdline::mainTmp), cmdline::serverPid);
-               vector<fs::path>::const_iterator addr = addrs.begin();
-               vector<fs::path>::const_iterator end = addrs.end();
+               FileNameList addrs = lyxSockets(to_filesystem8bit(cmdline::mainTmp), cmdline::serverPid);
+               FileNameList::const_iterator addr = addrs.begin();
+               FileNameList::const_iterator end = addrs.end();
                for (; addr != end; ++addr) {
                        // Caution: addr->string() is in filesystem encoding
-                       server.reset(new LyXDataSocket(FileName(to_utf8(from_filesystem8bit(addr->string())))));
+                       server.reset(new LyXDataSocket(*addr));
                        if (server->connected())
                                break;
                        lyxerr << "lyxclient: " << "Could not connect to "
-                            << addr->string() << endl;
+                            << addr->absFileName() << endl;
                }
                if (addr == end) {
                        lyxerr << "lyxclient: No suitable server found."
                               << endl;
                        return EXIT_FAILURE;
                }
-               cerr << "lyxclient: " << "Connected to " << addr->string() << endl;
+               cerr << "lyxclient: " << "Connected to " << addr->absFileName() << endl;
        }
 
        int const serverfd = server->fd();
@@ -608,7 +696,9 @@ int main(int argc, char * argv[])
                iowatch.wait();
                if (iowatch.isset(0)) {
                        string command;
-                       cin >> command;
+                       getline(cin, command);
+                       if (command.empty())
+                               continue;
                        if (command == "BYE:") {
                                server->writeln("BYE:");
                                saidbye = true;
@@ -625,6 +715,17 @@ int main(int argc, char * argv[])
        return EXIT_SUCCESS;
 }
 
+} // namespace lyx
+
+
+int main(int argc, char * argv[])
+{
+       lyx::lyxerr.setStream(cerr);
+
+       lyx::LyXClientApp app(argc, argv);
+       return app.exec();
+}
+
 
 namespace boost {