--- /dev/null
+/* \file Messages.cpp
+ * 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 "debug.h"
+#include "support/filetools.h"
+#include "support/package.h"
+#include "support/unicode.h"
+
+#include <boost/current_function.hpp>
+
+#include <cerrno>
+
+
+namespace lyx {
+
+using lyx::support::package;
+using std::endl;
+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;
+
+ string const locale_dir = package().locale_dir().toFilesystemEncoding();
+ cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.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() {}
+
+ docstring const get(string const & m) const
+ {
+ if (m.empty())
+ return from_ascii(m);
+
+ char * o = setlocale(LC_ALL, 0);
+ string old;
+ if (o)
+ old = o;
+ char * n = setlocale(LC_ALL, lang_.c_str());
+ if (!n)
+ // If we are unable to honour the request we just
+ // return what we got in.
+ return from_ascii(m);
+ errno = 0;
+ string const locale_dir = package().locale_dir().toFilesystemEncoding();
+ char const * c = bindtextdomain(PACKAGE, locale_dir.c_str());
+ int e = errno;
+ if (e) {
+ LYXERR(Debug::DEBUG)
+ << BOOST_CURRENT_FUNCTION << '\n'
+ << "Error code: " << errno << '\n'
+ << "Lang, mess: " << lang_ << " " << m << '\n'
+ << "Directory : " << package().locale_dir().absFilename() << '\n'
+ << "Rtn value : " << c << endl;
+ }
+
+ if (!bind_textdomain_codeset(PACKAGE, ucs4_codeset)) {
+ LYXERR(Debug::DEBUG)
+ << BOOST_CURRENT_FUNCTION << '\n'
+ << "Error code: " << errno << '\n'
+ << "Codeset : " << ucs4_codeset << '\n'
+ << endl;
+ }
+
+ textdomain(PACKAGE);
+
+ char const * tmp = m.c_str();
+ char const * msg = gettext(tmp);
+ docstring translated;
+ if (!msg) {
+ lyxerr << "Undefined result from gettext" << endl;
+ translated = from_ascii(tmp);
+ } else if (msg == tmp) {
+ //lyxerr << "Same as entered returned" << endl;
+ translated = from_ascii(tmp);
+ } else {
+ LYXERR(Debug::DEBUG) << "We got a translation" << endl;
+ char_type const * ucs4 = reinterpret_cast<char_type const *>(msg);
+ translated = ucs4;
+ }
+ setlocale(LC_ALL, old.c_str());
+ return translated;
+ }
+private:
+ ///
+ string lang_;
+};
+#endif
+
+#else // ENABLE_NLS
+// This is the dummy variant.
+class Messages::Pimpl {
+public:
+ Pimpl(string const &) {}
+
+ ~Pimpl() {}
+
+ docstring const get(string const & m) const
+ {
+ return from_ascii(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()
+{}
+
+
+docstring const Messages::get(string const & msg) const
+{
+ return pimpl_->get(msg);
+}
+
+
+} // namespace lyx
--- /dev/null
+// -*- 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 "support/docstring.h"
+
+#include <boost/scoped_ptr.hpp>
+
+
+namespace lyx {
+
+///
+class Messages {
+public:
+ ///
+ Messages();
+ ///
+ Messages(std::string const & l);
+ ///
+ ~Messages();
+ ///
+ docstring const get(std::string const & msg) const;
+private:
+ class Pimpl;
+ boost::scoped_ptr<Pimpl> pimpl_;
+};
+
+
+} // namespace lyx
+
+#endif
+++ /dev/null
-/**
- * \file boost.cpp
- * 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.h"
-#include "debug.h"
-#include "support/lyxlib.h"
-
-#include <boost/assert.hpp>
-
-#include <exception>
-
-
-namespace lyx {
-
-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();
-}
-
-
-}
-
-
-} // namespace lyx
--- /dev/null
+/**
+ * \file boost.cpp
+ * 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.h"
+#include "debug.h"
+#include "support/lyxlib.h"
+
+#include <boost/assert.hpp>
+
+#include <exception>
+
+
+namespace lyx {
+
+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();
+}
+
+
+}
+
+
+} // namespace lyx
+++ /dev/null
-/**
- * \file client.cpp
- * 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/filename.h"
-#include "support/unicode.h"
-#include "support/lstrings.h"
-
-#include <boost/filesystem/operations.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/scoped_ptr.hpp>
-
-// getpid(), getppid()
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-// struct timeval
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-
-// select()
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-// socket(), connect()
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-#include <sys/un.h>
-
-// fcntl()
-#include <fcntl.h>
-
-#include <cerrno>
-#include <cstdlib>
-#include <string>
-#include <vector>
-#include <map>
-#include <iostream>
-
-
-namespace lyx {
-
-using support::FileName;
-using 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);
-}
-
-
-/// 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)
-{
- 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->path() / "lyxsocket";
- if (fs::exists(lyxsocket)) {
- dirlist.push_back(lyxsocket);
- }
- }
- }
-
- return dirlist;
-}
-
-
-namespace socktools {
-
-
-/// Connect to the socket \p name.
-int connect(FileName const & name)
-{
- int fd; // File descriptor for the socket
- sockaddr_un addr; // Structure that hold the socket address
-
- string const encoded = name.toFilesystemEncoding();
- // char sun_path[108]
- string::size_type len = encoded.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;
- encoded.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,
- reinterpret_cast<struct sockaddr *>(&addr),
- sizeof(addr)) == -1) {
- cerr << "lyxclient: Could not connect to socket " << name.absFilename()
- << ": " << 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(FileName 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(FileName 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<docstring> 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<docstring> args;
- if (helper[argv[opt]]) {
- isset[argv[opt]] = true;
- int arg = opt + 1;
- while ((arg < argc) && (!helper[argv[arg]])) {
- args.push_back(from_local8bit(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<docstring> const &)
-{
- usage();
- exit(0);
-}
-
-
-docstring clientName(from_ascii(support::itoa(::getppid()) + ">" + support::itoa(::getpid())));
-
-int n(vector<docstring> const & arg)
-{
- if (arg.size() < 1) {
- cerr << "lyxclient: The option -n requires 1 argument."
- << endl;
- return -1;
- }
- clientName = arg[0];
- return 1;
-}
-
-
-docstring singleCommand;
-
-
-int c(vector<docstring> 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<docstring> const & arg)
-{
- if (arg.size() < 2) {
- cerr << "lyxclient: The option -g requires 2 arguments."
- << endl;
- return -1;
- }
- singleCommand = "LYXCMD:server-goto-file-row "
- + arg[0] + ' '
- + arg[1];
- return 2;
-}
-
-
-// empty if LYXSOCKET is not set in the environment
-docstring serverAddress;
-
-
-int a(vector<docstring> 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;
-}
-
-
-docstring mainTmp(from_ascii("/tmp"));
-
-
-int t(vector<docstring> 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<docstring> const & arg)
-{
- if (arg.size() < 1) {
- cerr << "lyxclient: The option -p requires 1 argument."
- << endl;
- return -1;
- }
- serverPid = to_ascii(arg[0]);
- return 1;
-}
-
-
-} // namespace cmdline
-
-} // namespace lyx
-
-
-int main(int argc, char * argv[])
-{
- using namespace lyx;
- lyxerr.rdbuf(cerr.rdbuf());
-
- char const * const lyxsocket = getenv("LYXSOCKET");
- if (lyxsocket)
- cmdline::serverAddress = from_local8bit(lyxsocket);
-
- 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.empty()) {
- server.reset(new LyXDataSocket(FileName(to_utf8(cmdline::serverAddress))));
- if (!server->connected()) {
- cerr << "lyxclient: " << "Could not connect to "
- << to_utf8(cmdline::serverAddress) << endl;
- return EXIT_FAILURE;
- }
- } 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();
- for (; addr != end; ++addr) {
- // Caution: addr->string() is in filesystem encoding
- server.reset(new LyXDataSocket(FileName(to_utf8(from_filesystem8bit(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:" + to_utf8(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(to_utf8(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;
-}
-
-
-namespace boost {
-
-void assertion_failed(char const* a, char const* b, char const* c, long d)
-{
- lyx::lyxerr << "Assertion failed: " << a << ' ' << b << ' ' << c << ' '
- << d << '\n';
-}
-
-} // namespace boost
-
--- /dev/null
+/**
+ * \file client.cpp
+ * 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/filename.h"
+#include "support/unicode.h"
+#include "support/lstrings.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+
+// getpid(), getppid()
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+// struct timeval
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+// select()
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+// socket(), connect()
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#include <sys/un.h>
+
+// fcntl()
+#include <fcntl.h>
+
+#include <cerrno>
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include <map>
+#include <iostream>
+
+
+namespace lyx {
+
+using support::FileName;
+using 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);
+}
+
+
+/// 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)
+{
+ 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->path() / "lyxsocket";
+ if (fs::exists(lyxsocket)) {
+ dirlist.push_back(lyxsocket);
+ }
+ }
+ }
+
+ return dirlist;
+}
+
+
+namespace socktools {
+
+
+/// Connect to the socket \p name.
+int connect(FileName const & name)
+{
+ int fd; // File descriptor for the socket
+ sockaddr_un addr; // Structure that hold the socket address
+
+ string const encoded = name.toFilesystemEncoding();
+ // char sun_path[108]
+ string::size_type len = encoded.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;
+ encoded.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,
+ reinterpret_cast<struct sockaddr *>(&addr),
+ sizeof(addr)) == -1) {
+ cerr << "lyxclient: Could not connect to socket " << name.absFilename()
+ << ": " << 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(FileName 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(FileName 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<docstring> 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<docstring> args;
+ if (helper[argv[opt]]) {
+ isset[argv[opt]] = true;
+ int arg = opt + 1;
+ while ((arg < argc) && (!helper[argv[arg]])) {
+ args.push_back(from_local8bit(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<docstring> const &)
+{
+ usage();
+ exit(0);
+}
+
+
+docstring clientName(from_ascii(support::itoa(::getppid()) + ">" + support::itoa(::getpid())));
+
+int n(vector<docstring> const & arg)
+{
+ if (arg.size() < 1) {
+ cerr << "lyxclient: The option -n requires 1 argument."
+ << endl;
+ return -1;
+ }
+ clientName = arg[0];
+ return 1;
+}
+
+
+docstring singleCommand;
+
+
+int c(vector<docstring> 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<docstring> const & arg)
+{
+ if (arg.size() < 2) {
+ cerr << "lyxclient: The option -g requires 2 arguments."
+ << endl;
+ return -1;
+ }
+ singleCommand = "LYXCMD:server-goto-file-row "
+ + arg[0] + ' '
+ + arg[1];
+ return 2;
+}
+
+
+// empty if LYXSOCKET is not set in the environment
+docstring serverAddress;
+
+
+int a(vector<docstring> 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;
+}
+
+
+docstring mainTmp(from_ascii("/tmp"));
+
+
+int t(vector<docstring> 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<docstring> const & arg)
+{
+ if (arg.size() < 1) {
+ cerr << "lyxclient: The option -p requires 1 argument."
+ << endl;
+ return -1;
+ }
+ serverPid = to_ascii(arg[0]);
+ return 1;
+}
+
+
+} // namespace cmdline
+
+} // namespace lyx
+
+
+int main(int argc, char * argv[])
+{
+ using namespace lyx;
+ lyxerr.rdbuf(cerr.rdbuf());
+
+ char const * const lyxsocket = getenv("LYXSOCKET");
+ if (lyxsocket)
+ cmdline::serverAddress = from_local8bit(lyxsocket);
+
+ 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.empty()) {
+ server.reset(new LyXDataSocket(FileName(to_utf8(cmdline::serverAddress))));
+ if (!server->connected()) {
+ cerr << "lyxclient: " << "Could not connect to "
+ << to_utf8(cmdline::serverAddress) << endl;
+ return EXIT_FAILURE;
+ }
+ } 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();
+ for (; addr != end; ++addr) {
+ // Caution: addr->string() is in filesystem encoding
+ server.reset(new LyXDataSocket(FileName(to_utf8(from_filesystem8bit(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:" + to_utf8(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(to_utf8(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;
+}
+
+
+namespace boost {
+
+void assertion_failed(char const* a, char const* b, char const* c, long d)
+{
+ lyx::lyxerr << "Assertion failed: " << a << ' ' << b << ' ' << c << ' '
+ << d << '\n';
+}
+
+} // namespace boost
+
+++ /dev/null
-/**
- * \file debug.cpp
- * 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/convert.h"
-#include "support/lstrings.h"
-
-#include <iostream>
-#include <iomanip>
-
-
-namespace lyx {
-
-using support::ascii_lowercase;
-using support::bformat;
-using support::isStrInt;
-
-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 const st = v.find(',');
- string const tmp(ascii_lowercase(v.substr(0, st)));
- if (tmp.empty())
- break;
- // Is it a number?
- if (isStrInt(tmp))
- l |= static_cast<type>(convert<int>(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 to_utf8(_(...)) re-entrance problem
- docstring const s = _(errorTags[i].desc);
- os << to_utf8(bformat(_("Debugging `%1$s' (%2$s)"),
- from_utf8(errorTags[i].name), s))
- << '\n';
- }
- }
- os.flush();
-}
-
-
-void lyx_debug_trait::showTags(ostream & os)
-{
- for (int i = 0; i < numErrorTags ; ++i)
- os << setw(10) << static_cast<unsigned int>(errorTags[i].level)
- << setw(13) << errorTags[i].name
- << " " << to_utf8(_(errorTags[i].desc)) << '\n';
- os.flush();
-}
-
-
-LyXErr lyxerr;
-
-
-} // namespace lyx
--- /dev/null
+/**
+ * \file debug.cpp
+ * 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/convert.h"
+#include "support/lstrings.h"
+
+#include <iostream>
+#include <iomanip>
+
+
+namespace lyx {
+
+using support::ascii_lowercase;
+using support::bformat;
+using support::isStrInt;
+
+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 const st = v.find(',');
+ string const tmp(ascii_lowercase(v.substr(0, st)));
+ if (tmp.empty())
+ break;
+ // Is it a number?
+ if (isStrInt(tmp))
+ l |= static_cast<type>(convert<int>(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 to_utf8(_(...)) re-entrance problem
+ docstring const s = _(errorTags[i].desc);
+ os << to_utf8(bformat(_("Debugging `%1$s' (%2$s)"),
+ from_utf8(errorTags[i].name), s))
+ << '\n';
+ }
+ }
+ os.flush();
+}
+
+
+void lyx_debug_trait::showTags(ostream & os)
+{
+ for (int i = 0; i < numErrorTags ; ++i)
+ os << setw(10) << static_cast<unsigned int>(errorTags[i].level)
+ << setw(13) << errorTags[i].name
+ << " " << to_utf8(_(errorTags[i].desc)) << '\n';
+ os.flush();
+}
+
+
+LyXErr lyxerr;
+
+
+} // namespace lyx
+++ /dev/null
-/**
- * \file src/gettext.cpp
- * 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"
-
-
-namespace lyx {
-
-
-#ifdef HAVE_LOCALE_H
-# include <locale.h>
-#endif
-
-using std::string;
-
-
-namespace {
-
-Messages & getLyXMessages()
-{
- static Messages lyx_messages;
-
- return lyx_messages;
-}
-
-} // anon namespace
-
-
-docstring 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
-
-
-} // namespace lyx
--- /dev/null
+/**
+ * \file src/gettext.cpp
+ * 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"
+
+
+namespace lyx {
+
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+using std::string;
+
+
+namespace {
+
+Messages & getLyXMessages()
+{
+ static Messages lyx_messages;
+
+ return lyx_messages;
+}
+
+} // anon namespace
+
+
+docstring 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
+
+
+} // namespace lyx
+++ /dev/null
-/* \file Messages.cpp
- * 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 "debug.h"
-#include "support/filetools.h"
-#include "support/package.h"
-#include "support/unicode.h"
-
-#include <boost/current_function.hpp>
-
-#include <cerrno>
-
-
-namespace lyx {
-
-using lyx::support::package;
-using std::endl;
-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;
-
- string const locale_dir = package().locale_dir().toFilesystemEncoding();
- cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.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() {}
-
- docstring const get(string const & m) const
- {
- if (m.empty())
- return from_ascii(m);
-
- char * o = setlocale(LC_ALL, 0);
- string old;
- if (o)
- old = o;
- char * n = setlocale(LC_ALL, lang_.c_str());
- if (!n)
- // If we are unable to honour the request we just
- // return what we got in.
- return from_ascii(m);
- errno = 0;
- string const locale_dir = package().locale_dir().toFilesystemEncoding();
- char const * c = bindtextdomain(PACKAGE, locale_dir.c_str());
- int e = errno;
- if (e) {
- LYXERR(Debug::DEBUG)
- << BOOST_CURRENT_FUNCTION << '\n'
- << "Error code: " << errno << '\n'
- << "Lang, mess: " << lang_ << " " << m << '\n'
- << "Directory : " << package().locale_dir().absFilename() << '\n'
- << "Rtn value : " << c << endl;
- }
-
- if (!bind_textdomain_codeset(PACKAGE, ucs4_codeset)) {
- LYXERR(Debug::DEBUG)
- << BOOST_CURRENT_FUNCTION << '\n'
- << "Error code: " << errno << '\n'
- << "Codeset : " << ucs4_codeset << '\n'
- << endl;
- }
-
- textdomain(PACKAGE);
-
- char const * tmp = m.c_str();
- char const * msg = gettext(tmp);
- docstring translated;
- if (!msg) {
- lyxerr << "Undefined result from gettext" << endl;
- translated = from_ascii(tmp);
- } else if (msg == tmp) {
- //lyxerr << "Same as entered returned" << endl;
- translated = from_ascii(tmp);
- } else {
- LYXERR(Debug::DEBUG) << "We got a translation" << endl;
- char_type const * ucs4 = reinterpret_cast<char_type const *>(msg);
- translated = ucs4;
- }
- setlocale(LC_ALL, old.c_str());
- return translated;
- }
-private:
- ///
- string lang_;
-};
-#endif
-
-#else // ENABLE_NLS
-// This is the dummy variant.
-class Messages::Pimpl {
-public:
- Pimpl(string const &) {}
-
- ~Pimpl() {}
-
- docstring const get(string const & m) const
- {
- return from_ascii(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()
-{}
-
-
-docstring const Messages::get(string const & msg) const
-{
- return pimpl_->get(msg);
-}
-
-
-} // namespace lyx
+++ /dev/null
-// -*- 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 "support/docstring.h"
-
-#include <boost/scoped_ptr.hpp>
-
-
-namespace lyx {
-
-///
-class Messages {
-public:
- ///
- Messages();
- ///
- Messages(std::string const & l);
- ///
- ~Messages();
- ///
- docstring const get(std::string const & msg) const;
-private:
- class Pimpl;
- boost::scoped_ptr<Pimpl> pimpl_;
-};
-
-
-} // namespace lyx
-
-#endif