/*******************************************************************************
Copyright by Telesoft Europe AB 1990, 1991.
Copyright by Telelogic Malmoe AB 1991, 1992, 1993, 1994.
Copyright by Telelogic AB 1994 - 2002.
This Program is owned by Telelogic and is protected by national
copyright laws and international copyright treaties. Telelogic
grants you the right to use this Program on one computer or in
one local computer network at any one time.
Under this License you may only modify the source code for the purpose
of adapting it to your environment. You must reproduce and include
any copyright and trademark notices on all copies of the source code.
You may not use, copy, merge, modify or transfer the Program except as
provided in this License.
Telelogic does not warrant that the Program will meet your
requirements or that the operation of the Program will be
uninterrupted and error free. You are solely responsible that the
selection of the Program and the modification of the source code
will achieve your intended results and that the results are actually
obtained.
*******************************************************************************/

/*
# clearcase sctpost.c@@/main/60 : 2002/05/06 pon
*/

/*********************************************************************
 **            PostMaster routines used by SDL Simulator            **
 *********************************************************************/

/*
CONTENTS: 
  Include Files
  External declarations
  Global variables and macros
  Forward declarations
  Function implementations
*/

/****+***************************************************************
  Include Files
********************************************************************/

#include "scttypes.h"

#if defined (XCONNECTPM) || defined (THREADED_MSCTRACE)
                /* To end of file */

#include "sctlocal.h"

#include "post.h"
#ifdef XITEXCOMM
#include "itex.h"
#endif
#include "sdt.h"
#define   MSCDIAGRAM            16
                /* Symbol fetched from sdtsym.h */

/****+***************************************************************
  External declarations
********************************************************************/

extern char xKernelVersion[];

/****+***************************************************************
  Global variables and macros
********************************************************************/

#define MAX_M_WRI_LENGTH 10256
  /* length of buffers */

typedef struct xSignalQueueStruct{
  int                        sender;
  int                        messtype;
  void                      *data;
  int                        len;
  struct xSignalQueueStruct *Next;
} *xSignalQueue;

static xSignalQueue SignalQueue = (xSignalQueue)0;

/* FIFO queue to save postmaster signals arriving when doing a RPC
   and waiting for the answer */

#ifdef XCOVERAGE
static int CoveragePID = 0;
#endif

static int ConnectedEditor = 0;

static char *xGRConvFrom = (char *)0;
static char *xGRConvTo   = (char *)0;

/****+***************************************************************
  Forward declarations
********************************************************************/

#ifdef XPMCOMM
static void xHandlePMInEnvSig (char *PMMessStr, int FromITEX);
#endif


/****+***************************************************************
  Function implementations
********************************************************************/

/*---+---------------------------------------------------------------
     PMRead 
-------------------------------------------------------------------*/
/* Read a postmaster message.
   Returns the result from the call to SPRead.
   On windows it will realloc new memory and free the
   memory returned from SPRead (in DLL?) by SPFree
*/

static int PMRead(int timeOut, int *sender, int *message, void **data, int *len)
{
#ifdef _Windows
  int result;
  void * tmpdata = NULL;

  result = SPRead(timeOut, sender, message, &tmpdata, len);
  if (tmpdata) {
    *data = malloc(*len);
    memcpy(*data, tmpdata, *len);
    SPFree(tmpdata);
  }  
  return result;
#else
  return SPRead(timeOut, sender, message, data, len);
#endif
}

/*---+---------------------------------------------------------------
     PMSend 
-------------------------------------------------------------------*/
/* Send a postmaster message.
   Returns the result from the call to SPSendToPid.
*/

int PMSend( int to, int mType, char * mess )
{
  int length;
  int result;

  if (mess != (char *)0)
    length = strlen(mess)+1;
  else
    length = 0;

  if (to == 0)
    result = SPBroadcast(mType, (void *)mess, length);
  else 
/*#ifdef THREADED_MSCTRACE
  {
    THREADED_TAKE_SEM
#endif *//* THREADED_MSCTRCAE */
    result = SPSendToPid(to, mType, (void *)mess, length);
#ifdef THREADED_MSCTRACE
    THREADED_WAIT_SEM_REL
 /* }*/
#endif /* THREADED_MSCTRACE */


  if (result == SPOK) return 0;
  return 1;
}

/*---+---------------------------------------------------------------
     PMBroadcast
-------------------------------------------------------------------*/
/* Broadcast a postmaster message.
   Returns the result from the call to SPBroadcast.
*/

int PMBroadcast( int mType, char * mess )
{
  int length;
  int result;

  if (mess != (char *)0) {
    length = strlen(mess)+1;
  } else {
    length = 0;
  }

  result = SPBroadcast(mType, (void *)mess, length);
  if (result == SPOK) return 0;
  return 1;
}


/*---+---------------------------------------------------------------
     PMQueueMessage
-------------------------------------------------------------------*/
/* Queue a message in the FIFO queue SignalQueue
*/

static void PMQueueMessage(int sender, int messtype, void *data, int len)
{
  xSignalQueue  NewRef, tmp;

  NewRef = (xSignalQueue)xAlloc((xptrint)sizeof(struct xSignalQueueStruct));
  if (NewRef == (xSignalQueue)0) {
    xPrintString("Cannot allocate more memory, losing message.\n");
    return;
  }
  NewRef->Next = (xSignalQueue)0;
  NewRef->sender = sender;
  NewRef->messtype = messtype;
  NewRef->data = data;
  NewRef->len = len;
  if (SignalQueue == (xSignalQueue)0) {
    SignalQueue = NewRef;
  }
  else {
    tmp = SignalQueue;
    while ( tmp->Next!=(xSignalQueue)0 )
      tmp = tmp->Next;
    tmp->Next = NewRef;
  }
}


/*---+---------------------------------------------------------------
     PMQueueCheck
-------------------------------------------------------------------*/
/* Check if there is a saved message matching reqMess from reqSender
   in SignalQueue.
   If so return it.
*/
static xbool PMQueueCheck(int reqMess, int reqSender,
                          int *sender, int *messtype, void **data, int *len)
{
  xSignalQueue tmp, tmpPrev = 0;

  tmp = SignalQueue;
  while (tmp) {
    if ( SP_MATCHREPLY(reqMess,tmp->messtype) &&
         (tmp->sender == reqSender || tmp->sender == 0) ) {
      *sender = tmp->sender;
      *messtype = tmp->messtype;
      *data = tmp->data;
      *len = tmp->len;
      if (tmp == SignalQueue)
        SignalQueue = tmp->Next;
      else
        tmpPrev->Next = tmp->Next;
      xFree((void**)&tmp);
      return (xbool)1;
    }
    tmpPrev = tmp;
    tmp = tmp->Next;
  }
  
  return (xbool)0;
}


/*---+---------------------------------------------------------------
     PMQueueRead
-------------------------------------------------------------------*/
/* First check if there is a saved message in the FIFO queue SignalQueue.
   If so return it, otherwise call PMRead.
*/
static int PMQueueRead(int timeOut, int *sender, int *messtype, void **data, int * len)
{
  xSignalQueue tmp;

  if (SignalQueue != (xSignalQueue)0) {
    tmp = SignalQueue;
    *sender = tmp->sender;
    *messtype = tmp->messtype;
    *data = tmp->data;
    *len = tmp->len;
    SignalQueue = tmp->Next;
    xFree((void**)&tmp);
    return SPOK;
  }
  
#ifdef _Windows
  if (0 == timeOut)
    timeOut = 1;
#endif
  
  return PMRead(timeOut, sender, messtype, data, len);
}


#ifdef XITEXCOMM
static xbool SavedIETMSCHEDULEReply = (xbool)0;
static int   WaitingForIETMSCHEDULEFrom = 0;
static int   SavedIETMSCHEDULEReplyLength = 0;
static void *SavedIETMSCHEDULEReplydata = NULL;

typedef struct xChannelListStruct {
  xChannelIdNode             channel;
  struct xChannelListStruct *Next;
} *xChannelList;

static xChannelList ITEXChannelList = (xChannelList)0;

/*---+---------------------------------------------------------------
     xAddToITEXChannelList
-------------------------------------------------------------------*/
xbool xAddToITEXChannelList(xChannelIdNode channel)
{
  xChannelList NewRef;
  xChannelList tmp;

  tmp = ITEXChannelList;
  while (tmp) {
    if (channel == tmp->channel || channel == tmp->channel->Reverse)
      break;
    tmp = tmp->Next;
  }
  if (tmp) {
    PRINTF("Channel already in list:");
    tmp = ITEXChannelList;
    while (tmp) {
      PRINTF2(" %s", tmp->channel->Name);
      tmp = tmp->Next;
    }
    PRINTF("\n");
    return (xbool)0;
  }
  
  NewRef = (xChannelList)xAlloc((xptrint)sizeof(struct xChannelListStruct));
  NewRef->channel = channel;
  NewRef->Next = ITEXChannelList;
  ITEXChannelList = NewRef;
  return (xbool)1;
}

/*---+---------------------------------------------------------------
     InITEXChannelList
-------------------------------------------------------------------*/
static xbool InITEXChannelList(xChannelIdNode channel)
{
  xChannelList tmp;

  tmp = ITEXChannelList;
  while (tmp) {
    if (channel == tmp->channel || channel == tmp->channel->Reverse)
      return (xbool)1;
    tmp = tmp->Next;
  }
  
  return (xbool)0;
}
#endif

/*---+---------------------------------------------------------------
     PM_RPC
-------------------------------------------------------------------*/
/* Remote procedure call using the postmaster.
   Note that 'reqMess' must be the id of the request message.
   Returns an integer representing the status of the reply (or
   indicating postmaster error):

   0:     Everything is ok
   1:     Server busy
   2,3:   Error from server
   10:    Status field incorrect in reply
   11:    Error from PMSend
   12:    SPERROR from PMRead
   >100:  Postmaster error

   'returnMess' will be the entire string received in the reply.
*/
#ifdef THREADED_MSCTRACE
int startup_msc = 1;
#endif /* THREADED_MSCTRACE */
int PM_RPC(
  int     to,
  int     reqMess,
  char  * mess,
  char ** returnMess )
{
  int result;
  int sender;
  void * data = NULL;
  int len=0;
  int messtype;

  /* Set defalt value for returnMess */
  *returnMess = NULL;

  /* Send Request */
  result = PMSend(to, reqMess, mess);
  if (result) return 11;

  /* Wait for Reply */
#ifdef THREADED_MSCTRACE
  if(startup_msc) {
#endif /* THREADED_MSCTRACE */
  result = PMRead(-1, &sender, &messtype, &data, &len);
  while (result == SPOK) {
    if ( SP_MATCHREPLY(reqMess,messtype) && (sender == to || sender == 0) )
      break;
#ifdef XITEXCOMM
    if (reqMess == IETMSCHEDULE) {
      /* Allow interruption if IETMSCHEDULE */
      xHandleAllPMSigs(sender, messtype, data, len);
      if (len > 0) free(data);
      if (messtype == SESIMUICOMMAND) {
        WaitingForIETMSCHEDULEFrom = to;
        xCheckMonitors();
        WaitingForIETMSCHEDULEFrom = 0;
        if (SavedIETMSCHEDULEReply) {
# ifdef XDEBUGPM
          printf("Restoring saved message IETMSCHEDULEREPLY in PM_RPC\n");
# endif
          len = SavedIETMSCHEDULEReplyLength;
          data = SavedIETMSCHEDULEReplydata;
          SavedIETMSCHEDULEReplydata = NULL;
          SavedIETMSCHEDULEReply = (xbool)0;
          break;
        }
      }
      if (PMQueueCheck(reqMess, to, &sender, &messtype, &data, &len)) {
        break;
      }
    }
    else
#endif
      PMQueueMessage(sender, messtype, data, len);
    result = PMRead(-1, &sender, &messtype, &data, &len);
  }
  if (len == 0) return 10;
  *returnMess = (char *)data;
  if (result != SPOK) return 12;

  /* Parse the status field */
  if (sscanf( *returnMess, "%d", &result ) != 1) return 10;
#ifdef XDEBUGPM
  if (result != 0) {
    printf("*** Error in RPC %d to %d: %s\n", reqMess, to, *returnMess);
    if (mess)
      printf("    Message was: %s\n", mess);
  }
#endif
  return result;
#ifdef THREADED_MSCTRACE
  }
else
  return 0;
#endif /* THREADED_MSCTRACE */
}


/*---+---------------------------------------------------------------
     PMStartTool
-------------------------------------------------------------------*/
/* Start a tool using the postmaster.
Returns the pid of the started tool (or 0 if failure).
*/

int PMStartTool( int toolType )
{
  int statusCode, pid;
  char str[100];
  char * retStr = NULL;

  sprintf( str, "%d", toolType );
  if (!PM_RPC( 0, SESTART, str, &retStr ) && 
      (sscanf( retStr, "%d %d", &statusCode, &pid )==2)) {
    if (retStr) free(retStr);
    return pid;
  } else {
    if (retStr) free(retStr);
    return 0;
  }
}


/*---+---------------------------------------------------------------
     PMStartSimUI
-------------------------------------------------------------------*/
/* Start a tool using the postmaster.
The parameters are only useful for the SImUI.
Returns the pid of the started tool (or 0 if failure).
*/

static int PMStartSimUI( int toolType )
{
  int statusCode, pid;
  char str[100];
  char * retStr = NULL;

  sprintf(str, "%d simulator %s %d",
          toolType, xSysD.SystemName, XSYSD xNoticeBoard.MyPID);
  if (!PM_RPC( 0, SESTART, str, &retStr ) &&
      (sscanf( retStr, "%d %d", &statusCode, &pid )==2)) {
    if (retStr) free(retStr);
    return pid;
  } else {
    if (retStr) free(retStr);
    return 0;
  }
}


/*---+---------------------------------------------------------------
     PMCheckAlive
-------------------------------------------------------------------*/
/* Returns 1 if 'pid' is alive otherwise 0 */

int PMCheckAlive( int pid )
{
  int statusCode, found;
  char str[100];
  char * retStr = NULL;

  sprintf( str, "%d", pid );
  if (!PM_RPC( 0, SEGETTOOLTYPE, str, &retStr ) && 
      (sscanf( retStr, "%d %d", &statusCode, &found )==2)) {
    if (retStr) free(retStr);
    return found;
  } else {
    if (retStr) free(retStr);
    return 0;
  }
}


/*---+---------------------------------------------------------------
     PMStopTool
-------------------------------------------------------------------*/
/* Stops a tool */

void PMStopTool( int pid )
{
  char * retStr = NULL;

  PM_RPC( pid, SESTOP, "1", &retStr );
  if (retStr) free(retStr);
}


/*---+---------------------------------------------------------------
     PMGetToolPId
-------------------------------------------------------------------*/
/* Returns the PId of one of the tools of type 'toolType'.
   returns 0 if no PIds are found 
*/

int PMGetToolPId( int toolType )
{
  int statusCode, no, pid;
  char str[100];
  char * retStr = NULL;

  sprintf( str, "%d", toolType );
  if (!PM_RPC( 0, SEGETTOOLPID, str, &retStr ) && 
      (sscanf( retStr, "%d %d %d", &statusCode, &no, &pid )==3)) {
    if (retStr) free(retStr);
    return pid;
  } else {
    if (retStr) free(retStr);
    return 0;
  }
}


/*---+---------------------------------------------------------------
     xInitPM
-------------------------------------------------------------------*/
#ifndef TARGETSIM
void xInitPM( int argc, char *argv[] )
{
#else /* TARGETSIM below */
void xInitPM( int dummyargc, char *dummyargv[] )
{
  int argc = 4;
  char * argv[4] = {"remsim", "-post","-1", "1"};
#endif /*TARGETSIM */
  int  self;
  int  I = 0;
  int  topToolType = SET_SIMULATOR;
  double topToolVersion = 4.4;
  char status[1000];

  XSYSD xNoticeBoard.PMConnected = (xbool)0;
  XSYSD xNoticeBoard.MyPID = 0;
  XSYSD xNoticeBoard.StartedFromPostmaster = 0;
#ifdef XITEXCOMM
  XSYSD xNoticeBoard.ITEXCommStarted = 0;
  XSYSD xNoticeBoard.TimeManager = 0;
#endif
#ifdef XPMCOMM
  XSYSD xNoticeBoard.CommStarted = 0;
#endif
#ifdef XSDLENVUI
  XSYSD xNoticeBoard.UIStarted = 0;
#endif
#ifdef XSIMULATORUI
  XSYSD xNoticeBoard.SimulatorUIStarted = 0;
#endif

#ifdef XMSCE
  XSYSD xNoticeBoard.MSCEStarted = 0;
  XSYSD xNoticeBoard.MSCDiagram = 0;
#endif
#ifdef TARGETSIM
  XSYSD xNoticeBoard.TargetParam = 0;
#endif

#if defined(THREADED_MSCTRACE) && defined(THREADOSE)
argc =1;
argv[0] = "dummy";
#endif /* THREADED_MSCTRACE && THREADED_OSE */
  if (argc==1) {
    self = SPInit(SET_SIMULATOR, argv[0], NULL);
    if (self == SPERROR) {
      printf("No connection with the Postmaster. Running stand-alone.\n");
    } else {
      printf("Connected with the Postmaster.\n");
      XSYSD xNoticeBoard.MyPID = (int)self;
      XSYSD xNoticeBoard.PMConnected = (xbool)1;
    }
#ifndef TARGETSIM
    if (!SPCheckI(topToolType, topToolVersion, status)) {
      printf(status);
      exit(0);
    }
#endif
  } else if (!strcmp(argv[1], "-version")) {
    printf("%s\n", xKernelVersion);
    exit(0);
  } else if (!strcmp(argv[1], "-nosdt")) {
    printf("Running stand alone.\n");
#ifndef TARGETSIM
    if (!SPCheckI(topToolType, topToolVersion, status)) {
      printf(status);
      exit(0);
    }
#endif
  } else if (!strcmp(argv[1], "-post")) {
    self = SPInit(SET_SIMULATOR, argv[0], NULL);
#ifdef TARGETSIM
    if (argc>3) {
      (void)sscanf(argv[3], "%d", &XSYSD xNoticeBoard.TargetParam);
      if (self == SPERROR && XSYSD xNoticeBoard.TargetParam > 0) {
        XSYSD xNoticeBoard.MyPID = (int)self;
        XSYSD xNoticeBoard.PMConnected = (xbool)1;
        XSYSD xNoticeBoard.StartedFromPostmaster = 1;
        (void)sscanf(argv[2], "%d", &(XSYSD xNoticeBoard.SimulatorUIStarted));
        return;
      }
    }
#endif
    if (self == SPERROR) {
      printf("No connection with the Postmaster. Aborting ...\n");
      SDL_Halt();
    }
    XSYSD xNoticeBoard.MyPID = (int)self;
    XSYSD xNoticeBoard.PMConnected = (xbool)1;
    XSYSD xNoticeBoard.StartedFromPostmaster = 1;
#ifdef XSIMULATORUI
    if (argc>2) {
      /* If more than one argument the next one should be the SIM UI pid */
      I = sscanf(argv[2], "%d", &(XSYSD xNoticeBoard.SimulatorUIStarted));
      if (I!=1) {
        xPrintString("Incorrect parameters when started using postmaster.\n");
        SDL_Halt();
      }
    }
#endif
  } else {
    printf("Incorrect program parameters. Aborting ...\n");
    SDL_Halt();
  }
}


/*---+---------------------------------------------------------------
     xClosePM
-------------------------------------------------------------------*/
void xClosePM (void)
{
  char status[1000];
  if ( XSYSD xNoticeBoard.PMConnected ) {
#ifdef XMONITOR
    xDisconnectEditor((xbool)1);
#endif
#ifdef XCOVERAGE
    if ( CoveragePID ) {
      PMStopTool(CoveragePID);
    }
#endif
    (void)PMBroadcast(SESTOPNOTIFY, NULL);
    (void)SPExit();
    XSYSD xNoticeBoard.PMConnected = (xbool)0;
  }
#ifndef TARGETSIM
#ifdef XSIMULATORUI
  if (!XSYSD xNoticeBoard.SimulatorUIStarted)
    (void)SPCheckC(status);
#endif
#endif
}


/*---+---------------------------------------------------------------
     xSendxTrStrReply
-------------------------------------------------------------------*/
void xSendxTrStrReply(
  int    sender,
  char * str)
{
  PMSend(sender, SESIMUIINTERNCOMMANDREPLY, str);
}

/*---+---------------------------------------------------------------
     xHandleAllPMSigs
-------------------------------------------------------------------*/
void xHandleAllPMSigs(
  int    sender,
  int    messtype,
  void * data,
  int    len )
{
  switch (messtype) {

    case SESTOP: {
      PMSend( sender, SESTOPREPLY, "" );
      SDL_Halt();
    }

    case SESTOPNOTIFY: {
#ifdef XMSCE
      if ( sender == XSYSD xNoticeBoard.MSCEStarted ) {
        XSYSD xNoticeBoard.MSCEStarted = (int)0;
        xMSCEditorStopped();
      }
#endif
#ifdef XSIMULATORUI
      if ( sender == XSYSD xNoticeBoard.SimulatorUIStarted ) {
        if (XSYSD xNoticeBoard.StartedFromPostmaster) {
          SDL_Halt();
        }
        XSYSD xNoticeBoard.SimulatorUIStarted = 0;
      }
#endif

#ifdef XCOVERAGE
      if ( sender == CoveragePID ) {
        CoveragePID = 0;
      }
#endif

      if ( sender == ConnectedEditor ) {
        ConnectedEditor = 0;
      }

      return;
    }

#ifdef XSIMULATORUI
    case SESIMULATORCOMMAND:
      if ( ! ConnectedEditor )
        return;
      /* fall through */
    case SESIMUICOMMAND:
    case SESIMUISTRING: {
      xHandleSimUIMessage(sender, (char *)data, len);
      if (sender != XSYSD xNoticeBoard.SimulatorUIStarted) {
        if (messtype == SESIMUICOMMAND)
          PMSend( sender, SESIMUICOMMANDREPLY, "0" );
        else if (messtype == SESIMUISTRING)
          PMSend( sender, SESIMUISTRINGREPLY, "0" );
      }
      return;
    }
#endif

#ifdef XPMCOMM
    case SESDLSIGNAL: {
      xHandlePMInEnvSig((char *)data, 0);
      return;
    }
#endif

#ifdef XSIMULATORUI
    case SESIMUIINTERNCOMMAND: {
      char *answer = xHandlePMInternCommand(sender, (char *)data, len);
      if (answer)
        PMSend(sender, SP_MAKEREPLY(messtype), answer);
      return;
    }
#endif

    default: {
#ifdef XITEXCOMM
      if (WaitingForIETMSCHEDULEFrom) {
        if ( SP_MATCHREPLY(IETMSCHEDULE, messtype) &&
             sender == WaitingForIETMSCHEDULEFrom ) {
# ifdef XDEBUGPM
          printf("Saving message %d in xHandleAllPMSigs\n", messtype);
          if (SavedIETMSCHEDULEReply)
            printf("Previously saved message %d in xHandleAllPMSigs lost\n",
                   messtype);
# endif
          SavedIETMSCHEDULEReply = (xbool)1;
          SavedIETMSCHEDULEReplyLength = len;
          SavedIETMSCHEDULEReplydata = xAlloc((xptrint)len);
          memcpy(SavedIETMSCHEDULEReplydata, data, len);
          break;
        }
      }
#endif
#ifdef XDEBUGPM
      printf("Message %d not handled in xHandleAllPMSigs\n", messtype);
#endif
      if SP_ISREQUEST(messtype) {
        PMSend(sender, SP_MAKEREPLY(messtype), "2 \"Service not supported\"");
      }
      break;
    }

  }
}


/*---+---------------------------------------------------------------
     xInPM
-------------------------------------------------------------------*/
void xInPM (void)
{
  int sender, messtype, len, result;
  void * data=NULL;
#ifdef XITEXCOMM
  SDL_Time T;
  char     strVar[100];
  WriteBuf *Buf;
  char   * retMess;
#endif

  if ( ! XSYSD xNoticeBoard.PMConnected ) return;

#ifdef TARGETSIM
  if ( XSYSD xNoticeBoard.MyPID == (int)SPERROR &&
       XSYSD xNoticeBoard.TargetParam > 0) {
    XSYSD xNoticeBoard.MyPID = SPInit(SET_SIMULATOR, (char *)0, NULL);
    if ( XSYSD xNoticeBoard.MyPID == (int)SPERROR)
      return;
  }
#endif
  result = PMQueueRead(0, &sender, &messtype, &data, &len);
  while (result == SPOK) {
    xHandleAllPMSigs(sender, messtype, data, len);
    if (data) {
      free(data);
      data = NULL;
    }
    result = PMQueueRead(0, &sender, &messtype, &data, &len);
  }
#ifndef TARGETSIM
  if ( result==SPERROR && 
       (GetSPerrno()==SPNOCHANNEL || GetSPerrno()==SPNOSESSION) ) {
    if (XSYSD xNoticeBoard.StartedFromPostmaster) {
      SDL_Halt();
    } else {
      xPrintString("\nLost contact with the Postmaster. Running stand-alone.\n");
      XSYSD xNoticeBoard.PMConnected = (xbool)0;
    }
  }
#endif
#ifdef XITEXCOMM
  if (xSysD.xNoticeBoard.ITEXCommStarted && !WaitingForIETMSCHEDULEFrom) {
    if (xSysD.xNoticeBoard.CommStarted ||
        xSysD.xReadyQueue->Suc != xSysD.xReadyQueue)
      T = SDL_Now();
    else if (xSysD.xTimerQueue->Suc != xSysD.xTimerQueue)
      T = ((xTimerNode)xSysD.xTimerQueue->Suc)->TimerTime;
    else
      T = xMaxTime;
    Buf = WriteBuf_New(30);
    xGenericWriteSort(Buf, (void *)&T, &ySDL_SDL_Time);
    (void)WriteBuf_Terminate(Buf);
    sprintf(strVar, "%s", WriteBuf_Data(Buf));
    WriteBuf_Del(&Buf);
    if (xSysD.xNoticeBoard.TimeManager == 0) {
      xSysD.xNoticeBoard.TimeManager = PMGetToolPId(IET_TIMEMANAGER);
      if (xSysD.xNoticeBoard.TimeManager == 0) {
        xPrintString("\nNo contact with ITEX.\n");
        xPrintString("Continuing without ITEX communication.\n");
        xSysD.xNoticeBoard.ITEXCommStarted = 0;
        return;
      }
    }
#ifdef XDEBUGPM_NO
    xWriteBuf_Fmt("IETMSCHEDULE:'%s'\n", strVar);
#endif
#ifdef XDEBUGPM_NO2
    printf("IETMSCHEDULE:'%s'\n", strVar);
#endif
    result = PM_RPC(xSysD.xNoticeBoard.TimeManager, IETMSCHEDULE, strVar, &retMess);
    if (result != 0) {
      xPrintString("Error in ITEX communication while scheduling\n");
      return;
    }
    xChangeInputLine(retMess);
    (void)xGenericReadSort((void *)&len, &ySDL_SDL_Integer); /* Status, ignore */
    (void)xGenericReadSort((void *)&xSysD.xSystemTime, &ySDL_SDL_Time);
    (void)xGenericReadSort((void *)&len, &ySDL_SDL_Integer);
    xRestoreInputLine();
#ifdef XDEBUGPM_NO
    xWriteBuf_Fmt("IETMSCHEDULE: In:'%s', Out:'%s'\n", strVar, retMess);
#endif
#ifdef XDEBUGPM_NO2
    printf("IETMSCHEDULE: In:'%s', Out:'%s'\n", strVar, retMess);
#endif
    free(retMess);

    while (len-- > 0) {
      result = PM_RPC(xSysD.xNoticeBoard.TimeManager, IETMGETSIGNAL, 0, &retMess);
#ifdef XDEBUGPM
      xWriteBuf_Fmt("IETMGETSIGNAL: Out:'%s'\n", retMess);
#endif
      if (result != 0) {
        xPrintString("Error in ITEX communication while receiving signals\n");
        return;
      }
      xHandlePMInEnvSig(retMess, 1);
      free(retMess);
    }
  }
#endif
}


/*---+---------------------------------------------------------------
     xGetTargetDirectory
-------------------------------------------------------------------*/
/*
 * Retrieves the target directory from the Organizer.
 * If the target directory cannot be retrieved or is not specified
 * by the user xGetTargetDirectory returns NULL.
 * The target directory always ends with slash ("/") ("\" on PC).
 */
char *xGetTargetDirectory (void)
{
#ifdef XSIMULATORUI
  int   organizer;
  char *reply;
  char  targetDir[256];
  int   statusCode;

  if (XSYSD xNoticeBoard.SimulatorUIStarted) {
    /* Get/Check Organizer PId */
    organizer = PMGetToolPId(SET_ORGANIZER);
    if (organizer) {
      if ( ! PM_RPC(organizer, SEGETDIRECTORY, "0", &reply) &&
           (sscanf(reply, "%d %254s", &statusCode, targetDir) == 2)) {
#ifdef _Windows
        if (targetDir[strlen(targetDir) - 1] != '\\')
          strcat(targetDir, "\\");
#else
        if (targetDir[strlen(targetDir) - 1] != '/')
          strcat(targetDir, "/");
#endif
        if (reply != (char *)0) free(reply);
        reply = (char *)malloc(strlen(targetDir) + 1);
        return strcpy(reply, targetDir);
      }
      if (reply != (char *)0) free(reply);
    }
  }
#endif
  return NULL;
}


/*---+---------------------------------------------------------------
     xGetInstallDirectory
-------------------------------------------------------------------*/
/*
 * Retrieves the SDT install directory from the SDT postmaster.
 * If the target directory cannot be retrieved xGetInstallDirectory
 * returns NULL.
 */
char *xGetInstallDirectory (void)
{
  int   postmaster;
  char *reply;
  char  installDir[256];
  int   statusCode;

  if (XSYSD xNoticeBoard.PMConnected) {
    /* Get Postmaster PId */
    postmaster = PMGetToolPId(SET_POST);
    if (postmaster) {
      if ( ! PM_RPC(postmaster, SEGETINSTALLDIR, "", &reply) &&
           (sscanf(reply, "%d %254s", &statusCode, installDir) == 2)) {
        if (reply != (char *)0) free(reply);
        reply = (char *)malloc(strlen(installDir) + 1);
        return strcpy(reply, installDir);
      }
      if (reply != (char *)0) free(reply);
    }
  }
  return NULL;
}


#ifdef XSIMULATORUI
/*---+---------------------------------------------------------------
     StartSimUI
-------------------------------------------------------------------*/
/* Starts the simulator UI. 
   Returns the PId of the SimUI (or 0 if not successfull).
   Updates xNoticeBoard with the SimUI PId.
*/

int StartSimUI (void)
{
  if ( ! XSYSD xNoticeBoard.PMConnected ) return 0;

  XSYSD xNoticeBoard.SimulatorUIStarted = PMStartSimUI(SET_SIMULATOR_UI);
  return XSYSD xNoticeBoard.SimulatorUIStarted;
}
#endif


#ifdef XMONITOR
/*---+---------------------------------------------------------------
     xConnectToEditor
-------------------------------------------------------------------*/
#define EDITORMENUNAME "\"&Breakpoints\""
int xConnectToEditor (void)
{
  char   mess[1200];
  char * retStr;

  if ( ! XSYSD xNoticeBoard.PMConnected ) {
    return 0;
  }

  if (ConnectedEditor) {
    xPrintString("Editor already connected\n");
    return 0;
  }

  ConnectedEditor = PMStartTool(SET_SDLE);

  if ( ! ConnectedEditor) {
    xPrintString("Editor could not be connected\n");
    return 0;
  }

  PM_RPC(ConnectedEditor, SEMENUDELETE, EDITORMENUNAME, &retStr);
  if (retStr) free(retStr);
  PM_RPC(ConnectedEditor, SEMENUADD, EDITORMENUNAME, &retStr);
  if (retStr) free(retStr);

  sprintf(mess, "%s %s 0 %s 0 0 %d %s 0 %d %s",
          EDITORMENUNAME,
          "\"&Set Breakpoint...\"",
          "\"Set a breakpoint with a command\"",
          1,
          "\"\"",
          SESIMULATORCOMMAND,
          "\"Breakpoint-At %g\"");
  PM_RPC(ConnectedEditor, SEMENUADDITEM, mess, &retStr);
  if (retStr) free(retStr);

  sprintf(mess, "%s %s 0 %s 0 0 %d %s 0 %d %s",
          EDITORMENUNAME,
          "\"Set &Breakpoint\"",
          "\"Set a breakpoint\"",
          1,
          "\"\"",
          SESIMULATORCOMMAND,
          "\"Breakpoint-At %g -\"");
  PM_RPC(ConnectedEditor, SEMENUADDITEM, mess, &retStr);
  if (retStr) free(retStr);

  sprintf(mess, "%s %s 0 %s 0 0 %d %s 0 %d %s",
          EDITORMENUNAME,
          "\"&Remove Breakpoint\"",
          "\"Remove breakpoints at symbol\"",
          1,
          "\"\"",
          SESIMULATORCOMMAND,
          "\"Remove-At %g\"");
  PM_RPC(ConnectedEditor, SEMENUADDITEM, mess, &retStr);
  if (retStr) free(retStr);

  sprintf(mess, "%s %s 0 %s 0 0 %d %s 0 %d %s",
          EDITORMENUNAME,
          "\"S&ave Breakpoints\"",
          "\"Save all breakpoints on a file\"",
          0,
          "\"\"",
          SESIMULATORCOMMAND,
          "\"Save-Breakpoints breakpoints.com\"");
  PM_RPC(ConnectedEditor, SEMENUADDITEM, mess, &retStr);
  if (retStr) free(retStr);

  sprintf(mess, "%s %s 0 %s 0 0 %d %s 0 %d %s",
          EDITORMENUNAME,
          "\"R&estore Breakpoints\"",
          "\"Restore all breakpoints from a file\"",
          0,
          "\"\"",
          SESIMULATORCOMMAND,
          "\"Include-File breakpoints.com\"");
  PM_RPC(ConnectedEditor, SEMENUADDITEM, mess, &retStr);
  if (retStr) free(retStr);

  xUpdateBreakpoints((xbool)1);
  return ConnectedEditor;
}

/*---+---------------------------------------------------------------
     xDisconnectEditor
-------------------------------------------------------------------*/
void xDisconnectEditor(xbool silent)
{
  char * retStr;
  int    lastSimulator;
  int    statusCode;

  if ( ! XSYSD xNoticeBoard.PMConnected ) {
    return;
  }

  if ( ! ConnectedEditor ) {
    if ( ! silent )
      xPrintString("Editor not connected\n");
    return;
  }

  if (PM_RPC(ConnectedEditor, SESDLEBREAKPOINTREF, "0 1", &retStr) ||
      sscanf(retStr, "%d %d", &statusCode, &lastSimulator) != 2 ) {
    xPrintString("\nError sending SESDLEBREAKPOINTREF.\n" );
    lastSimulator = 0;   /* ????? */
  }
  if (retStr) free(retStr);

  if (lastSimulator) {
    PM_RPC(ConnectedEditor, SEMENUDELETE, EDITORMENUNAME, &retStr);
    if (retStr) free(retStr);
  }

  if ( ! silent )
    xPrintString("Editor disconnected\n");
  ConnectedEditor = 0;

  return;
}
#endif


/*******************************************************************
     SDL signal communication via the PostMaster
*******************************************************************/

#if defined(XPMCOMM) || defined(XITEXCOMM) || defined (THREADED_MSCTRACE)

/*---+---------------------------------------------------------------
     xStrEq
-------------------------------------------------------------------*/
static xbool xStrEq(
  char *a,
  char *b )
{
  unsigned int l, i;

  l = strlen(a);
  if ( l != strlen(b) ) return (xbool)0;
  if ( l > 0 ) {
    for ( i=0; i<l; i++ ) {
      if ( xToLower(a[i]) != xToLower(b[i]) )
        return (xbool)0;
    }
  }
  return (xbool)1;
}


/*---+---------------------------------------------------------------
     xEnvFindSignalId
-------------------------------------------------------------------*/
XSIGTYPE xEnvFindSignalId (char  *NameString )
{
  xIdNode  ChanId;
  XSIGTYPE SId;
  int      i = 0;
  int      k;

#ifdef XIDNAMES
  for ( ChanId = xEnvId->ToId[0];
        ChanId != (xIdNode)0; 
        ChanId = xEnvId->ToId[++i] ) {
    k = 0;
    for ( SId = ((xChannelIdNode)ChanId)->SignalSet[0];
          SId != (XSIGTYPE)0;
          SId = ((xChannelIdNode)ChanId)->SignalSet[++k] )
      if (xStrEq(NameString, SId->Name))
        return SId;
  }
#endif
  return (XSIGTYPE)0;
}


#ifdef XITEXCOMM
/*---+---------------------------------------------------------------
     xEnvFindChannelId
-------------------------------------------------------------------*/
xIdNode xEnvFindChannelId (char  *NameString )
{
  xIdNode  ChanId;
  int      i = 0;

#ifdef XIDNAMES
  for ( ChanId = xEnvId->ToId[0];
        ChanId != (xIdNode)0; 
        ChanId = xEnvId->ToId[++i] ) {

    if (xStrEq(NameString, ChanId->Name))
      return ChanId;
  }
#endif
  return (xIdNode)0;
}
#endif



/*---+---------------------------------------------------------------
     xPM_Read_SDL_PId
-------------------------------------------------------------------*/
int xPM_Read_SDL_PId (SDL_PId  * Result)
{
  xxToken Token;
  char    strVar[256];

  Token = xScanToken(strVar);
  if ( Token != xxId ) return 0;
  if ( sscanf(strVar, "%d", &(*Result).GlobalNodeNr) != 1 ) return 0;
  Token = xScanToken(strVar);
  if ( Token != xxId ) return 0;
#ifdef X_XPTRINT_LONG
  if ( sscanf(strVar, "%lu", (xptrint*)&(*Result).LocalPId) != 1 ) return 0;
#else
  if ( sscanf(strVar, "%u", (xptrint*)&(*Result).LocalPId) != 1 ) return 0;
#endif
  return 1;
}



#if defined(XSIGPRIO) || defined(XSIGPRSPRIO) || defined(XPRSSIGPRIO)
/*---+---------------------------------------------------------------
     xPM_Read_Prio
-------------------------------------------------------------------*/
static int xPM_Read_Prio (int  * Result)
{
  xxToken Token;
  char    strVar[256];

  Token = xScanToken(strVar);
  if (Token != xxId) return 0;
  if (!sscanf(strVar, "%d", Result)) return 0;
  return 1;
}
#endif


/*---+---------------------------------------------------------------
     xOutPM 
-------------------------------------------------------------------*/
void xOutPM( xSignalNode *S, xChannelIdNode Channel ) 
{
  xIdNode TmpId;
  WriteBuf *Buf;
  char   *tmpStr;
#ifdef XITEXCOMM
  xbool   toITEX;
  xbool   old_xUse_ASN1_Syntax = XSYSD xUse_ASN1_Syntax;
          /* Only needed if communicating with Itex simulator which
             do not use ASN.1 syntax */
#endif

  if ( ! XSYSD xNoticeBoard.PMConnected ) {
#ifdef XDEBUGPM
    printf("Error in xOutPM: No connection with the Postmaster!\n");
#endif
    xReleaseSignal(S);
    return;
  }

  Buf = WriteBuf_New(60);
#ifdef XITEXCOMM
  if ( xSysD.xNoticeBoard.ITEXCommStarted &&
       ( ! xSysD.xNoticeBoard.CommStarted || InITEXChannelList(Channel) ) )
    toITEX = (xbool)1;
  else
    toITEX = (xbool)0;
  if ( xSysD.xNoticeBoard.ITEXCommStarted && toITEX ) {
    WriteBuf_Add_String(Buf, Channel->Name, 0);
    WriteBuf_Add_String(Buf, " ", 0);
    XSYSD xUse_ASN1_Syntax = (xbool)0; /* Use SDL value notation */
    XSYSD xUse_Itex_Syntax = (xbool)1;
  }
#endif

  WriteBuf_Add_String(Buf, (*S)->NameNode->Name, 0);
  WriteBuf_Add_String(Buf, " ", 0);

  XSYSD xRaW_use_Global_PId = (xbool)1;
  if ( xEq_SDL_PId((*S)->Receiver, xEnv) ) {
    xGenericWriteSort(Buf, (void *)&SDL_NULL, &ySDL_SDL_PId);
  } else {
    xGenericWriteSort(Buf, (void *)&(*S)->Receiver, &ySDL_SDL_PId);
  }

  if ( xEq_SDL_PId((*S)->Sender, xEnv) )
    (*S)->Sender.GlobalNodeNr = xGlobalNodeNumber();
  WriteBuf_Add_String(Buf, " ", 0);
  xGenericWriteSort(Buf, (void *)&(*S)->Sender, &ySDL_SDL_PId);

#if defined(XSIGPRIO) || defined(XSIGPRSPRIO) || defined(XPRSSIGPRIO)
  WriteBuf_Add_Fmt(Buf, 13, " %d", (*S)->Prio);
#endif

  for ( TmpId=(*S)->NameNode->First; TmpId!=(xIdNode)0; TmpId=TmpId->Suc ) {
    if ( TmpId->EC != xSignalParEC ) continue;
    WriteBuf_Add_String(Buf, " ", 0);
    xGenericWriteSort(Buf,
		      (void *)(((xVarIdNode)TmpId)->Offset + (xptrint)(*S)),
		      ((xVarIdNode)TmpId)->TypeNode);
  }
  (void)WriteBuf_Terminate(Buf);
  XSYSD xRaW_use_Global_PId = (xbool)0;

#ifdef XITEXCOMM
  if ( xSysD.xNoticeBoard.ITEXCommStarted && toITEX ) {
    XSYSD xUse_Itex_Syntax = (xbool)0;
    XSYSD xUse_ASN1_Syntax = old_xUse_ASN1_Syntax;
                               /* Set back to old value notation */
    if (xSysD.xNoticeBoard.TimeManager == 0) {
      xSysD.xNoticeBoard.TimeManager = PMGetToolPId(IET_TIMEMANAGER);
      if (xSysD.xNoticeBoard.TimeManager == 0) {
        xPrintString("\nNo contact with ITEX.\n");
        xPrintString("Continuing without ITEX communication.\n");
        xSysD.xNoticeBoard.ITEXCommStarted = 0;
	WriteBuf_Del(&Buf);
        return;
      }
    }
#ifdef XDEBUGPM
    PRINTF2("IETMSENDSIGNAL : '%s'\n", WriteBuf_Data(Buf));
#endif
    if (PM_RPC(xSysD.xNoticeBoard.TimeManager, IETMSENDSIGNAL,
	       WriteBuf_Data(Buf), &tmpStr)) {
#ifdef XDEBUGPM
      printf("String : %s\n", WriteBuf_Data(Buf));
#endif
      xPrintString("Error while sending signal to ITEX.\n");
      xPrintString("Error in connection with ITEX for SDL signal ");
      xPrintString((*S)->NameNode->Name);
      xPrintString("\n");
    }
#ifdef XDEBUGPM
    else {
      printf("xOutPM for ITEX: %s\n", WriteBuf_Data(Buf));
    }
#endif
    free(tmpStr);
 
  } else
#endif
  if ( PMBroadcast(SESDLSIGNAL, WriteBuf_Data(Buf)) ) {
#ifdef XDEBUGPM
    printf("String : %s\n", WriteBuf_Data(Buf));
#endif
    xPrintString("Error while sending signal via the Postmaster.\n");
    xPrintString("Error in connection with the Postmaster for signal ");
    xPrintString((*S)->NameNode->Name);
    xPrintString("\n");
  }
#ifdef XDEBUGPM
  else {
    printf("xOutPM: %s\n", WriteBuf_Data(Buf));
  }
#endif
  xReleaseSignal(S);
  WriteBuf_Del(&Buf);
  return;
}


/*---+---------------------------------------------------------------
     xHandlePMInEnvSig
-------------------------------------------------------------------*/
static void xHandlePMInEnvSig(
  char *PMMessStr, int FromITEX ) 
{
  char        SigName[256];
  char        strVar[MAX_READ_LENGTH];
  xxToken     Token;
  xIdNode     TmpId;
  XSIGTYPE    SId = (XSIGTYPE)0;
  SDL_PId     ReceiverPId;
  SDL_PId     SenderPId;
  xSignalNode S;
  xIdNode     ViaList[2];
#if defined(XSIGPRIO) || defined(XSIGPRSPRIO) || defined(XPRSSIGPRIO)
  int         Prio;
#endif
#ifdef XDEBUGPM
  WriteBuf  *Buf;
#endif

  if ( ! PMMessStr )
    return;

#ifdef XDEBUGPM
  printf("*** PM Communication In: %s\n", PMMessStr);
#endif
  xChangeInputLine(PMMessStr);
  ViaList[0] = 0;

  /* Handle Channel (if ITEX com) */
#ifdef XITEXCOMM
  if (FromITEX) {
    Token = xScanToken(SigName);  /* Skip status */
    Token = xScanToken(SigName);  /* Channel name */
    if (Token != xxId) {
#ifdef XDEBUGPM
      printf( "A Signal from ITEX was discarded!\n");
      printf( "  Channel name not correct\n");
#endif
      xRestoreInputLine();
      return;
    }
    ViaList[0] = xEnvFindChannelId(SigName);
    if ( ViaList[0] == (xIdNode)0 ) {
#ifdef XDEBUGPM
      printf( "A Signal from ITEX was discarded!\n");
      printf( "  Channel: %s; Not recognised by the system.\n", SigName);
#endif
      xRestoreInputLine();
      return;
    }
    ViaList[1] = 0;
#ifdef XDEBUGPM
    printf( "  Channel: %s; OK\n", ViaList[0]->Name);
#endif
  }
#endif

  /* Handle signal */
  Token = xScanToken(SigName);
  if (Token != xxId) {
#ifdef XDEBUGPM
    printf( "A Signal from the Postmaster was discarded!\n");
    printf( "  Signal name not correct\n");
#endif
    xRestoreInputLine();
    return;
  }
  SId = xEnvFindSignalId(SigName);
  if ( SId == (XSIGTYPE)0 ) {
#ifdef XDEBUGPM
    printf( "A Signal from the Postmaster was discarded!\n");
    printf( "  Signal: %s; Not recognised by the system.\n", SigName);
#endif
    xRestoreInputLine();
    return;
  }
#ifdef XDEBUGPM
  printf( "  Signal: %s; OK\n", SId->Name);
#endif

  /* Handle Receiver */
  if (! xPM_Read_SDL_PId(&ReceiverPId)) {
#ifdef XDEBUGPM
    printf( "A Signal from the Postmaster was discarded!\n");
    printf( "  Signal: %s; ReceiverPId not correct\n", SigName);
#endif
    xRestoreInputLine();
    return;
  }
  if ( ReceiverPId.GlobalNodeNr != xGlobalNodeNumber() &&
       ! xEq_SDL_PId_NULL(ReceiverPId) ) {
#ifdef XDEBUGPM
    printf("A Signal from the Postmaster was discarded!\n");
    printf("  Signal: %s; No possible receiver in this system.\n", SigName);
    printf("  Receiver was: ");
    XSYSD xRaW_use_Global_PId = (xbool)1;
    Buf = WriteBuf_New(24);
    xGenericWriteSort(Buf, (void *)&ReceiverPId, &ySDL_SDL_PId);
    (void)WriteBuf_Terminate(Buf);
    printf(WriteBuf_Data(Buf));
    WriteBuf_Del(&Buf);
    XSYSD xRaW_use_Global_PId = (xbool)0;
    printf(";\n");
#endif
    xRestoreInputLine();
    return;
  }
#ifdef XDEBUGPM
  printf("  Receiver: ");
  XSYSD xRaW_use_Global_PId = (xbool)1;
  Buf = WriteBuf_New(24);
  xGenericWriteSort(Buf, (void *)&ReceiverPId, &ySDL_SDL_PId);
  (void)WriteBuf_Terminate(Buf);
  printf(WriteBuf_Data(Buf));
  WriteBuf_Del(&Buf);
  XSYSD xRaW_use_Global_PId = (xbool)0;
  printf("; OK\n");
#endif

  /* Handle Sender */
  if (! xPM_Read_SDL_PId(&SenderPId)) {
#ifdef XDEBUGPM
    printf( "A Signal from the Postmaster was discarded!\n");
    printf( "  Signal: %s; SenderPId not correct\n", SigName);
#endif
    xRestoreInputLine();
    return;
  }
  if ( SenderPId.GlobalNodeNr == xGlobalNodeNumber() ) {
#ifdef XDEBUGPM
    printf( "A Signal from the Postmaster was discarded!\n");
    printf( "  Signal: %s; Just sent FROM this system.\n", SigName);
#endif
    xRestoreInputLine();
    return;
  }
#ifdef XDEBUGPM
  printf( "  Sender: ");
  XSYSD xRaW_use_Global_PId = (xbool)1;
  Buf = WriteBuf_New(24);
  xGenericWriteSort(Buf, (void *)&SenderPId, &ySDL_SDL_PId);
  (void)WriteBuf_Terminate(Buf);
  printf(WriteBuf_Data(Buf));
  WriteBuf_Del(&Buf);
  XSYSD xRaW_use_Global_PId = (xbool)0;
  printf( "; OK\n");
#endif

  if (xEq_SDL_PId_NULL(SenderPId)) SenderPId = xEnv;
#ifndef XOPTCHAN
  if (ReceiverPId.LocalPId == 0) ReceiverPId = xNotDefPId;
#endif

  S = xGetSignal(SId, ReceiverPId, SenderPId);
#ifdef XDEBUGPM
  printf( "  Signal allocated\n");
#endif


#if defined(XSIGPRIO) || defined(XSIGPRSPRIO) || defined(XPRSSIGPRIO)
  if (! xPM_Read_Prio(&Prio)) {
    xRestoreInputLine();
    return;
  }
#endif
  XSYSD xRaW_use_Global_PId = (xbool)1;
  for ( TmpId=SId->First; TmpId!=(xIdNode)0; TmpId=TmpId->Suc ) {
    if ( TmpId->EC != xSignalParEC ) continue;
    Token = xScanToken(strVar);  /* Skip comma */
    if (Token != xxComma) {
      xUngetToken(Token, strVar);
    }
    if ( ! xGenericReadSort((void *)(((xVarIdNode)TmpId)->Offset + (xptrint)S),
                           ((xVarIdNode)TmpId)->TypeNode ) ) {
      xPrintString(
        "\nError in signal parameter while receiving signal from the Postmaster\nSignal ");
      xPrintString(SigName);
      xPrintString(" discarded\n");
      xPrintString("Message was  ");
      xPrintString(PMMessStr);
      xPrintString("\n");
      xReleaseSignal(&S);
      xRestoreInputLine();
      XSYSD xRaW_use_Global_PId = (xbool)0;
      return;
    }
  }
  XSYSD xRaW_use_Global_PId = (xbool)0;
  xRestoreInputLine();

#ifdef XDEBUGPM
  printf( "  Signal parameters read (if any)\n");
#endif

#if defined(XSIGPRIO) || defined(XSIGPRSPRIO) || defined(XPRSSIGPRIO)
  if (ViaList[0] != 0)
    SDL_Output(S, Prio, ViaList);
  else
    SDL_Output(S, Prio, (xIdNode *)0);
#else
  if (ViaList[0] != 0)
    SDL_Output(S, ViaList);
  else
    SDL_Output(S, (xIdNode *)0);
#endif

#ifdef XDEBUGPM
  printf("*** End of PM Communication In\n");
#endif
  return;
}

#endif
       /* XPMCOMM || XITEXCOMM */


#ifdef XSDLENVUI
/*******************************************************************
     Start external UI
*******************************************************************/

/*---+---------------------------------------------------------------
     xInit_UI_sdlenv 
-------------------------------------------------------------------*/
int xInit_UI_sdlenv (void)
{
  if ( !xSysD.xNoticeBoard.PMConnected ) return 0;
  XSYSD xNoticeBoard.UIStarted = PMStartTool(SET_SDLENV);
  return XSYSD xNoticeBoard.UIStarted;
}
#endif
       /* XSDLENVUI */


#ifdef XCOVERAGE
/*---+---------------------------------------------------------------
     xStartCoverageViewer
-------------------------------------------------------------------*/
int xStartCoverageViewer(char *TempFileName)
{
  char *retStr = NULL;

  if ( !xSysD.xNoticeBoard.PMConnected ) return 0;

  if ( !CoveragePID || !PMCheckAlive(CoveragePID) ) {
    /* Start Coverage Viewer */
    CoveragePID = PMStartTool( SET_COVERAGEVIEWER );
    if (CoveragePID == 0) {
      return 0;
    }
  }

  /* Send Open to coverage viewer */
  PM_RPC( CoveragePID, SECOVOPEN, TempFileName, &retStr );
  if (retStr) free(retStr);

  /* Send Mode to coverage viewer */
  PM_RPC( CoveragePID, SECOVMODE, "SYMBOL", &retStr );
  if (retStr) free(retStr);

  /* Send Visibility to coverage viewer */
  PM_RPC( CoveragePID, SECOVVISIBILITY, "0 1", &retStr );
  if (retStr) free(retStr);

  /* Send PopUp to coverage viewer */
  PM_RPC( CoveragePID, SEPOPUP, NULL, &retStr );
  if (retStr) free(retStr);

  return CoveragePID;
}
#endif
       /* XCOVERAGE */


/*---+---------------------------------------------------------------
     MSCFilter2
-------------------------------------------------------------------*/
/*
If str contains quotation mark or backslash returns a copy with
each quotation mark and backslash escaped
*/
static char * MSCFilter2(
  char *str,
  char buffer[MAX_M_WRI_LENGTH])
{
  char *pstr;

  if (strchr(str, '"') == NULL && strchr(str, '\\') == NULL)
    return str;

  pstr = buffer;
  while (*str != '\0') {
    if (*str == '"')
      *(pstr++) = '\\';
    else if (*str == '\\')
      *(pstr++) = '\\';
    *(pstr++) = *(str++);
  }
  *pstr = '\0';
  return buffer;
}


/*---+---------------------------------------------------------------
     MSCFilter3
-------------------------------------------------------------------*/
/* Escape each quotation mark and backslash */
static void MSCFilter3(WriteBuf *Buf)
{
  char *tmp;
  int pos, Apost;
  unsigned int new_length;

  tmp = WriteBuf_Data(Buf);
  pos = 0; Apost = 0;
  for (pos=0; pos<WriteBuf_Length(Buf); pos++) {
    if (tmp[pos] == '"' || tmp[pos] == '\\')
      Apost++;
  }
  if (Apost == 0)
    return;

  WriteBuf_Secure(Buf, Apost);
  new_length = WriteBuf_Length(Buf) + Apost;
  for (pos=WriteBuf_Length(Buf)-1; pos>=0 && Apost>0; pos--) {
    WriteBuf_Data(Buf)[pos+Apost] = WriteBuf_Data(Buf)[pos];
    if (WriteBuf_Data(Buf)[pos] == '"' || WriteBuf_Data(Buf)[pos] == '\\') {
      Apost--;
      WriteBuf_Data(Buf)[pos+Apost] = '\\';
    }
  }
  WriteBuf_Set_Length(Buf, new_length);
}


/*---+---------------------------------------------------------------
     xInitGRConversion
-------------------------------------------------------------------*/
void xInitGRConversion (void)
{
  char *fromStr;
  char *toStr;

  fromStr = getenv("SDTGRCONVFROMDIR");
  if (fromStr && fromStr[0] != '\0') {
    toStr = getenv("SDTGRCONVTODIR");
    if (toStr) {
      xGRConvFrom = (char *)xAlloc(strlen(fromStr) + 1);
      strcpy(xGRConvFrom, fromStr);
      xGRConvTo = (char *)xAlloc(strlen(toStr) + 1);
      strcpy(xGRConvTo, toStr);
    }
  }
}

/*---+---------------------------------------------------------------
     xSetGRConversion
-------------------------------------------------------------------*/
void xSetGRConversion(xbool doSet, char *fromStr, char *toStr)
{
  if (doSet) {
    if (xGRConvFrom)
      xFree((void **)&xGRConvFrom);
    xGRConvFrom = fromStr;
    if (xGRConvTo)
      xFree((void **)&xGRConvTo);
    xGRConvTo = toStr;
    if (xGRConvFrom[0] == '\0') {
      xFree((void **)&xGRConvFrom);
      xFree((void **)&xGRConvTo);
      PRINTF("Removed conversion\n");
    }
  }

  if (xGRConvFrom && xGRConvTo) {
    PRINTF3("\"%s\" = \"%s\"\n", xGRConvFrom, xGRConvTo);
  }
  else {
    PRINTF("No conversion\n");
  }
}

/*---+---------------------------------------------------------------
     xGRConversion
-------------------------------------------------------------------*/
/*
If GR-Conversion is on replace xGRConvFrom with xGRConvTo in str.
If reverse replace xGRConvTo with xGRConvFrom.
*/
char *xGRConversion(xbool reverse, char *str, char *buffer)
{
  char *pos1;
  char *fromStr;
  char *toStr;

  if (xGRConvFrom == (char *)0)
    return str;

  if (reverse) {
    fromStr = xGRConvTo;
    toStr = xGRConvFrom;
  }
  else {
    fromStr = xGRConvFrom;
    toStr = xGRConvTo;
  }
  pos1 = strstr(str, fromStr);
  if ( ! pos1 )
    return str;

  strncpy(buffer, str, pos1 - str);
  strcpy(buffer + (pos1 - str), toStr);
  strcat(buffer, pos1 + strlen(fromStr));
  return buffer;
}


/*******************************************************************
     Show SDT references
*******************************************************************/

/*---+---------------------------------------------------------------
     xGRTraceSymbol
-------------------------------------------------------------------*/
void xGRTraceSymbol (char *ConfPos)
{
  int organizer;
  char mess[MAX_M_WRI_LENGTH];
  char * reply;
  char   buffer[MAX_M_WRI_LENGTH];
  int  rv;
#ifdef DEBUG
  char *Pos1;
  char *Pos2;
#endif
  char  buffer2[2 * 256];
  static int messageShowed = 0;

  if (ConfPos == (char *)0 || strlen(ConfPos) < (unsigned)2)
    return;

  if (xSysD.xNoticeBoard.PMConnected) {
    /* Get/Check Organizer PId */
    organizer = PMGetToolPId(SET_ORGANIZER);
    if (organizer == 0) return;

    ConfPos = xGRConversion((xbool)0, ConfPos, buffer2);
    /* Send trace */
    sprintf(mess, "\"%s\" 0", MSCFilter2(ConfPos, buffer));
    rv = PM_RPC(organizer, SESHOWREF, mess, &reply);
    if (reply != (char *)0) free(reply);
#ifdef DEBUG
    if (rv) {
      strcpy(buffer, ConfPos);
      Pos1 = strchr(buffer, '/');
      if (Pos1 == NULL) {
        Pos1 = strchr(buffer, '\\');
        if (Pos1) {
          if (*(Pos1 - 1) == ':') { /* Windows drive */
            Pos1--;
            Pos1--;
          }
        }
      }
      if (Pos1) {
        Pos2 = strrchr(ConfPos, '/');
        if (Pos2 == NULL) 
          Pos2 = strrchr(ConfPos, '\\');
        strcpy(Pos1, Pos2 + 1);
        PRINTF3("TRYING %s instead of %s\n", buffer, ConfPos);
        sprintf(mess, "\"%s\" 0", buffer);
        rv = PM_RPC(organizer, SESHOWREF, mess, &reply);
        if (reply != (char *)0) free(reply);
      }
    }
#endif
    if (rv && ! messageShowed) {
      PRINTF2("Could not show %s.\nThis message is only given once.\n",
              ConfPos);
      messageShowed = 1;
    }
  }
}


#ifdef XMONITOR
/*---+---------------------------------------------------------------
     xUpdateBreakpoints
-------------------------------------------------------------------*/
void xUpdateBreakpoints(xbool silent)
{
  char              mess[MAX_M_WRI_LENGTH];
  char             *strP = mess;
  int               count = 0;
  char              buffer[MAX_M_WRI_LENGTH];
  xAtBreakpointNode BP;
  char             *reply;
  char             *gRReference;
  char              buffer2[2 * 256];

  if ( ! xSysD.xNoticeBoard.PMConnected )
    return;

  if ( ! ConnectedEditor ) {
    if ( ! silent )
      xPrintString("Editor not connected\n");
    return;
  }

  if (xSysD.AtBreakpoints == (xAtBreakpointNode)0) {
    PM_RPC(ConnectedEditor, SESDLEBREAKPOINTREF, "0 0", &reply);
    if (reply != (char *)0) free(reply);
    if ( ! silent )
      xPrintString("No graphical breakpoint defined\n");
    return;
  }

  for ( BP = xSysD.AtBreakpoints; BP; BP = BP->Next ) {
    count++;
  }
  sprintf(strP, "%d", count);
  while (*strP) strP++;
  for ( BP = xSysD.AtBreakpoints; BP; BP = BP->Next ) {
    gRReference = xGRConversion((xbool)0, BP->GRReference, buffer2);
    sprintf(strP, " \"%s\"", MSCFilter2(gRReference, buffer));
    while (*strP) strP++;
  }
  sprintf(strP, " 0");
  PM_RPC(ConnectedEditor, SESDLEBREAKPOINTREF, mess, &reply);
  if (reply != (char *)0) free(reply);
}
#endif


#if defined (XMSCE) || defined (THREADED_MSCTRACE)
/*******************************************************************
     MSC trace
*******************************************************************/

/*---+---------------------------------------------------------------
     xStartMSC
-------------------------------------------------------------------*/
xbool xStartMSC (void)
{
  char * reply;
  char   mess[256];
  int    statusCode;

  if (xSysD.MSCLogStarted) {
    if (xSysD.xNoticeBoard.MSCEStarted) {
      (void)PM_RPC( xSysD.xNoticeBoard.MSCEStarted, SEPOPUP, NULL, &reply );
      if (reply) free(reply);
    }
    return (xbool)1;
  }

  if (xSysD.xNoticeBoard.MSCEStarted == 0 ||
      !PMCheckAlive(xSysD.xNoticeBoard.MSCEStarted)) {
    xSysD.xNoticeBoard.MSCEStarted = PMGetToolPId(SET_MSCE);
    if (xSysD.xNoticeBoard.MSCEStarted == 0) {
      xSysD.xNoticeBoard.MSCEStarted = PMStartTool(SET_MSCE);
      xSysD.xNoticeBoard.MSCDiagram = 0;
      if (xSysD.xNoticeBoard.MSCEStarted == 0) {
        xPrintString("\nCould not start MSC editor.\n" );
        return (xbool)0;
      }
    }
  }

  /* Get/Check diagram and buffer */
  sprintf(mess, "%d SimulatorTrace \"\"", MSCDIAGRAM);
  if ( PM_RPC(xSysD.xNoticeBoard.MSCEStarted, SEMSCECREATEDIAGRAM,
             mess, &reply) ||
       sscanf(reply, "%d %d",
              &statusCode, &xSysD.xNoticeBoard.MSCDiagram) != 2 ) {
    xPrintString("\nCould not create an MSC diagram.\n" );
    if (reply != (char *)0) free(reply);
    xSysD.xNoticeBoard.MSCEStarted = 0;
    return (xbool)0;
  }
  if (reply != (char *)0) free(reply);

  /* Show diagram */
  sprintf(mess, "%d \"\"", xSysD.xNoticeBoard.MSCDiagram);
  (void)PM_RPC(xSysD.xNoticeBoard.MSCEStarted, SESHOW, mess, &reply);
  if (reply != (char *)0) free(reply);

  return (xbool)1;
}


/*---+---------------------------------------------------------------
     xMPrintString
-------------------------------------------------------------------*/
void xMPrintString (char * Str)
{
  char * returnMess;
  char   mess[256];
  int    ObjId, dummy;

  static WriteBuf *buf = 0;
  static WriteBuf *buf2 = 0;
  static int SDTMSCTRACENOPOPUP = 737;

  if (SDTMSCTRACENOPOPUP == 737) {
    if (getenv("SDTMSCTRACEPOPUP"))
      SDTMSCTRACENOPOPUP = 0;
    else
      SDTMSCTRACENOPOPUP = 1;
  }
  if ( ! buf )
    buf = WriteBuf_New(200);
  else
    WriteBuf_Clear(buf);
  if ( ! buf2 )
    buf2 = WriteBuf_New(200);
  else
    WriteBuf_Clear(buf2);

  returnMess = (char *)0;
  WriteBuf_Add_String(buf2, Str, 0);
  MSCFilter3(buf2);
  xAddBuf_Fmt(buf, "%d 0 \"", xSysD.xNoticeBoard.MSCDiagram);
  WriteBuf_Add_WriteBuf(buf, buf2);
  WriteBuf_Add_Char(buf, '"');
  WriteBuf_Terminate(buf);
  if ( PM_RPC(xSysD.xNoticeBoard.MSCEStarted, SEINSERTOBJECT,
                WriteBuf_Data(buf), &returnMess) ) {
    xPrintString("Error while drawing MSC event\n");
    if (returnMess != (char *)0) free(returnMess);
    return;
  }
#ifdef THREADED_MSCTRACE
  if(startup_msc) {
#endif /* THREADED_MSCTRACE */
  if (sscanf(returnMess, "%d %d", &dummy, &ObjId) != 2)
    ObjId = -1; 
  if (returnMess != (char *)0) free(returnMess);

  if (ObjId == -1) return;
  if (SDTMSCTRACENOPOPUP)
    sprintf(mess, "%d %d 0 0", xSysD.xNoticeBoard.MSCDiagram, ObjId);
  else
    sprintf(mess, "%d %d", xSysD.xNoticeBoard.MSCDiagram, ObjId);
  if ( PM_RPC(xSysD.xNoticeBoard.MSCEStarted, SESHOWOBJECT,
                mess, &returnMess) ) {
    xPrintString("Error while showing MSC event\n");
    if (returnMess != (char *)0) free(returnMess);
    return;
  }
  if (returnMess != (char *)0) free(returnMess);
#ifdef THREADED_MSCTRACE
  }
#endif /* THREADED_MSCTRACE */
}


#endif
       /* XMSCE */


#ifdef XSIMULATORUI

/*---+---------------------------------------------------------------
     xSendPrintString
-------------------------------------------------------------------*/
void xSendPrintString (char * Str)
{
  char * retStr;

  PM_RPC(xSysD.xNoticeBoard.SimulatorUIStarted, SESIMUISTRING, Str, &retStr);
  if (retStr) free(retStr);
}

/*---+---------------------------------------------------------------
     xSendCommandReply
-------------------------------------------------------------------*/
void xSendCommandReply (void)
{
  PMSend(xSysD.xNoticeBoard.SimulatorUIStarted, SESIMUICOMMANDREPLY, "0");
}

/*---+---------------------------------------------------------------
     xSendUIChange
-------------------------------------------------------------------*/
void xSendUIChange (void)
{
  char * retStr;

  PM_RPC(xSysD.xNoticeBoard.SimulatorUIStarted, SESIMUICHANGE, "0",
         &retStr);
  if (retStr) free(retStr);
}

/*---+---------------------------------------------------------------
     xLoopForMessage
-------------------------------------------------------------------*/
void xLoopForMessage (void)
{
  int sender, messtype, len, result;
  void * data=NULL;

#ifdef TARGETSIM
  while (1) {
    if ( XSYSD xNoticeBoard.MyPID == (int)SPERROR &&
         XSYSD xNoticeBoard.TargetParam > 0)
      XSYSD xNoticeBoard.MyPID = SPInit(SET_SIMULATOR, (char *)0, NULL);
    if ( XSYSD xNoticeBoard.MyPID == (int)SPERROR)
      continue;
#endif
  result = PMQueueRead(-1, &sender, &messtype, &data, &len);
  while (result == SPOK) {
    xHandleAllPMSigs(sender, messtype, data, len);
    if (data) {
      free(data);
      data = NULL;
    }
    if (xSysD.SESIMUICOMFlag) return;
    result = PMQueueRead(-1, &sender, &messtype, &data, &len);
  }
#ifdef TARGETSIM
  }
#else
  if ( result==SPERROR && 
       (GetSPerrno()==SPNOCHANNEL || GetSPerrno()==SPNOSESSION) ) {
    if (XSYSD xNoticeBoard.StartedFromPostmaster) {
      SDL_Halt();
    } else {
      xPrintString("\nLost contact with the Postmaster. Running stand alone.\n");
      XSYSD xNoticeBoard.PMConnected = (xbool)0;
    }
  }
#endif
}
#endif
       /* XSIMULATORUI */

#endif
       /* XCONNECTPM */

