/**********************************************************************
 * 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: options.c,v 1.2 2007/04/06 00:43:18 jkubasta Exp $
 *
 * Contributors:
 * IBM - Initial API and implementation
 **********************************************************************/

#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#ifdef _WIN32
#include <io.h>
#include <direct.h>
#define MKDIR(dirname) mkdir(dirname)
#else
#define MKDIR(dirname) mkdir((dirname), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
#endif

#include "options.h"
#include "filters.h"
#include "JvmpiWriter.h"
#include "eventmask.h"
#include "print.h"
#include "utility.h"

/**
  * MACROS
  * To make the code more readable ;-)
  */
#ifdef _WIN32
 #define STRICOLL _stricoll		/* Case insensitive on Windows */
#else
 #define STRICOLL strcoll		/* Case sensitive on other platforms */
#endif

/* following two undefs were added to avoid conflict from new java.h defs ... 135623 */
#undef ATTACH_THREAD
#undef DETACH_THREAD

#if defined __cplusplus && defined _HPUX
  #define ENV(e) e
 #define ATTACH_THREAD(env) (_jvmpiAgent_jvm)->AttachCurrentThread((void**)&env, NULL)
 #define DETACH_THREAD() (_jvmpiAgent_jvm)->DetachCurrentThread()
 #define ENVPARM(env)
#else
 #define ENV(e) (*e)
 #define ATTACH_THREAD(env) (*_jvmpiAgent_jvm)->AttachCurrentThread(_jvmpiAgent_jvm,  (void**)&env, NULL)
 #define DETACH_THREAD() (*_jvmpiAgent_jvm)->DetachCurrentThread(_jvmpiAgent_jvm)
  #define ENVPARM(env) env,
#endif

#define BOOLTOSTRING(b) (b ? "true" : "false")


#ifdef MVS
#pragma convlit(suspend)
#endif
static const char* piAgentVersion= "@(#)piAgent version 6.0.0.0";
#ifdef MVS
#pragma convlit(resume)
#endif

/** Globals
  */
Options _jvmpiAgent_Options =
{
  0							/* Do not output Unreferenced Symbols */
 ,1							/* Provide timestamps by default */
 ,0							/* Debug Hash table option */
 ,0							/* Standalone mode */
 ,0							/* Application mode */
 ,1							/* Enabled mode */
 ,0							/* TraceExceptions */
 ,0							/* EnableExceptions - MW Changed the default to "no" */
 ,0							/* enableLineCoverage -  */
 ,0                         /* CollationValues  */
 ,1                         /* Filters */
 ,1                         /* Options */
 ,0                         /* TraceIdrefs  */
 ,1                         /* GcDefaults */
 ,0                         /* MethodCounts  */
 ,0                         /* ClassLoadDetails */
 ,0 						/* MethodDetail */
 ,1                         /* OBJ_ALLOC_IS_ARRAY (default) */
 ,0                         /* CONTEXT_FLOW */
 ,1                         /* TICKET (default) */
 ,0							/* MODE SET */
 ,0							/* EXCEPTION TRACING SET */
 ,0							/* LINE COVERAGE SET */
 ,0							/* GC SET */
 ,0							/* HEAP INFO COUNT SET */
 ,0							/* HEAP INFO FILE PREFIX SET */
 ,0							/* Jinsight I/O */
 ,0							/* cpuTime */
 ,0							/* LLDATA_ENABLED */
 ,IdStyleStatic
 ,Filter4Owner				/* Heap dump preference (default) */
 ,GcDeletes
 ,StackInfoContiguous		/* Stack mode preference (default) */
 ,CompressNone              /* Compression level (default) */ /* 140009 */ 
 /* ,HeapInfoAll -- Depreciated */
 ,TraceModeFull
 ,TraceStartModeFilter	
 ,BurstModeNone	
 ,MonitorNone
 ,0							/* Burst timer */
 ,0							/* Burst invocations */
 ,1							/* boundary depth */
 ,2							/* heapInfoCount */
 #ifdef _HPUX
 ,{(enum _dataTarget)0,0}	/* Target Handle initialization - 171664 initialize to RA_SOCKET (0) type */
 #else
 ,{0,0}						/* Target Handle initialization - 171664 initialize to RA_SOCKET (0) type */
 #endif
 , NULL						/* The invocation options from the command line */
 , NULL						/* Filter File  (to be initialized) */
 , NULL						/* Triggers file (to be initialized) */
 , NULL						/* Default process name (to be initialized) */
 , NULL						/* Default process type (to be initialized) */
 , NULL						/* Default trace file name (to be initialized) */
 , NULL						/* heapInfoFilePrefix (to be initialized) */
 , NULL						/*Default profile file name (to be initialized) */
 , NULL						/* Defualt working dir (to be initialized) */
 , NULL						/* agent extension library name to load (empty means none) (to be initialized) */
 , NULL                     /* currently no unknown options */ 
 , 0                        /* method_counts_only is off by default */ 
};

#define DEFAULT_FILTER_FILENAME		"filters.txt"
#define DEFAULT_TRIGGER_FILENAME	"triggers.txt"
#define DEFAULT_PROCESS_NAME		"Java Profiling Agent"
#define DEFAULT_PROCESS_TYPE		"Profiler"
#define DEFAULT_OUTPUT_FILENAME		"trace.trcxml"
#define DEFAULT_HEAPINFO_FILEPREFIX "optHeap"
#define DEFAULT_PROFILE_FILE		"jvmpi.pro"
#define DEFAULT_WORK_DIR			"."
#define DEFAULT_EXTENSION_LIBRARY	""

void initializeJvmpiAgentOptionsDefaults() {
	/* initialize filterFileName */ 
	_jvmpiAgent_Options.filterFileName = (char *) malloc(strlen(DEFAULT_FILTER_FILENAME)+1);
	strcpy(_jvmpiAgent_Options.filterFileName,DEFAULT_FILTER_FILENAME);

	/* initialize trigger filename */ 
	_jvmpiAgent_Options.triggerFileName = (char *)malloc(strlen(DEFAULT_TRIGGER_FILENAME)+1);
	strcpy(_jvmpiAgent_Options.triggerFileName, DEFAULT_TRIGGER_FILENAME); 

	/* initialize process name */ 
	_jvmpiAgent_Options.processName = (char *)malloc(strlen(DEFAULT_PROCESS_NAME)+1); 
	strcpy(_jvmpiAgent_Options.processName,DEFAULT_PROCESS_NAME); 

	/* initialize process type */
	_jvmpiAgent_Options.processType = (char *)malloc(strlen(DEFAULT_PROCESS_TYPE)+1); 
	strcpy(_jvmpiAgent_Options.processType,DEFAULT_PROCESS_TYPE); 

	/* initialize output file */ 
	_jvmpiAgent_Options.outputFileName = (char *)malloc(strlen(DEFAULT_OUTPUT_FILENAME)+1);
	strcpy(_jvmpiAgent_Options.outputFileName,DEFAULT_OUTPUT_FILENAME);

	/* initialize the heap info file prefix */ 
	_jvmpiAgent_Options.heapInfoFilePrefix = (char *)malloc(strlen(DEFAULT_HEAPINFO_FILEPREFIX)+1);
	strcpy(_jvmpiAgent_Options.heapInfoFilePrefix,DEFAULT_HEAPINFO_FILEPREFIX); 

	/* intiialize the profile file */ 
	_jvmpiAgent_Options.profileFile = (char *)malloc(strlen(DEFAULT_PROFILE_FILE)+1); 
	strcpy(_jvmpiAgent_Options.profileFile,DEFAULT_PROFILE_FILE);

	/* initiailize the working dir */ 
	_jvmpiAgent_Options.workDir = (char *)malloc(strlen(DEFAULT_WORK_DIR)+1); 
	strcpy(_jvmpiAgent_Options.workDir,DEFAULT_WORK_DIR); 

	/* initialize the extension library */ 
	_jvmpiAgent_Options.extensionLibrary = (char *)malloc(strlen(DEFAULT_EXTENSION_LIBRARY)+1); 
	strcpy(_jvmpiAgent_Options.extensionLibrary,DEFAULT_EXTENSION_LIBRARY); 

}

static int getToken(char **src, char *buf, int buflen, char sep)
{
 int i;
 char *p = *src;
 for (i = 0; i < buflen; i++)
 {
   if (p[i] == 0 || p[i] == sep)
   {
     buf[i] = 0;
     if (p[i] == sep)
     {
       i++;
     }
	  *src += i;
	  return i;
   }
   buf[i] = p[i];
 }
 /* overflow */
 return 0;
}


/** PRINT_USAGE **********************************************************************
  * Print the command line useage of the program.
  */
void printUsage()
{
#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
#endif
	fprintf(stdout,
	"\n%s\n"
    "usage: -XrunpiAgent[:[help]|[<option>=<value>, ...]]\n"
    "\n"
    "Option Name and Values\tDescription (Default value)\n"
    "----------------------\t---------------------------\n"
    "file=<file>\t\tName of output file.  Only used when server=standalone.(trace.trcxml)\n"
    "filters=<file>\t\tName of filter definitions.  Only used when server=standalone.(filters.txt)\n"
#if 0
    "profile=<file>\t\tname of profile file.  Only used when server=standalone.(jvmpi.pro)\n"
#ifdef _DEBUG
    "debug=hash\t\toutputs the specified debugging information. (disabled in production build)\n"
#endif
#endif
	"mode=full|noObjectCorrelation|sampling|heap|optHeap\tCollect object execution information?.(full)\n"
	"server=standalone|enabled|controlled|application\tSpecifies how the Agent is to be run.(enabled)\n"
#if 0
    "enableExceptionTracing=yes|no\tEnable JVM Exception tracing.(no)\n"
	"enableLineCoverage=no|yes\tEnable Line coverage.(no)\n"
#endif
	"trackGcEvent=default|none|moves|frees|movesAndFrees\t Specifies the GC events that need to be tracked\n"
	"optHeapCount\tSpecifies the number of heap dumps in each cycle, default 2, maximum 50\n"
	"optHeapFilePrefix\tSpecifies the prefix of heap dump files (optHeap)\n"
	"extensionLibrary\tSpecifies an agent extension library path and name to load in stand-alone mode\n"
    "Example: java -XrunpiAgent:file=log.trcxml <classname>\n"
	"\n", piAgentVersion);
	fflush(stdout); 
#ifdef MVS                    /* 174190 */
#pragma convlit(resume)
#endif
}

/** STRIP_LEADING_BLANKS **************************************************************
  * Remove all spaces from the beginning of a buffer
  */
static char * stripLeadingBlanks(char * buffer)
{
 int i;
 int len = strlen(buffer);
 for (i = 0; i <= len; i++)
 {
  if (!isspace(buffer[i]))
  {
   return buffer+i;
  }
 }
 return buffer;
}



#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
#endif

static int setBooleanOption(char * value, char * key, int defaultValue)
{
 if (STRICOLL(value, "true") == 0)
  {
   return 1;
  }
  else if(STRICOLL(value, "false") == 0)
  {
   return 0;
  }
  else
  {
   fprintf(stderr, "Invalid %s option value \"%s\"\n", key, value);
   fflush(stderr); 
   return defaultValue;
  }
}

#ifdef MVS                    /* 174190 */
#pragma convlit(resume)
#endif

/* Piyush Agarwal 
   Get the absolute directory path for the optheap working dir*/
static void jvmpiAgent_getWorkDir(char* buf)
{
/* Bug 64476 */
#ifdef MVS
#pragma convlit(suspend)
#endif
#ifdef MVS
__atoe(_jvmpiAgent_Options.workDir) ;
#endif
	realpath(_jvmpiAgent_Options.workDir,buf);
	buf += strlen(buf);
#ifdef MVS
__etoa(_jvmpiAgent_Options.workDir) ;
#endif
#ifdef _WIN32
	*buf = '\\'; /* file delim in Windows */
#else
	*buf = '/'; /* file delim in Unix */
#endif
	buf += 1; *buf = '\0';
#ifdef MVS
#pragma convlit(resume)
#endif

}

/** PRINT_OPTIONS *********************************************************************
  *
  */
void jvmpiAgent_printOptions()
{
 char fulldirpath[PATH_MAX];
 ThreadPrivateStorage *tps=jvmpiAgent_getThreadLocalStorage(0);

 jvmpiAgent_PrintOption(tps, "CLASS_LOAD_DETAILS", BOOLTOSTRING(_jvmpiAgent_Options.classLoadDetails));
 jvmpiAgent_PrintOption(tps, "METHOD_DETAILS", BOOLTOSTRING(_jvmpiAgent_Options.methodDetails));
 jvmpiAgent_PrintOption(tps, "COLLATION_VALUES", BOOLTOSTRING(_jvmpiAgent_Options.collationValues));
 jvmpiAgent_PrintOption(tps, "CONTEXT_FLOW", BOOLTOSTRING(_jvmpiAgent_Options.contextFlow));
#if 0
 jvmpiAgent_PrintOption(tps, "EXCEPTION_TRACING", BOOLTOSTRING(_jvmpiAgent_Options.traceExceptions));
#endif
 jvmpiAgent_PrintOption(tps, "FILTERS", BOOLTOSTRING(_jvmpiAgent_Options.filters));
 /* "GC" is depreciated */
 jvmpiAgent_PrintOption(tps, "TRACK_GC_EVENT_TYPES", _jvmpiAgent_Options.gc == GcNone ? "none" : _jvmpiAgent_Options.gc == GcDeletes ? "frees" : _jvmpiAgent_Options.gc == GcMoves ? "moves" : "freesAndMoves");
 jvmpiAgent_PrintOption(tps, "ID_STYLE", _jvmpiAgent_Options.idStyle == IdStyleStatic ? "static" : _jvmpiAgent_Options.idStyle == IdStyleRelocatable ? "relocatable" : "staticAndRelocatable");
 jvmpiAgent_PrintOption(tps, "OBJ_REF_MODE", _jvmpiAgent_Options.objRefMode == RespectFilter ? "respectFilter" : _jvmpiAgent_Options.objRefMode == Filter4Owner ? "filterOwner" : "ignoreFilter");
 jvmpiAgent_PrintOption(tps, "METHOD_COUNTS", BOOLTOSTRING(_jvmpiAgent_Options.methodCounts));
 jvmpiAgent_PrintOption(tps, "OBJ_ALLOC_IS_ARRAY", BOOLTOSTRING(_jvmpiAgent_Options.objAllocIsArray));
 jvmpiAgent_PrintOption(tps, "OPTIONS", BOOLTOSTRING(_jvmpiAgent_Options.options));
 jvmpiAgent_PrintOption(tps, "STACK_INFORMATION", _jvmpiAgent_Options.stackInfo == StackInfoNone ? "none" : _jvmpiAgent_Options.stackInfo == StackInfoNormal ? "normal" : _jvmpiAgent_Options.stackInfo == StackInfoBoundary ? "boundary" : _jvmpiAgent_Options.stackInfo == StackInfoContiguous ? "contiguous" : "boundaryAndContiguous");
 jvmpiAgent_PrintOption(tps, "COMPRESS", _jvmpiAgent_Options.compressLevel == CompressNone ? "none" : "aggregate");  /* 140009 */
 /* Depreciated: jvmpiAgent_PrintOption(tps, "ALLOCATION_INFORMATION", _jvmpiAgent_Options.heapInfo == HeapInfoAll ? "all" : "none" ); */
 jvmpiAgent_PrintOption(tps, "TRACE_MODE", 
	 _jvmpiAgent_Options.mode == TraceModeFull ? "full" : 
	 _jvmpiAgent_Options.mode == TraceModeNoObjectCorrelation ? "noObjectCorrelation" : 
	 _jvmpiAgent_Options.mode == TraceModeStackSampling ? "sampling" : 
	 _jvmpiAgent_Options.mode == TraceHeap ? "heap" : 
	 _jvmpiAgent_Options.mode == TraceOptimizedHeap ? "optHeap" : 
	 _jvmpiAgent_Options.mode == TraceModeNone ? "none" : 
	 "unknown_mode_value");
 jvmpiAgent_PrintOption(tps, "TICKET", BOOLTOSTRING(_jvmpiAgent_Options.ticket));
 jvmpiAgent_PrintOption(tps, "TIMESTAMPS", BOOLTOSTRING(_jvmpiAgent_Options.timestamp));
 jvmpiAgent_PrintOption(tps, "TRACE_IDREFS", BOOLTOSTRING(_jvmpiAgent_Options.traceIdrefs));
 jvmpiAgent_PrintOption(tps, "UNREFERENCED_SYMBOLS", BOOLTOSTRING(_jvmpiAgent_Options.unreferencedSymbols));
 jvmpiAgent_PrintOption(tps, "CPU_TIME", BOOLTOSTRING(_jvmpiAgent_Options.cpuTime));
 jvmpiAgent_PrintOption(tps, "LLDATA_ENABLED", BOOLTOSTRING(_jvmpiAgent_Options.llDataEnabled));
 jvmpiAgent_PrintOption(tps, "HEAP_INFO_FILE_PREFIX", _jvmpiAgent_Options.heapInfoFilePrefix);
 jvmpiAgent_PrintOption(tps, "MONITOR_MODE",_jvmpiAgent_Options.monitorMode == MonitorAll ? "all" : "none");
 jvmpiAgent_PrintOption(tps, "METHOD_COUNTS_ONLY", BOOLTOSTRING(_jvmpiAgent_Options.methodCountsOnly)); 

 /* Piyush Agarwal */
 /* Send options specifying that this is an optimized heap and also the work dir */
  /* Giri: <Defect 64462> Added the check for standalone mode instead of controlled mode */
 if ( !_jvmpiAgent_Options.standalone && _jvmpiAgent_Options.mode == TraceOptimizedHeap )
 {
   jvmpiAgent_getWorkDir(fulldirpath) ;
/* Bug 64476 */
#ifdef MVS
   __etoa(fulldirpath) ;
#endif
   jvmpiAgent_PrintOption(tps, "WORK_DIR", fulldirpath);
   jvmpiAgent_PrintOption(tps, "HEAP_FILE_TYPE", "optHeap" );
   jvmpiAgent_PrintOption(tps, "MULTIPLE_HEAP_DUMPS", "true" );
   jvmpiAgent_PrintOption(tps, "HEAP_FILE_SOURCE", "RAC" );
   
 }
 jvmpiAgent_PrintOption(tps, "EXTENSION_LIBRARY", _jvmpiAgent_Options.extensionLibrary);

 /* 60879 print all the 'unknown' options. These are the options that the piAgent doesn't care about. Despite
 this, we need to echo these options back to the UI. */ 
 {
	 generic_option *cur_unknown = _jvmpiAgent_Options.unknowns; 
	 while (cur_unknown != NULL) {
		 jvmpiAgent_PrintOption(tps,cur_unknown->key,cur_unknown->value);
		 cur_unknown = cur_unknown->next; 
	 }
 }
}

/**
 * addUnknownOption - 60879 add a key,value pair that the piAgent doesn't care about
 * as an 'unknown' to the _jvmpiAgent_Options structure so that we can later echo
 * it back to the UI. 
 ***/ 
 static void addUnknownOption(char *key, char *value) {
	 /* _jvmpiAgent_Options.unknowns is essentially a linked list. We only expect to encounter a dozen 
	    or so unknown options, and moreover, we only do this processing once at start up. Hence the
		performance impact of not using a more sophisticated data structure is negligible.  */ 
		

	 /* find a spot in the linked list where we can add the new unknown */ 
	 generic_option *new_unknown = NULL; 
	 if (_jvmpiAgent_Options.unknowns == NULL) {
		 _jvmpiAgent_Options.unknowns = (generic_option *) malloc(sizeof(generic_option)); 
		 memset(_jvmpiAgent_Options.unknowns,0,sizeof(generic_option));
		 new_unknown = _jvmpiAgent_Options.unknowns; 
	 } else {
		 generic_option *cur_unknown = _jvmpiAgent_Options.unknowns; 
		 while (cur_unknown->next != NULL) {
			 cur_unknown = cur_unknown->next; 
		 }
		 new_unknown = (generic_option *) malloc(sizeof(generic_option)); 
		 memset(new_unknown,0,sizeof(generic_option)); 
		 cur_unknown->next = new_unknown; 
	 }

	 /* set the new unknown option */ 
	 new_unknown->key = (char *) malloc(strlen(key)*sizeof(char)+1); 
	 strcpy(new_unknown->key,key); 
	 new_unknown->value = (char *) malloc(strlen(value)*sizeof(char)+1); 
	 strcpy(new_unknown->value,value); 
	
 }




/** SET_PROFILE_OPTION *******************************************************************
  *
  */
#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
#endif

int jvmpiAgent_SetProfileOption(char * key, char * value)
{

	if (key == NULL || value == NULL) {
		return 0;
	}

 if (STRICOLL(key, "CLASS_LOAD_DETAILS") == 0)
 {
  _jvmpiAgent_Options.classLoadDetails = setBooleanOption(value, key, _jvmpiAgent_Options.classLoadDetails);
 }

 else if (STRICOLL(key,"METHOD_COUNTS_ONLY") == 0) 
 {
	 _jvmpiAgent_Options.methodCountsOnly = setBooleanOption(value, key, _jvmpiAgent_Options.methodCountsOnly);
	 /* turn on methodCounts option if methodCountsOnly option is turned on */ 
	 _jvmpiAgent_Options.methodCounts = setBooleanOption(value, key, _jvmpiAgent_Options.methodCountsOnly);
 }

 else if (STRICOLL(key, "METHOD_DETAILS") == 0)
 {
  _jvmpiAgent_Options.methodDetails = setBooleanOption(value, key, _jvmpiAgent_Options.methodDetails);
 }

 else if (STRICOLL(key, "COLLATION_VALUES") == 0)
 {
  _jvmpiAgent_Options.collationValues = setBooleanOption(value, key, _jvmpiAgent_Options.collationValues);
 }
 else if (STRICOLL(key, "CONTEXT_FLOW") == 0)
 {
  _jvmpiAgent_Options.contextFlow = setBooleanOption(value, key, _jvmpiAgent_Options.contextFlow);
 }
 else if (STRICOLL(key, "EXCEPTION_TRACING") == 0)
 {
  if(!_jvmpiAgent_Options.exceptionTracingSet)
  {
    _jvmpiAgent_Options.traceExceptions = setBooleanOption(value, key, _jvmpiAgent_Options.traceExceptions);
    /* Call the Java method to record the Exception Tracing state change */
    if (_jvmpiAgent_setExceptionTracing)
	{
      JNIEnv *env;
	  ATTACH_THREAD(env);
      ENV(env)->CallStaticVoidMethod(ENVPARM(env) _jvmpiAgent_JVMPIException, _jvmpiAgent_setExceptionTracing, (jboolean)_jvmpiAgent_Options.traceExceptions );
	  DETACH_THREAD();
	}
  }
 }
 else if (STRICOLL(key, "FILTERS") == 0)
 {
  _jvmpiAgent_Options.filters = setBooleanOption(value, key, _jvmpiAgent_Options.filters);
 }
 else if ((STRICOLL(key, "GC") == 0 || STRICOLL(key, "TRACK_GC_EVENT_TYPES") == 0)
			&& !_jvmpiAgent_Options.gcSet)
 {
  if (STRICOLL(value, "default") == 0)
  {
   _jvmpiAgent_Options.gcDefault = 1;
  }
  else
  {
   _jvmpiAgent_Options.gcDefault = 0;
   if (STRICOLL(value, "none") == 0)
   {
    _jvmpiAgent_Options.gc = GcNone;
   }
   else if (STRICOLL(value, "deletes") == 0 || STRICOLL(value, "frees") == 0)
   {
	/* "deletes" should be depreciated */
    _jvmpiAgent_Options.gc = GcDeletes;
   }
   else if (STRICOLL(value, "moves") == 0)
   {
    _jvmpiAgent_Options.gc = GcMoves;
   }
   else if (STRICOLL(value, "deletesAndMoves") == 0 || STRICOLL(value, "movesAndFrees") == 0)
   {
	/* "deletesAndMoves" should be depreciated */
    _jvmpiAgent_Options.gc = GcDeletesAndMoves;
   }
   else
   {
    fprintf(stderr, "Invalid %s option value \"%s\"\n", key, value);
	fflush(stderr); 
    return -1;
   }
  }
 }
 else if (STRICOLL(key, "ID_STYLE") == 0)
 {
  if (STRICOLL(value, "static") == 0)
  {
   _jvmpiAgent_Options.idStyle = IdStyleStatic;
  }
  else if (STRICOLL(value, "relocatable") == 0)
  {
   _jvmpiAgent_Options.idStyle = IdStyleRelocatable;
  }
  else if (STRICOLL(value, "staticAndRelocatable") == 0)
  {
   _jvmpiAgent_Options.idStyle = IdStyleStaticAndRelocatable;
  }
  else
  {
   fprintf(stderr, "Invalid %s option value \"%s\"\n", key, value);
   fflush(stderr); 
   return -1;
  }
 }
 else if (STRICOLL(key, "OBJ_REF_MODE") == 0)
 {
  if (STRICOLL(value, "respectFilter") == 0)
  {
   _jvmpiAgent_Options.objRefMode = RespectFilter;
  }
  else if (STRICOLL(value, "filterOwner") == 0)
  {
   _jvmpiAgent_Options.objRefMode = Filter4Owner;
  }
  else if (STRICOLL(value, "ignoreFilter") == 0)
  {
   _jvmpiAgent_Options.objRefMode = IgnoreFilter;
  }
  else
  {
   fprintf(stderr, "Invalid %s option value \"%s\"\n", key, value);
   fflush(stderr); 
   return -1;
  }
 }
 else if (STRICOLL(key, "TRACE_MODE") == 0)
 {
  if(!_jvmpiAgent_Options.modeSet)
  {
    if (STRICOLL(value, "full") == 0)
	{
      _jvmpiAgent_Options.mode = TraceModeFull;
	}
	else if (STRICOLL(value, "noObjectCorrelation") == 0)
	{
      _jvmpiAgent_Options.mode = TraceModeNoObjectCorrelation;
	}
    else if (STRICOLL(value, "sampling") == 0)
	{
       _jvmpiAgent_Options.mode = TraceModeStackSampling;
	}
	else if (STRICOLL(value, "heap") == 0)
	{
	  _jvmpiAgent_Options.mode = TraceHeap;
	  if ( _jvmpiAgent_Options.gcDefault )
	    _jvmpiAgent_Options.gc = GcMoves;
	}
	else if (STRICOLL(value, "optHeap") == 0)
	{
	  _jvmpiAgent_Options.mode = TraceOptimizedHeap;
	  if ( _jvmpiAgent_Options.gcDefault )
	    _jvmpiAgent_Options.gc = GcMoves;
	
	}
	else if (STRICOLL(value, "none") == 0)
	{
	  _jvmpiAgent_Options.mode = TraceModeNone;
	}
	else
	{
      fprintf(stderr, "Invalid %s option value \"%s\"\n", key, value);
	  fflush(stderr); 
      return -1;
	}
  }
 }
 else if(STRICOLL(key, "BURST_MODE")==0)
 {
	if(STRICOLL(value, "invocations")==0)
	{
		_jvmpiAgent_Options.burstMode=BurstModeInvocations;
	}
	else if(STRICOLL(value, "seconds")==0)
	{
		_jvmpiAgent_Options.burstMode=BurstModeSeconds;
	}
	else if(STRICOLL(value, "secondsAndInvocations")==0)
	{
		_jvmpiAgent_Options.burstMode=BurstModeSecondsAndInvocations;
	}
 }
 else if(STRICOLL(key, "MONITOR_MODE")==0)
 {
	 if(STRICOLL(value, "all")==0) {
		 _jvmpiAgent_Options.monitorMode = MonitorAll;
	 }
		
	 else 	
	 {
		 _jvmpiAgent_Options.monitorMode = MonitorNone;
	 }
 }
	
 else if(STRICOLL(key, "BURST_INVOCATIONS")==0)
 {
   _jvmpiAgent_Options.burstInvocations=atoi(value);
 }
 else if(STRICOLL(key, "BURST_SECONDS")==0)
 {
   _jvmpiAgent_Options.burstSeconds=atoi(value);
 }
 else if(STRICOLL(key, "TRACE_START_MODE")==0)
 {
	if(STRICOLL(value, "filter")==0)
	{
		 _jvmpiAgent_Options.startMode=TraceStartModeFilter;
	}
	else if(STRICOLL(value, "triggerSingleThreaded")==0)
	{
		_jvmpiAgent_Options.startMode=TraceStartModeTriggerSingleThreaded;
	}
	else if(STRICOLL(value, "triggerMultiThreaded")==0)
	{
		_jvmpiAgent_Options.startMode=TraceStartModeTriggerMultiThreaded;
	}
 }
 else if (STRICOLL(key, "METHOD_COUNTS") == 0)
 {
  _jvmpiAgent_Options.methodCounts = setBooleanOption(value, key, _jvmpiAgent_Options.methodCounts);
 }
 else if (STRICOLL(key, "OBJ_ALLOC_IS_ARRAY") == 0)
 {
  _jvmpiAgent_Options.objAllocIsArray = setBooleanOption(value, key, _jvmpiAgent_Options.objAllocIsArray);
 }
 else if (STRICOLL(key, "OPTIONS") == 0)
 {
  _jvmpiAgent_Options.options = setBooleanOption(value, key, _jvmpiAgent_Options.options);
 }
 else if (STRICOLL(key, "STACK_INFORMATION") == 0)
 {
  if (STRICOLL(value, "none") == 0)
  {
   _jvmpiAgent_Options.stackInfo = StackInfoNone;
  }
  else if (STRICOLL(value, "normal") == 0)
  {
   _jvmpiAgent_Options.stackInfo = StackInfoNormal;
  }
  else if (STRICOLL(value, "boundary") == 0)
  {
   _jvmpiAgent_Options.stackInfo = StackInfoBoundary;
  }
  else if (STRICOLL(value, "contiguous") == 0)
  {
   _jvmpiAgent_Options.stackInfo = StackInfoContiguous;
  }
  else if (STRICOLL(value, "boundaryAndContiguous") == 0)
  {
   _jvmpiAgent_Options.stackInfo = StackInfoBoundaryAndContiguous;
  }
  else
  {
   fprintf(stderr, "Invalid %s option value \"%s\"\n", key, value);
   fflush(stderr); 
   return -1;
  }
 }
 /* pre-aggregation: set compressLevel based on the option value */
 else if(STRICOLL(key, "COMPRESS")==0)   /* 140009 */
 {
  if (STRICOLL(value, "none") == 0)
  {
   _jvmpiAgent_Options.compressLevel=CompressNone;
  }
  else if (STRICOLL(value, "aggregate") == 0)
  {
   _jvmpiAgent_Options.compressLevel=CompressAggregate; 
  } 
  else 
  {
   fprintf(stderr, "Invalid %s option value \"%s\", it must be none or aggregate\n", key, value);
   fflush(stderr); 
   return -1;
  }	 
 }
 else if(STRICOLL(key, "ALLOCATION_INFORMATION") == 0)
 {
	  if (STRICOLL(value, "none") == 0)
	  {
	   /* Depreciated: _jvmpiAgent_Options.heapInfo = HeapInfoNone; */
	   _jvmpiAgent_Options.mode = TraceModeNoObjectCorrelation;
	  }
	  else if (STRICOLL(value, "optHeap") == 0) {
		_jvmpiAgent_Options.mode = TraceOptimizedHeap;
	  }
	  else
	  {
	   /* Depreciated _jvmpiAgent_Options.heapInfo = HeapInfoAll; */
	   _jvmpiAgent_Options.mode = TraceModeFull;
	  }
 }
 else if(STRICOLL(key, "BOUNDARY_DEPTH")==0)
 {
   _jvmpiAgent_Options.boundaryDepth=atoi(value);
 }
 else if (STRICOLL(key, "TICKET") == 0)
 {
  _jvmpiAgent_Options.ticket = setBooleanOption(value, key, _jvmpiAgent_Options.ticket);
 }
 else if (STRICOLL(key, "TIMESTAMPS") == 0)
 {
  _jvmpiAgent_Options.timestamp = setBooleanOption(value, key, _jvmpiAgent_Options.timestamp);
 }
 else if (STRICOLL(key, "TRACE_IDREFS") == 0)
 {
  _jvmpiAgent_Options.traceIdrefs = setBooleanOption(value, key, _jvmpiAgent_Options.traceIdrefs);
 }
 else if (STRICOLL(key, "UNREFERENCED_SYMBOLS") == 0)
 {
  _jvmpiAgent_Options.unreferencedSymbols = setBooleanOption(value, key, _jvmpiAgent_Options.unreferencedSymbols);
 }
 else if (STRICOLL(key, "THREAD_CPU_TIME") == 0 || STRICOLL(key, "CPU_TIME") == 0 )
 {
  _jvmpiAgent_Options.cpuTime = setBooleanOption(value, key, _jvmpiAgent_Options.cpuTime);
 }
 else if (STRICOLL(key, "LLDATA_ENABLED") == 0)
 {
  _jvmpiAgent_Options.llDataEnabled = setBooleanOption(value, key, _jvmpiAgent_Options.llDataEnabled);
 }
 else if (STRICOLL(key, "HEAP_INFO_COUNT") == 0 && !_jvmpiAgent_Options.heapInfoCountSet)
 {
  _jvmpiAgent_Options.heapInfoCount = atoi(value);
  if (_jvmpiAgent_Options.heapInfoCount<2 || _jvmpiAgent_Options.heapInfoCount>50)
  {
    fprintf(stderr, "Invalid %s option value \"%s\", it must be between 2 and 50\n", key, value);
	fflush(stderr); 
    return -1;
  }
 }
 else if (STRICOLL(key, "HEAP_INFO_FILE_PREFIX") == 0 && !_jvmpiAgent_Options.heapInfoFilePrefixSet)
 {
  strcpyrealloc(&_jvmpiAgent_Options.heapInfoFilePrefix, value);
 }
 else if (STRICOLL(key, "EXTENSION_LIBRARY") == 0) {
  strcpyrealloc(&_jvmpiAgent_Options.extensionLibrary, value);
 }
 else {
	 /* 60879 add the unknown profiling option to the 'unknowns' list so that we 
	 can echo it back to the UI */ 
	 addUnknownOption(key,value); 
 }



 /**** bugzilla_54553 - it is valid to send non-profiling options to the RAC. 
 else
 {
  fprintf(stderr, "Unknown Profile Option \"%s\"\n", key);
  return -1;
 }
 */ 
 return 0;
}


int jvmpiAgent_processProfile(char * fileName)
{
 int rc = 0, linelen;
 FILE * profileFile = NULL;
 fpos_t filepos; 
 char *buffer; 
 char *strippedBuffer; 

#ifdef MVS                    /* 174190 */
 __atoe(fileName);
#endif
 profileFile = fopen(fileName, "r");
 if (!profileFile) return -1;
 /* loop until we reach the end of file */ 
 while (feof(profileFile) == 0) {
	 int len, i, ch;
	 char *end;
	 char *key;
	 char *value; 

	 /* save current file position */ 
	 if (fgetpos(profileFile,&filepos) != 0) {
		 return -1; 
	 }

	 /* determine the length of the current line */ 
	 linelen = 0; 
	 do {
		 ch = fgetc(profileFile); 
		 linelen++; 
	 } while(ch != EOF && ch != '\n'); 
	 /* allocate enough buffer space for the current line */ 
	 buffer = (char *)malloc(linelen + 1); 
	 /* rewind to the beginning of the line */ 
	 if (fsetpos(profileFile,&filepos) != 0) {
		 free(buffer);
		 return -1;
	 }

	 /* read the line */ 
	 if (!fgets(buffer,linelen+1,profileFile)) {
		 /* loop termination condition */ 
		 free(buffer); 
		 break; 
	 }
	 /* Truncate the buffer at the start of a comment */
   
	 end = strchr(buffer, '*');
  
   
	 if (end) {
		 *end = '\0';
	 }
   
	 strippedBuffer = stripLeadingBlanks(buffer);
	 len = strlen(strippedBuffer);
	 if (!len) {
		 /* free the original buffer */
		 free(buffer);
		 continue;
	 }

   
	 /* Parse key */
   
	 for (i = 0; i < len; i++) {
	
		 if (isspace(strippedBuffer[i]) || strippedBuffer[i] == '=') {
			 key = (char *)malloc(i+1);
			 strncpy(key, strippedBuffer, i);
			 key[i] = '\0';
			 strippedBuffer = strippedBuffer+i;
			 break;
		 }
	 }  
	 strippedBuffer = stripLeadingBlanks(strippedBuffer);
   
	 if (strippedBuffer[0] != '=') {
         fprintf(stderr, "Syntax error in profile file\n");
		 fflush(stderr); 
         rc = -1;
		 /* free the original buffer */ 
		 free(buffer); 
		 break;
	 } else {
         strippedBuffer = strippedBuffer+1;
         strippedBuffer = stripLeadingBlanks(strippedBuffer);
		 /* Parse value */
		 for (i = 0; i <= len; i++) {
             if (isspace(strippedBuffer[i]) || strippedBuffer[i] == '\0') {
                 value = (char *)malloc(i+1); 
                 strncpy(value, strippedBuffer, i);
                 value[i] = '\0';
				 break;
			 }
		 }
	/*MW changed so that one bad option won't stop option processing */
/*	if ( */
		 jvmpiAgent_SetProfileOption(key,value);
/*	== -1)
	{
	 rc = -1;
	 break;
	}
*/ }
   
		 free(buffer); 
		 free(key);
		 free(value); 
 }

 if (_jvmpiAgent_Options.gcDefault) {
     if (_jvmpiAgent_Options.mode == TraceHeap || _jvmpiAgent_Options.mode == TraceOptimizedHeap) {
         _jvmpiAgent_Options.gc = GcMoves;
	 } else {
         _jvmpiAgent_Options.gc = _jvmpiAgent_Options.idStyle == IdStyleStatic ? GcDeletes : GcDeletesAndMoves;
	 }
 }
 fclose(profileFile);
 return rc;
}

#ifdef MVS                    /* 174190 */
#pragma convlit(resume)
#endif

/** PROCESS_INVOCATION_OPTIONS *******************************************
  * Takes the command line parameters and populates the _jvmpiAgent_Options
  * with the correct values based upon the options specified.
  * @param   optionString - the command line args
  * @returns
  */

int jvmpiAgent_ProcessInvocationOptions(char *str)
{
 char *buf = 0; 
 int buflen; 
 int outputSpecified = 0;
 if (str == NULL) str = "";

 /* if "help" is specified print out the useage */
 if ((STRICOLL(str, "help")) == 0)
  {
   return -1;
  }

 while (*str)
  {
   buflen= strlen(str)+1; 
   buf = (char *)malloc(buflen); 
   if (!buf) {
	   goto mem_error; 
   }

   /* All options contain an "=" */
   if (!getToken(&str, buf, buflen, '='))
    {
     goto bad_option;
    }
   /* Specied output file */
   if (STRICOLL(buf, "file") == 0)
    {
     if (outputSpecified || !getToken(&str, buf, buflen, ','))
      {
       goto bad_option;
      }
     strcpyrealloc(&_jvmpiAgent_Options.outputFileName, buf);
     outputSpecified = 1;
    }
   else if (STRICOLL(buf, "enableExceptionTracing") == 0)
   {
    if (!getToken(&str, buf, buflen, ','))
    {
     goto bad_option;
    }
    if (STRICOLL(buf, "yes") == 0)
    {
     _jvmpiAgent_Options.enableExceptionTracing = 1;
	 _jvmpiAgent_Options.exceptionTracingSet =1;
    }
    else if (STRICOLL(buf, "no") == 0)
    {
     _jvmpiAgent_Options.enableExceptionTracing = 0;
	 _jvmpiAgent_Options.exceptionTracingSet =1;
    }
    else
    {
     goto bad_option;
    }
   }
   else if (STRICOLL(buf, "enableLineCoverage") == 0)
   {
    if (!getToken(&str, buf, buflen, ','))
    {
     goto bad_option;
    }
    if (STRICOLL(buf, "yes") == 0)
    {
     _jvmpiAgent_Options.enableLineCoverage = 1;
	 _jvmpiAgent_Options.lineCoverageSet = 1;
    }
    else if (STRICOLL(buf, "no") == 0)
    {
     _jvmpiAgent_Options.enableLineCoverage = 0;
	 _jvmpiAgent_Options.lineCoverageSet = 1;
    }
    else
    {
     goto bad_option;
    }
   }
   else if (STRICOLL(buf, "filters") == 0)
    {
     if (!getToken(&str, buf, buflen, ','))
      {
       goto bad_option;
      }
     strcpyrealloc(&_jvmpiAgent_Options.filterFileName,buf);
    }
   else if (STRICOLL(buf, "debug") == 0)
    {
     if (!getToken(&str, buf, buflen, ','))
      {
       goto bad_option;
      }
     if (STRICOLL(buf,"hash") == 0)
      {
       _jvmpiAgent_Options.debugHash = 1;
	 }
	 else
	  {
       goto bad_option;
      }
    }
    /* Mode of operation */
    else if (STRICOLL(buf, "server") == 0)
    {
     if (!getToken(&str, buf, buflen, ','))
     {
      goto bad_option;
     }
	 /* If standalone */
     if (STRICOLL(buf,"standalone") == 0)
     {
      _jvmpiAgent_Options.standalone = 1;
	  _jvmpiAgent_Options.enabled = 0;
	 }
	 /* If enabled */
	 else if (STRICOLL(buf, "enabled") == 0)
	 {
	  _jvmpiAgent_Options.standalone = 0;
	  _jvmpiAgent_Options.enabled = 1;
	 }
	 /* If controlled */
     else if (STRICOLL(buf, "controlled") == 0)
	 {
	  _jvmpiAgent_Options.standalone = 0;
	  _jvmpiAgent_Options.enabled = 0;
	 }
	 /* If application */
	 else if (STRICOLL(buf, "application") == 0)
	 {
	  _jvmpiAgent_Options.standalone = 0;
	  _jvmpiAgent_Options.enabled = 1;
	  _jvmpiAgent_Options.application=1;
	 }
	 /* If application, partially controlled by the RAC itself */
	 else if (STRICOLL(buf, "applicationControlled") == 0) /* 215066 */
	 {
	  _jvmpiAgent_Options.standalone = 0;
	  _jvmpiAgent_Options.enabled = 0;
	  _jvmpiAgent_Options.application=1;
	 }
	 else
	  {
       goto bad_option;
      }
    }
    else if (STRICOLL(buf, "mode") == 0)
    {
     if (_jvmpiAgent_Options.modeSet || !getToken(&str, buf, buflen, ','))
     {
      goto bad_option;
     }
	 /* If standalone */
     if (STRICOLL(buf,"full") == 0)
     {
      _jvmpiAgent_Options.mode = TraceModeFull;
	  _jvmpiAgent_Options.modeSet = 1;
	 }
	 /* If enabled */
	 else if (STRICOLL(buf, "noObjectCorrelation") == 0)
	 {
	  _jvmpiAgent_Options.mode = TraceModeNoObjectCorrelation;
	  _jvmpiAgent_Options.modeSet = 1;
	 }
	 /* If controlled */
     else if (STRICOLL(buf, "sampling") == 0)
	 {
	  _jvmpiAgent_Options.mode = TraceModeStackSampling;
	  _jvmpiAgent_Options.modeSet = 1;
	 }
	 /* If heap */
	 else if (STRICOLL(buf, "heap") == 0)
	 {
	  _jvmpiAgent_Options.mode = TraceHeap;
	  _jvmpiAgent_Options.modeSet = 1;
	 }
	 /* If optimizedHeap */
     else if (STRICOLL(buf, "optHeap") == 0)
	 {
	  _jvmpiAgent_Options.mode = TraceOptimizedHeap;
	  _jvmpiAgent_Options.modeSet = 1;
	 }
	 else if (STRICOLL(buf, "none") == 0)
	 {
	  /* See Bugzilla 57136 for all use of TraceModeNone */
	  _jvmpiAgent_Options.mode = TraceModeNone;
	  _jvmpiAgent_Options.modeSet = 1;
	 }
	 else
	 {
       goto bad_option;
     }
    }
	else if (STRICOLL(buf, "trackGcEvent") == 0)
	{
     if (_jvmpiAgent_Options.gcSet || !getToken(&str, buf, buflen, ','))
     {
       goto bad_option;
     }

     if (STRICOLL(buf,"default") == 0)
     {
      _jvmpiAgent_Options.gcDefault = 1;
	  _jvmpiAgent_Options.gcSet = 1;
	 }
	 else if (STRICOLL(buf, "none") == 0)
	 {
	  _jvmpiAgent_Options.gcDefault = 0;
	  _jvmpiAgent_Options.gc = GcNone;
	  _jvmpiAgent_Options.gcSet = 1;
	 }
     else if (STRICOLL(buf, "moves") == 0)
	 {
	  _jvmpiAgent_Options.gcDefault = 0;
	  _jvmpiAgent_Options.gc = GcMoves;
	  _jvmpiAgent_Options.gcSet = 1;
	 }
	 else if (STRICOLL(buf, "frees") == 0)
	 {
	  _jvmpiAgent_Options.gcDefault = 0;
	  _jvmpiAgent_Options.gc = GcDeletes;
	  _jvmpiAgent_Options.gcSet = 1;
	 }
     else if (STRICOLL(buf, "movesAndFrees") == 0)
	 {
	  _jvmpiAgent_Options.gcDefault = 0;
	  _jvmpiAgent_Options.gc = GcDeletesAndMoves;
	  _jvmpiAgent_Options.gcSet = 1;
	 }
	 else
	 {
       goto bad_option;
     }
	 /* end of GC */
	}
	else if (STRICOLL(buf, "workDir") == 0)
	{
	  if (!getToken(&str, buf, buflen, ','))
      {
       goto bad_option;
      }
     strcpyrealloc(&_jvmpiAgent_Options.workDir, buf);

	 /* create the directory */
	 if (MKDIR(_jvmpiAgent_Options.workDir) != 0 && errno != EEXIST) {
		 /* couldn't create the dir and it doesn't exists either */
		 perror(_jvmpiAgent_Options.workDir);
		 goto bad_option;
	 }

	 /* end of workDir */
	}
    else if (STRICOLL(buf, "profile") == 0)
    {
     _jvmpiAgent_Options.profileFile;
     if (!getToken(&str, buf, buflen, ','))
      {
       goto bad_option;
      }
     strcpyrealloc(&_jvmpiAgent_Options.profileFile,buf);
    }
	else if (STRICOLL(buf, "optHeapFilePrefix") == 0)
    {
     if (_jvmpiAgent_Options.heapInfoFilePrefixSet || !getToken(&str, buf, buflen, ','))
      {
       goto bad_option;
      }
     strcpyrealloc(&_jvmpiAgent_Options.heapInfoFilePrefix, buf);
     _jvmpiAgent_Options.heapInfoFilePrefixSet = 1;
    }
	else if (STRICOLL(buf, "optHeapCount") == 0)
	{
	 if (_jvmpiAgent_Options.heapInfoCountSet || !getToken(&str, buf, buflen, ','))
      {
       goto bad_option;
      }
#ifdef MVS
#pragma convlit(suspend)
     __atoe(buf) ;
     _jvmpiAgent_Options.heapInfoCount = atoi(buf);
     __etoa(buf) ;
#pragma convlit(resume)
#else
     _jvmpiAgent_Options.heapInfoCount = atoi(buf);
#endif
	 if (_jvmpiAgent_Options.heapInfoCount < 2 || _jvmpiAgent_Options.heapInfoCount > 50)
      {
#ifdef MVS
#pragma convlit(suspend)
       __atoe(buf); /* for fprintf's use */
#endif
       fprintf(stderr, "optHeapCount=%s, it must be between 2 and 50", buf);
#ifdef MVS
       __etoa(buf); /* undo previous conversion */
#pragma convlit(resume)
#endif
	   fflush(stderr); 
       goto bad_option;
      }
     _jvmpiAgent_Options.heapInfoCountSet = 1;
	}
	else if (STRICOLL(buf, "extensionLibrary") == 0)
	{
	 if (!getToken(&str, buf, buflen, ','))
      {
       goto bad_option;
      }
	 strcpyrealloc(&_jvmpiAgent_Options.extensionLibrary, buf);
	}
	else
	{
         /* 57110 Silently ignore options starting with "ext-"
          * because they're destined for an agent extension.
          * I would use STRNICOLL(buf, "ext-", 4) if there were one.
          * Copy the bytes manually rather than trust in having
          * memcpy on all platforms. (Sure it isn't called _memcpy...?)
          */
         char prefix[5];
         prefix[0] = buf[0];
         prefix[1] = buf[1];
         prefix[2] = buf[2];
         prefix[3] = buf[3];
         prefix[4] = '\0';
         if (STRICOLL(prefix, "ext-") == 0) {
           /* consume up to the comma, error out if nothing after "=" */
		   if (!getToken(&str, buf, buflen, ',')) {
              goto bad_option;
           }
           else {
           	  /* This is a well-formed ext- option. Do not error out. */
           }
         }
         else {
	   		/* unknown option */
#ifdef MVS
#pragma convlit(suspend)
			__atoe(buf);
#endif
	   		fprintf(stderr, "Unknown option \"%s\"\n", buf);
#ifdef MVS
			__etoa(buf);
#pragma convlit(resume)
#endif
			fflush(stderr); 
	   		goto bad_option;
	 	 }
	}

  }

  if (_jvmpiAgent_Options.gcDefault
      && (_jvmpiAgent_Options.mode == TraceHeap || _jvmpiAgent_Options.mode == TraceOptimizedHeap))
  {
    _jvmpiAgent_Options.gc = GcMoves;
  }
  if (buf) {
	  free (buf); 
  }
  return 0;

bad_option:
  if (buf) {
	free(buf); 
  }
#ifdef MVS
#pragma convlit(suspend)
#endif
  fprintf(stderr, "Bad PIAgent option\n");
#ifdef MVS
#pragma convlit(resume)
#endif
  fflush(stderr); 
  /* printUsage(); (JvmpiWriter will print the usage()) */
  return -1;
mem_error:
#ifdef MVS
#pragma convlit(suspend)
#endif
  fprintf(stderr, "Memory allocation error\n"); 
#ifdef MVS
#pragma convlit(resume)
#endif
  fflush(stderr); 
  return -1; 
}

/** CHECK_OPTIONS_CONSISTENCY ********************************************
  * Checks whether there is any conflict or inconsistency among various
  * options.
  * @returns -1 if error, 0 if no error
  */
int jvmpiAgent_CheckOptionsConsistency()
{
	/* The TraceOptimizedHeap trace-mode can be set only in stand-alone mode */
	if (_jvmpiAgent_Options.mode == TraceOptimizedHeap) {
#ifdef MVS
#pragma convlit(suspend)
#endif
		if (!_jvmpiAgent_Options.standalone && 
			!jvmpiAgent_isControlled() ) {
			fprintf(stderr, "The TraceOptimizedHeap trace-mode can be set either in stand-alone or controlled mode.\n");
			fflush(stderr); 
			return -1;
		}
		if (_jvmpiAgent_Options.gc != GcMoves && _jvmpiAgent_Options.gc != GcNone) {
			fprintf(stderr, "In TraceOptimizedHeap trace-mode, TrackGcEvent must be either Moves or None\n");
			fflush(stderr); 
			return -1;
		}
#ifdef MVS
#pragma convlit(resume)
#endif
	}

	return 0;
}

unsigned int jvmpiAgent_isPrintObjId()
{
 return (_jvmpiAgent_Options.idStyle == IdStyleRelocatable || _jvmpiAgent_Options.idStyle == IdStyleStaticAndRelocatable);
}

unsigned int jvmpiAgent_isPrintStaticId()
{
 return (_jvmpiAgent_Options.idStyle == IdStyleStatic || _jvmpiAgent_Options.idStyle == IdStyleStaticAndRelocatable);
}

unsigned int jvmpiAgent_isPrintMethodId()
{
 return (_jvmpiAgent_Options.idStyle == IdStyleRelocatable || _jvmpiAgent_Options.idStyle == IdStyleStaticAndRelocatable);
}

unsigned int jvmpiAgent_isTracingHeap()
{
 return (_jvmpiAgent_Options.mode==TraceModeFull || _jvmpiAgent_Options.mode==TraceHeap || _jvmpiAgent_Options.mode==TraceOptimizedHeap );
}

unsigned int jvmpiAgent_isControlled()
{
  return ( _jvmpiAgent_Options.standalone == 0 &&  _jvmpiAgent_Options.enabled ==0  ) ;
}
