]> git.lyx.org Git - lyx.git/blobdiff - src/Server.cpp
continue spellchecking after "replace all"
[lyx.git] / src / Server.cpp
index 26cc2033f90f0e3db13ae0f85e9a31a793945e78..d7a2e2514c285a26a533bfa67b39ac6bf79c6b5e 100644 (file)
@@ -3,7 +3,7 @@
  * This file is part of LyX, the document processor.
  * Licence details can be found in the file COPYING.
  *
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
  * \author Jean-Marc Lasgouttes
  * \author Angus Leeming
  * \author John Levon
 #include <config.h>
 
 #include "Server.h"
-#include "debug.h"
 #include "FuncRequest.h"
 #include "LyXAction.h"
 #include "LyXFunc.h"
+
 #include "frontends/Application.h"
 
+#include "support/debug.h"
 #include "support/FileName.h"
 #include "support/lstrings.h"
-#include "support/lyxlib.h"
 
 #include <boost/bind.hpp>
 
 #endif
 #include <fcntl.h>
 
+using namespace std;
+using namespace lyx::support;
 
 namespace lyx {
 
-using support::compare;
-using support::FileName;
-using support::rtrim;
-using support::split;
-using support::unlink;
-
-using std::endl;
-using std::string;
-
-
 /////////////////////////////////////////////////////////////////////
 //
 // LyXComm
@@ -80,7 +72,7 @@ using std::string;
 #if !defined (HAVE_MKFIFO)
 // We provide a stub class that disables the lyxserver.
 
-LyXComm::LyXComm(std::string const &, Server *, ClientCallbackfct)
+LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
 {}
 
 void LyXComm::openConnection()
@@ -115,7 +107,7 @@ void LyXComm::send(string const & msg)
 #else // defined (HAVE_MKFIFO)
 
 
-LyXComm::LyXComm(std::string const & pip, Server * cli, ClientCallbackfct ccb)
+LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
        : pipename_(pip), client_(cli), clientcb_(ccb)
 {
        ready_ = false;
@@ -173,7 +165,7 @@ void LyXComm::closeConnection()
        }
 
        if (!ready_) {
-               lyxerr << "LyXComm: Already disconnected" << endl;
+               LYXERR0("LyXComm: Already disconnected");
                return;
        }
 
@@ -186,13 +178,39 @@ void LyXComm::closeConnection()
 
 int LyXComm::startPipe(string const & file, bool write)
 {
+       static bool stalepipe = false;
        FileName const filename(file);
-       if (::access(filename.toFilesystemEncoding().c_str(), F_OK) == 0) {
-               lyxerr << "LyXComm: Pipe " << filename << " already exists.\n"
-                      << "If no other LyX program is active, please delete"
-                       " the pipe by hand and try again." << endl;
-               pipename_.erase();
-               return -1;
+       if (filename.exists()) {
+               if (!write) {
+                       // Let's see whether we have a stale pipe.
+                       int fd = ::open(filename.toFilesystemEncoding().c_str(),
+                                       O_WRONLY | O_NONBLOCK);
+                       if (fd >= 0) {
+                               // Another LyX instance is using it.
+                               ::close(fd);
+                       } else if (errno == ENXIO) {
+                               // No process is reading from the other end.
+                               stalepipe = true;
+                               LYXERR(Debug::LYXSERVER,
+                                       "LyXComm: trying to remove "
+                                       << filename);
+                               filename.removeFile();
+                       }
+               } else if (stalepipe) {
+                       LYXERR(Debug::LYXSERVER, "LyXComm: trying to remove "
+                               << filename);
+                       filename.removeFile();
+                       stalepipe = false;
+               }
+               if (filename.exists()) {
+                       lyxerr << "LyXComm: Pipe " << filename
+                              << " already exists.\nIf no other LyX program"
+                                 " is active, please delete the pipe by hand"
+                                 " and try again."
+                              << endl;
+                       pipename_.erase();
+                       return -1;
+               }
        }
 
        if (::mkfifo(filename.toFilesystemEncoding().c_str(), 0600) < 0) {
@@ -206,7 +224,7 @@ int LyXComm::startPipe(string const & file, bool write)
        if (fd < 0) {
                lyxerr << "LyXComm: Could not open pipe " << filename << '\n'
                       << strerror(errno) << endl;
-               unlink(filename);
+               filename.removeFile();
                return -1;
        }
 
@@ -232,7 +250,7 @@ void LyXComm::endPipe(int & fd, string const & filename, bool write)
                       << '\n' << strerror(errno) << endl;
        }
 
-       if (unlink(FileName(filename)) < 0) {
+       if (FileName(filename).removeFile() < 0) {
                lyxerr << "LyXComm: Could not remove pipe " << filename
                       << '\n' << strerror(errno) << endl;
        }
@@ -260,6 +278,12 @@ void LyXComm::read_ready()
        int const charbuf_size = 100;
        char charbuf[charbuf_size];
 
+       // As O_NONBLOCK is set, until no data is available for reading,
+       // read() doesn't block but returns -1 and set errno to EAGAIN.
+       // After a client that opened the pipe for writing, closes it
+       // (and no other client is using the pipe), read() would always
+       // return 0 and thus the connection has to be reset.
+
        errno = 0;
        int status;
        // the single = is intended here.
@@ -281,24 +305,25 @@ void LyXComm::read_ready()
                                        clientcb_(client_, cmd);
                                        //\n or not \n?
                        }
-               }
-               if (errno == EAGAIN) {
-                       errno = 0;
-                       return;
-               }
-               if (errno != 0) {
-                       lyxerr << "LyXComm: " << strerror(errno) << endl;
+               } else {
+                       if (errno == EAGAIN) {
+                               // Nothing to read, continue
+                               errno = 0;
+                               return;
+                       }
+                       // An error occurred, better bailing out
+                       LYXERR0("LyXComm: " << strerror(errno));
                        if (!read_buffer_.empty()) {
-                               lyxerr << "LyXComm: truncated command: "
-                                      << read_buffer_ << endl;
+                               LYXERR0("LyXComm: truncated command: " << read_buffer_);
                                read_buffer_.erase();
                        }
                        break; // reset connection
                }
        }
 
-       // The connection gets reset in errno != EAGAIN
-       // Why does it need to be reset if errno == 0?
+       // The connection gets reset when read() returns 0 (meaning that the
+       // last client closed the pipe) or an error occurred, in which case
+       // read() returns -1 and errno != EAGAIN.
        closeConnection();
        openConnection();
        errno = 0;
@@ -308,8 +333,7 @@ void LyXComm::read_ready()
 void LyXComm::send(string const & msg)
 {
        if (msg.empty()) {
-               lyxerr << "LyXComm: Request to send empty string. Ignoring."
-                      << endl;
+               LYXERR0("LyXComm: Request to send empty string. Ignoring.");
                return;
        }
 
@@ -318,8 +342,7 @@ void LyXComm::send(string const & msg)
        if (pipename_.empty()) return;
 
        if (!ready_) {
-               lyxerr << "LyXComm: Pipes are closed. Could not send "
-                      << msg << endl;
+               LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
        } else if (::write(outfd_, msg.c_str(), msg.length()) < 0) {
                lyxerr << "LyXComm: Error sending message: " << msg
                       << '\n' << strerror(errno)
@@ -355,7 +378,7 @@ void ServerCallback(Server * server, string const & msg)
        server->callback(msg);
 }
 
-Server::Server(LyXFunc * f, std::string const & pipes)
+Server::Server(LyXFunc * f, string const & pipes)
        : numclients_(0), func_(f), pipes_(pipes, this, &ServerCallback)
 {}
 
@@ -373,6 +396,13 @@ Server::~Server()
 }
 
 
+int compare(char const * a, char const * b, unsigned int len)
+{
+       using namespace std;
+       return strncmp(a, b, len);
+}
+
+
 // Handle data gotten from communication, called by LyXComm
 void Server::callback(string const & msg)
 {
@@ -460,8 +490,7 @@ void Server::callback(string const & msg)
                                                "Server: ignoring bye messge from unregistered client" << client);
                                }
                        } else {
-                               lyxerr <<"Server: Undefined server command "
-                                      << cmd << '.' << endl;
+                               LYXERR0("Server: Undefined server command " << cmd << '.');
                        }
                        return;
                }
@@ -500,7 +529,7 @@ void Server::callback(string const & msg)
 }
 
 
-// Send a notify messge to a client, called by WorkAreaKeyPress
+// Send a notify message to a client, called by WorkAreaKeyPress
 void Server::notifyClient(string const & s)
 {
        pipes_.send("NOTIFY:" + s + "\n");