/****************************************************************************
**
**  Name:  event.c
**
**  Description:
**       Routines to support the event definition management.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_186/trace/event.c_v  $
** 
**    Rev 1.2   27 May 1997 15:29:26   Judy
** No change.
** 
**    Rev 1.1   04 Feb 1997 18:18:58   Judy
** 
**    Rev 1.0   16 Dec 1996 15:25:34   Judy
** Initial revision.
** 
**    Rev 1.3   15 Nov 1996 16:48:36   Judy
** 
**    Rev 1.2   23 Oct 1996 18:08:58   Judy
** 
**    Rev 1.1   06 Sep 1996 17:28:48   Judy
** 
**    Rev 1.0   27 Aug 1996 15:23:12   Judy
** Initial revision.
** 
**    Rev 1.0   27 Aug 1996 14:56:22   Judy
** Initial revision.
** 
**    Rev 1.0   14 Jun 1996 17:04:58   Judy
** Initial revision.
** 
**    Rev 1.46   02 Jun 1994 13:53:10   dennis
** Made many changes to make the event window operation more friendly. Put
** in checks to make sure the start and end data values did not exceed
** the data limit, checked to see if the address length plus the start
** address value exceeded the address limit, dont allow a mask field to be
** defined if no start field is defined, when start field is blanked out,
** blank out the end and mask fields, etc.
** 
**    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_186/trace/event.c_v   1.2   27 May 1997 15:29:26   Judy  $
**
**  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 _BKROOT_
#include "bkroot.h"
#endif
#ifndef _HLPENTRY_
#include "hlpentry.h"
#endif
/*
#ifndef _ABI_DEF_
#include "abidef.h"
#endif */
#ifndef  _SDS2ABI_
#include "sds2abi.h"
#endif

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

#define MAX_VALUE_STR   16
#define MAX_EVENTS 8

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


#define MAX_NAME_LENGTH 63
#define TRIG_EVENT_LEN MAX_NAME_LENGTH-10
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;
DESCRIPTOR eventId=0L;
			/****************************
			 *                          *
			 *     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);
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);
VOID GetBusData (U16 *data);

			/****************************
			 *                          *
			 *      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);
}

//#ifndef _BORLANDC_
/**************************************************************************
**
** WEP {Windows Exit Procedure}
**
** Description: DLL exit procedure to perform cleanup for the DLL before it
**              is unloaded. - not to be used with BC++ compiler.
**
**	Parameters:
**    input:
**       nParam:     Message to indicate whether all of Windows is shutting
**                   down or just the DLL itself.
**
**    output:
**       return a 1 to indicate success
**
**************************************************************************
int FAR PASCAL EXPORT WEP(int nParam) {

   switch(nParam) {
      case WEP_SYSTEM_EXIT:
         break;
      case WEP_FREE_DLL:
         break;
      default:
         break;
   }
   if (eventId !=0)
      TFree(eventId);
   return(TRUE);
}
#endif */
/*****************************************************************************
** 
**    EvtOpenEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtOpenEvent(DESCRIPTOR FAR *id, LPSTR templateName) {
   EVENT FAR *event;
   RETCODE err;
     if( eventId ) {
      *id = eventId;
      return(GOOD);
   }
   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;
   eventId = *id;
   return(GOOD);
}

/*****************************************************************************
** 
**    EvtFreeEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtFreeEvent() {
   if (eventId !=0)
      TFree(eventId);
   eventId=0;
   return(GOOD);
}
/*****************************************************************************
** 
**    EvtCloseEvent
** 
*****************************************************************************/
RETCODE EXPORT EvtCloseEvent(DESCRIPTOR id) {
        return(GOOD);
}
RETCODE EXPORT EvtAcceptEvent(DESCRIPTOR id) {
RETCODE err;
U16 idx,tmpIdx, dataMask, i;
U32 tmpMask;
BUS_EVENT mp_event;
EVENT_DEF *evt;

   if( eventId==0L )
      return(GOOD);

   if( (err=TmpltTemplateClose(((EVENT FAR *)id)->templateId)) != GOOD ) 
      return(err);
   
   if ( (err=Sds2AbiClearEvent(-1)) != GOOD ) return(err); //clear all events
   tmpIdx=0;
   GetBusData(&dataMask);
   for( idx = 0; idx < MAX_EVENTS; idx++ ) {
      evt = &eventList[idx];
      if (evt->eventName[0] == '\0' || evt->eventName[TRIG_EVENT_LEN] == '\0')
         continue;
      mp_event.enable =  1;
      mp_event.addrLow  = evt->start.xilinxGroup[0];
      if ( (evt->mask.xilinxGroup[0]&0xfffffL) == 0xfffffL) {
         mp_event.addrSpec = 2; /* range address */
         mp_event.addrHigh = evt->end.xilinxGroup[0];
      } else { 
         mp_event.addrSpec = 3; /* wildcard address */
         mp_event.addrHigh = evt->mask.xilinxGroup[0]&0xfffffL;
      }
      mp_event.dataSpec = 3; /* wildcard value */
      mp_event.dataLow  = evt->start.xilinxGroup[2];
      mp_event.dataHigh = evt->mask.xilinxGroup[2] & dataMask;
      mp_event.status   = evt->start.xilinxGroup[1];
      tmpMask = (evt->mask.xilinxGroup[1] & 0xffffL) << 16;
      mp_event.status |= tmpMask;
      for (i=0;evt->eventName[TRIG_EVENT_LEN+i]!='\0';i++) {
          if ( (err=Sds2AbiSetEvent(evt->eventName[TRIG_EVENT_LEN+i],
              &mp_event)) != GOOD ) return(err);
          tmpIdx=evt->eventName[TRIG_EVENT_LEN+i];
      }
   }
   if (tmpIdx != 0) {
      mp_event.enable=0x8001;
      if ( (err=Sds2AbiSetEvent(tmpIdx,
         &mp_event)) != GOOD ) return(err);
   }
   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++;
	 } /* if */
	 evt = &eventList[eventIdx];
	 if((err=ReadNumber(hFile, &tmpInt))!=GOOD) return(err);
	 evt->endAddrFunction = (END_FUNC)tmpInt;

	 /* Get the starting address/data string */
	 if((err=AllocateAndReadString(hFile, &evt->addrStartText))!=GOOD)
	    return(err);

	 /* Get the ending address/data string */
	 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);
	 } /* for */
	 /* we need to convert text strings for start and end 
	    address to actual values.  This assigns values to symbolics.
	  */
      {
	 DESCRIPTOR id;
	 U32 start,end;
	     char *endPtr;

	 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 */
	 } /* if */
	 
	 if( evt->addrEndText ) {  
	    /* !!! check for ".." here */
			if( evt->endAddrFunction == END_LEN_FUNC) {
	       if( !evt->addrStartText ) return(ER_STRESSED_OUT_SRVR);
	       end = strtoul(evt->addrEndText, &endPtr, 0);
	       if (*endPtr != '\0') return (ER_INVALID_DIGIT);
	       end += start;
			} /* if */
			else {
	       if((err=ConvTextToU32(evt->addrEndText,&end,TRUE))!=GOOD) 
		  return(err);
			} /* else */

	    if((err=TmpltSetValue(id,&evt->end,end))!=GOOD ) return(err);
	    if( !evt->addrStartText ) {
	       if((err=TmpltSetValue(id,&evt->start,end))!=GOOD ) return(err);
	    } /* if */
		 } /* if */
      }/**/
      /* 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 */
      } /* for */
      if(_lclose(hFile) == -1) return(ER_CANT_CLOSE_FILE);
      return(GOOD);
   } /* if */
   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 < MAX_EVENTS; idx++ ) {
	 EVENT_DEF *evt;
	 evt = &eventList[idx];
         if (evt->eventName[0]== '\0') continue;
	 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;

   event = (EVENT FAR *)id;
   if( !EventExists(eventName,&eventIdx) ) {
      RETCODE err;
      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. 
       */
//!! 186  if((err=EvtSetActiveField(id,"emon"))!= GOOD ) return(err);
//!! 186  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);
   if ( (err=Sds2AbiClearEvent(event->activeEvent)) != GOOD ) return(err);
   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);
   if ( (err=Sds2AbiClearEvent(event->activeEvent)) != GOOD ) return(err);
   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. *

      if( eventInUse ) {
	 if( tracing ) return(ER_TRACING_ON);
	 if( emulating!=EM_HALTED ) return(ER_TRIGGER_USING_EVENT);
      }
   }                         <Judy 2/3/1997> */
   for( idx = 0; idx < MAX_EVENTS; 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);
}

/*****************************************************************************
** 
**    EvtSetTrigEvent
** 
**    Description:
**       If the event selected by trigger, then put trigNo into
**       eventList[].eventName[].
**
*****************************************************************************/
RETCODE EXPORT EvtSetTrigEvent(U16 trigEvent, U8 trigNo) {
   int i;
   for (i=0; i<8; i++) {
       if (eventList[trigEvent].eventName[TRIG_EVENT_LEN+i]=='\0') {
          eventList[trigEvent].eventName[TRIG_EVENT_LEN+i]=trigNo;
          break;
       }
   }
   return GOOD;
}
/*****************************************************************************
** 
**    EvtClsTrigEvent
** 
**    Description:
**       To clear eventList[].eventName[MAX_NAME_LENGTH-1].
**
*****************************************************************************/
RETCODE EXPORT EvtClsTrigEvent() {
   U8 i,j;
   for(i=0; i<MAX_EVENTS; i++)
      for (j=0;j<8;j++)
          eventList[i].eventName[TRIG_EVENT_LEN+j]='\0';
   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 ) {
      if((err=TmpltGetValue(event->templateId,
		&eventList[event->activeEvent].start,
		&startValue)) != GOOD ) return(err);
      value = startValue;
   } 
   else {
       if( !isItAddr ||   /* data field or addr field and end addr func */
	  (eventList[event->activeEvent].endAddrFunction==END_ADDR_FUNC) ) {
	 if( (err=ConvTextToU32(end, &value, isItAddr)) != GOOD ) return(err);
	 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){
		    U8 length;
		    U32 maxValue;

		    /* Check to make sure the ending data value is not too large */
	    if ((err = TmpltGetNumBits(event->templateId, &length))
		       != GOOD) return(err);

		    if (length < 32) {
		       maxValue = (U32) ((1L<<length) - 1);
			   if (value > maxValue) return(ER_END_DATA_VALUE_TOO_BIG);
		    }
		 }
      }
      if( isItAddr && 
	 (eventList[event->activeEvent].endAddrFunction==END_LEN_FUNC) ) {
	 U32 startValue;
		 char *endPtr;
		 U8 length;
		 U32 maxValue;

	 /* We will now check to make sure that the starting value plus */
		 /* the length is not greater than the address allowed.         */
	 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 = strtoul(end, &endPtr, 0);
	 if (*endPtr != '\0') return (ER_INVALID_DIGIT);
	 value += startValue;

	 if ((err = TmpltGetNumBits(event->templateId, &length))
		    != GOOD) return(err);
		 if (length >= 32) {
		    if (value < startValue) return(ER_END_LENGTH_VALUE_TOO_BIG);
		 }
		 else {
		    maxValue = (U32) ((1L<<length) - 1);
			if (value > maxValue) return(ER_END_LENGTH_VALUE_TOO_BIG);
		 }
     }
   }
   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 = 0xfffffL;
      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;
   U32 startValue;
   BOOLEAN valChanged;

   err = GOOD;
   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 we have a mask value, but we do not have a starting address/data */
   /* value, this is an error condition. Go ahead and set the value to 0  */
   /* and return the error.                                               */
   if ((err=TmpltGetValue(event->templateId,
	&eventList[event->activeEvent].start,&startValue)) != GOOD)
		return(err);
   valChanged =
      (eventList[event->activeEvent].startChanged[event->activeGroup]
      || eventList[event->activeEvent].endChanged[event->activeGroup]);
   if ((value != 0) && ((startValue == 0) && !valChanged)) {
      value = 0;
      if( (err = TmpltSetValue(event->templateId,
	   &eventList[event->activeEvent].mask,
	   value)) != GOOD ) return(err);
      eventList[event->activeEvent].maskChanged[event->activeGroup] 
	 = FALSE;
	  return(ER_NO_START_VALUE_DEFINED);
   }
   if( (err = TmpltSetValue(event->templateId, 
	       &eventList[event->activeEvent].mask,
	       value)) != GOOD ) return(err);
   eventList[event->activeEvent].maskChanged[event->activeGroup] 
      = !blankingOut;
   return(err);
}

/*****************************************************************************
** 
**    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
**
**    This routine handles both the address start and data start fields.
*****************************************************************************/
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 (blankingOut) {
      /* If we blanked out the start value, blank out all the other fields */
	  /* as well. They are not valid without a start value.                */
      if( (err = TmpltSetValue(event->templateId, 
	       &eventList[event->activeEvent].start,
	       value)) != GOOD ) return(err);
      eventList[event->activeEvent].startChanged[event->activeGroup]= FALSE;
      if( (err = TmpltSetValue(event->templateId, 
	       &eventList[event->activeEvent].end,
	       value)) != GOOD ) return(err);
      eventList[event->activeEvent].endChanged[event->activeGroup]= FALSE;
      if( (err = TmpltSetValue(event->templateId, 
	       &eventList[event->activeEvent].mask,
	       value)) != GOOD ) return(err);
      eventList[event->activeEvent].maskChanged[event->activeGroup]= FALSE;

      /* Now set the addrStartText string to an empty string */
      if( isItAddr && ((err=HandleTextString(event,start,TRUE))!=GOOD) )
	 return(err);

      /* Now set the addrEndText string to an empty string */
      if( isItAddr && ((err=HandleTextString(event,start,FALSE))!=GOOD) )
	 return(err);
   }
   else {
      /* If we are dealing with a data value, then check to make sure */
      /* the value entered does not exceed the data value limit.      */
      if (!isItAddr) {
	 U8 length;
	     U32 maxValue;
	 if ((err = TmpltGetNumBits(event->templateId, &length))
		    != GOOD) return(err);
	     if (length < 32) {
		maxValue = (U32) ((1L<<length) - 1);
	    if (value > maxValue) return(ER_START_DATA_VALUE_TOO_BIG);
	     } /* if */
      } /* if */

      /* Set the start value */
      if( (err = TmpltSetValue(event->templateId, 
	       &eventList[event->activeEvent].start,
	       value)) != GOOD ) return(err);
	  /* Set the changed flag to indicate that we have a non blank value */
      eventList[event->activeEvent].startChanged[event->activeGroup]=TRUE;

      /* Now set the addrStartText string to the text in the start field */
      if( isItAddr && ((err=HandleTextString(event,start,TRUE))!=GOOD) )
	 return(err);

	 /* If the mask field is blank set it to all F's */
     if( !eventList[event->activeEvent].maskChanged[event->activeGroup] ) {
	 U32 maskValue = 0xfffffL;
		 
		 /* Set the mask value */
	 if((err=TmpltSetValue(event->templateId,
	       &eventList[event->activeEvent].mask,
	       maskValue)) != GOOD ) return(err);
      } /* if */

      /* If the end field is blank, set it to the start field value  */
      /* unless we are dealing with the address length, in that case */
	  /* default the length to 1.                                    */
      if( !eventList[event->activeEvent].endChanged[event->activeGroup] ) {
	 if( isItAddr ) {
	    if(eventList[event->activeEvent].endAddrFunction!=END_ADDR_FUNC){
			   value = 1;
	       if((err=TmpltSetValue(event->templateId,
		   &eventList[event->activeEvent].end,value)) != GOOD ) 
		  return(err);
	       if((err=HandleTextString(event,"1",FALSE))!=GOOD) 
		  return(err);
	       return(GOOD);  /* !!! this is borderline error condition. */
		    } /* if */
	 if((err=HandleTextString(event,
	    eventList[event->activeEvent].addrStartText,FALSE))!=GOOD) 
	    return(err);
	 } /* if */
	 if((err=TmpltSetValue(event->templateId,
	      &eventList[event->activeEvent].end,value)) != GOOD ) 
	    return(err);
      } /* if */
      else {
	 if(isItAddr 
	    && eventList[event->activeEvent].endAddrFunction==END_LEN_FUNC) {
	    U32 endLen;
		    char *endPtr;
		    U8 length;
		    U32 maxValue;
		    U32 startValue;

	    endLen = strtoul(eventList[event->activeEvent].addrEndText, &endPtr, 0);
	    if (*endPtr != '\0') return (ER_INVALID_DIGIT);
		    startValue = value;
	    value += endLen;

	    if ((err = TmpltGetNumBits(event->templateId, &length))
		       != GOOD) return(err);
		    if (length >= 32) {
		       if (value < startValue) return(ER_END_LENGTH_VALUE_TOO_BIG);
		    } /* if */
		    else {
		       maxValue = (U32) ((1L<<length) - 1);
		       if (value > maxValue) return(ER_END_LENGTH_VALUE_TOO_BIG);
		    } /* else */
	    if((err=TmpltSetValue(event->templateId,
		 &eventList[event->activeEvent].end,value)) != GOOD) return(err);
	 }/* if */
      } /* else */
   } /* else */      
   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();
   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));
}
/*****************************************************************************
** 
**    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);
}

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

/*************************** CLI FUNCTIONS ******************************/
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);
   }
   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 EXPORT 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 EXPORT 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);

      /* Modified by Dennis Lamb, May 23, 1994.                        */
      /* Changed this code to support 386 stuff. Call used to be:      */
	  /* if((err=AdrGetAddrOffset(addrDesc,value))!=GOOD) return(err); */
      if((err=AdrGetAddrPhysicalOffset(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);
   if( eventInUse && tracing ) return(ER_TRACING_ON);
   if((err=BkGetEmulationStatus(&emulating))!=GOOD) return(err);
   if( eventInUse && (emulating!=EM_HALTED) )
      return(ER_TRIGGER_USING_EVENT);    <Judy 2/3/1997> */
   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';
	  */
	  text[0] = '\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';
	  */
	  text[0] = '\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;
   }         
}

VOID GetBusData (U16 *data) {
   PROBE_TYPE specificProcessor;

   ProcReturnSpecificProcessor(&specificProcessor);
   switch (specificProcessor) {
      case I80C186_MP:
      case I80C186XL_MP:
      case I80C186EA_MP:
      case I80C186EB_MP:
      case I80C186EC_MP:
           *data = 0xffff;
        break;
      case I80C188_MP:
      case I80C188XL_MP:
      case I80C188EA_MP:
      case I80C188EB_MP:
      case I80C188EC_MP:
        *data = 0xff;
        break;
   }
}

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