/****************************************************************************
**
**  Name:  event.c
**
**  Description:
**       Routines to support the event definition management.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_68k/trace/event.c_v  $
** 
**    Rev 1.3   06 May 1998 16:22:36   Gene
** remove edma- initial setting for LC302
** 
**    Rev 1.2   23 Mar 1998 17:24:22   gene
** added LC302
** 
**    Rev 1.1   18 Mar 1997 09:04:58   gene
** 
**    Rev 1.0   13 Feb 1997 09:07:12   gene
** Initial revision.
** 
**    Rev 1.4   21 Jun 1996 14:48:04   kevin
** defined hLib
** 
**    Rev 1.3   18 Jun 1996 13:58:38   kevin
** In 302 case, set edma- high for all events.
** 
**    Rev 1.2   13 Jun 1996 16:28:16   kevin
** set edma- event to high while open event
** 
**    Rev 1.1   27 Dec 1995 15:37:52   kevin
** modified EvtSetActiveEvent() to limit the max number of events to 8
** 
**    Rev 1.0   07 Sep 1995 11:22:10   gene
** Initial revision.
** 
**    Rev 1.45   05 May 1994 15:45:56   dennis
** Fixes problem with event address mask field. ppr 9110 and 8867. Treat
** address mask field as a hex value, not an address value.
** 
**    Rev 1.44   22 Apr 1994 15:18:52   marilyn
** Removed confirmation dialog from EvtDeleteAllEvents.
** 
**    Rev 1.43   27 Jul 1993 14:36:08   john
** Modified calls to TmpltGetValueText to match new interface
** 
**    Rev 1.42   13 Jul 1993 19:07:02   doug
** Move errors to errtext/mkerrors.h and use generic syntax error
** 
**    Rev 1.41   28 Jun 1993 09:33:12   ron
** changed MessageBox to ErrMessageBox, in order to get help button
** 
**    Rev 1.40   15 Jun 1993 15:00:06   john
** Restoring events now causes the trigger logic to be updated if a 
** restored event matches (name wise) an event programmed as a trigger.
** 
**    Rev 1.39   07 Apr 1993 17:23:54   mindy
** passing pointer to XILINX_GROUP to speed things up.
** 
**    Rev 1.38   14 Jan 1993 16:09:22   john
** switched file from unix format to dos format (LF->CRLF)
** 
**    Rev 1.37   14 Jan 1993 06:19:22   doug
** Fixed UAE
** 
**    Rev 1.36   05 Jan 1993 15:19:16   courtney
** Removed MemAlloc and related macros (no longer used).
** 
**    Rev 1.35   09 Dec 1992 14:39:16   john
** The event server would allow address ranges to be set with the end
** address smaller than the start address.  The server now prevents this
** from happening.  This makes switching from length->range mode a
** little clunkier when the length is a number smaller than the start addr.
** 
**    Rev 1.34   25 Oct 1992 11:24:12   mindy
** valid active event check was erroring out when there wasn't a problem
** so I changed the test condition one more time!
** 
**    Rev 1.33   21 Oct 1992 16:39:38   mindy
** a) cleaned up all the warnings.
** b) removed delete all event routines and cli counterpart.
** c) activeEvent checked against numEvents now
** d) fixed pprs 6264 and 6625 - how start/end amd mask interact.
** 
**    Rev 1.32   30 Sep 1992 08:33:10   mindy
** if mask is blank just return
** 
**    Rev 1.31   30 Sep 1992 07:47:50   mindy
** If we can't create a new event then I don't want to affect the currently
** active event.
** 
**    Rev 1.30   16 Sep 1992 18:49:20   mindy
** use sdn calls instead of sd
** 
**    Rev 1.29   16 Sep 1992 09:32:08   mindy
** check error condition from checkEventId
** 
**    Rev 1.28   09 Sep 1992 09:52:14   mindy
** added close routines needed
** 
**    Rev 1.27   08 Sep 1992 15:59:18   mindy
** changes unknown (john)
** 
**    Rev 1.26   31 Aug 1992 08:24:54   mindy
** cleaned some of the many warnings
** 
**    Rev 1.25   29 Aug 1992 08:57:30   doug
** use emulation status variables in sd probe, removed from breakpoint
** 
**    Rev 1.24   14 Aug 1992 08:40:00   mindy
** cli interface broken with new start vs startmask stuff
** 
**    Rev 1.23   11 Aug 1992 09:51:00   mindy
** made ReadNUmber public
** 
**    Rev 1.22   10 Aug 1992 08:02:48   mindy
** replaced initCServer routine for tom's new server registration
** 
**    Rev 1.21   10 Aug 1992 05:48:36   mindy
** working on fixing bugs in save/restore
** 
**    Rev 1.20   06 Aug 1992 07:27:32   mindy
** Changed the way text strings are used in events.  Really only need to
** save the text of the template field for the address field since it's
** the only field that supports symbols.  Also by redoing it this way
** I can handle the saving and restoring of addresses when the end length
** function is in use.
** 
**    Rev 1.19   03 Aug 1992 06:23:06   mindy
** Added end value function support.  Ending value can either be the ending
** address or an ending address offset.
** 
**    Rev 1.18   10 Jul 1992 13:10:42   mindy
** Removing the trace depedency to see if bc3.1 works - no luck!
** 
**    Rev 1.17   10 Jul 1992 09:00:14   mindy
** added include file(s) needed to get rid of 3.1 warnings
** 
**    Rev 1.16   25 Jun 1992 13:35:04   jim
** bxgetemulationstatus changed names too!!!
** 
**    Rev 1.15   25 Jun 1992 13:24:00   jim
** bkptexec split into bkroot.h and bkptexec.h!
** 
**    Rev 1.14   15 Jun 1992 09:58:00   mindy
** a) All routines that modify an event first check to see if event can be
**    changed.  Tracing must be off and sequencer disabled if event is used
**    in the active trigger setup.
** b) Added mask get and set routines.
** b) added StartAndMask get and set routines ( this is the old set start
**    routine - these routines should be called for VALUE fields). The 
**    set and get Start should be called for RANGE fields (i.e.: addr and data).
** d) Setting start affected end and mask if either haven't been explicitedly
**    set.  End affects start and mask if either is not explicitedly set.
** e) setting start and end use address text conversion routines instead of
**    using local routine - this allows symbolic support.
** f) When events are saved we save the event's text and value.  This will allow
**    us to restore symbolics.  When events are restored the text is run through
**    the address conversion routine to get the values. (more symbolic support
**    stuff).
** g) Save and restore changed to be in ASCII and also to support symbolic 
**    events.
** 
**    Rev 1.13   14 May 1992 11:38:10   mindy
** removed GetErrorText routine and added ErrInitDLL call
** 
**    Rev 1.12   13 May 1992 08:11:00   mindy
** added get error text routine
** 
**    Rev 1.11   23 Apr 1992 11:07:14   mindy
** a) changed memory allocation to use TMalloc - not GlobalAlloc
** b) changed cli commands to use eventId - a local copy of id created
**    by eventOpen from cli.
** c) added keyword support to cli commands since cli server can't do it
**    globally.
** 
**    Rev 1.10   27 Feb 1992 11:29:32   mindy
** when using just start values(not ranges) end must match start
** 
**    Rev 1.9   23 Jan 1992 14:01:44   ernie
** Moved where emon was being automatically set.  Now we set it whenever
** a new event is created this allows the presenter to see emon being
** set so the user can change it (i.e.: hw types would want to do this)
** 
**    Rev 1.8   17 Jan 1992 11:20:24   courtney
** Revised LibMain return type.
** 
**    Rev 1.7   07 Jan 1992 10:34:12   ernie
** a) use BOOLEAN not BOOL
** b) when no end value given we need to set the end to the start not the
**    end mask value.
** c) bit emon bit so we don't trigger if data appears before going into
**    emulation.
** 
**    Rev 1.6   11 Dec 1991 14:52:14   mindy
** Moved in a local copy of LibMain since event server is in its own
** dll now.
** 
**    Rev 1.5   06 Dec 1991 10:33:48   mindy
** moved common prototypes into local.h
** 
**    Rev 1.4   02 Dec 1991 10:58:04   mindy
** a) use global errors for mem lock and alloc errors
** b) indexes for cli commands off - added two trace cli commands.
** c) when only a start is given need to set end == start.
** 
**    Rev 1.3   20 Nov 1991 10:56:46   mindy
** a) Changed the way mask were handled.  Before I had a start and an end mask
** value but there wasn't a good way to handle making sure they matched - and
** what to do if the masks didn't match (also when to catch this mismatch!).
** So now there's just one mask - and the last value entered (either start or
** end) determines the final mask.  This approach is rather awkward because of
** how the event presenter linearily updates the event server.  The end values
** are always the last ones sent.  The other approach was to always use the 
** largest mask but that would restrict shortening up a mask!  Obviously that
** is subject to change.
** b) cli indexes changed because trace search commands were added.
** 
**    Rev 1.2   15 Nov 1991 15:07:36   mindy
** a) changed error numbers
** b) added cli command routines
** c) fixed bug in convert LPSTR routine
** d) fixed bug in FigureMask.. routine
** 
**    Rev 1.1   07 Nov 1991 14:34:02   mindy
** fixed a bug in the text conversion routine
** 
**    Rev 1.0   01 Nov 1991 09:21:36   mindy
** Initial revision.
** 
**  $Header:   S:/tbird/mt2_68k/trace/event.c_v   1.3   06 May 1998 16:22:36   Gene  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#include "ctype.h"
#include "stdlib.h"
#ifndef __STRING_H
#include <string.h>
#endif
#ifndef _BASEWIND_
#include "basewind.h"
#endif
#ifndef _EVENT_
#include "event.h"
#endif
#ifndef _EVTTMPLT_
#include "evttmplt.h"
#endif
#ifndef _ADDR_
#include "addr.h"
#endif
#ifndef _CLISRV_
#include "clisrv.h"
#endif
#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif
#ifndef _LOCAL_
#include "local.h"
#endif
#ifndef _SDPROBE_
#include "sdprobe.h"
#endif
#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif
#ifndef _TRACE_
#include "trace.h"
#endif
#ifndef _TRIG_
#include "trig.h"
#endif
#ifndef _PROC_
#include "proc.h"
#endif
#ifndef _BKROOT_
#include "bkroot.h"
#endif
#ifndef _HLPENTRY_
#include "hlpentry.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

#define MAX_VALUE_STR   16
#define MAX_EVENTS 64

#define CheckValidEvent() \
  if( !numEvents || (event->activeEvent >= MAX_EVENTS) ) \
     return(ER_NO_ACTIVE_EVENT) 


#define MAX_NAME_LENGTH 63
typedef struct {
   S8 eventName[MAX_NAME_LENGTH+1];
   END_FUNC endAddrFunction;
   LPSTR addrStartText;
   LPSTR addrEndText;
   BOOLEAN startChanged[NUM_GROUPS];
   BOOLEAN endChanged[NUM_GROUPS];
   BOOLEAN maskChanged[NUM_GROUPS];
   BOOLEAN not[NUM_GROUPS];
   XILINX_GROUP start;
   XILINX_GROUP end;
   XILINX_GROUP mask;
} EVENT_DEF;

typedef struct {
   DESCRIPTOR templateId;           /* id of template to use */   
   LOOP_VAR nextEventPtr;           /* index to start sending next event */
   LOOP_VAR activeEvent;            /* index into eventList of active event.
                                       an Index >= MAX_EVENTS means there's
                                       no active event. */
   XILINX_NUMBER activeGroup;       /* which xilinx group does currently
                                       selected template field belong */
   FIELD_TYPE activeType;           /* Keep track of active field type to
                                       save time calling template server */
} EVENT;

typedef struct {
   U32 lo;
   U32 hi;
   U32 mask;
   U8  not;
} SD_EVENT;

                        /****************************
                         *                          *
                         *    EXTERNAL VARIABLES    *
                         *                          *
                         ****************************/


                        /****************************
                         *                          *
                         *     LOCAL STORAGE        *
                         *                          *
                         ****************************/

static HANDLE cliServerHandle = 0;       /* return address for CLI results */
static U16 numEvents;                   /* number of events defined */
static EVENT_DEF eventList[MAX_EVENTS]; /* list of event names and values */
HANDLE hLib;

                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/
RETCODE AllocateAndReadString(int hFile, LPSTR *str);
RETCODE CheckEntryConditions(DESCRIPTOR id);
RETCODE CreateNewEvent(LPSTR eventName, LOOP_VAR FAR *index);
VOID    ClearEvent(LOOP_VAR event);
RETCODE ConvTextToU32AndMask(LPSTR data,U32 *value,U32 *mask,
                             DISPLAY_FORMAT format);
RETCODE ConvTextToU32(LPSTR data, U32 *value, BOOLEAN symbolsOK);
BOOLEAN EventExists(LPSTR eventName, LOOP_VAR FAR *index);
RETCODE FigureMaskedValueString(LPSTR value,LPSTR mask,LPSTR results,
           U16 maxLen);
VOID    FreeEventText(LOOP_VAR idx);
RETCODE HandleTextString(EVENT FAR *evt, LPSTR text, BOOLEAN doStart);
RETCODE ReadBoolean(int hFile, BOOLEAN *val);
RETCODE ReadString(int hFile, LPSTR str, int maxLen);
BOOLEAN StringBlank(LPSTR str);
RETCODE TextualizeValue(EVENT FAR *event, XILINX_GROUP FAR *bits, 
                         BOOLEAN valChanged, LPSTR text, U16 maxLen);

/* Routine added by Dennis Lamb. Routine calls TmpltGetMaskValueText */
/* instead of TmpltGetValueText. This fixes the problem where the    */
/* mask field for the address was putting in "FFFFFF cpu" instead of */
/* "0xFFFFFF". This is because the mask was treated just like an     */
/* address. See other comments in the code below. May 5, 1994        */
RETCODE TextualizeMaskValue(EVENT FAR *event, XILINX_GROUP FAR *bits, 
                         BOOLEAN valChanged, LPSTR text, U16 maxLen);

RETCODE WriteBlanks(int hFile, int numOf);
RETCODE WriteLong(int hFile, U32 num);
RETCODE WriteNewLine(int hFile);
RETCODE WriteNumber(int hFile, int num);
RETCODE WriteString(int hFile, LPSTR str);

                        /****************************
                         *                          *
                         *      EXECUTABLE CODE     *
                         *                          *
                         ****************************/

#pragma argsused
int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD cbHeapSize,
    LPSTR lpszCmdLine) {
   LOOP_VAR i;

   hLib = hInstance;
   numEvents = 0;
   for(i=0; i<MAX_EVENTS; i++) eventList[i].eventName[0] = '\0';
   ErrInitDLL(MODULE_EVENT,"event.dll");
   /* initialize successfully */
    return(TRUE);
}

/**************************************************************************
**
** InitCServer
**
***************************************************************************/
RETCODE EXPORT InitCServer(HANDLE cliHandle, HANDLE dllHandle) {
   CSERVER_NEW_REGISTRATION FAR * msgBufPtr;
   cliServerHandle = cliHandle;
   msgBufPtr = (CSERVER_NEW_REGISTRATION FAR *)
               TMalloc(sizeof(CSERVER_VARIABLE_VALUE));
   if (msgBufPtr == NULL) return(ER_OUT_OF_MEMORY);
   msgBufPtr->stringResourceHandle = dllHandle;
   msgBufPtr->serverNameIndex = 30;
   msgBufPtr->dllNameIndex = 31;
   msgBufPtr->numberOfCommandsIndex = 32;
   msgBufPtr->commandStartIndex = 33;
   SendMessage(cliHandle, CLI_NEW_SVR_REGISTRATION, CLI_NEW_SVR_REGISTRATION,
      (DWORD)msgBufPtr);
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtOpenEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtOpenEvent(DESCRIPTOR FAR *id, LPSTR templateName) {
   EVENT FAR *event;
   RETCODE err;

   if((*id=(DESCRIPTOR)TMalloc(sizeof(EVENT)))==NULL)
      return(ER_OUT_OF_MEMORY);
   event = (EVENT FAR*)*id;
   if( (err=TmpltOpenTemplate(&event->templateId)) != GOOD ) return(err);
   if( (err=TmpltSetTemplateName(event->templateId, templateName)) != GOOD ) 
      return(err);
   event->nextEventPtr = MAX_EVENTS;
   event->activeEvent = MAX_EVENTS;
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtCloseEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtCloseEvent(DESCRIPTOR id) {
   RETCODE err;
   if( (err=TmpltTemplateClose(((EVENT FAR *)id)->templateId)) != GOOD ) 
      return(err);
   TFree((LPSTR)id);
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtRestoreEvents
** 
*****************************************************************************/
RETCODE EXPORT EvtRestoreEvents(LPSTR fileName) {
   int hFile;
   U32 tmpInt;
   U16 numOf;
   S8 name[MAX_NAME_LENGTH+1];
   LOOP_VAR idx, grp, eventIdx;
   RETCODE err;
   BOOLEAN trigFound;   /* don't really care what the value of this is */
   if (fileName && (lstrlen(fileName) > 0)) {
      if((hFile = _lopen(fileName,OF_READ)) == -1) return(ER_CANT_OPEN_FILE);
      if((err=ReadNumber(hFile, &tmpInt))!=GOOD) return(err);
      numOf = (U16)tmpInt;
      for( idx = 0; idx < numOf; idx++ ) {
         EVENT_DEF *evt;
         if((err=ReadString(hFile, name, MAX_NAME_LENGTH))!=GOOD) return(err);
         if( !EventExists(name,&eventIdx) ) {
            RETCODE err;
            if( (err=CreateNewEvent(name,&eventIdx)) != GOOD ) 
               return(err);
            numEvents++;
         }
         evt = &eventList[eventIdx];
         if((err=ReadNumber(hFile, &tmpInt))!=GOOD) return(err);
         evt->endAddrFunction = (END_FUNC)tmpInt;
         if((err=AllocateAndReadString(hFile, &evt->addrStartText))!=GOOD)
            return(err);
         if((err=AllocateAndReadString(hFile, &evt->addrEndText))!=GOOD)
            return(err);

         for( grp = 0; grp < NUM_GROUPS; grp++ ) {
            if((err=ReadBoolean(hFile, &evt->not[grp]))!=GOOD) return(err);
            if((err=ReadNumber(hFile, &evt->start.xilinxGroup[grp]))!=GOOD) 
               return(err);
            if((err=ReadBoolean(hFile, &evt->startChanged[grp]))!=GOOD) 
               return(err);
            if((err=ReadNumber(hFile, &evt->end.xilinxGroup[grp]))!=GOOD) 
               return(err);
            if((err=ReadBoolean(hFile, &evt->endChanged[grp]))!=GOOD) 
               return(err);
            if((err=ReadNumber(hFile, &evt->mask.xilinxGroup[grp]))!=GOOD) 
               return(err);
            if((err=ReadBoolean(hFile, &evt->maskChanged[grp]))!=GOOD) 
               return(err);
         }
         /* we need to convert text strings for start and end 
            address to actual values.  This assigns values to symbolics.
          */
      {
         DESCRIPTOR id;
         U32 start,end;
         if((err=TmpltOpenTemplate(&id)) != GOOD ) return(err);
         if((err=TmpltSetFieldName(id,"address"))!=GOOD) return(err);
         if( evt->addrStartText ) {  
            if((err=ConvTextToU32(evt->addrStartText,&start,TRUE))!=GOOD) 
               return(err);
            if((err=TmpltSetValue(id,&evt->start,start))!=GOOD ) return(err);
            if( !evt->addrEndText ) {
               if((err=TmpltSetValue(id,&evt->end,start))!=GOOD ) return(err);
            }
         }
         if( evt->addrEndText ) {  
            /* !!! check for ".." here */
            if((err=ConvTextToU32(evt->addrEndText,&end,TRUE))!=GOOD) 
               return(err);
            if( evt->endAddrFunction == END_LEN_FUNC ) {
               if( !evt->addrStartText ) return(ER_STRESSED_OUT_SRVR);
               end += start;
            }
            if((err=TmpltSetValue(id,&evt->end,end))!=GOOD ) return(err);
            if( !evt->addrStartText ) {
               if((err=TmpltSetValue(id,&evt->start,end))!=GOOD ) return(err);
            }
         }
      }
      /* if the event being restored matches one programmed in the trigger */
      /* logic, force the event to be marked modified.  This will cause */
      /* the restored events to reprogram the trigger logic the next time */
      /* the trace system is started. */
      if ((err = TrigEventInTrigger(name, &trigFound)) != GOOD) {
         _lclose(hFile);
         return(err);
      }
      }
      if(_lclose(hFile) == -1) return(ER_CANT_CLOSE_FILE);
      return(GOOD);
   }
   return(ER_NO_FILE_GIVEN);
}

/*****************************************************************************
** 
**    EvtSaveAsEvents
** 
*****************************************************************************/
RETCODE EXPORT EvtSaveAsEvents(LPSTR fileName) {
   int hFile;
   LOOP_VAR idx, grp;
   RETCODE err;
   if (fileName && (lstrlen(fileName) > 0)) {
      if((hFile = _lcreat(fileName,0)) == -1) return(ER_CANT_OPEN_FILE);
      if((err=WriteNumber(hFile,numEvents))!=GOOD) return(err);
      if((err=WriteNewLine(hFile))!=GOOD) return(err);
      for( idx = 0; idx < numEvents; idx++ ) {
         EVENT_DEF *evt;
         evt = &eventList[idx];
         if((err=WriteString(hFile,evt->eventName))!=GOOD)
            return(err);
         if((err=WriteNumber(hFile,evt->endAddrFunction))!=GOOD) return(err);
         if((err=WriteString(hFile,evt->addrStartText))!=GOOD) return(err);
         if((err=WriteString(hFile,evt->addrEndText))!=GOOD) return(err);
         if((err=WriteNewLine(hFile))!=GOOD) return(err);
         for( grp = 0; grp < NUM_GROUPS; grp++ ) {
            if((err=WriteBlanks(hFile,3))!=GOOD) return(err);
            if((err=WriteNumber(hFile,evt->not[grp]))!=GOOD) return(err);

            if((err=WriteLong(hFile,evt->start.xilinxGroup[grp]))!=GOOD) 
               return(err);
            if((err=WriteNumber(hFile,evt->startChanged[grp]))!=GOOD) 
               return(err);
            if((err=WriteNewLine(hFile))!=GOOD) return(err);

            if((err=WriteBlanks(hFile,6))!=GOOD) return(err);
            if((err=WriteLong(hFile,evt->end.xilinxGroup[grp]))!=GOOD) 
               return(err);
            if((err=WriteNumber(hFile,evt->endChanged[grp]))!=GOOD) 
               return(err);
            if((err=WriteNewLine(hFile))!=GOOD) return(err);
      
            if((err=WriteBlanks(hFile,6))!=GOOD) return(err);
            if((err=WriteLong(hFile,evt->mask.xilinxGroup[grp]))!=GOOD) 
               return(err);
            if((err=WriteNumber(hFile,evt->maskChanged[grp]))!=GOOD) 
               return(err);
            if((err=WriteNewLine(hFile))!=GOOD) return(err);
         }
      }
      if(_lclose(hFile) == -1) return(ER_CANT_CLOSE_FILE);
      return(GOOD);
   }
   return(ER_NO_FILE_GIVEN);
}

/*****************************************************************************
** 
**    EvtSetActiveEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtSetActiveEvent(DESCRIPTOR id, LPSTR eventName) {
   EVENT FAR *event;
   LOOP_VAR eventIdx;
   PROBE_TYPE Processor;

   event = (EVENT FAR *)id;
   if( !EventExists(eventName,&eventIdx) ) {
      RETCODE err;
      if (numEvents >= 8)
         return(ER_TOO_MANY_EVENTS);
      if( (err=CreateNewEvent(eventName,&eventIdx)) != GOOD ) 
         return(err);
      event->activeEvent = eventIdx;
      numEvents++;
      /* want the emon bit active for all events - do this automatically
         for the user. 
       */
      if((err=EvtSetActiveField(id,"emon"))!= GOOD ) return(err);
      if((err=EvtSetStartAndMask(id,"1"))!=GOOD) return(err);

      ProcReturnSpecificProcessor(&Processor);
      if (Processor == M68302_MP) {
         if((err=EvtSetActiveField(id,"edma-"))!= GOOD ) return(err);
         if((err=EvtSetStartAndMask(id,"1"))!=GOOD) return(err);
      }
   }
   else {
      event->activeEvent = eventIdx;
   }
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetActiveEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtGetActiveEvent(DESCRIPTOR id,LPSTR eventName,U16 maxLen){
   EVENT FAR *event;
   event = (EVENT FAR *)id;
   CheckValidEvent();
   if( (lstrlen(eventList[event->activeEvent].eventName)+1) > maxLen )
      return(ER_NOT_ENOUGH_STORAGE);
   lstrcpy(eventName,eventList[event->activeEvent].eventName);
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtDoesEventExist
** 
*****************************************************************************/
RETCODE EXPORT EvtDoesEventExist(LPSTR eventName, BOOLEAN FAR *exists) {
   LOOP_VAR pos;
   *exists = EventExists(eventName,&pos);
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtClearEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtClearEvent(DESCRIPTOR id) {
   EVENT FAR *event;
   RETCODE err;
   if( (err=CheckEntryConditions(id))!=GOOD ) return(err);
   event = (EVENT FAR *)id;
   CheckValidEvent();
   FreeEventText(event->activeEvent);
   ClearEvent(event->activeEvent);
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtDeleteEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtDeleteEvent(DESCRIPTOR id) {
   EVENT FAR *event;
   RETCODE err;
   if( (err=CheckEntryConditions(id))!=GOOD ) return(err);
   event = (EVENT FAR *)id;
   CheckValidEvent();
   eventList[event->activeEvent].eventName[0] = '\0';
   FreeEventText(event->activeEvent);
   numEvents--;
   event->activeEvent = MAX_EVENTS;  /* now there's no valid active event */
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtDeleteAllEvents
** 
*****************************************************************************/
RETCODE EXPORT EvtDeleteAllEvents(VOID){
   RETCODE err;
   LOOP_VAR idx;
   BOOLEAN tracing, eventInUse;
   EMULATION_STATE emulating;

   if((err=SdnReadMember(SDN_TRACING,&tracing))!=GOOD) return(err);
   if((err=BkGetEmulationStatus(&emulating))!=GOOD) return(err);
   /* Check all events to see if they are used in the trigger before
      deleting any of the events.
   */            
   for( idx = 0; idx < numEvents; idx++ ) {
      if((err=TrigEventInTrigger(eventList[idx].eventName,
              &eventInUse))!=GOOD) return(err);
      /* I only want to cause trouble if event is in trigger AND
         we are tracing and/or emulating.  Otherwise user may want 
         to delete events and restore event file before starting
         up again.
      */
// <gene>     if( eventInUse ) {
//         if( tracing ) return(ER_TRACING_ON);
//         if( emulating!=EM_HALTED ) return(ER_TRIGGER_USING_EVENT);
//      }
   }
   for( idx = 0; idx < numEvents; idx++ ) {
      eventList[idx].eventName[0] = '\0';
      FreeEventText(idx);
   }
   numEvents = 0;
 
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtSetActiveField
** 
*****************************************************************************/
RETCODE EXPORT EvtSetActiveField(DESCRIPTOR id, LPSTR fieldName) {
   RETCODE err;
   EVENT FAR *event;
   event = (EVENT FAR *)id;
   if((err=TmpltSetFieldName(event->templateId, fieldName))!=GOOD)
      return(err);
   if((err=TmpltGetGroup(event->templateId,&event->activeGroup))!=GOOD)
      return(err);
   if((err=TmpltGetFieldType(event->templateId,&event->activeType))!=GOOD ) 
      return(err);
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetActiveField
** 
*****************************************************************************/
RETCODE EXPORT EvtGetActiveField(DESCRIPTOR id, LPSTR fieldName, 
                                 U16 maxLen) {
   return(TmpltGetFieldName(((EVENT FAR *)id)->templateId, fieldName, maxLen));
}

/*****************************************************************************
** 
**    EvtSetNotCondition
** 
*****************************************************************************/
RETCODE EXPORT EvtSetNotCondition(DESCRIPTOR id, BOOLEAN not) {
   EVENT FAR *event;
   RETCODE err;
   if( (err=CheckEntryConditions(id))!=GOOD ) return(err);
   event = (EVENT FAR *)id;
   CheckValidEvent();
   /* only rangable template fields(i.e.: addr and data) can
      support the NOT option. */
   if( event->activeType == VALUE_FIELD ) return(ER_NOT_NOT_ALLOWED);
   eventList[event->activeEvent].not[event->activeGroup] = not;
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetNotCondition
** 
*****************************************************************************/
RETCODE EXPORT EvtGetNotCondition(DESCRIPTOR id, BOOLEAN FAR *not) {
   EVENT FAR *event;
   event = (EVENT FAR *)id;
   CheckValidEvent();
   if( event->activeType == VALUE_FIELD ) return(ER_NOT_NOT_ALLOWED);
   *not = eventList[event->activeEvent].not[event->activeGroup];
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtSetEndFunction
** 
*****************************************************************************/
RETCODE EXPORT EvtSetEndFunction(DESCRIPTOR id, END_FUNC func) {
   EVENT FAR *event;
   RETCODE err;
   if( (err=CheckEntryConditions(id))!=GOOD ) return(err);
   event = (EVENT FAR *)id;
   CheckValidEvent();
   eventList[event->activeEvent].endAddrFunction = func;
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetEndFunction
** 
*****************************************************************************/
RETCODE EXPORT EvtGetEndFunction(DESCRIPTOR id, END_FUNC FAR *func) {
   EVENT FAR *event;
   event = (EVENT FAR *)id;
   CheckValidEvent();
   if( event->activeType == VALUE_FIELD ) return(ER_NOT_NOT_ALLOWED);
   *func = eventList[event->activeEvent].endAddrFunction;
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtSetEnd
** 
*****************************************************************************/
RETCODE EXPORT EvtSetEnd(DESCRIPTOR id, LPSTR end) {
   EVENT FAR *event;
   RETCODE err;
   BOOLEAN isItAddr, blankingOut;
   S8 activeField[50];
   U32 value, startValue;
   if( (err=CheckEntryConditions(id))!=GOOD ) return(err);
   event = (EVENT FAR *)id;
   CheckValidEvent();
   /* only rangable template fields(i.e.: addr and data) can set an end */
   if( event->activeType == VALUE_FIELD ) return(ER_END_NOT_ALLOWED);
   if((err=TmpltGetFieldName(event->templateId,(LPSTR )&activeField,50))
      !=GOOD) return(err);
   isItAddr = (lstrcmp(activeField,"address")==0);
   blankingOut = StringBlank(end);
   if( blankingOut ) {
      value = 0;
   } 
   else {
      if( (err=ConvTextToU32(end, &value, isItAddr)) != GOOD ) return(err);
      if( !isItAddr ||   /* data field or addr field and end addr func */
          (eventList[event->activeEvent].endAddrFunction==END_ADDR_FUNC) ) {
         if((err=TmpltGetValue(event->templateId,
                   &eventList[event->activeEvent].start,
                   &startValue)) != GOOD ) return(err);
         if ( startValue > value ) {
            value = startValue;
            if((err=TmpltSetValue(event->templateId,
                     &eventList[event->activeEvent].end,
                     value)) != GOOD ) return(err);
            if( isItAddr ) eventList[event->activeEvent].addrEndText=0x0;
            return(ER_INVALID_RANGE_SPEC);
         }
      }
      if( isItAddr && 
         (eventList[event->activeEvent].endAddrFunction==END_LEN_FUNC) ) {
         U32 startValue;
         if( !eventList[event->activeEvent].startChanged[event->activeGroup] )
            return(ER_DEFINE_START_FIRST);
         if((err=TmpltGetValue(event->templateId,
                   &eventList[event->activeEvent].start,
                   &startValue)) != GOOD ) return(err);
         value += startValue;
      }
   }
   if((err=TmpltSetValue(event->templateId,
               &eventList[event->activeEvent].end,
               value)) != GOOD ) return(err);
   /* if user is blanking out a field reset changed status */
   eventList[event->activeEvent].endChanged[event->activeGroup]=!blankingOut;
   if( isItAddr && ((err=HandleTextString(event,end,FALSE))!=GOOD) )
      return(err);
   if( !eventList[event->activeEvent].startChanged[event->activeGroup] ) {
      /* if processing address field then copy end text to start text */
      /* this will only happen if end address function is address not len */
      if( isItAddr && ((err=HandleTextString(event,
         eventList[event->activeEvent].addrEndText,TRUE))!=GOOD) )
         return(err);         
      if((err=TmpltSetValue(event->templateId,
               &eventList[event->activeEvent].start,
               value)) != GOOD ) return(err);
   }
   if( !eventList[event->activeEvent].maskChanged[event->activeGroup] ) {
      if( blankingOut 
         && !eventList[event->activeEvent].startChanged[event->activeGroup]) 
         value = 0L;
      else value = 0xffffffffL;
      if((err=TmpltSetValue(event->templateId,
               &eventList[event->activeEvent].mask,
               value)) != GOOD ) return(err);
   }   
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetEnd
** 
*****************************************************************************/
RETCODE EXPORT EvtGetEnd(DESCRIPTOR id, LPSTR end, U16 maxLen) {
   BOOLEAN isItAddr;
   EVENT FAR *event;
   RETCODE err;
   S8 activeField[50];
   event = (EVENT FAR *)id;
   CheckValidEvent();
   if( event->activeType == VALUE_FIELD ) return(ER_END_NOT_ALLOWED);
   if((err=TmpltGetFieldName(event->templateId,(LPSTR )&activeField,50))
      !=GOOD) return(err);
   isItAddr = (lstrcmp(activeField,"address")==0);
   if( isItAddr && eventList[event->activeEvent].addrEndText ) {
      lstrcpy(end,eventList[event->activeEvent].addrEndText);
   }
   else {
      if((err=TextualizeValue(event, &eventList[event->activeEvent].end, 
         (eventList[event->activeEvent].startChanged[event->activeGroup]
          || eventList[event->activeEvent].endChanged[event->activeGroup]),
          end, maxLen)) != GOOD) return(err);
   }
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtSetMask
** 
*****************************************************************************/
RETCODE EXPORT EvtSetMask(DESCRIPTOR id, LPSTR mask) {
   EVENT FAR *event;
   BOOLEAN blankingOut;
   char *endPtr;
   U32 value;
   RETCODE err;
   if( (err=CheckEntryConditions(id))!=GOOD ) return(err);
   event = (EVENT FAR *)id;
   CheckValidEvent();
   if( event->activeType == VALUE_FIELD ) return(ER_ONLY_FOR_RANGES);
   blankingOut = StringBlank(mask);
   if( blankingOut ) value = 0;
   else {
      value = strtoul(mask, &endPtr, 0);
      if (*endPtr != '\0') return (ER_INVALID_DIGIT);
   }
   if( (err = TmpltSetValue(event->templateId, 
               &eventList[event->activeEvent].mask,
               value)) != GOOD ) return(err);
   eventList[event->activeEvent].maskChanged[event->activeGroup] 
      = !blankingOut;
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetMask
** 
*****************************************************************************/
RETCODE EXPORT EvtGetMask(DESCRIPTOR id, LPSTR mask, U16 maxLen) {
   EVENT FAR *event;
   RETCODE err;
   event = (EVENT FAR *)id;
   CheckValidEvent();

   /* Changed the call from TextualizeValue to TextualizeMaskValue.   */
   /* TextualizeValue would call TmpltGetValueText which would return */
   /* the string as an address (with space designators defined if the */
   /* function codes (fc0, fc1, fc2) are active.  May 5, 1994         */ 
   if((err=TextualizeMaskValue(event, &eventList[event->activeEvent].mask, 
              eventList[event->activeEvent].maskChanged[event->activeGroup],
              mask, maxLen)) != GOOD) return(err);
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtSetStart
** 
*****************************************************************************/
RETCODE EXPORT EvtSetStart(DESCRIPTOR id, LPSTR start) {
   EVENT FAR *event;
   BOOLEAN isItAddr, blankingOut;
   S8 activeField[50];
   U32 value;
   RETCODE err;
   if( (err=CheckEntryConditions(id))!=GOOD ) return(err);
   event = (EVENT FAR *)id;
   CheckValidEvent();
   if( event->activeType == VALUE_FIELD ) return(ER_ONLY_FOR_RANGES);
   if((err=TmpltGetFieldName(event->templateId,(LPSTR )&activeField,50))
      !=GOOD) return(err);
   isItAddr = (lstrcmp(activeField,"address")==0);
   blankingOut = StringBlank(start);
   if( blankingOut ) {
      value = 0;
   }
   else {
      if( (err=ConvTextToU32(start, &value, isItAddr)) != GOOD ) return(err);
   }
   if( (err = TmpltSetValue(event->templateId, 
               &eventList[event->activeEvent].start,
               value)) != GOOD ) return(err);
   eventList[event->activeEvent].startChanged[event->activeGroup]=!blankingOut;
   if( isItAddr && ((err=HandleTextString(event,start,TRUE))!=GOOD) )
      return(err);
   if( !eventList[event->activeEvent].maskChanged[event->activeGroup] ) {
      U32 maskValue = 0L;
      if( !blankingOut 
         || eventList[event->activeEvent].endChanged[event->activeGroup]) 
         maskValue = 0xffffffffL;
      if((err=TmpltSetValue(event->templateId,
               &eventList[event->activeEvent].mask,
               maskValue)) != GOOD ) return(err);
   }
   if( !eventList[event->activeEvent].endChanged[event->activeGroup] ) {
      if( isItAddr ) {
         if((err=HandleTextString(event,
            eventList[event->activeEvent].addrStartText,FALSE))!=GOOD) 
            return(err);
         if(eventList[event->activeEvent].endAddrFunction!=END_ADDR_FUNC)
            return(GOOD);  /* !!! this is borderline error condition. */
      }
      if((err=TmpltSetValue(event->templateId,
              &eventList[event->activeEvent].end,value)) != GOOD ) 
         return(err);
   }
   else {
      if(isItAddr 
         && eventList[event->activeEvent].endAddrFunction==END_LEN_FUNC) {
         U32 endLen;
         if( (err=ConvTextToU32(eventList[event->activeEvent].addrEndText, 
            &endLen, isItAddr)) != GOOD ) return(err);
         value += endLen;
         if((err=TmpltSetValue(event->templateId,
              &eventList[event->activeEvent].end,value)) != GOOD) return(err);
      }
   }      
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetStart
** 
*****************************************************************************/
RETCODE EXPORT EvtGetStart(DESCRIPTOR id, LPSTR start, U16 maxLen) {
   EVENT FAR *event;
   RETCODE err;
   BOOLEAN isItAddr;
   S8 activeField[50];
   event = (EVENT FAR *)id;
   CheckValidEvent();
   if((err=TmpltGetFieldName(event->templateId,(LPSTR )&activeField,50))
      !=GOOD) return(err);
   isItAddr = (lstrcmp(activeField,"address")==0);
   if( isItAddr && eventList[event->activeEvent].addrStartText ) {
      lstrcpy(start,eventList[event->activeEvent].addrStartText);
   }
   else {
      if((err=TextualizeValue(event, &eventList[event->activeEvent].start, 
              eventList[event->activeEvent].startChanged[event->activeGroup],
              start, maxLen)) != GOOD) return(err);
   }
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtSetStartAndMask
** 
*****************************************************************************/
RETCODE EXPORT EvtSetStartAndMask(DESCRIPTOR id, LPSTR start) {
   EVENT FAR *event;
   U32 value, mask;
   DISPLAY_FORMAT format;
   RETCODE err;
   if( (err=CheckEntryConditions(id))!=GOOD ) return(err);
   if( StringBlank(start) ) return(GOOD);
   event = (EVENT FAR *)id;
   CheckValidEvent();
//6/13/96   if( event->activeType != VALUE_FIELD ) return(ER_USE_SET_START);
   if( (err=TmpltGetDisplayFormat(event->templateId, &format)) != GOOD )
      return(err);
   if( (err=ConvTextToU32AndMask(start, &value, &mask, format)) != GOOD )
      return(err);
   if((err=TmpltSetValue(event->templateId, 
            &eventList[event->activeEvent].start,
            value)) != GOOD ) return(err);
   if((err=TmpltSetValue(event->templateId, 
            &eventList[event->activeEvent].mask,
            mask)) != GOOD ) return(err);
   if((err=TmpltSetValue(event->templateId,
            &eventList[event->activeEvent].end,
            value)) != GOOD ) return(err);
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetStartAndMask
** 
*****************************************************************************/
RETCODE EXPORT EvtGetStartAndMask(DESCRIPTOR id, LPSTR start, U16 maxLen) {
   EVENT FAR *event;
   S8 value[MAX_VALUE_STR], mask[MAX_VALUE_STR];
   RETCODE err;
   event = (EVENT FAR *)id;
   CheckValidEvent();
   if( (err = TmpltGetValueText(event->templateId, 
               &eventList[event->activeEvent].start,
               value, MAX_VALUE_STR-1, TRUE)) != GOOD ) return(err);
 
   /* Changed the call from TmpltGetValueText to TmpltGetMaskValueText. */
   /* This may not have had to be changed, since I am not sure if this  */
   /* call is ever made to get address information (my guess is not).   */
   /* Change made by Dennis Lamb, May 5, 1994.                          */
   if( (err = TmpltGetMaskValueText(event->templateId, 
               &eventList[event->activeEvent].mask,
               mask, MAX_VALUE_STR-1)) != GOOD ) return(err);
   return(FigureMaskedValueString(value,mask,start,maxLen));
}

/*****************************************************************************
** 
**    EvtNumDefinedEvents
** 
*****************************************************************************/
RETCODE EXPORT EvtNumDefinedEvents(DESCRIPTOR id, U16 FAR *num) {
   *num = numEvents;
   ((EVENT FAR *)id)->nextEventPtr = 0;
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetNextEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtGetNextEvent(DESCRIPTOR id, LPSTR name, U16 maxLen) {
   EVENT FAR *event;
   event = (EVENT FAR *)id;
   lstrcpy(name,"");       /* send back an empty string if at end of list */
   for( ; event->nextEventPtr < MAX_EVENTS; event->nextEventPtr++ ) {
      if(eventList[event->nextEventPtr].eventName[0] != '\0') {
         /* found a defined event */
         if( (lstrlen(eventList[event->nextEventPtr].eventName)+1) > maxLen ) 
            return(ER_NOT_ENOUGH_STORAGE);
         lstrcpy(name,eventList[event->nextEventPtr].eventName);
         event->nextEventPtr++;
         break;
      }
   }
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtGetEventGroupInfo
** 
*****************************************************************************/
RETCODE EXPORT EvtGetEventGroupInfo(DESCRIPTOR id, XILINX_NUMBER xilinx,
                                    EVENT_GROUP_INFO FAR *info) {
   EVENT FAR *event;
   event = (EVENT FAR *)id;
   CheckValidEvent();
   info->lo=eventList[event->activeEvent].start.xilinxGroup[xilinx];
   info->hi=eventList[event->activeEvent].end.xilinxGroup[xilinx];
   info->mask =
      eventList[event->activeEvent].mask.xilinxGroup[xilinx];
   info->not = eventList[event->activeEvent].not[xilinx];
   return(GOOD);
}

/*************************** CLI FUNCTIONS ******************************/
static DESCRIPTOR eventId=0;
RETCODE CheckEventId(VOID) {
   if( !eventId ) return(EvtOpenEvent(&eventId,"default"));
   return(GOOD);
}

RETCODE EXPORT EventCliOpen(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err;
   if( argc != 2 ) return(ER_CLI_SYNTAX);
   if( !eventId ) {
      if( (err=EvtOpenEvent(&eventId,&cmdString[(U16)argv[1]])) != GOOD )
         return(err);
   }
   return(SendCliResults((LPSTR)"event opened",cliServerHandle));
}

#pragma argsused
RETCODE EXPORT EventCliClose(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err=GOOD;
   if( eventId ) {
      err = EvtCloseEvent(eventId);
      eventId = 0;
   }
   return(err);
}

RETCODE EXPORT EventCliRestoreEvents(LPSTR cmdString, U32 argc, U32 argv[]) {
   if( argc == 2 ) return(EvtRestoreEvents(&cmdString[(U16)argv[1]]));
   return(ER_CLI_SYNTAX);
}

RETCODE EXPORT EventCliSaveEvents(LPSTR cmdString, U32 argc, U32 argv[]) {
   if( argc == 2 ) return(EvtSaveAsEvents(&cmdString[(U16)argv[1]]));
   return(ER_CLI_SYNTAX);
}

RETCODE EXPORT EventCliEvent(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   if( argc == 2 ) {
      if((err=EvtSetActiveEvent(eventId,&cmdString[(U16)argv[1]]))!=GOOD) 
         return(err);
   }
   if((err=EvtGetActiveEvent(eventId,resultBuff,128))!=GOOD) return(err);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT EventCliEventExist(LPSTR cmdString, U32 argc, U32 argv[]) {
   BOOLEAN value;
   S8 resultBuff[128];
   RETCODE err;
   if( argc != 2 ) return(ER_CLI_SYNTAX);
   if( (err=EvtDoesEventExist(&cmdString[(U16)argv[1]],&value)) != GOOD ) 
      return(err);
   wsprintf(resultBuff,"EVENT: %s ", &cmdString[(U16)argv[1]]);
   if( value ) lstrcat(resultBuff,"exists");
   else lstrcat(resultBuff,"does NOT exists");
   return(SendCliResults(resultBuff,cliServerHandle));
}

#pragma argsused
RETCODE EXPORT EventCliClearEvent(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   return(EvtClearEvent(eventId));
}

#pragma argsused
RETCODE EXPORT EventCliDeleteEvent(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   return(EvtDeleteEvent(eventId));
}

#pragma argsused
RETCODE EXPORT EventCliDeleteAllEvents(LPSTR cmdString,U32 argc,U32 argv[]) {
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   return(EvtDeleteAllEvents());
}

RETCODE EXPORT EventCliField(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   if( argc == 2 ) {
      if( (err=EvtSetActiveField(eventId, &cmdString[(U16)argv[1]])) != GOOD ) 
         return(err);
   }
   if((err=EvtGetActiveField(eventId,resultBuff,128))!=GOOD) return(err);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT EventCliNotCondition(LPSTR cmdString, U32 argc, U32 argv[]) {
   BOOLEAN value;
   S8 resultBuff[128];
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   if( argc == 2 ) {
      value = ParseBoolean(&cmdString[(U16)argv[1]]);
      if((err=EvtSetNotCondition(eventId,value))!=GOOD) return(err);
   }
   if((err=EvtGetNotCondition(eventId,&value))!=GOOD) return(err);
   if( value ) lstrcpy(resultBuff,"TRUE");
   else lstrcpy(resultBuff,"FALSE");
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT EventCliEnd(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   if( argc == 2 ) {
      if( (err=EvtSetEnd(eventId, &cmdString[(U16)argv[1]])) != GOOD ) 
         return(err);
   }
   if((err=EvtGetEnd(eventId,resultBuff,128))!=GOOD) return(err);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT EventCliStart(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   EVENT FAR *event;
   if((err=CheckEventId())!=GOOD) return(err);
   event = (EVENT FAR *)eventId;
   if( event->activeType == VALUE_FIELD ) {
      if( argc == 2 ) {
         if((err=EvtSetStartAndMask(eventId, &cmdString[(U16)argv[1]]))!=GOOD)
            return(err);
      }
      if((err=EvtGetStartAndMask(eventId, resultBuff,128))!=GOOD) 
         return(err);   
   }
   else {
      if( argc == 2 ) {
         if( (err=EvtSetStart(eventId, &cmdString[(U16)argv[1]])) != GOOD ) 
            return(err);
      }
      if((err=EvtGetStart(eventId,resultBuff,128))!=GOOD) return(err);
   }
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT EventCliEventGroupInfo(LPSTR cmdString, U32 argc, U32 argv[]) {
   EVENT_GROUP_INFO grpInfo;
   XILINX_NUMBER group=R_GROUP;
   LPSTR ptr;
   S8 resultBuff[128];
   RETCODE err;
   if( argc != 2 ) return(ER_CLI_SYNTAX);
   if((err=CheckEventId())!=GOOD) return(err);
   ptr = &cmdString[(U16)argv[1]];
   if(strncmpi(ptr, "r_group", strlen(ptr))==0) 
      group = R_GROUP;
   else if(strncmpi(ptr, "s_group", strlen(ptr))==0) 
      group = S_GROUP;
   else if(strncmpi(ptr, "t_group", strlen(ptr))==0) 
      group = T_GROUP;
   else if(strncmpi(ptr, "u_group", strlen(ptr))==0) 
      group = U_GROUP;
   if((err=EvtGetEventGroupInfo(eventId,group,&grpInfo))!=GOOD) return(err);
   wsprintf(resultBuff,"lo: %08lx; hi: %08lx; mask: %08lx; not: %s",
      grpInfo.lo, grpInfo.hi, grpInfo.mask, grpInfo.not ? "TRUE" : "FALSE");
   return(SendCliResults(resultBuff,cliServerHandle));
}

#pragma argsused
RETCODE EXPORT EventCliNumDefinedEvents(LPSTR cmdString,U32 argc,U32 argv[]) {
   U16 num;
   S8 resultBuff[128];
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   if( (err=EvtNumDefinedEvents(eventId,&num)) != GOOD ) return(err);
   wsprintf(resultBuff,"%d", num);
   return(SendCliResults(resultBuff,cliServerHandle));
}

#pragma argsused
RETCODE EXPORT EventCliGetNextEvent(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   if((err=CheckEventId())!=GOOD) return(err);
   if((err=EvtGetNextEvent(eventId,resultBuff,128)) != GOOD) return(err);
   return(SendCliResults(resultBuff,cliServerHandle));
}

/****************************** LOCAL FUNCTIONS *****************************/
/*****************************************************************************
** 
**    ConvTextToU32AndMask
** 
**    Description:
**       Converts a string with X's for don't cares to a 32 bit value and
**       mask.
**
**    Parameters:
**       input:
**          data:    string to be converted
**          format:  which base to use when translating string to value.
**       output:
**          value:   translated value
**          mask:    mask of don't cares (0=don't care)
*****************************************************************************/
RETCODE ConvTextToU32AndMask(LPSTR data, U32 *value, U32 *mask, 
                       DISPLAY_FORMAT format) {
   LOOP_VAR i = 0;
   U8 digit;
   U8 base;
   *value = *mask = 0;             /* 0 means don't care */
   switch(format) {
      case DISP_HEX: base = 16; break;
      case DISP_DEC: base = 10; break;
      case DISP_OCT: base = 8; break;
      case DISP_BIN:
      case ASSERT_DEF:
      case ASSERT_FIRST:   base = 2; break;
      default:
         return(ER_INVALID_DISP_FORMAT);
   }
         
   for(; data[i]!='\0'; i++) {
      U8 digitVal;
      digit = toupper(data[i]);
      *value *= base;
      *mask *= base;
      if(digit=='X') {
         if( format == DISP_DEC ) 
            return(ER_NO_MASK_SUPPORTED);
         else continue;
      }
      else if((digit>='0') && (digit<='9')) {
         digitVal = digit-'0'; 
         *mask += base - 1;
      } else if((digit>='A') && (digit<='F')) {
         digitVal = (digit-'A') + 10;
         *mask += base - 1;
      } else return(ER_INVALID_DIGIT);
      if( digitVal >= base ) return(ER_INVALID_DIGIT);
      *value += digitVal;
   }
   if( format == DISP_DEC ) *mask = -1;   
   return(GOOD);
}

/*****************************************************************************
** 
**    ConvTextU32
** 
**    Description:
**       Converts a string to a 32 bit value.  THe string is an "address"
**    Which means we send the string to the address routine and let it parse
**    literal numbers, symbols and symbols with offsets.
**
**    Parameters:
**       input:
**          data:    string to be converted
**       output:
**          value:   translated value
*****************************************************************************/
RETCODE ConvTextToU32(LPSTR data, U32 *value, BOOLEAN isItAddress) {
   DESCRIPTOR addrDesc;
   RETCODE err;
   if( isItAddress ) {
      /* Addr conv text to address routine eats up the string - so
         make a copy to send since calling routines usually wants
         a good copy of the string to save around.
       */
      S8 tempString[256];
      lstrcpy(tempString,data);   
      if((err=AdrCreateAddress(&addrDesc))!=GOOD) return(err);
      if((err=AdrSetAddrSymbolUsage(addrDesc,TRUE))!=GOOD) return(err);
      if((err=AdrConvTextToAddress(addrDesc,tempString))!=GOOD) return(err);
      if((err=AdrGetAddrOffset(addrDesc,value))!=GOOD) return(err);
      if((err=AdrDestroyAddress(addrDesc))!=GOOD) return(err);
   }
   else {
      S8 *endPtr;
      *value = strtoul(data, &endPtr, 0);
      if (*endPtr != 0) return(ER_CANT_CONV_TEXT);
   }
   return(GOOD);
}

/*****************************************************************************
** 
**    EventExists
** 
**    Description:
**       Tells whether an event name is currently defined
**
**    Parameters:
**       input:
**          eventName:  name of event
**       output:
**          index:      index into table of event (if TRUE returned)
*****************************************************************************/
BOOLEAN EventExists(LPSTR eventName, LOOP_VAR FAR *index) {
   for((*index)=0; (*index)<MAX_EVENTS; (*index)++) {
      if(!lstrcmp(eventName, eventList[*index].eventName)) return(TRUE);
   }
   return(FALSE);
}

/*****************************************************************************
** 
**    ClearEvent
** 
**    Description:
**       Sets all the fields of an event to NOP state.
**
**    Parameters:
**       input:
**          event:      index of event in eventList to clear out
**       output:
**          none
*****************************************************************************/
VOID ClearEvent(LOOP_VAR event) {
   LOOP_VAR i;
   eventList[event].addrStartText = NULL;
   eventList[event].addrEndText = NULL;
   eventList[event].endAddrFunction = END_ADDR_FUNC;
   for( i = 0; i < NUM_GROUPS; i++ ) {
      eventList[event].startChanged[i] = FALSE;
      eventList[event].endChanged[i] = FALSE;
      eventList[event].maskChanged[i] = FALSE;
      eventList[event].not[i] = 0;
      eventList[event].start.xilinxGroup[i] = 0;
      eventList[event].end.xilinxGroup[i] = 0;
      eventList[event].mask.xilinxGroup[i] = 0;
   }
}

/*****************************************************************************
** 
**    CreateNewEvent
** 
**    Description:
**       Adds a new event to the event list, if there is room.
**
**    Parameters:
**       input:
**          eventName:  name of event
**       output:
**          index:      index into table of event (if no error returned)
*****************************************************************************/
RETCODE CreateNewEvent(LPSTR eventName, LOOP_VAR FAR *index) {
   *index = MAX_EVENTS;   /* put an invalid index value initially */
   if(lstrlen(eventName)>MAX_NAME_LENGTH) return(ER_NAME_TOO_LONG);
   for((*index)=0; (*index)<MAX_EVENTS; (*index)++) {
      if(eventList[*index].eventName[0] == '\0') { /* available */
         lstrcpy(eventList[*index].eventName, eventName);
         ClearEvent(*index);
         return(GOOD);
      }
   }
   return(ER_TOO_MANY_EVENTS);
}

/*****************************************************************************
** 
**    FigureMaskedValueString
** 
**    Description:
**       Takes a value string and a mask string and figures out what
**       the final text string should be.
**
**    Parameters:
**       input:
**          value:      text string of value field
**          mask:       text string for mask to apply to field
**          maxLen:     length of storage
**       output:
**          results:    storage for final results
*****************************************************************************/
RETCODE FigureMaskedValueString(LPSTR value, LPSTR mask, 
                                LPSTR results, U16 maxLen) {
   LOOP_VAR length, i;
   length = lstrlen(value);
   if( length != lstrlen(mask) ) return(ER_MASK_VALUE_PROBLEM);
   if( length > maxLen ) return(ER_NOT_ENOUGH_STORAGE);
   for( i = 0; i < length; i++ ) {
      if( mask[i] == '0' ) results[i] = 'X';
      else results[i] = value[i];
   }
   results[i] = '\0';
   return(GOOD);    
}

/*****************************************************************************
** 
**    ParseBoolean
** 
**    Description:
**       Scans the incoming string to determine if value is TRUE or FALSE
**       Returns boolean value.
**
**    Parameters:
**       input:
**          ptr:        string  to scan
**       output:
**          none
**
*****************************************************************************/
BOOLEAN EXPORT ParseBoolean(LPSTR ptr) {
   BOOLEAN val = FALSE;
   if( ptr[0] == '1' )
      val = TRUE;
   else if(strncmpi(ptr, "on", strlen(ptr))==0) 
      val = TRUE;
   else if(strncmpi(ptr, "true", strlen(ptr))==0) 
      val = TRUE;
   return(val);
}

RETCODE CheckEntryConditions(DESCRIPTOR id) {
   EVENT FAR *event;
   BOOLEAN tracing, eventInUse;
   EMULATION_STATE emulating;
   RETCODE err;
   event = (EVENT FAR *)id;
   if((err=SdnReadMember(SDN_TRACING,&tracing))!=GOOD) return(err);
   if((err=TrigEventInTrigger(eventList[event->activeEvent].eventName,
                              &eventInUse))!=GOOD) return(err);
// <gene>  if( eventInUse && tracing ) return(ER_TRACING_ON);
//   if((err=BkGetEmulationStatus(&emulating))!=GOOD) return(err);
//   if( eventInUse && (emulating!=EM_HALTED) )
//      return(ER_TRIGGER_USING_EVENT);
   return(GOOD);
}

RETCODE TextualizeValue(EVENT FAR *event, XILINX_GROUP FAR *bits, 
                         BOOLEAN valChanged, LPSTR text, U16 maxLen) {
   RETCODE err;
   U32 value;                         
   if((err=TmpltGetValue(event->templateId,bits,&value))!=GOOD)
      return(err);
   if( !valChanged && (value==0) ){
      /* if value never defined and value zero'd - return a blank string */
      text[0] = ' ';
      text[1] = '\0';
      err=GOOD;
   }
   else {
      err=TmpltGetValueText(event->templateId,bits,text,maxLen, TRUE);
   }
   return(err);
}

/* This routine was added by Dennis Lamb, May 5 1994. This is part of */
/* the code to fix the address mask field in the event window. This   */
/* routine calls TmpltGetMaskValueText to get the mask as a string.   */
RETCODE TextualizeMaskValue(EVENT FAR *event, XILINX_GROUP FAR *bits, 
                         BOOLEAN valChanged, LPSTR text, U16 maxLen) {
   RETCODE err;
   U32 value;                         
   if((err=TmpltGetValue(event->templateId,bits,&value))!=GOOD)
      return(err);
   if( !valChanged && (value==0) ){
      /* if value never defined and value zero'd - return a blank string */
      text[0] = ' ';
      text[1] = '\0';
      err=GOOD;
   }
   else {
      err=TmpltGetMaskValueText(event->templateId,bits,text,maxLen);
   }
   return(err);
}

RETCODE WriteNumber(int hFile, int num) {
   S8 buf[20], sizeBuf;
   wsprintf(buf,"%d",num);
   sizeBuf = lstrlen(buf);
   if(_lwrite(hFile,buf, sizeBuf)!=sizeBuf) return(ER_WRITING_FILE);
   if(_lwrite(hFile,"  ",2)!=2) return(ER_WRITING_FILE);
   return(GOOD);
}

RETCODE WriteLong(int hFile, U32 num) {
   S8 buf[20], sizeBuf;
   wsprintf(buf,"0x%08lX",num);
   sizeBuf = lstrlen(buf);
   if(_lwrite(hFile,buf, sizeBuf)!=sizeBuf) return(ER_WRITING_FILE);
   if(_lwrite(hFile,"  ",2)!=2) return(ER_WRITING_FILE);
   return(GOOD);
}

#define EMPTY_STRING "empty"
RETCODE WriteString(int hFile, LPSTR str) {
   U8 sizeBuf;
   LPSTR buf;
   buf = str;
   if( (str==NULL) || (lstrlen(str) == 0) ) buf = EMPTY_STRING;
   sizeBuf = lstrlen(buf);
   if(_lwrite(hFile,buf, sizeBuf)!=sizeBuf) return(ER_WRITING_FILE);
   if(_lwrite(hFile,"  ",2)!=2) return(ER_WRITING_FILE);
   return(GOOD);
}

RETCODE WriteNewLine(int hFile) {
   if(_lwrite(hFile,"\r\n",2)!=2) return(ER_WRITING_FILE);
   return(GOOD);
}

RETCODE WriteBlanks(int hFile, int numOf) {
   int actNum;
   actNum = min(numOf, 25);
   if(_lwrite(hFile,"                         ",
              actNum)!=actNum) return(ER_WRITING_FILE);
   return(GOOD);
}

LPSTR ReadObject(int hFile, LPSTR storage, int maxLen) {
   char c=' ';
   LOOP_VAR i=0;
   while( isspace(c) ) {
      if( _lread(hFile,&c,1) != 1 ) return(NULL);
   }
   while( !isspace(c) ) {
      if( i==maxLen ) return(NULL);    /* hit end of storage string */
      storage[i++] = c;
      if( _lread(hFile,&c,1) != 1 ) return(NULL);
   }
   storage[i]='\0';
   return(storage);
}

RETCODE ReadBoolean(int hFile, BOOLEAN *val) {
   U32 num;
   RETCODE err;
   if((err=ReadNumber(hFile,&num))!=GOOD) return(err);
   *val = (BOOLEAN)num;
   return(GOOD);
}

RETCODE EXPORT ReadNumber(int hFile, U32 *num) {
   S8 buf[20];
   char *ptr;
   if( ReadObject(hFile,buf,19) == NULL ) return(ER_READING_FILE);
   *num = strtoul(buf,&ptr,0);
   if( lstrlen(ptr) != 0 ) return(ER_READING_FILE);
   return(GOOD);
}

RETCODE AllocateAndReadString(int hFile, LPSTR *str) {
   if((*str=TMalloc(MAX_SYMNAME_LENGTH+1))==NULL) return(ER_OUT_OF_MEMORY);
   if( ReadObject(hFile,*str,MAX_SYMNAME_LENGTH) == NULL ) 
      return(ER_READING_FILE);
   if( strcmp(*str,EMPTY_STRING)==0 ) {
      TFree(*str);
      *str = NULL;
   }
   return(GOOD);
}

RETCODE ReadString(int hFile, LPSTR str, int maxLen) {
   if( ReadObject(hFile,str,maxLen) == NULL ) return(ER_READING_FILE);
   return(GOOD);
}

RETCODE HandleTextString(EVENT FAR *evt, LPSTR text, BOOLEAN doStart){
   EVENT_DEF *ePtr = &eventList[evt->activeEvent];
   LPSTR *textPtr;
   textPtr = doStart ? &ePtr->addrStartText
                     : &ePtr->addrEndText;
   if( *textPtr == NULL ) {                   
      if((*textPtr=TMalloc(MAX_SYMNAME_LENGTH+1))==NULL) 
         return(ER_OUT_OF_MEMORY);
   }
   **textPtr = '\0';
   lstrcpy(*textPtr, text);
   return(GOOD);
}
   
BOOLEAN StringBlank(LPSTR str) {
   BOOLEAN blank = TRUE;
   LOOP_VAR i;
   for(i=0;i<lstrlen(str);i++) {
      if( !isspace(str[i]) ) blank = FALSE;
   }
   return(blank);
}

VOID FreeEventText(LOOP_VAR idx) {
   if( eventList[idx].addrStartText != NULL ) {
      TFree(eventList[idx].addrStartText);
      eventList[idx].addrStartText = NULL;
   }
   if( eventList[idx].addrEndText != NULL ) {
      TFree(eventList[idx].addrEndText);
      eventList[idx].addrEndText = NULL;
   }         
}

/******************************** E O F ***********************************/
