// -*- C++ -*- /* This file is part of * ====================================================== * * LyX, The Document Processor * * Copyright (C) 1995 Matthias Ettrich * Copyright (C) 1995-1998 The LyX Team. *
*======================================================*/
/** Docu : To use the lyxserver define the name of the pipe in your lyxrc: \serverpipe "/home/myhome/.lyxpipe" Then use .lyxpipe.in and .lyxpipe.out to communicate to LyX. Each message consists of a single line in ASCII. Input lines (client -> LyX) have the following format: "LYXCMD:<clientname>:<functionname>:<argument>" Answers from LyX look like this: "INFO:<clientname>:<functionname>:<data>" [asierra970531] Or like this in case of error: "ERROR:<clientname>:<functionname>:<error message>" where <clientname> and <functionname> are just echoed. If LyX notifies about a user defined extension key-sequence, the line looks like this: "NOTIFY:<key-sequence>" [asierra970531] New server-only messages to implement a simple protocol "LYXSRV:<clientname>:<protocol message>" where <protocol message> can be "hello" or "bye". If hello is received LyX will inform the client that it's listening its messages, and 'bye' will inform that lyx is closing.
See development/server_monitor.c for an example client. Purpose: implement a client/server lib for LyX
*/
#ifdef __EMX__
HPIPE fd;
APIRET rc; int errnum; // Try create one instance of named pipe with the mode O_RDONLY|O_NONBLOCK. // The current emx implementation of access() won't work with pipes.
rc = DosCreateNPipe(tmp.c_str(), &fd, NP_ACCESS_INBOUND,
NP_NOWAIT|0x01, 0600, 0600, 0); if (rc == ERROR_PIPE_BUSY) { #else if (access(tmp.c_str(), F_OK) == 0) { #endif
lyxerr.print("LyXComm: Pipe " + tmp + " already exists.");
lyxerr.print("If no other LyX program is active, please delete" " the pipe by hand and try again.");
pipename = LString(); return;
} #ifndef __EMX__ if (mkfifo(tmp.c_str(), 0600) < 0) {
lyxerr.print("LyXComm: Could not create pipe " + tmp);
lyxerr.print(strerror(errno)); return;
};
infd = open(tmp.c_str(), O_RDONLY|O_NONBLOCK); #else if (rc != NO_ERROR) {
errnum = TranslateOS2Error(rc);
lyxerr.print("LyXComm: Could not create pipe " + tmp);
lyxerr.print(strerror(errnum)); return;
}; // Listen to it.
rc = DosConnectNPipe(fd); if (rc != NO_ERROR && rc != ERROR_PIPE_NOT_CONNECTED) {
errnum = TranslateOS2Error(rc);
lyxerr.print("LyXComm: Could not create pipe " + tmp);
lyxerr.print(strerror(errnum)); return;
}; // Imported handles can be used both with OS/2 APIs and emx // library functions.
infd = _imphandle(fd); #endif if (infd < 0) {
lyxerr.print("LyXComm: Could not open pipe " + tmp);
lyxerr.print(strerror(errno)); return;
}
fl_add_io_callback(infd, FL_READ, callback, (void*)this);
LString tmp = pipename + ".in"; #ifdef __EMX__ // Notify the operating system.
rc = DosDisConnectNPipe(infd); if (rc != NO_ERROR) {
errnum = TranslateOS2Error(rc);
lyxerr.print("LyXComm: Could not disconnect pipe " + tmp);
lyxerr.print(strerror(errnum)); return;
} #endif if (close(infd) < 0) {
lyxerr.print("LyXComm: Could not close pipe " + tmp);
lyxerr.print(strerror(errno));
} #ifndef __EMX__ // OS/2 named pipes will be automatically removed. if (unlink(tmp.c_str()) < 0){
lyxerr.print("LyXComm: Could not remove pipe " + tmp);
lyxerr.print(strerror(errno));
}; #endif
} if(outfd > -1) {
LString tmp = pipename + ".out"; #ifdef __EMX__
rc = DosDisConnectNPipe(outfd); if (rc != NO_ERROR) {
errnum = TranslateOS2Error(rc);
lyxerr.print("LyXComm: Could not disconnect pipe " + tmp);
lyxerr.print(strerror(errnum)); return;
} #endif if (close(outfd) < 0) {
lyxerr.print("LyXComm: Could not close pipe " + tmp);
lyxerr.print(strerror(errno));
} #ifndef __EMX__ if (unlink(tmp.c_str()) < 0){
lyxerr.print("LyXComm: Could not remove pipe " + tmp);
lyxerr.print(strerror(errno));
}; #endif
}
ready = false;
}
// Receives messages and sends then to client void LyXComm::callback(int fd, void *v)
{
LyXComm * c = (LyXComm *) v;
if (lyxerr.debugging(Error::LYXSERVER)) {
lyxerr.print(LString("LyXComm: Receiving from fd ") + int(fd));
}
constint CMDBUFLEN = 100; char charbuf[CMDBUFLEN];
LString cmd; // nb! make lsbuf a class-member for multiple sessions static LString lsbuf;
errno = 0; int status; // the single = is intended here. while((status = read(fd,charbuf,CMDBUFLEN-1)))
{// break and return in loop if(status > 0) // got something
{
charbuf[status]='\0'; // turn it into a c string
lsbuf += charbuf;
lsbuf.strip('\r'); // commit any commands read while(lsbuf.charPos('\n') >= 0) // while still // commands // left
{ // split() grabs the entire string if // the delim /wasn't/ found. ?:-P
lsbuf.split(cmd,'\n');
lyxerr.debug(LString("LyXComm: status:")
+ status + ", lsbuf:" + lsbuf
+ ", cmd:" + cmd,
Error::LYXSERVER); if(!cmd.empty())
c->clientcb(c->client, cmd); //\n or not \n?
}
} if(errno == EAGAIN)
{ // EAGAIN is not really an error , it means we're // only reading too fast for the writing process on // the other end of the pipe.
errno = 0; return; // up to libforms select-loop (*crunch*)
} if(errno != 0 )
{
lyxerr.print(LString("LyXComm: ") + strerror(errno)); if(!lsbuf.empty())
{
lyxerr.print("LyxComm: truncated command: "
+ lsbuf);
lsbuf.clean();
} break; // reset connection
}
}
c->closeConnection();
c->openConnection();
errno=0;
}
void LyXComm::send(LString const & msg) { if (msg.empty()) {
lyxerr.print("LyXComm: Request to send empty string. Ignoring."); return;
}
if (!ready) {
lyxerr.print("LyXComm: Pipes are closed. Could not send "+ msg);
} elseif (write(outfd, msg.c_str(), msg.length()) < 0) {
lyxerr.print("LyXComm: Error sending message: " + msg);
lyxerr.print(strerror(errno));
lyxerr.print("LyXComm: Resetting connection");
closeConnection();
openConnection();
} #ifdef __EMX__
APIRET rc; int errnum;
rc = DosResetBuffer(outfd); // To avoid synchronization problems. if (rc != NO_ERROR) {
errnum = TranslateOS2Error(rc);
lyxerr.print("LyXComm: Message could not be flushed: " +msg);
lyxerr.print(strerror(errnum));
} #endif
}
// LyXServer class
LyXServer::~LyXServer()
{ // say goodbye to clients so they stop sending messages if (clients > 0) pipes.send("LYXSRV:*:bye");
}
/* ---F+------------------------------------------------------------------ *\ Function : ServerCallback Called by : LyXComm Purpose : handle data gotten from communication
\* ---F------------------------------------------------------------------- */
// --- lookup and exec the command ------------------
if (server_only) {
LString buf; // return the greeting to inform the client that // we are listening. if (cmd == "hello") { // One more client
serv->clients++;
buf = "LYXSRV:" + client + ":hello";
lyxerr.debug("LyXServer: Greeting " + client, Error::LYXSERVER);
serv->pipes.send(buf);
} elseif (cmd == "bye") { // If clients==0 maybe we should reset the pipes // to prevent fake callbacks
serv->clients--;
lyxerr.debug("LyXServer: Client " + client + " said goodbye",
Error::LYXSERVER);
} else {
lyxerr.print("LyXServer: Undefined server command " + cmd + ".");
} return;
}
if (!cmd.empty()) { // which lyxfunc should we let it connect to? // The correct solution would be to have a // specialized (non-gui) BufferView. But how do // we do it now? Probably we should just let it // connect to the lyxfunc in the single LyXView we // support currently. (Lgb)
if(!rval.empty()) { if (action<0 || serv->func->errorStat())
buf = "ERROR:"; else
buf = "INFO:";
buf += LString(client) + ":" + cmd + ":" + rval + "\n";
serv->pipes.send(buf); // !!! we don't do any error checking - // if the client won't listen, the // message is lost and others too // maybe; so the client should empty // the outpipe before issuing a request.
} // not found
}
} /* while *p */
}
/* ---F+------------------------------------------------------------------ *\ Function : LyxNotifyClient Called by : WorkAreaKeyPress Purpose : send a notify messge to a client Parameters: s - string to send Returns : nothing
\* ---F------------------------------------------------------------------- */
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.1Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.