]> git.lyx.org Git - features.git/commitdiff
lyxclient moved from development and cleaned up a bit + some assorted fixes.
authorLars Gullik Bjønnes <larsbj@gullik.org>
Sat, 4 Sep 2004 12:13:50 +0000 (12:13 +0000)
committerLars Gullik Bjønnes <larsbj@gullik.org>
Sat, 4 Sep 2004 12:13:50 +0000 (12:13 +0000)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8967 a592a061-630c-0410-9148-cb99ea01b6c8

18 files changed:
ChangeLog
configure.ac
po/POTFILES.in
src/ChangeLog
src/Makefile.am
src/client/.cvsignore [new file with mode: 0644]
src/client/Makefile.am [new file with mode: 0644]
src/client/boost.C [new file with mode: 0644]
src/client/client.C [new file with mode: 0644]
src/client/debug.C [new file with mode: 0644]
src/client/debug.h [new file with mode: 0644]
src/client/gettext.C [new file with mode: 0644]
src/client/gettext.h [new file with mode: 0644]
src/client/lyxclient.man [new file with mode: 0644]
src/client/messages.C [new file with mode: 0644]
src/client/messages.h [new file with mode: 0644]
src/support/ChangeLog
src/support/tostr.C

index a26b7b0fafeb34be482e1acdd30afc1c4efce7db..afc80394727ad2cb58c9afe25ae9cad7c3a71747 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2004-09-04  Lars Gullik Bjonnes  <larsbj@gullik.net>
+
+       * configure.ac (AC_CONFIG_FILES): add src/client/Makefile
+
 2004-09-03  Georg Baum  <Georg.Baum@post.rwth-aachen.de>
 
        * configure.ac: print error message if uic or moc is not found
index d37ee87019687cc64f86a70a0358e266794aa662..4d578cadd4bda4a11a068641114d12fde106a734 100644 (file)
@@ -413,6 +413,7 @@ AC_CONFIG_FILES([Makefile  m4/Makefile \
        po/Makefile.in \
        sourcedoc/Doxyfile \
        sourcedoc/Makefile \
+       src/client/Makefile \
        src/Makefile \
        src/version.C-tmp:src/version.C.in \
        src/tex2lyx/Makefile \
index 225ff4f4b48a0ab82a4aae812c04e7ba69514f01..c6375970dc9d7f78e17dbcaf32645d0e11bbab06 100644 (file)
@@ -10,6 +10,8 @@ src/buffer.C
 src/buffer_funcs.C
 src/bufferlist.C
 src/bufferparams.C
+src/client/debug.C
+src/client/gettext.h
 src/converter.C
 src/debug.C
 src/exporter.C
index 060df91447072510ffd5ce63440b66b3dba43569..ed860f8eb78bc075f926c39d6a4f4abbdfe570a4 100644 (file)
@@ -1,3 +1,10 @@
+2004-09-04  Lars Gullik Bjonnes  <larsbj@gullik.net>
+
+       * client: new dir
+
+       * Makefile.am (SUBDIRS): change order of subdirs and add client dir
+       (BOOST_LIBS): use top_buildir when looking for the file
+
 2004-08-30  Lars Gullik Bjonnes  <larsbj@gullik.net>
 
        * pch.h: do not use include boost/format.hpp, multiple symbols
index 3222ac92cf126089e9cbe6b7a24630f152580d94..815b94f370585bd4e35847aa6c0cda1749208961 100644 (file)
@@ -4,7 +4,7 @@ DISTCLEANFILES += config.h libintl.h version.C stamp-version version.C-tmp
 
 MAINTAINERCLEANFILES += $(srcdir)/config.h.in
 
-SUBDIRS = mathed insets graphics support frontends tex2lyx
+SUBDIRS = mathed insets graphics support frontends . client tex2lyx
 
 EXTRA_DIST = config.h.in stamp-h.in version.C.in \
        Sectioning.h \
@@ -21,8 +21,8 @@ LYX_POST_LIBS = frontends/controllers/libcontrollers.la \
        support/libsupport.la
 
 if USE_INCLUDED_BOOST
-BOOST_LIBS = ../boost/libs/regex/src/libboostregex.la \
-       ../boost/libs/signals/src/libboostsignals.la
+BOOST_LIBS = $(top_builddir)/boost/libs/regex/src/libboostregex.la \
+       $(top_builddir)/boost/libs/signals/src/libboostsignals.la
 else
 BOOST_LIBS = -lboost_regex -lboost_signals
 endif
diff --git a/src/client/.cvsignore b/src/client/.cvsignore
new file mode 100644 (file)
index 0000000..4a2dc28
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile.in
+Makefile
+lyxclient
+lyxclient.1
+.deps
+.libs
diff --git a/src/client/Makefile.am b/src/client/Makefile.am
new file mode 100644 (file)
index 0000000..57096f9
--- /dev/null
@@ -0,0 +1,29 @@
+include $(top_srcdir)/config/common.am
+
+EXTRA_DIST = lyxclient.man
+
+man_MANS = lyxclient.1
+
+bin_PROGRAMS = lyxclient
+
+INCLUDES = $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(PCH_FLAGS)
+
+lyxclient_LDADD = \
+       $(top_builddir)/src/support/libsupport.la \
+       $(top_builddir)/boost/libs/filesystem/src/libboostfilesystem.la \
+       $(top_builddir)/boost/libs/regex/src/libboostregex.la
+
+lyxclient_SOURCES = \
+       boost.C \
+       client.C \
+       debug.C \
+       debug.h \
+       gettext.C \
+       gettext.h \
+       messages.C \
+       messages.h
+
+lyxclient.1:
+       cp -p $(srcdir)/lyxclient.man lyxclient.1
diff --git a/src/client/boost.C b/src/client/boost.C
new file mode 100644 (file)
index 0000000..6a1274d
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * \file boost.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "lyx_main.h"
+#include "debug.h"
+#include "support/lyxlib.h"
+
+#include <boost/assert.hpp>
+
+#include <exception>
+
+using std::endl;
+
+namespace boost {
+
+void throw_exception(std::exception const & e)
+{
+       lyxerr << "Exception caught:\n"
+           << e.what() << endl;
+       BOOST_ASSERT(false);
+}
+
+
+void assertion_failed(char const * expr, char const * function,
+                     char const * file, long line)
+{
+       lyxerr << "Assertion triggered in " << function
+              << " by failing check \"" << expr << "\""
+              << " in file " << file << ":" << line << endl;
+       lyx::support::abort();
+}
+
+
+}
diff --git a/src/client/client.C b/src/client/client.C
new file mode 100644 (file)
index 0000000..56cde72
--- /dev/null
@@ -0,0 +1,596 @@
+/**
+ * \file client.C
+ * 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
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+
+#include <config.h>
+
+#include "debug.h"
+#include "support/lstrings.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+
+// getpid(), getppid()
+#include <sys/types.h>
+#include <unistd.h>
+
+// select()
+#include <sys/select.h>
+
+// socket(), connect()
+#include <sys/socket.h>
+#include <sys/un.h>
+
+// fcntl()
+#include <fcntl.h>
+
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include <map>
+#include <iostream>
+
+using lyx::support::prefixIs;
+
+using boost::scoped_ptr;
+namespace fs = boost::filesystem;
+
+using std::string;
+using std::vector;
+using std::cout;
+using std::cerr;
+using std::cin;
+using std::endl;
+
+
+namespace support {
+
+string itoa(unsigned int i)
+{
+       return boost::lexical_cast<string>(i);
+}
+
+
+// Parts stolen from lyx::support::DirList()
+// Returns the absolute pathnames of all lyx local sockets
+vector<fs::path> lyxSockets(string const & dir, string const & pid)
+{
+       vector<fs::path> dirlist;
+
+       fs::path dirpath(dir);
+
+       if (!fs::exists(dirpath) || !fs::is_directory(dirpath)) {
+               lyxerr << dir << " does not exist or is not a directory."
+                      << endl;
+               return dirlist;
+       }
+
+       fs::directory_iterator beg((fs::path(dir)));
+       fs::directory_iterator end;
+
+       for (; beg != end; ++beg) {
+               if (prefixIs(beg->leaf(), "lyx_tmpdir" + pid)) {
+                       fs::path lyxsocket = *beg / "lyxsocket";
+                       if (fs::exists(lyxsocket)) {
+                               dirlist.push_back(lyxsocket);
+                       }
+               }
+       }
+
+       return dirlist;
+}
+
+
+namespace socktools {
+
+
+int connect(string const & name)
+{
+       int fd; // File descriptor for the socket
+       sockaddr_un addr; // Structure that hold the socket address
+
+       // char sun_path[108]
+       string::size_type len = name.size();
+       if (len > 107) {
+               cerr << "lyxclient: Socket address '" << name
+                    << "' too long." << endl;
+               return -1;
+       }
+       // Synonims for AF_UNIX are AF_LOCAL and AF_FILE
+       addr.sun_family = AF_UNIX;
+       name.copy(addr.sun_path, 107);
+       addr.sun_path[len] = '\0';
+
+       if ((fd = ::socket(PF_UNIX, SOCK_STREAM, 0))== -1) {
+               cerr << "lyxclient: Could not create socket descriptor: "
+                    << strerror(errno) << endl;
+               return -1;
+       }
+       if (::connect(fd, (struct sockaddr *)&addr, SUN_LEN(&addr)) == -1) {
+               cerr << "lyxclient: Could not connect to socket " << name
+                    << ": " << strerror(errno) << endl;
+               ::close(fd);
+               return -1;
+        }
+       if (::fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+               cerr << "lyxclient: Could not set O_NONBLOCK for socket: "
+                    << strerror(errno) << endl;
+               ::close(fd);
+               return -1;
+       }
+       return fd;
+}
+
+
+} // namespace socktools
+} // namespace support
+
+
+
+// Class IOWatch ------------------------------------------------------------
+class IOWatch {
+public:
+       IOWatch();
+       void clear();
+       void addfd(int);
+       bool wait(double);
+       bool wait();
+       bool isset(int fd);
+private:
+       fd_set des;
+       fd_set act;
+};
+
+
+IOWatch::IOWatch()
+{
+       clear();
+}
+
+
+void IOWatch::clear()
+{
+       FD_ZERO(&des);
+}
+
+
+void IOWatch::addfd(int fd)
+{
+       FD_SET(fd, &des);
+}
+
+
+bool IOWatch::wait(double timeout)
+{
+       timeval to;
+       to.tv_sec = static_cast<long int>(timeout);
+       to.tv_usec = static_cast<long int>((timeout - to.tv_sec)*1E6);
+       act = des;
+       return select(FD_SETSIZE, &act,
+                     (fd_set *)0, (fd_set *)0, &to);
+}
+
+
+bool IOWatch::wait()
+{
+       act = des;
+       return select(FD_SETSIZE, &act,
+                     (fd_set *)0, (fd_set *)0, (timeval *)0);
+}
+
+
+bool IOWatch::isset(int fd) {
+       return FD_ISSET(fd, &act);
+}
+// ~Class IOWatch ------------------------------------------------------------
+
+
+// Class LyXDataSocket -------------------------------------------------------
+// Modified LyXDataSocket class for use with the client
+class LyXDataSocket {
+public:
+       LyXDataSocket(string const &);
+       ~LyXDataSocket();
+       // File descriptor of the connection
+       int fd() const;
+       // Connection status
+       bool connected() const;
+       // Line buffered input from the socket
+       bool readln(string &);
+       // Write the string + '\n' to the socket
+       void writeln(string const &);
+private:
+       // File descriptor for the data socket
+       int fd_;
+       // True if the connection is up
+       bool connected_;
+       // buffer for input data
+       string buffer;
+};
+
+
+LyXDataSocket::LyXDataSocket(string const & address)
+{
+       if ((fd_ = support::socktools::connect(address)) == -1) {
+               connected_ = false;
+       } else {
+               connected_ = true;
+       }
+}
+
+
+LyXDataSocket::~LyXDataSocket()
+{
+       ::close(fd_);
+}
+
+
+int LyXDataSocket::fd() const
+{
+       return fd_;
+}
+
+
+bool LyXDataSocket::connected() const
+{
+       return connected_;
+}
+
+
+// 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'
+bool LyXDataSocket::readln(string & line)
+{
+       int const charbuf_size = 100;
+        char charbuf[charbuf_size]; // buffer for the ::read() system call
+       int count;
+       string::size_type pos;
+
+       // read and store characters in buffer
+       while ((count = ::read(fd_, charbuf, charbuf_size - 1)) > 0) {
+               charbuf[count] = '\0'; // turn it into a c string
+               buffer += charbuf;
+       }
+
+       // Error conditions. The buffer must still be
+       // processed for lines read
+       if (count == 0) { // EOF -- connection closed
+               connected_ = false;
+       } else if ((count == -1) && (errno != EAGAIN)) { // IO error
+               cerr << "lyxclient: IO error." << endl;
+               connected_ = false;
+       }
+
+       // Cut a line from buffer
+       if ((pos = buffer.find('\n')) == string::npos)
+               return false; // No complete line stored
+       line = buffer.substr(0, pos);
+       buffer = buffer.substr(pos + 1);
+       return true;
+}
+
+
+// Write a line of the form <key>:<value> to the socket
+void LyXDataSocket::writeln(string const & line)
+{
+       string linen(line + '\n');
+       int size = linen.size();
+       int written = ::write(fd_, linen.c_str(), size);
+       if (written < size) { // Allways mean end of connection.
+               if ((written == -1) && (errno == EPIPE)) {
+                       // The program will also receive a SIGPIPE
+                       // that must be catched
+                       cerr << "lyxclient: connection closed while writing."
+                            << endl;
+               } else {
+                       // Anything else, including errno == EAGAIN, must be
+                       // considered IO error. EAGAIN should never happen
+                       // when line is small
+                       cerr << "lyxclient: IO error: " << strerror(errno);
+               }
+               connected_ = false;
+       }
+}
+// ~Class LyXDataSocket -------------------------------------------------------
+
+
+// Class CmdLineParser -------------------------------------------------------
+class CmdLineParser {
+public:
+       typedef int (*optfunc)(vector<char *> const & args);
+       std::map<string, optfunc> helper;
+       std::map<string, bool> isset;
+       bool parse(int, char * []);
+       vector<char *> nonopt;
+};
+
+
+bool CmdLineParser::parse(int argc, char * argv[])
+{
+       int opt = 1;
+       while (opt < argc) {
+               vector<char *> args;
+               if (helper[argv[opt]]) {
+                       isset[argv[opt]] = true;
+                       int arg = opt + 1;
+                       while ((arg < argc) && (!helper[argv[arg]])) {
+                               args.push_back(argv[arg]);
+                               ++arg;
+                       }
+                       int taken = helper[argv[opt]](args);
+                       if (taken == -1)
+                               return false;
+                       opt += 1 + taken;
+               } else {
+                       if (argv[opt][0] == '-') {
+                               if ((argv[opt][1] == '-')
+                                  && (argv[opt][2]== '\0')) {
+                                       ++opt;
+                                       while (opt < argc) {
+                                               nonopt.push_back(argv[opt]);
+                                               ++opt;
+                                       }
+                                       return true;
+                               } else {
+                                       cerr << "lyxclient: unknown option "
+                                            << argv[opt] << endl;
+                                       return false;
+                               }
+                       }
+                       nonopt.push_back(argv[opt]);
+                       ++opt;
+               }
+       }
+       return true;
+}
+// ~Class CmdLineParser -------------------------------------------------------
+
+
+
+namespace cmdline {
+
+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;
+}
+
+
+int h(vector<char *> const &)
+{
+       usage();
+       exit(0);
+}
+
+
+string clientName(support::itoa(::getppid()) + ">" + support::itoa(::getpid()));
+
+int n(vector<char *> const & arg)
+{
+       if (arg.size() < 1) {
+               cerr << "lyxclient: The option -n requires 1 argument."
+                    << endl;
+               return -1;
+       }
+       clientName = arg[0];
+       return 1;
+}
+
+
+string singleCommand;
+
+
+int c(vector<char *> const & arg)
+{
+       if (arg.size() < 1) {
+               cerr << "lyxclient: The option -c requires 1 argument."
+                    << endl;
+               return -1;
+       }
+       singleCommand = arg[0];
+       return 1;
+}
+
+
+int g(vector<char *> const & arg)
+{
+       if (arg.size() < 2) {
+               cerr << "lyxclient: The option -g requires 2 arguments."
+                    << endl;
+               return -1;
+       }
+       singleCommand = "LYXCMD:server-goto-file-row "
+               + string(arg[0]) + ' '
+               + string(arg[1]);
+       return 2;
+}
+
+
+// 0 if LYXSOCKET is not set in the environment
+char * serverAddress = getenv("LYXSOCKET");
+
+
+int a(vector<char *> const & arg)
+{
+       if (arg.size() < 1) {
+               cerr << "lyxclient: The option -a requires 1 argument."
+                    << endl;
+               return -1;
+       }
+       // -a supercedes LYXSOCKET environment variable
+       serverAddress = arg[0];
+       return 1;
+}
+
+
+string mainTmp("/tmp");
+
+
+int t(vector<char *> const & arg)
+{
+       if (arg.size() < 1) {
+               cerr << "lyxclient: The option -t requires 1 argument."
+                    << endl;
+               return -1;
+       }
+       mainTmp = arg[0];
+       return 1;
+}
+
+
+string serverPid; // Init to empty string
+
+
+int p(vector<char *> const & arg)
+{
+       if (arg.size() < 1) {
+               cerr << "lyxclient: The option -p requires 1 argument."
+                    << endl;
+               return -1;
+       }
+       serverPid = arg[0];
+       return 1;
+}
+
+
+} // namespace cmdline
+
+
+
+
+
+int main(int argc, char * argv[])
+{
+       lyxerr.rdbuf(cerr.rdbuf());
+
+       CmdLineParser args;
+       args.helper["-h"] = cmdline::h;
+       args.helper["-c"] = cmdline::c;
+       args.helper["-g"] = cmdline::g;
+       args.helper["-n"] = cmdline::n;
+       args.helper["-a"] = cmdline::a;
+       args.helper["-t"] = cmdline::t;
+       args.helper["-p"] = cmdline::p;
+
+       // Command line failure conditions:
+       if ((!args.parse(argc, argv))
+          || (args.isset["-c"] && args.isset["-g"])
+          || (args.isset["-a"] && args.isset["-p"])) {
+               cmdline::usage();
+               return 1;
+       }
+
+       scoped_ptr<LyXDataSocket> server;
+
+       if (cmdline::serverAddress) {
+               server.reset(new LyXDataSocket(cmdline::serverAddress));
+               if (!server->connected()) {
+                       cerr << "lyxclient: " << "Could not connect to "
+                            << cmdline::serverAddress << endl;
+                       return EXIT_FAILURE;
+               }
+       } else {
+               // We have to look for an address.
+               // serverPid can be empty.
+               vector<fs::path> addrs = support::lyxSockets(cmdline::mainTmp, cmdline::serverPid);
+               vector<fs::path>::const_iterator addr = addrs.begin();
+               vector<fs::path>::const_iterator end = addrs.end();
+               for (; addr != end; ++addr) {
+                       server.reset(new LyXDataSocket(addr->string()));
+                       if (server->connected())
+                               break;
+                       lyxerr << "lyxclient: " << "Could not connect to "
+                            << addr->string() << endl;
+               }
+               if (addr == end) {
+                       lyxerr << "lyxclient: No suitable server found."
+                              << endl;
+                       return EXIT_FAILURE;
+               }
+               cerr << "lyxclient: " << "Connected to " << addr->string() << endl;
+       }
+
+       int const serverfd = server->fd();
+
+       IOWatch iowatch;
+       iowatch.addfd(serverfd);
+
+       // Used to read from server
+       string answer;
+
+       // Send greeting
+       server->writeln("HELLO:" + cmdline::clientName);
+       // wait at most 2 seconds until server responds
+       iowatch.wait(2.0);
+       if (iowatch.isset(serverfd) && server->readln(answer)) {
+               if (prefixIs(answer, "BYE:")) {
+                       cerr << "lyxclient: Server disconnected." << endl;
+                       cout << answer << endl;
+                       return EXIT_FAILURE;
+               }
+       } else {
+               cerr << "lyxclient: No answer from server." << endl;
+               return EXIT_FAILURE;
+       }
+
+       if (args.isset["-g"] || args.isset["-c"]) {
+               server->writeln(cmdline::singleCommand);
+               iowatch.wait(2.0);
+               if (iowatch.isset(serverfd) && server->readln(answer)) {
+                       cout << answer;
+                       if (prefixIs(answer, "ERROR:"))
+                               return EXIT_FAILURE;
+                       return EXIT_SUCCESS;
+               } else {
+                       cerr << "lyxclient: No answer from server." << endl;
+                       return EXIT_FAILURE;
+               }
+       }
+
+       // Take commands from stdin
+       iowatch.addfd(0); // stdin
+       bool saidbye = false;
+       while ((!saidbye) && server->connected()) {
+               iowatch.wait();
+               if (iowatch.isset(0)) {
+                       string command;
+                       cin >> command;
+                       if (command == "BYE:") {
+                               server->writeln("BYE:");
+                               saidbye = true;
+                       } else {
+                               server->writeln("LYXCMD:" + command);
+                       }
+               }
+               if (iowatch.isset(serverfd)) {
+                       while(server->readln(answer))
+                               cout << answer << endl;
+               }
+       }
+
+       return EXIT_SUCCESS;
+}
diff --git a/src/client/debug.C b/src/client/debug.C
new file mode 100644 (file)
index 0000000..5da41b9
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * \file debug.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "debug.h"
+#include "gettext.h"
+
+#include "support/lstrings.h"
+
+#include <iostream>
+#include <iomanip>
+
+using lyx::support::ascii_lowercase;
+using lyx::support::bformat;
+using lyx::support::isStrInt;
+using lyx::support::strToInt;
+
+using std::setw;
+using std::string;
+using std::ostream;
+
+namespace {
+
+struct error_item {
+       Debug::type level;
+       char const * name;
+       char const * desc;
+};
+
+
+error_item errorTags[] = {
+       { Debug::NONE,      "none",      N_("No debugging message")},
+       { Debug::INFO,      "info",      N_("General information")},
+       { Debug::DEBUG,  "debug",  N_("Developers general debug messages")},
+       { Debug::ANY,       "any",       N_("All debugging messages")}
+};
+
+
+int const numErrorTags = sizeof(errorTags)/sizeof(error_item);
+
+} // namespace anon
+
+
+lyx_debug_trait::type lyx_debug_trait::value(string const & val)
+{
+       type l = Debug::NONE;
+       string v(val);
+       while (!v.empty()) {
+               string::size_type st = v.find(',');
+               string tmp(ascii_lowercase(v.substr(0, st)));
+               if (tmp.empty())
+                       break;
+               // Is it a number?
+               if (isStrInt(tmp))
+                       l |= static_cast<type>(strToInt(tmp));
+               else
+               // Search for an explicit name
+               for (int i = 0 ; i < numErrorTags ; ++i)
+                       if (tmp == errorTags[i].name) {
+                               l |= errorTags[i].level;
+                               break;
+                       }
+               if (st == string::npos) break;
+               v.erase(0, st + 1);
+       }
+       return l;
+}
+
+
+void lyx_debug_trait::showLevel(ostream & os, lyx_debug_trait::type level)
+{
+       // Show what features are traced
+       for (int i = 0; i < numErrorTags ; ++i) {
+               if (errorTags[i].level != Debug::ANY
+                   && errorTags[i].level != Debug::NONE
+                   && errorTags[i].level & level) {
+                       // avoid _(...) re-entrance problem
+                       string const s = _(errorTags[i].desc);
+                       os << bformat(_("Debugging `%1$s' (%2$s)"),
+                                       errorTags[i].name, s)
+                          << '\n';
+               }
+       }
+       os.flush();
+}
+
+
+void lyx_debug_trait::showTags(ostream & os)
+{
+       for (int i = 0; i < numErrorTags ; ++i)
+               os << setw(7) << static_cast<unsigned int>(errorTags[i].level)
+                  << setw(10) << errorTags[i].name
+                  << "  " << _(errorTags[i].desc) << '\n';
+       os.flush();
+}
+
+LyXErr lyxerr;
diff --git a/src/client/debug.h b/src/client/debug.h
new file mode 100644 (file)
index 0000000..68caf83
--- /dev/null
@@ -0,0 +1,70 @@
+// -*- C++ -*-
+/**
+ * \file debug.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef LYXDEBUG_H
+#define LYXDEBUG_H
+
+#include "support/debugstream.h"
+
+/** Ideally this should have been a namespace, but since we try to be
+    compilable on older C++ compilators too, we use a struct instead.
+    This is all the different debug levels that we have.
+*/
+struct lyx_debug_trait {
+       ///
+       enum type {
+               ///
+               NONE = 0,
+               ///
+               INFO       = (1 << 0),
+               ///
+               DEBUG      = (1 << 31),
+               ///
+               ANY = 0xffffffff
+       };
+
+       static bool match(type a, type b) {
+               return (a & b);
+       }
+
+       /** A function to convert symbolic string names on debug levels
+           to their numerical value.
+       */
+       static type value(std::string const & val);
+
+       /** Display the tags and descriptions of the current debug level
+           of ds
+       */
+       static void showLevel(std::ostream & o, type level);
+
+       /** show all the possible tags that can be used for debugging */
+       static void showTags(std::ostream & o);
+
+};
+
+
+
+inline
+void operator|=(lyx_debug_trait::type & d1, lyx_debug_trait::type d2)
+{
+       d1 = static_cast<lyx_debug_trait::type>(d1 | d2);
+}
+
+
+// std::ostream & operator<<(std::ostream & o, Debug::type t);
+
+typedef basic_debugstream<lyx_debug_trait> LyXErr;
+typedef LyXErr::debug Debug;
+
+extern LyXErr lyxerr;
+
+#endif
diff --git a/src/client/gettext.C b/src/client/gettext.C
new file mode 100644 (file)
index 0000000..2f08de5
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * \file src/gettext.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "gettext.h"
+#include "messages.h"
+
+
+#ifdef HAVE_LOCALE_H
+#  include <locale.h>
+#endif
+
+using std::string;
+
+
+namespace {
+
+Messages & getLyXMessages()
+{
+       static Messages lyx_messages;
+
+       return lyx_messages;
+}
+
+} // anon namespace
+
+
+string const _(string const & str)
+{
+       return getLyXMessages().get(str);
+}
+
+
+#ifdef ENABLE_NLS
+
+void locale_init()
+{
+#  ifdef HAVE_LC_MESSAGES
+       setlocale(LC_MESSAGES, "");
+#  endif
+       setlocale(LC_CTYPE, "");
+       setlocale(LC_NUMERIC, "C");
+}
+
+#else // ENABLE_NLS
+
+void locale_init()
+{
+       setlocale(LC_NUMERIC, "C");
+}
+
+#endif
diff --git a/src/client/gettext.h b/src/client/gettext.h
new file mode 100644 (file)
index 0000000..7cb097a
--- /dev/null
@@ -0,0 +1,64 @@
+// -*- C++ -*-
+/**
+ * \file src/gettext.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef GETTEXT_H
+#define GETTEXT_H
+
+#include <string>
+
+/*
+ * Native Language Support
+ *
+ * The general idea is that any string that should be translated is handled
+ * as follows:
+ *     _("string")
+ *
+ * Static strings are special, obviously and must be flagged as follows:
+ *     static str = N_("string");
+ *
+ * And wherever they are used:
+ *     _(str)
+ *
+ * Every file where there are strings needs:
+ *     #include "gettext.h"
+ *
+ * Remember to mention each of these files in "po/POFILES.in"
+ *
+ * The main() needs a locale_init() and a gettext_init() in the beginning.
+ */
+
+/*
+ * General translation notes:
+ *   Commands/options are not translated
+ *   Debug messages are not translated
+ *   Panic/fatal (that should not happen) messages need not be translated
+ */
+
+
+//#ifdef ENABLE_NLS
+
+///
+std::string const _(std::string const &);
+
+//#else // ENABLE_NLS
+
+///
+//#  define _(str) (str)
+
+//#endif
+
+#  define N_(str) (str)              // for detecting static strings
+
+///
+void locale_init();
+
+#endif
diff --git a/src/client/lyxclient.man b/src/client/lyxclient.man
new file mode 100644 (file)
index 0000000..967f623
--- /dev/null
@@ -0,0 +1,83 @@
+.\" Man page for lyxclient.
+.\" Use the following command to view man page:
+.\"
+.\"  tbl lyxclient.1 | nroff -man | less
+.\"
+.TH LYXCLIENT 1 "Oct 2003" "Version 1.4" "lyxclient 1.4"
+.SH NAME
+lyxclient \- send commands to a running LyX editor
+.\"
+.\" setup
+.de Cr
+.ie n (c)
+.el \(co
+..
+.SH SYNOPSIS
+\fBlyxclient\fR [ \fIoptions\fR ]
+.br
+.SH DESCRIPTION
+When LyX starts, it creates a unique, per-process local socket in the
+temporary directory through which commands can be sent. That is, it can act
+like a server, accepting connections from clients. \fBlyxclient\fR
+can be used as such client. \fBlyxclient\fR will take care of all
+connection and communication protocol details, leaving you (or your app)
+free to concentrate on what you want to send to LyX.
+.SH SERVER IDENTIFICATION OPTIONS
+\fBlyxclient\fR must first identify to which server (i.e. a running LyX)
+commands are to be sent. The following options are used to specify the server.
+.TP 6
+.TP
+.BI \-p " pid"
+specify the \fIpid\fR of the running LyX process to which \fBlyxclient\fR
+should send commands.
+.TP
+.BI \-a " socket_address"
+specify explicitly which socket special file should be used. These special
+files are located inside lyx_tmpdir<lyx_pid><hash>, in the temporary
+directory. There is one per running LyX process.
+.TP
+.BI \-t " tmp_dir"
+if LyX is configured to use a temporary directory other than /tmp, you must
+inform \fBlyxclient\fR of this.
+.PP
+If neither \fB-a\fR nor \fB-p\fR are invoked, \fBlyxclient\fR will search for
+sockets in /tmp (or \fItmp_dir\fR if the \fB-t\fR option is used) and use
+the first socket to which it can connect.
+This is safe if you are running only one LyX process at any one time.
+.SH COMMAND MODE OPTIONS
+\fBlyxclient\fR can send commands to LyX from both the command-line
+and from standard input.
+LyX commands are documented in <fixme>.
+.TP 6
+.BI \-c " command"
+send a single \fIcommand\fR, print LyX information to standard output and exit.
+.TP
+.BI \-g " file line"
+this is simply a wrapper for the command 'server-goto-file-row \fIfile\fR \fIline\fR'. It is used by the DVI previewer to elicit inverse DVI search.
+.PP
+If neither \fB-c\fR nor \fB-g\fR are used, \fBlyxclient\fR will regard any
+standard input as commands to be sent to LyX, printing LyX's responses to
+standard output. Commands are
+separated by newlines (the '\\n' character). To finish communication
+and terminate the \fBlyxclient\fR process, send the command 'BYE:'.
+.SH MISCELANEOUS OPTIONS
+.TP 6
+.BI \-n " name"
+when starting communication, \fBlyxclient\fR sends an idenfifier
+string to LyX. By default, this string is "PPID>PID", where PPID is
+\fBlyxclient\fR's parent pid and pid is \fBlyxclient\fR's pid.
+Use this option to override this default.
+.TP
+.BI \-h
+print the \fBlyxclient\fR version and summarize its usage.
+.SH ENVIRONMENT
+.TP
+.B LYXSOCKET
+can be used to specify the socket special file that must be used.
+LyX sets this variable.
+It is overridden by the \fB-a\fR option.
+.SH SEE ALSO
+lyx(1), xdvi(1), lyx functions <fixme>.
+.SH AUTHORS
+João Luis M. Assirati <assirati@fma.if.usp.br> is the principal author
+of lyxclient.
diff --git a/src/client/messages.C b/src/client/messages.C
new file mode 100644 (file)
index 0000000..d1aa3f5
--- /dev/null
@@ -0,0 +1,147 @@
+/* \file messages.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "messages.h"
+#include "support/filetools.h"
+#include "support/path_defines.h"
+
+using lyx::support::GetEnvPath;
+using lyx::support::lyx_localedir;
+
+using std::string;
+
+
+#ifdef ENABLE_NLS
+
+
+#if 0
+
+-#include <locale>
+
+// This version of the Pimpl utilizes the message capability of
+// libstdc++ that is distributed with GNU G++.
+class Messages::Pimpl {
+public:
+       typedef std::messages<char>::catalog catalog;
+
+       Pimpl(string const & l)
+               : lang_(l),
+                 loc_gl(lang_.c_str()),
+                 mssg_gl(std::use_facet<std::messages<char> >(loc_gl))
+       {
+               //lyxerr << "Messages: language(" << l
+               //       << ") in dir(" << dir << ")" << std::endl;
+
+               cat_gl = mssg_gl.open(PACKAGE, loc_gl, lyx_localedir().c_str());
+
+       }
+
+       ~Pimpl()
+       {
+               mssg_gl.close(cat_gl);
+       }
+
+       string const get(string const & msg) const
+       {
+               return mssg_gl.get(cat_gl, 0, 0, msg);
+       }
+private:
+       ///
+       string lang_;
+       ///
+       std::locale loc_gl;
+       ///
+       std::messages<char> const & mssg_gl;
+       ///
+       catalog cat_gl;
+};
+#else
+
+#ifdef HAVE_LOCALE_H
+#  include <locale.h>
+#endif
+
+#  if HAVE_GETTEXT
+#    include <libintl.h>      // use the header already in the system *EK*
+#  else
+#    include "../intl/libintl.h"
+#  endif
+
+// This is a more traditional variant.
+class Messages::Pimpl {
+public:
+       Pimpl(string const & l)
+               : lang_(l)
+       {
+               //lyxerr << "Messages: language(" << l
+               //       << ") in dir(" << dir << ")" << std::endl;
+
+       }
+
+       ~Pimpl() {}
+
+       string const get(string const & m) const
+       {
+               if (m.empty())
+                       return m;
+
+               char * old = strdup(setlocale(LC_ALL, 0));
+               char * n = setlocale(LC_ALL, lang_.c_str());
+               bindtextdomain(PACKAGE, lyx_localedir().c_str());
+               textdomain(PACKAGE);
+               const char* msg = gettext(m.c_str());
+               setlocale(LC_ALL, old);
+               free(old);
+               // If we are unable to honour the request we just
+               // return what we got in.
+               return (!n ? m : string(msg));
+       }
+private:
+       ///
+       string lang_;
+};
+#endif
+
+#else // ENABLE_NLS
+// This is the dummy variant.
+class Messages::Pimpl {
+public:
+       Pimpl(string const &) {}
+
+       ~Pimpl() {}
+
+       string const get(string const & m) const
+       {
+               return m;
+       }
+};
+#endif
+
+
+Messages::Messages()
+       : pimpl_(new Pimpl(""))
+{}
+
+
+Messages::Messages(string const & l)
+       : pimpl_(new Pimpl(l))
+{}
+
+
+// We need this for the sake of scoped_ptr
+Messages::~Messages()
+{}
+
+
+string const Messages::get(string const & msg) const
+{
+       return pimpl_->get(msg);
+}
diff --git a/src/client/messages.h b/src/client/messages.h
new file mode 100644 (file)
index 0000000..c4b2fa2
--- /dev/null
@@ -0,0 +1,33 @@
+// -*- C++ -*-
+/* \file messages.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef MESSAGES_H
+#define MESSAGES_H
+
+#include <boost/scoped_ptr.hpp>
+#include <string>
+
+///
+class Messages {
+public:
+       ///
+       Messages();
+       ///
+       Messages(std::string const & l);
+       ///
+       ~Messages();
+       ///
+       std::string const get(std::string const & msg) const;
+private:
+       class Pimpl;
+       boost::scoped_ptr<Pimpl> pimpl_;
+};
+
+#endif
index 743a38368a633ad3c520e10b45e1b51dd7d6b545..f1636c967bf0e82da562f39cab635e6a7e845639 100644 (file)
@@ -1,3 +1,7 @@
+2004-09-04  Lars Gullik Bjonnes  <larsbj@gullik.net>
+
+       * tostr.C: reimplement using lexical_cast
+
 2004-08-30  Lars Gullik Bjonnes  <larsbj@gullik.net>
 
        * pch.h: do not use include boost/format.hpp, multiple symbols
index 81058d5d87959de332856034a168b64c80cfabb5..d490413f849c261e7991b317df684d36c7acf09c 100644 (file)
@@ -4,16 +4,19 @@
  * Licence details can be found in the file COPYING.
  *
  * \author André Pönitz
+ * \author Lars Gullik Bjønnes
  *
  * Full author contact details are available in file CREDITS.
  */
 
 #include <config.h>
 
-#include <sstream>
+#include <boost/lexical_cast.hpp>
+
+
+using boost::lexical_cast;
 
 using std::string;
-using std::ostringstream;
 
 
 string const tostr(bool b)
@@ -24,33 +27,25 @@ string const tostr(bool b)
 
 string const tostr(unsigned int i)
 {
-       ostringstream os;
-       os << i;
-       return os.str();
+       return lexical_cast<string>(i);
 }
 
 
 string const tostr(long int i)
 {
-       ostringstream os;
-       os << i;
-       return os.str();
+       return lexical_cast<string>(i);
 }
 
 
 string const tostr(double d)
 {
-       ostringstream os;
-       os << d;
-       return os.str();
+       return lexical_cast<string>(d);
 }
 
 
 string const tostr(int i)
 {
-       ostringstream os;
-       os << i;
-       return os.str();
+       return lexical_cast<string>(i);
 }
 
 
@@ -62,7 +57,5 @@ string const tostr(string const & s)
 
 string const tostr(long unsigned int i)
 {
-        ostringstream os;
-        os << i;
-        return os.str();
+       return lexical_cast<string>(i);
 }