/*   ncbimain.c
* ===========================================================================
*
*                            PUBLIC DOMAIN NOTICE                          
*               National Center for Biotechnology Information
*                                                                          
*  This software/database is a "United States Government Work" under the   
*  terms of the United States Copyright Act.  It was written as part of    
*  the author's official duties as a United States Government employee and 
*  thus cannot be copyrighted.  This software/database is freely available 
*  to the public for use. The National Library of Medicine and the U.S.    
*  Government have not placed any restriction on its use or reproduction.  
*                                                                          
*  Although all reasonable efforts have been taken to ensure the accuracy  
*  and reliability of the software and data, the NLM and the U.S.          
*  Government do not and cannot warrant the performance or results that    
*  may be obtained by using this software or data. The NLM and the U.S.    
*  Government disclaim all warranties, express or implied, including       
*  warranties of performance, merchantability or fitness for any particular
*  purpose.                                                                
*                                                                          
*  Please cite the author in any work or product based on this material.   
*
* ===========================================================================
*
* File Name:  ncbimain.c
*
* Author:  Ostell
*
* Version Creation Date:   2/25/91
*
* Version Number:  1.1
*
* File Description: 
*   	portable main() and argc, argv handling
*   	DOS version for dumb terminals
*
* Modifications:  
* --------------------------------------------------------------------------
* Date     Name        Description of modification
* -------  ----------  -----------------------------------------------------
* 2/25/91  Ostell      add support to GetArgs for args separated from tags
*
* $Log: ncbimain.dos,v $
Revision 5.0  1996/05/28  13:18:57  ostell
Set to revision 5.0

Revision 4.0  1995/07/26  13:46:50  ostell
force revision to 4.0

Revision 2.9  1995/05/15  18:45:58  ostell
added Log line

*
*
* ==========================================================================
*/

#include <ncbi.h>
#include <ncbiwin.h>

/*****************************************************************************
*
*   main()
*     this replaces the normal program main()
*     handles argc and argv
*     does any required windows initialization
*
*****************************************************************************/
static int targc;
static char ** targv;

int main (int argc, char *argv[])

{
	Nlm_Int2 retval;

	targc = argc;
	targv = argv;
	Nlm_SetupArguments (argc, argv);

#ifdef MSC_VIRT
	if (! _vheapinit(0, 1250, _VM_ALLSWAP))
	{
		ErrPost(CTX_NCBIOBJ, 1, "Can't open virtual memory");
		return 1;
	}
#endif

	retval = Nlm_Main();
	                   /**** do any cleanup here *************/
	Nlm_FreeConfigStruct ();
	ErrSetLogfile(NULL,0);

#ifdef MSC_VIRT
	_vheapterm();
#endif
	return retval;
}

#define MAX_ARGS 50       /* maximum args this can process */
/*****************************************************************************
*
*   Nlm_GetArgs(ap)
*   	returns user startup arguments
*
*****************************************************************************/
Nlm_Boolean Nlm_GetArgs (Nlm_CharPtr progname, Nlm_Int2 numargs, Nlm_ArgPtr ap)

{
	static Nlm_CharPtr types[9] = {
		NULL,
		"T/F",
		"Integer",
		"Real",
		"String",
		"File In",
		"File Out",
		"Data In",
		"Data Out" };
	Nlm_Boolean okay = FALSE, all_default = TRUE, range;
	Nlm_Int2 i, j;
	Nlm_Int4 ifrom, ito;
	Nlm_FloatHi ffrom, fto;
	Nlm_ArgPtr curarg;
	Nlm_Boolean resolved[MAX_ARGS];
	Nlm_CharPtr arg;
	Nlm_Char tmp;
	Nlm_Boolean ok;

	if ((ap == NULL) || (numargs == 0) || (numargs > MAX_ARGS))
		return okay;

	curarg = ap;                        /* set defaults */
	Nlm_MemFill(resolved, '\0', (MAX_ARGS * sizeof(Nlm_Boolean)));

	for (i = 0; i < numargs; i++, curarg++)
	{
		if ((curarg->type < ARG_BOOLEAN) ||
			 (curarg->type > ARG_DATA_OUT))
		{
			Message(MSG_ERROR, "Invalid Arg->type in %s", curarg->prompt);
			return okay;
		}
		curarg->intvalue = 0;
		curarg->floatvalue = 0.0;
		curarg->strvalue = NULL;
		if (curarg->defaultvalue != NULL)
		{
			resolved[i] = TRUE;
			switch (curarg->type)
			{
				case ARG_BOOLEAN:
					if (TO_UPPER(*curarg->defaultvalue) == 'T')
						curarg->intvalue = 1;
					else
						curarg->intvalue = 0;
					break;
				case ARG_INT:
					sscanf(curarg->defaultvalue, "%ld", &curarg->intvalue);
					break;
				case ARG_FLOAT:
					sscanf(curarg->defaultvalue, "%lf", &curarg->floatvalue);
					break;
				case ARG_STRING:
				case ARG_FILE_IN:
				case ARG_FILE_OUT:
				case ARG_DATA_IN:
				case ARG_DATA_OUT:
					curarg->strvalue = StringSave (curarg->defaultvalue);
					break;
			}
		}
		else if (curarg->optional == FALSE)
			all_default = FALSE;    /* must have some arguments */
	}
		                  /**** show usage if no args on command line ***/
	if ((targc == 1) && (all_default == TRUE))   /* no args ok */
		return TRUE;

	if ((targc == 1) || (*(targv[1]+1) == '\0'))
	{
		printf("\n%s   arguments:\n\n", progname);
		curarg = ap;

		for (i = 0, j=0; i < numargs; i++, j++, curarg++)
		{
			printf("  -%c  %s [%s]", curarg->tag, curarg->prompt,
				types[curarg->type]);
			if (curarg->optional)
				printf("  Optional");
			printf("\n");
			if (curarg->defaultvalue != NULL)
				printf("    default = %s\n", curarg->defaultvalue);
			if ((curarg->from != NULL) || (curarg->to != NULL))
			{
				if ((curarg->type == ARG_DATA_IN) ||
					(curarg->type == ARG_DATA_OUT))
					printf("    Data Type = %s\n", curarg->from);
				else
					printf("    range from %s to %s\n", curarg->from, curarg->to);
			}
		}
		printf("\n");
		return okay;
	}

	for (i = 1; i < targc; i++)
	{
		arg = targv[i];
		if (*arg != '-')
		{
			Message(MSG_ERROR, "Arguments must start with -");
			return okay;
		}
		arg++;
		curarg = ap;
		for (j = 0; j < numargs; j++, curarg++)
		{
			if (*arg == curarg->tag)
				break;
		}
		if (j == numargs)
		{
			Message(MSG_ERROR, "Invalid argument: %s", targv[i]);
			return okay;
		}
		arg++;
        if (*arg == '\0')
        {
			ok = FALSE;
            if ((i + 1) < targc)  /* argument comes after space */
            {
				if (*targv[i + 1] == '-')
				{
					tmp = *(targv[i+1]+1);
					if (((curarg->type == ARG_INT) || (curarg->type == ARG_FLOAT)) &&
						((tmp == '.') || (IS_DIGIT(tmp))))
						ok = TRUE;
				}
				else
					ok = TRUE;
				if (ok)
				{
	                i++;
    	            arg = targv[i];
				}
            }

            if ((!ok) && (curarg->type != ARG_BOOLEAN))
			{
				Message(MSG_ERROR, "No argument given for %s", curarg->prompt);
				return okay;
			}
        }
		resolved[j] = TRUE;
		switch (curarg->type)
		{
			case ARG_BOOLEAN:
				if (TO_UPPER(*arg) == 'T')
					curarg->intvalue = 1;
				else if (TO_UPPER(*arg) == 'F')
					curarg->intvalue = 0;
				else if (*arg == '\0')
					curarg->intvalue = 1;
				break;
			case ARG_INT:
				sscanf(arg, "%ld", &curarg->intvalue);
				if ((curarg->from != NULL) || (curarg->to != NULL))
				{
                    range = TRUE;
                    if (curarg->from != NULL)
                    {
    					sscanf(curarg->from, "%ld", &ifrom);
                        if (curarg->intvalue < ifrom)
                            range = FALSE;
                    }
                    if (curarg->to != NULL)
                    {              
    					sscanf(curarg->to, "%ld", &ito);
                        if (curarg->intvalue > ito)
                            range = FALSE;
                    }
					if (! range)
                    {
						Message(MSG_ERROR, "%s [%ld] is out of range [%s to %s]", curarg->prompt,
							curarg->intvalue, curarg->from, curarg->to);
						return okay;
					}
				}
 				break;
			case ARG_FLOAT:
				sscanf(arg, "%lf", &curarg->floatvalue);
				if ((curarg->from != NULL) || (curarg->to != NULL))
				{
                    range = TRUE;
                    if (curarg->from != NULL)
                    {
    					sscanf(curarg->from, "%lf", &ffrom);
                        if (curarg->floatvalue < ffrom)
                            range = FALSE;
                    }
                    if (curarg->to != NULL)
                    {
					    sscanf(curarg->to, "%lf", &fto);
                        if (curarg->floatvalue > fto)
                            range = FALSE;
                    }
					if (! range)
					{
						Message(MSG_ERROR, "%s [%g] is out of range [%s to %s]", curarg->prompt, 
							curarg->floatvalue, curarg->from, curarg->to);
						return okay;
					}
				}
				break;
			case ARG_STRING:
			case ARG_FILE_IN:
			case ARG_FILE_OUT:
			case ARG_DATA_IN:
			case ARG_DATA_OUT:
				curarg->strvalue = StringSave (arg);
				break;
		}    /*** end switch ****/
	}       
	curarg = ap;
	okay = TRUE;
	for (i = 0; i < numargs; i++, curarg++)
	{
		if ((! curarg->optional) && (! resolved[i]))
		{
			Message(MSG_ERROR, "%s was not given an argument", curarg->prompt);
			okay = FALSE;
		}
	}
	return okay;
}
