X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fclient%2Fclient.cpp;h=023e73e96b44e45facfb9af06232bd0164a0287b;hb=28be7d552f62cc02fa86d7f79201d089bfb2d7b5;hp=5a5fbae2a716c1b494c6dcd114aa99f02615d928;hpb=138b23fac84930cdbfada0067c61480989041113;p=lyx.git diff --git a/src/client/client.cpp b/src/client/client.cpp index 5a5fbae2a7..023e73e96b 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -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. */ @@ -12,14 +12,14 @@ #include -#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 -#include -#include +#include "support/Messages.h" +#include "support/unicode.h" +#include "support/unique_ptr.h" // getpid(), getppid() #ifdef HAVE_SYS_TYPES_H @@ -48,63 +48,90 @@ // fcntl() #include +// strerror() +#include + #include +#include #include +#include #include #include #include #include +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(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 lyxSockets(string const & dir, string const & pid) +FileNameList lyxSockets(string const & dir, string const & pid) { - vector 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(&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 : // 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 const & args); - std::map helper; - std::map isset; + map helper; + map isset; bool parse(int, char * []); vector 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 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 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 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 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 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 const & arg) } -docstring mainTmp(from_ascii("/tmp")); int t(vector 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 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 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 server; + unique_ptr 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 addrs = support::lyxSockets(to_filesystem8bit(cmdline::mainTmp), cmdline::serverPid); - vector::const_iterator addr = addrs.begin(); - vector::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 { @@ -635,4 +736,3 @@ void assertion_failed(char const* a, char const* b, char const* c, long d) } } // namespace boost -