/**********************************************************************
 * Copyright (c) 2005, 2007 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: filters.c,v 1.2 2007/04/06 00:39:06 jkubasta Exp $
 * 
 * Contributors: 
 * IBM - Initial API and implementation
 **********************************************************************/

/*
 *
 * Source File Name = filters.c
 *
 * Descriptive Name = Profiling Agent filter handling code
 *
 * Function:
 *           jvmpiAgent_initializeFilters
 *           jvmpiAgent_checkFilters
 *           parseFilterPattern
 *           jvmpiAgent_addFilter
 *           jvmpiAgent_applyFilters
 *           jvmpiAgent_processFilters
 *           jvmpiAgent_printFilters
 *
 *    Defines:
 *
 * Dependencies:
 *    None
 *
 * Restrictions:
 *    None
 *
 * Change Activity:
 * Defect Date        Who Description
 * ====== =========== === ==============================================
 *               2001 rkd Initial drop
 * 173995 May/15/2001 dns Fixed bugs causing heap corruption
 * 174190 May/30/2001 dns 390 Porting changes
 *
 ******************************************************************************/


#if (defined _HPUX || defined _AIX || defined _SOLARIS)
	#include <inttypes.h>
#elif defined __linux__
	#include <stdint.h>
#else
	#define INT32_MAX 2147483647
#endif


#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "filters.h"
#include "JvmpiWriter.h"
#include "print.h"
#include "utility.h"

static Filter *_jvmpiAgent_Filters = NULL;  /* Pointer to a list of active Filter elements 174190 made static */
static int _filterCount = 0; /* Number of active Filter elements in list */
static int _filterListSize = FILTER_LIST_INCREMENT; /* Current size (in # of Filter elements) of
                                                    the pending Filter element buffer */
static Filter *_filterListBuffer = 0; /* Pointer to a list of pending Filter elements */
static int _filterListBufferCount = 0; /* Number of pending Filter elements in list */
static char _pathDelimiter;

static Trigger    *_jvmpiAgent_Triggers     =NULL;
static Trigger    *_triggerListBuffer       =0;
static int         _triggerListBufferCount  =0;
static int         _triggerCount            =0;
static int         _triggerListSize         =TRIGGER_LIST_INCREMENT;

/* Start literal conversions from ebcdic to ascii for OS400 */ 
#ifdef __OS400__
#pragma convert(819) 
#endif

/*
 This function initializes the data structures used by the filter mechanism.
*/
void jvmpiAgent_initializeFilters(char pathDelimiter)
{
 _jvmpiAgent_Filters = (Filter *)jvmpiAgent_Calloc(sizeof(Filter)*FILTER_LIST_INCREMENT);
 _filterListBuffer = (Filter *)jvmpiAgent_Calloc(sizeof(Filter)*FILTER_LIST_INCREMENT);
 _pathDelimiter = pathDelimiter;
}


/** str_fits_ptrn *********************************************************************************
  * This function returns a non-zero value if the string matches the pattern, or a zero.  The
  * input pointers can be empty srings, but cannot be NULL.  All strings and patterns, including
  * the empty ones are handled properly.
  *
  * @param str          the string to match the pattern
  * @param ptrn         the pattern to match the string
  * @param ptrn_type    the type of the pattern
  * @param ptrn_len     the length of the pattern
  * @returns    a non-zero value if the string fits into the pattern, or zero otherwise.
  */
int str_fits_ptrn(const char* str, const char* ptrn, const int ptrn_type, const int ptrn_len) {
    int off; /* the offset of the start of comparison in a prefix match */

	if (str == 0 || ptrn == 0) {
		return 0; 
	}

    /* A zero-length (empty) pattern matches all strings including the empty ones.  Otherwise, an exact
       match, prefix, or suffix match will be performed.  The first case is really not really a special
       case as it has already been coverted under the other three.  So, this case is really included
       for clarity purposes only.  */
    return !ptrn_len ||
           (ptrn_type == NONE && !strcmp(ptrn, str)) ||
           (ptrn_type == PREFIX && (off = strlen(str) - ptrn_len) >= 0 && !strcmp(ptrn, str + off)) ||
           (ptrn_type == SUFFIX && !strncmp(ptrn, str, ptrn_len));
}


/** match_mthd_fltr *******************************************************************************
  * This function returns the first method filter from the class filter list, matching the method
  * name.
  *
  * @param mthd_fltr_lst        the method filter list from which a match is searched
  * @param mthd_fltr_lst_len    the length of the above list
  * @param mthd_name            the method name to match
  * @returns    the first matching method filter, or NULL if none is found.
  */
MethodFilter_t *match_mthd_fltr(MethodFilter_t *mthd_fltr_lst, const unsigned int mthd_fltr_lst_len, const char *mthd_name) {
    unsigned int i; /* the loop control variable */
    MethodFilter_t *mthd_fltr; /* a method filter from a class filter */

    /* Iterate through the method filter list to find the first matching method filter. */
    for (i = 0; i < mthd_fltr_lst_len; i++) {

        mthd_fltr = mthd_fltr_lst + i;
        if (str_fits_ptrn(mthd_name, mthd_fltr -> pattern, mthd_fltr -> genericPattern, mthd_fltr -> patternLength)) {
            return mthd_fltr;
        }
    }
    return NULL;
}


/** match_cls_mthd_fltr ***************************************************************************
  * This function returns the first class filter from the class filter list, matching the class
  * and method names.  If the method name supplied is an empty string, the first matching class
  * filter with a wildcard method filter will be picked.
  *
  * @param cls_fltr_lst     the class filter list from which a match is searched
  * @param cls_fltr_lst_len the length of the above list
  * @param cls_name         the class name to match
  * @param mthd_name        the method name to match
  * @returns    the first matching class filter, or NULL if none is found.
  */
Filter *match_cls_mthd_fltr(Filter *cls_fltr_lst, int cls_fltr_lst_len, char *cls_name, char *mthd_name) {
    int i; /* the loop control variable */
    Filter *cls_fltr; /* a class filter from the filter list */
    MethodFilter_t *mthd_fltr; /* a method filter from a class filter */
	char *reg_cls_name; /* the class name without JNI style array notation */ 

	/* bugzilla 70263 - remove the array notation from the front of a class name so we filter 
	array classes as well. For example, if the class name is '[[Ljava.lang.Thread', the
	following code will set reg_cls_name to 'java.lang.Thread'. */ 

#ifdef __OS400__
#pragma convert(819)
#endif 
	reg_cls_name = strrchr(cls_name,'['); /* returns the last occurence of '[' */ 
	if (reg_cls_name != NULL && reg_cls_name[1] == 'L') {
		reg_cls_name += 2; /* skip to the point after the 'L' */ 
	} else {
		reg_cls_name = cls_name; 
	}
#ifdef __OS400__
#pragma convert(0)
#endif 


    /* Iterate through the class filter list to find the first filter matching the class and method names. */
    for (i = 0; i < cls_fltr_lst_len; i++) {

        cls_fltr = cls_fltr_lst + i;
        if (!str_fits_ptrn(reg_cls_name, cls_fltr -> pattern, cls_fltr -> genericPattern, cls_fltr -> patternLength)) {
            continue;
        }
        mthd_fltr = match_mthd_fltr(cls_fltr -> methodDetails, cls_fltr -> methodDetailCount, mthd_name);
        if (mthd_fltr) {
            return cls_fltr;
        }
    }
    return NULL;
}


/** jvmpiAgent_getFilter **************************************************************************
  * This function returns the first class filter that matches the class and method names.
  *
  * @param cls_name     the class name to match
  * @param mthd_name    the method name to match
  * @returns    the first matching class filter, or NULL if none is found.
  */
Filter *jvmpiAgent_getFilter(char *cls_name, char *mthd_name) {

    return match_cls_mthd_fltr(_jvmpiAgent_Filters, _filterCount, cls_name, mthd_name);
}


/** jvmpiAgent_getClassFilterMode *****************************************************************
  * This function determines whether a class is to be INCLUDED or EXCLUDED.  This can occur if
  * the class filter has a wildcard method filter, or if the class filter itself is NULL, i.e.,
  * the class does not match any existing filter.
  *
  * @param cls_fltr the matching filter for this class
  * @returns    INCLUDE or EXCLUDE as is appropriate.
  */
enum FilterMode jvmpiAgent_getClassFilterMode(Filter *cls_fltr) {
    MethodFilter_t *mthd_fltr; /* the method filter for the default methods */

    mthd_fltr = cls_fltr ? match_mthd_fltr(cls_fltr -> methodDetails, cls_fltr -> methodDetailCount, "") : NULL;
    return mthd_fltr ? mthd_fltr -> mode : INCLUDE;
}


/** jvmpiAgent_checkMethodFilters *****************************************************************
  * This function determines whether a method is to be INCLUDED or EXCLUDED.  This can occur if
  * the class filter has a matching method filter, or if the class filter itself is NULL, i.e.,
  * the class does not match any existing filter.
  *
  * @param mthd_name    the method name to match
  * @param cls_fltr     the matching filter for this class
  * @returns    INCLUDE or EXCLUDE as is appropriate.
  */
int jvmpiAgent_checkMethodFilters(char *mthd_name, Filter *cls_fltr) {
    MethodFilter_t *mthd_fltr; /* the method filter for the default methods */

    mthd_fltr = cls_fltr ? match_mthd_fltr(cls_fltr -> methodDetails, cls_fltr -> methodDetailCount, mthd_name) : NULL;
    return (mthd_fltr ? mthd_fltr -> mode : INCLUDE);
}


/*
 This function takes a filterpattern and determines if it is a prefix (leading "*"), suffix (trailing "*"), or
 exact match (no "*") type pattern.  It returns the type and adjusts the pointer to the filterPattern buffer
 to exclude the "*")
*/
static enum GenericPattern parseFilterPattern(char ** filterPattern)
{
 enum GenericPattern genericPattern;

 char *p = strchr(*filterPattern, '*');
 if(_setPathDelimiter)
 {
	_pathDelimiter = _setPathDelimiter;
 }
 if (p == NULL)
 {
  genericPattern = NONE;
 }
 else if (p == *filterPattern)
 {
  genericPattern = PREFIX;
  (*filterPattern)++; /* Bump the buffer pointer past the "*" */
 }
 else if (p == (*filterPattern + strlen(*filterPattern)-1))
 {
  genericPattern = SUFFIX;
  *p = '\0'; /* Truncate the buffer to eliminate the "*" */
 }
 else
 {
  /* Error "*" found imbedded within pattern */
  genericPattern = NONE;
 }

 /*
  Translate the path delimiter character specified in the filterPattern to the path delimiter
  character used by the current JVM (this value was specified during filter initialization.
 */
 if (_pathDelimiter == '.')
 {
  int i;
  for (i=strlen(*filterPattern)-1; i >= 0; i--)
  {
   if ((*filterPattern)[i] == '/') (*filterPattern)[i] = '.';
  }
 }
 else if (_pathDelimiter == '/')
 {
  int i;
  for (i=strlen(*filterPattern)-1; i >= 0; i--)
  {
   if ((*filterPattern)[i] == '.') (*filterPattern)[i] = '/';
  }
 }
 return genericPattern;

}


/** get_cls_fltr **********************************************************************************
  * This function returns a matching class filtering from the class filter list provided,
  * or a NULL pointer if none is found.  Matching filters must share the same filter pattern,
  * type, and length.
  *
  * @param cls_fltr_lst     the class filter list from which a match is searched
  * @param cls_fltr_lst_len the length of the above list
  * @param cls_ptrn         the class pattern to match
  * @param cls_ptrn_type    the type of the class pattern to match
  * @param cls_ptrn_len     the length of the class pattern to match
  */
Filter *get_cls_fltr(Filter *cls_fltr_lst, unsigned int cls_fltr_lst_len,
                     char *cls_ptrn, enum GenericPattern cls_ptrn_type, unsigned int cls_ptrn_len) {
    unsigned int i; /* the loop control variable */
    Filter *cls_fltr; /* a class filter from the filter list */

    for (i = 0; i < cls_fltr_lst_len; i++) {

        cls_fltr = cls_fltr_lst + i;
        if (cls_fltr -> patternLength == cls_ptrn_len &&
            cls_fltr -> genericPattern == cls_ptrn_type &&
            !strcmp(cls_fltr -> pattern, cls_ptrn)) {
            return cls_fltr;
        }
    }
    return NULL;
}


/** get_mthd_fltr *********************************************************************************
  * This function returns a matching method filtering from the method filter list provided,
  * or a NULL pointer if none is found.  Matching filters must share the same filter pattern,
  * type, and length.
  *
  * @param mthd_fltr_lst        the method filter list from which a match is searched
  * @param mthd_fltr_lst_len    the length of the above list
  * @param mthd_ptrn            the method pattern to match
  * @param mthd_ptrn_type       the type of the method pattern to match
  * @param mthd_ptrn_len        the length of the method pattern to match
  */
MethodFilter_t *get_mthd_fltr(MethodFilter_t *mthd_fltr_lst, unsigned int mthd_fltr_lst_len,
                              char *mthd_ptrn, enum GenericPattern mthd_ptrn_type, unsigned int mthd_ptrn_len) {
    unsigned int i; /* the loop control variable */
    MethodFilter_t *mthd_fltr; /* a method filter from the filter list */

    for (i = 0; i < mthd_fltr_lst_len; i++) {
        mthd_fltr = mthd_fltr_lst + i;
        if (mthd_fltr -> patternLength == mthd_ptrn_len &&
            mthd_fltr -> genericPattern == mthd_ptrn_type &&
            !strcmp(mthd_fltr -> pattern, mthd_ptrn)) {
            return mthd_fltr;
        }
    }
    return NULL;
}


/** jvmpiAgent_addFilter **************************************************************************
  * This function appends a new filter using the class and method patterns with the filtering
  * mode.  The filters are saved in an ordered list, and the order in which they are inserted
  * makes a difference.  The filters will not be used until they are applied by calling
  * jvmpiAgent_ApplyFilters().  NULL, empty strings, and '*'s are all treated as wildcard
  * characters.
  *
  * @param cls_ptrn     the pattern to match a class
  * @param mthd_ptrn    the method pattern to match
  * @param mode         whether the method will be INCLUDED or EXCLUDED
  */
void jvmpiAgent_addFilter(char *cls_ptrn, char *mthd_ptrn, enum FilterMode mode) {
    Filter *cls_fltr; /* the class filter to add or modify */
    MethodFilter_t *mthd_fltr; /* the method filter to add or modify */
    enum GenericPattern cls_ptrn_type, mthd_ptrn_type; /* the class and method pattern types */
    unsigned int cls_ptrn_len, mthd_ptrn_len; /* the class and method pattern lengths */

#ifdef MVS                    /* 174190 */
    if (cls_ptrn != NULL) {
        __etoa(cls_ptrn);
    }
    if (mthd_ptrn != NULL) {
       __etoa(mthd_ptrn);
    }
#elif __OS400__
	if (cls_ptrn != NULL) {
       cls_ptrn = as400_etoa(cls_ptrn);
    }
    if (mthd_ptrn != NULL) {
       mthd_ptrn = as400_etoa(mthd_ptrn);
    }
#endif

    /* Ensure that NULL pointers are replaced with empty strings to eliminate special cases. */
    if (cls_ptrn == NULL) {
        cls_ptrn = "";
    }
    if (mthd_ptrn == NULL) {
        mthd_ptrn = "";
    }

    /* Try to locate an existing class filter.  Create a new class filter if none found. */
    cls_ptrn_type = parseFilterPattern(&cls_ptrn);
    cls_ptrn_len = strlen(cls_ptrn);
    cls_fltr = get_cls_fltr(_filterListBuffer, _filterListBufferCount, cls_ptrn, cls_ptrn_type, cls_ptrn_len);
    if (!cls_fltr) {

        /* Enlarge the filter buffer if necessary. */
        if (_filterListBufferCount >= _filterListSize) {
            _filterListSize += FILTER_LIST_INCREMENT;
            _filterListBuffer = (Filter *) realloc(_filterListBuffer, _filterListSize);
        }

        /* Create the class filter for this method. */
        cls_fltr = _filterListBuffer + _filterListBufferCount;
        cls_fltr -> genericPattern = cls_ptrn_type;
        cls_fltr -> patternLength = cls_ptrn_len;
        cls_fltr -> pattern = (char *) jvmpiAgent_Calloc(cls_ptrn_len + 1);
        strcpy(cls_fltr -> pattern, cls_ptrn);
        cls_fltr -> methodDetailCount = 0;
        _filterListBufferCount++;

    } else if (cls_fltr -> methodDetailCount >= MAX_METHOD_FILTERS_PER_CLASS) {

        /* If there is no more room for the method filter, the filter will be dropped. */
        return;
    }

    /* If there already exists an identical filter, then the new filter will be ignored. */
    mthd_ptrn_type = parseFilterPattern(&mthd_ptrn);
    mthd_ptrn_len = strlen(mthd_ptrn);
    mthd_fltr = get_mthd_fltr(cls_fltr -> methodDetails, cls_fltr -> methodDetailCount,
        mthd_ptrn, mthd_ptrn_type, mthd_ptrn_len);
    if (mthd_fltr) {
        return;
    }

    /* Insert the method filter into the class filter. */
    mthd_fltr = cls_fltr -> methodDetails + cls_fltr -> methodDetailCount;
    mthd_fltr -> genericPattern = mthd_ptrn_type;
    mthd_fltr -> patternLength = mthd_ptrn_len;
    strcpy((mthd_fltr -> pattern = (char *) jvmpiAgent_Calloc(mthd_ptrn_len + 1)), mthd_ptrn);
    mthd_fltr -> mode = mode;
    cls_fltr -> methodDetailCount++;
}


/* PR */
void jvmpiAgent_changeDelimiter()
{

 int i;
 char sunch = '.';
 char *tempFilterPattern;
 memcpy(_filterListBuffer, _jvmpiAgent_Filters, _filterCount * sizeof(Filter));
 for (i=0; i < _filterCount; i++)
 {
  int j = 0;
  tempFilterPattern = _filterListBuffer[i].pattern;
  for (j=strlen(tempFilterPattern)-1; j >= 0; j--)
  {
   if(_setPathDelimiter == sunch)
   {
	   if(tempFilterPattern[j] == '/')
	   {
		   (tempFilterPattern[j] = sunch);
	   }
   }
  }
   strcpy(_filterListBuffer[i].pattern, tempFilterPattern);
 }
 jvmpiAgent_applyFilters();

}
/* PR */

/*
 This function is used to replace the current set of filters with the pending set of filters.
*/
void jvmpiAgent_applyFilters()
{
 int i;
 if (!_filterListBufferCount) return; /* Empty list so this may be an extaneous apply, so ignore it */

 for (i=0; i < _filterCount; i++)  /* 173995 - replaced _filterListBufferCount with _filterCount for loop upper bound */
 {
#ifndef _DEBUG
  free(_jvmpiAgent_Filters[i].pattern);
#endif
  _jvmpiAgent_Filters[i].pattern=NULL;
 }
 free(_jvmpiAgent_Filters);
 _jvmpiAgent_Filters=NULL;
 _jvmpiAgent_Filters = (Filter *)jvmpiAgent_Calloc(sizeof(Filter)*_filterListSize);
 memcpy(_jvmpiAgent_Filters, _filterListBuffer, _filterListBufferCount * sizeof(Filter));
 _filterCount = _filterListBufferCount;
 _filterListBufferCount = 0;
 memset(_filterListBuffer, '\0', sizeof(Filter)*_filterListSize);

 /* After the filter process, we need to set the tracing flags of the primitive classes */
 jvmpiAgent_SetTracingFlagsOnPrimitives();
}


int jvmpiAgent_processFilters(char * fileName) {
	FILE * filterFile = NULL;
	char classPattern[250];
	char methodPattern[250];
	char mode[100];

#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
	__atoe(fileName);
#elif __OS400__
#pragma convert(0)
#endif
	filterFile = fopen(fileName, "r");
	if (!filterFile) return -1;

	while (fscanf(filterFile, "%s %s %s\n", classPattern, methodPattern, mode) != EOF) {
		jvmpiAgent_addFilter(classPattern, methodPattern, strcmp("INCLUDE", mode) == 0 ? INCLUDE : EXCLUDE);
	}
	fclose(filterFile);
#ifdef MVS                    /* 174190 */
#pragma convlit(resume)
#elif __OS400__
#pragma convert(819)
#endif

	jvmpiAgent_applyFilters();
	return 0;
}


void jvmpiAgent_printFilters()
{
 int i;
 for (i=0; i < _filterCount; i++)
 {
  jvmpiAgent_printFilter(jvmpiAgent_getThreadLocalStorage(0), &_jvmpiAgent_Filters[i]);
 }
}


void jvmpiAgent_initializeTriggers(char pathDelimiter) {
	_jvmpiAgent_Triggers = (Trigger *)jvmpiAgent_Calloc(sizeof(Trigger)*TRIGGER_LIST_INCREMENT);
	_triggerListBuffer = (Trigger *)jvmpiAgent_Calloc(sizeof(Trigger)*TRIGGER_LIST_INCREMENT);
	_pathDelimiter = pathDelimiter;
}


int jvmpiAgent_processTriggers(char *filename) {
	FILE * triggerFile = NULL;
	char methodname[256];
	char classname[1024];
	int count;

#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
	__atoe(filename);
#elif __OS400__
#pragma convert(0)
#endif
	triggerFile = fopen(filename, "r");
	if(!triggerFile) {
		return -1;
	}

	while (fscanf(triggerFile, "%s %s %d\n", methodname, classname, &count) != EOF)  {
	  /* printf("Processing Trigger: %s %s %d\n", methodname, classname, count); */
	  jvmpiAgent_addTrigger(methodname, classname, count);
	}

	fclose(triggerFile);
#ifdef MVS                    /* 174190 */
#pragma convlit(resume)
#elif __OS400__
#pragma convert(819) 
#endif
	jvmpiAgent_applyTriggers();
	return 0;
}

int jvmpiAgent_checkTrigger(char *classname, char *methodname) {
  int i;
  for (i=0; i < _triggerCount; i++)  {
    Trigger *tp = &_jvmpiAgent_Triggers[i];
    if ((tp->methodname[0] == '*' || !strcmp(tp->methodname, methodname))
	&& (tp->classname[0] == '*' || !strcmp(tp->classname, classname))) {
      
      return tp->count;
      
    }
  }
  return INT32_MAX;
}

int jvmpiAgent_addTrigger(char *methodname,
			  char *classname,
			  int count)
{
	if (_triggerListBufferCount >= _triggerListSize) {
		/* Reallocate a larger buffer for the filters */
		_triggerListSize += TRIGGER_LIST_INCREMENT;
		_triggerListBuffer = (Trigger *)realloc(_triggerListBuffer, _triggerListSize);
	}

#ifdef MVS                    /* 174190 */
	__etoa(methodname);
	__etoa(classname);
#elif __OS400__
	if (methodname != NULL) {
		methodname = as400_etoa(methodname);
	}
	if (classname != NULL) {
		classname = as400_etoa(classname); 
	}
#endif

	/* Set the length of the pattern and allocate and set the pattern into the list of pending filters */
  _triggerListBuffer[_triggerListBufferCount].methodnameLength =
    strlen(methodname);
  STRDUP(_triggerListBuffer[_triggerListBufferCount].methodname,
	 methodname); /* 236501 */
  _triggerListBuffer[_triggerListBufferCount].classnameLength =
    strlen(classname);
  STRDUP(_triggerListBuffer[_triggerListBufferCount].classname,
	 classname);
  _triggerListBuffer[_triggerListBufferCount].count = count;
  _triggerListBufferCount++;
	return 0;
}

void jvmpiAgent_applyTriggers() {
	int i;
	if (!_triggerListBufferCount) {
		return; /* Empty list so this may be an extaneous apply, so ignore it */
	}

	for (i=0; i < _triggerCount; i++) {
		free(_jvmpiAgent_Triggers[i].methodname);
		_jvmpiAgent_Triggers[i].methodname=NULL;
		free(_jvmpiAgent_Triggers[i].classname);
	    _jvmpiAgent_Triggers[i].classname=NULL;
	}
	free(_jvmpiAgent_Triggers);
	_jvmpiAgent_Triggers=NULL;

	_jvmpiAgent_Triggers = (Trigger*)jvmpiAgent_Calloc(sizeof(Trigger)*_triggerListSize);
	memcpy(_jvmpiAgent_Triggers, _triggerListBuffer, _triggerListBufferCount * sizeof(Trigger));
	_triggerCount = _triggerListBufferCount;
	_triggerListBufferCount = 0;
	BZERO(_triggerListBuffer, sizeof(Trigger)*_triggerListSize);
}
/* stop literal conversions from ebcdic to ascii for as400 */ 
#ifdef __OS400__
#pragma convert(0) 
#endif
