/*----------------------------------------------------------------------------
 *
 *  parse.c
 *  ------
 *
 *  Purpose: Provide commandline parsing routines
 *
 *  Licensed Materials - Property of IBM
 *
 *  (C) Copyright International Business Machines Corp., 1994, 2000
 *  All rights reserved
 *
 *  US Government Users Restricted Rights -
 *  Use, duplication, or disclosure restricted
 *  by GSA ADP Schedule Contract with IBM Corp.
 *
 *  Modifications:
 *     5.0.1.0 24Jan00(jok) Add tenureFailedGCCount option (13154)
 *
 *----------------------------------------------------------------------------*/

#include "esuser.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/*--------------------------------------------------------------------------*/
/*  DEBUG support                                                           */
/*--------------------------------------------------------------------------*/

#ifdef DEBUG01
#define dbg_printf( x ) { printf x ; fflush( stdout ); }
#else
#define dbg_printf( x )
#endif


#ifdef ESVM_HAS_FILE_SYSTEM /* priv. proto (autogen) */
static I_32 EsStrICmp PROTOTYPE((char *string1, char *string2));
#endif /* ESVM_HAS_FILE_SYSTEM (autogen) */


BOOLEAN EsFindImageFileName PROTOTYPE((int argc, char *argv[], char *envp[], EsGlobalInfo * info));
BOOLEAN EsParseCommandLineOptions PROTOTYPE((int argc, char *argv[], char *envp[], EsGlobalInfo * info));


void VMCALL EsParseIniFileOptions PROTOTYPE((EsGlobalInfo *globalInfo, EsVMOptions vmOptions[]));
void VMCALL EsPrivateParseCommandLineOptions PROTOTYPE((int argc, char *argv[], char *envp[], EsGlobalInfo * info));

I_32 VMCALL EsFileOpen PROTOTYPE((char * path, I_32 flags, I_32 mode));
I_32 VMCALL EsFileClose PROTOTYPE((I_32 fd));
#define	EsOpenRead		1	/* Values for EsFileOpen */

EsVMOptions vmOptions[] = {
	{ "fixedSpaceSize", NULL, DEFAULT_VALUE },
	{ "newSpaceSize", NULL, DEFAULT_VALUE },
	{ "oldSpaceSize", NULL, DEFAULT_VALUE },
	{ "allocationIncrement", NULL, DEFAULT_VALUE },
	{ "lowMinimum", NULL, DEFAULT_VALUE },
	{ "maximumMemoryLimit", NULL, DEFAULT_VALUE },
	{ "codeCacheSize", NULL, DEFAULT_VALUE },
	{ "runtimeFlags", NULL, DEFAULT_VALUE },
	{ "messageLevel", NULL, DEFAULT_VALUE },
	{ "copyOnWrap", NULL, DEFAULT_VALUE },
        { "tenureFailedGCCount", NULL, DEFAULT_VALUE },
	{ NULL, NULL, DEFAULT_VALUE }
};
/*
 *	This function is provided to parse command line options before they
 *	are passed into the VM.  There is a sample loop that allows each option
 *	to be examined, followed by calls to the two internal function that do all
 *	VM supported (or private) calls.
 *
 *	To modify default values, add them to the third column of EsVMOptionsStruct.
 *	The following flags are reserved for VM use:
 *	-i, -l, -m, -r
 *	and should not be used.
 *
 *	Note that the rightmost command line argument ending in .icx or as part of a
 *	-i option will be taken to be the image name, overriding any default.  Should
 *	this not be desired, remove the code from below.
 */
#ifdef USE_PROTOTYPES
BOOLEAN EsParseCommandLineOptions(int argc, char *argv[], char *envp[], EsGlobalInfo * info)
#else
BOOLEAN EsParseCommandLineOptions(argc, argv, envp, info)
int argc;
char *argv[];
char *envp[];
EsGlobalInfo * info;
#endif
{
	int i, len;

	/* must init out of line because some compilers don't dynamically init structs. */
	vmOptions[0].address = (U_32 *) &info->fixedSpaceSize;
	vmOptions[1].address = (U_32 *) &info->newSpaceSize;
	vmOptions[2].address = (U_32 *) &info->oldSpaceSize;
	vmOptions[3].address = (U_32 *) &info->allocationIncrement;
	vmOptions[4].address = (U_32 *) &info->lowMinimum;
	vmOptions[5].address = (U_32 *) &info->memoryMax;
	vmOptions[6].address = (U_32 *) &info->codeCacheSize;
	vmOptions[7].address = (U_32 *) &info->runtimeFlags;
	vmOptions[8].address = (U_32 *) &info->messageLevel;
	vmOptions[9].address = (U_32 *) &info->copyOnWrap;
	vmOptions[10].address = (U_32 *) &info->tenureFailedGCCount;


   dbg_printf( ("Entering parser, %d commandline arguments:\n", argc) );
	for(i=1; i < argc; i++) {
      dbg_printf( ("\t%s\n", argv[i]) );
      if(argv[i][0] == '-') {
			switch(tolower(argv[i][1])) {
				case 'i':
					if ((tolower(argv[i][2]) == 'n') && 
					    (tolower(argv[i][3]) == 'i') &&
					    (tolower(argv[i][4]) == ':'))  {
						strncpy(info->iniName, &argv[i][5], MAX_IMAGE_PATH_LENGTH);
						info->iniName[MAX_IMAGE_PATH_LENGTH-1] = (char) 0;
						}
					else {
						strncpy(info->imageName, &argv[i][2], MAX_IMAGE_PATH_LENGTH);
						info->imageName[MAX_IMAGE_PATH_LENGTH-1] = (char) 0;
					   }
					break;
			} /* switch */
		} else {
#ifdef ESVM_HAS_FILE_SYSTEM
			/* check to see if this is an image filename by examining the extension */
			len = strlen(argv[i]);
			if((len < 4) || EsStrICmp(argv[i] + len - 4, ".icx")) {
				/* must be a document name. */
			} else {
				/* this is a Smalltalk image name.  Save it away for later use. */
				strncpy(info->imageName, argv[i], MAX_IMAGE_PATH_LENGTH);
				info->imageName[MAX_IMAGE_PATH_LENGTH-1] = (char) 0;
			}
#endif /* ESVM_HAS_FILE_SYSTEM */
		}	/* if */
	}	/* for */

   dbg_printf( ("Provided image name: %s\n", info->imageName) );
   dbg_printf( ("Provided ini name: %s\n", info->iniName) );

	/* The following call may be removed if no VM internal options are to be set. */

	/* call internal command line parser. */
	EsPrivateParseCommandLineOptions(argc, argv, envp, info);

#ifdef ESVM_HAS_FILE_SYSTEM
	if(!EsFindImageFileName(argc, argv, envp, info)) {
		return FALSE;
	}
#endif /* ESVM_HAS_FILE_SYSTEM */

	/* use the ini file and the struct provided to collect any remaining options */
	EsParseIniFileOptions(info, vmOptions);

	return TRUE;
} /* EsParseCommandLineOptions */


#ifdef ESVM_HAS_FILE_SYSTEM /* (autogen) */
/*
 *	Finds the image filename.
 *	This is called AFTER EsGetCommandLineOptions().
 *	Algorithm:
 *		1.	Check to see if info->imageName has a name in it.  Done if present (don't check in dir.)
 *		2.	Look for "<app name>.icx" in directory <app name>.exe was found.  Done if found.
 *		3.	Look for "<app name>.icx" in current working directory.  Done if found.
 *		4. Look for "image" in current working directory. Done if found.
 *		5. Fail.
 */
#ifdef USE_PROTOTYPES
BOOLEAN EsFindImageFileName(int argc, char *argv[], char *envp[], EsGlobalInfo * info)
#else
BOOLEAN EsFindImageFileName(argc, argv, envp, info)
int argc;
char *argv[];
char *envp[];
EsGlobalInfo * info;
#endif
{
	char tryName[MAX_IMAGE_PATH_LENGTH], defName[MAX_IMAGE_PATH_LENGTH], unparsedName[MAX_IMAGE_PATH_LENGTH], *start, *dotLoc;
	BOOLEAN imageNameProvided = FALSE;
	I_32 fd, len;

#ifdef MAC
	EsGetImageFileName(imageName,info);
#endif

	/* extract exe name and add .icx to form default image name. */
	if(0 == argc) {
		strcpy(defName, "es");
	} else {
		strncpy(defName, argv[0], MAX_IMAGE_PATH_LENGTH);		/* use exe name as base. */
	}

	defName[MAX_IMAGE_PATH_LENGTH - 1] = (char) 0;	/* ensure 0 termination. */
	start = strrchr(defName, DIR_SEPARATOR);
	if(start) {
		start+=1;
	} else {
		start = defName;
	}

	strcpy(info->defaultImageName, start);	/* copy exe filename (no path present) */

#ifdef EXE_EXTENSION_CHAR
	/* Search backwards from end to get the extension character and clip there. */
	if(dotLoc = strrchr(info->defaultImageName, EXE_EXTENSION_CHAR)) {
		*dotLoc = (char ) 0;	/* blow away the extension */
	}	/* otherwise, not found. */
#endif
	strcat(info->defaultImageName, ".icx");

	/* we should make a copy of the names so as not to modify the caller's info */
	if(info->imageName && (strlen(info->imageName) > 0)) {
		strcpy(unparsedName, info->imageName);		/* use user provided name as a base. */
		imageNameProvided = TRUE;
	} else {
		if(0 == argc) {
			strcpy(unparsedName, "es");
		} else {
		strncpy(unparsedName, argv[0], MAX_IMAGE_PATH_LENGTH);		/* use exe name as base. */
		}
		unparsedName[MAX_IMAGE_PATH_LENGTH - 1] = (char) 0;	/* ensure 0 termination. */
	}

	/* extract the path */
	start = strrchr(unparsedName, DIR_SEPARATOR);
	if(!start) {
		strcpy(info->imageName, unparsedName);
		info->imagePath[0] = (char) 0;	/* no path info provided. */
	} else {
		strcpy(info->imageName, (char *) ((U_32)start+1));	/* copy filename */
		strcpy(info->imagePath, unparsedName);				/* copy path. */
		info->imagePath[start - unparsedName] = (char) 0;	/* remove filename */
	}

	if(imageNameProvided)
		return TRUE;	/* return without looking.  The user hard coded a name/path. */

	strcpy(info->imageName, info->defaultImageName);				/* copy default name to image name. */

	/* step 2 - search for image where exe was found */
	if(info->imagePath && (len = strlen(info->imagePath))) {
		strcpy(tryName, info->imagePath);
		tryName[len] = DIR_SEPARATOR;
		tryName[len+1] = (char) 0;
	} else {
		tryName[0] = (char) 0;	/* prepare for a null imagePath */
	}
	strcat(tryName, info->imageName);
	if((fd = EsFileOpen(tryName, EsOpenRead, 0)) >= 0) {
		EsFileClose(fd);
		return TRUE; /* the current values for path and name are just fine. */
	}

	/* step 3 - search for image in current working directory */
	strcpy(tryName, info->imageName);
	if((fd = EsFileOpen(tryName, EsOpenRead, 0)) >= 0) {
		EsFileClose(fd);
		info->imagePath[0] = (char) 0;
		return TRUE; /* slam path name and return success. */
	}

	/* step 4 - compatibility, search for image in the current working directory */
	strcpy(tryName, "image");
	if((fd = EsFileOpen(tryName, EsOpenRead, 0)) >= 0) {
		EsFileClose(fd);
		strcpy(info->imageName, tryName);	/* reset name. */
		info->imagePath[0] = (char) 0;				/* reset path. */
		return TRUE;	/* slam both path and name, return success. */
	}

	return FALSE;	/* fail out. */
}
#endif /* ESVM_HAS_FILE_SYSTEM (autogen) */



#ifdef ESVM_HAS_FILE_SYSTEM /* (autogen) */
/*
 *	A simple stricmp because not all platforms support it or give it
 *	an odd name.
 *	0 on identical (barring case)
 *	non 0 on different.  We do not guarantee + or -
 */
#ifdef USE_PROTOTYPES
static I_32 EsStrICmp(char *string1, char *string2)
#else
static I_32 EsStrICmp(string1, string2)
char *string1, *string2;
#endif
{
	int len1,len2,x;

	len1 = strlen(string1);
	len2 = strlen(string2);

	if(len1 != len2)
		return 1;

	for(x=0;x<len1;x++) {
		if(tolower(*string1) != tolower(*string2))
			return 1;
		string1++; string2++;
	}
	return 0;
}
#endif /* ESVM_HAS_FILE_SYSTEM (autogen) */


