products/Sources/formale Sprachen/C/Lyx/src image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: lyxserver.C   Sprache: C

Original von: Lyx©

// -*- 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
*/


#include <config.h>

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include FORMS_H_LOCATION

#ifdef __GNUG__
#pragma implementation
#endif

#include "lyxserver.h"
#include "lyxfunc.h"
#include "lyx_main.h"
#include "error.h"

#ifdef __EMX__
#include <stdlib.h>
#include <io.h>
#define OS2EMX_PLAIN_CHAR
#define INCL_DOSNMPIPES
#define INCL_DOSERRORS
#include <os2.h>
#include "os2_errortable.h"
#endif

//  $Id: lyxserver.C,v 1.1.1.1 1998/04/20 21:14:52 larsbj Exp $

#if !defined(lint) && !defined(WITH_WARNINGS)
static char vcid[] = "$Id: lyxserver.C,v 1.1.1.1 1998/04/20 21:14:52 larsbj Exp $";
#endif /* lint */
 
/* === variables ========================================================= */

extern LyXAction lyxaction;

// LyXComm class
 
 // Open pipes
void LyXComm::openConnection() {
 lyxerr.debug("LyXComm: Opening connection", Error::LYXSERVER);
       
 // If we are up, that's an error
 if (ready) {
  lyxerr.print("LyXComm: Already connected");
  return;
 }
 // We assume that we don't make it
 ready = false;
 
 if (pipename.empty()) return;

 // --- prepare input pipe ---------------------------------------
 
 LString tmp = pipename + ".in";
       
#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);
 
 // --- prepare output pipe ---------------------------------------
 
 tmp = pipename + ".out";
       
#ifndef __EMX__       
 if (access(tmp.c_str(), F_OK) == 0) {
#else
 rc = DosCreateNPipe(tmp.c_str(), &fd, NP_ACCESS_DUPLEX,
  NP_NOWAIT|0x01, 0600, 0600, 0);

 if (rc == ERROR_PIPE_BUSY) {
#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;
 };
 if (access(tmp.c_str(), F_OK) != 0) {
  lyxerr.print("LyXComm: Pipe " + tmp + " does not exist");
  return;
 }
 outfd = open(tmp.c_str(), O_RDWR);
#else
 if (rc != NO_ERROR) {
  errnum = TranslateOS2Error(rc);
  lyxerr.print("LyXComm: Could not create pipe " + tmp);
  lyxerr.print(strerror(errnum));
  return;
 }
 rc = DosConnectNPipe(fd);
 if (rc == ERROR_BAD_PIPE) {
  lyxerr.print("LyXComm: Pipe " + tmp + " does not exist");
  return;
 }
 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;
 }
 outfd = _imphandle(fd);
#endif
 if (outfd < 0) {
  lyxerr.print("LyXComm: Could not open pipe " + tmp);
  lyxerr.print(strerror(errno));
  return;
 }
 if (fcntl(outfd, F_SETFL, O_NONBLOCK) < 0) {
  lyxerr.print("LyXComm: Could not set flags on pipe " + tmp);
  lyxerr.print(strerror(errno));
  return;
 };
 // We made it!
 ready = true;
 lyxerr.debug("LyXComm: Connection established", Error::LYXSERVER);
}
 
/// Close pipes
void LyXComm::closeConnection() {
#ifdef __EMX__
 APIRET rc;
 int errnum;
#endif
        lyxerr.debug("LyXComm: Closing connection", Error::LYXSERVER);

 if (pipename.empty()) {
         return;
 }

 if (!ready) {
  lyxerr.print("LyXComm: Already disconnected");
  return;
 }
 
 if(infd > -1) {
  fl_remove_io_callback(infd, FL_READ, callback);
 
  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));
 }
 
        const int 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 (lyxerr.debugging(Error::LYXSERVER)) {
  lyxerr.print("LyXComm: Sending '" + msg + '\'');
 }

 if (pipename.empty()) return;

 if (!ready) {
  lyxerr.print("LyXComm: Pipes are closed. Could not send "+ msg);
 } else if (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------------------------------------------------------------------- */


void LyXServer::callback(LyXServer * serv, LString const & msg)
{
 lyxerr.debug("LyXServer: Received: '" + msg + '\'', Error::LYXSERVER);
 
 char const *p = msg.c_str();
 
 // --- parse the string --------------------------------------------
 //
 //  Format: LYXCMD:<client>:<func>:<argstring>\n
 //
 bool server_only = false;
 while(*p) {
  // --- 1. check 'header' ---
         if (strncmp(p, "LYXSRV:", 7)==0) {
   server_only = true
  } else if(0!=strncmp(p, "LYXCMD:", 7)) {
   lyxerr.print("LyXServer: Unknown request");
   return;
  }
  p += 7;
  
  // --- 2. for the moment ignore the client name ---
  LString client;
  while(*p && *p != ':')
   client += char(*p++);
  if(*p == ':') p++;
  if(!*p) return;
  
  // --- 3. get function name ---
  LString cmd;
  while(*p && *p != ':')
   cmd += char(*p++);
  
  // --- 4. parse the argument ---
  LString arg;
  if(!server_only && *p == ':' && *(++p)) {
   while(*p && *p != '\n')
    arg += char(*p++);
   if(*p) p++;
  }
 
  lyxerr.debug("LyXServer: Client: '" + client + "' Command: '" + cmd + "' Argument: '" + arg + '\'', Error::LYXSERVER);
  
  // --- 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);
   } else if (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)

   int action = lyxaction.LookupFunc(cmd.c_str());
   //int action = -1;
   LString rval, buf;
      
   if (action>=0) {
    rval = serv->func->Dispatch(action, arg.c_str());
   } else {
    rval = "Unknown command";
   }

   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------------------------------------------------------------------- */


void LyXServer::notifyClient(LString const & s)
{
 LString buf = LString("NOTIFY:") + s + "\n";
 pipes.send(buf);
}


¤ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet)  ¤





Download des
Quellennavigators
Download des
sprechenden Kalenders

in der Quellcodebibliothek suchen




Haftungshinweis

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.


Bot Zugriff