/*	enough.c						*/
/*								*/
/*	Run from a CLI execute file.  If the resources you are	*/
/*	checking for exist enough returns a return code of zero	*/
/*	(0), if not it returns a warning value of five (5).	*/
/*	Enough can be used to check for available memory and/or	*/
/*	disk space, along with the existence of files.		*/
/*								*/
/*	Syntax:							*/
/*		enough [{MEM|FAST|CHIP} nnn[K]]	[EXISTS file]	*/
/*		   [DISK drv: fff[K]]				*/
/*								*/
/*	Typical usage (in startup script):			*/
/*		failat 10					*/
/*		enough MEM 880k					*/
/*		if NOT warn					*/
/*		    copy df0: ram: all				*/
/*		    assign c: ram:c				*/
/*		    assign ....					*/
/*		endif						*/
/*								*/
/*	Logic:
 *	1. verify CLI parameters, as they are used.
 *	2. For memory (MEM, FAST and CHIP) checks use Avail() to
 * 	    see if there is enough memory.
 *	3. For disk (DISK) checks use Info()
 *	4. For existence testing (EXISTS) disable requesters and
 *	    use Lock().
 *	5. If any of them fail return 5.
 *	6. If there is a syntax error in the command line return 20.
 *
 *	Notes and cautions:
 *	1. the do_<function>() functions should be stand-alone.
 *	    freeing any resources they might allocate.
 *	2. the do_<function>() functions should increment the
 *	    cur_argc pointer past their keyword and any parameters
 *	    they use.  This is a global.
 *	3. MAX_KEYWD_LEN is the length of the longest keyword, or more
 *	
 *	New featues that might be added:
 *	1. enough<cr> currently does nothing, could add a check for
 *	    this case and return DIE_BADARGS.
 *	2. Be nice to add something that would test for enough room
 *	    on a disk for a given file (enough FILESPACE foo bar:)
 */


#include "exec/types.h"
#include "exec/memory.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"
/*
#include "stdio.h"
#include "clib/macros.h"
*/

/*		------------ Constant Definitions ------------	*/

/*	version release and date information			*/
#define	VERNO		1
#define	RELNO		0
#define	DATE		"13-May-86"
#define AUTHOR		Bruce A. Barrett
#define PUBLIC_DOMAIN	TRUE

/*	reason for terminating through cleanup()		*/
#define DIE_OK		0
#define DIE_MEM		1
#define	DIE_NOOUTPUT	2
#define DIE_BADARGS	3
#define DIE_S_DIR	4
#define DIE_D_DIR	5
#define	DIE_S_FILE	6
#define	DIE_D_FILE	7
#define DIE_FIBOVERFLOW	8
#define DIE_FIBUNDERFLOW 9
#define	DIE_CTRL_C	10
#define DIE_NOT_ENOUGH	11

#define MAX_KEYWD_LEN	12

/*		For debugging, as required	*/
#define FIX FALSE
#if FIX
#define	ROUTINE(foo)	kprintf(foo)	/* debug */
#else
#define ROUTINE(foo)			/* don't */
#endif

/*		------------ Global Variables ------------	*/

    int		f_lock;
    struct	FileInfoBlock *file_info_block;
    int		cur_argc;
    int		gl_argc;


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

{

/*		------------  Local Variables ------------	*/
    char	key_wd[MAX_KEYWD_LEN];
    int		ret_val;


/*								*/
/*		M A I N    L O G I C				*/
/*								*/

/* setup */
    ROUTINE("main\n");
/*
   kprintf("\n---------------------------------\n");
   kprintf("%s: Version %ld.%ld, %s\n", argv[0], VERNO, RELNO, DATE);
*/
    gl_argc = argc;

    ret_val = DIE_OK;
    cur_argc = 1;
    while ( (cur_argc < argc) && (ret_val == DIE_OK)) {
	testbreak();
	uc_copy(key_wd, argv[cur_argc]);
	
	 if (0 == strcmp(&key_wd[0],"MEM"))	ret_val = do_mem(argv);
    else if (0 == strcmp(&key_wd[0],"CHIP"))	ret_val = do_chip(argv);
    else if (0 == strcmp(&key_wd[0],"FAST"))	ret_val = do_fast(argv);

    else if (0 == strcmp(&key_wd[0],"DISK"))	ret_val = do_disk(argv);
    else if (0 == strcmp(&key_wd[0],"EXISTS"))  ret_val = do_exists(argv);
    else 	{ret_val = DIE_BADARGS;
        printf("%s: Version %ld.%ld, %s\n", argv[0], VERNO, RELNO, DATE);
    	}
    
    }
    

    cleanup(argv, ret_val);

}

/*		------------ suppress_IO_err() ------------	*/
/*	Prevent AmigaDOS from putting up a "Please insert 	*/
/*	volume..." requester.					*/
APTR
suppress_IO_err()
{
    struct Process *my_proc, *FindTask();
    APTR	old_window;
    
    ROUTINE("suppress_IO_err\n");
    my_proc = FindTask("");
    old_window = my_proc->pr_WindowPtr;
    my_proc->pr_WindowPtr = (APTR) -1;
    return(old_window);
}
    
/*		------------ allow_IO_err() ------------	*/
/*	Allow AmigaDOS to put up a "Please insert volume..." 	*/
/*	requester.						*/
void
allow_IO_err(old_wind)
    APTR	old_wind;
{
    struct Process *my_proc;

    ROUTINE("allow_IO_err\n");
    my_proc = FindTask("");
    my_proc->pr_WindowPtr = old_wind;
}
    

/*	---------- do_mem_type() ------------------------------	*/
/*	Given a memory type, see if there is enough available	*/

do_mem_type(argv, type)
    char	*argv[];
    int		type;
{
    int		avail;		/* memory available of this type */
    int		need;		/* memory of this type needed */
    
    ROUTINE("do_mem_type\n");
    if (cur_argc >= gl_argc)
        return(DIE_BADARGS);
    avail = AvailMem(type);
    sscanf(argv[cur_argc], "%d", &need);
    cur_argc++;
    if (need == 0)
        return(DIE_BADARGS);
    if ((need*1024) <= avail)
        return(DIE_OK);
    else
        return(DIE_NOT_ENOUGH);
}

/*	---------- do_mem() ------------------------------	*/
do_mem(argv)
    char	*argv[];
{
    ROUTINE("do_mem\n");
    cur_argc++;
    return(do_mem_type(argv, MEMF_LARGEST));
}

/*	---------- do_chip() ------------------------------	*/
do_chip(argv)
    char	*argv[];
{
    ROUTINE("do_chip\n");
    cur_argc++;
    return(do_mem_type(argv, MEMF_CHIP|MEMF_LARGEST));
}

/*	---------- do_fast() ------------------------------	*/
do_fast(argv)
    char	*argv[];
{
    ROUTINE("do_fast\n");
    cur_argc++;
    return(do_mem_type(argv, MEMF_FAST|MEMF_LARGEST));
}

/*	---------- do_disk() ------------------------------	*/
/*	Format is: ENOUGH DISK disk_name: fff[k]		*/


do_disk(argv)
    char	*argv[];
{						/* do_disk */
    int		need;
    int		ret_val;
    LONG	my_lock;
    LONG	free;
    BOOL	result;
    APTR	old_ptr;
    struct InfoData *info_data;
    
    ROUTINE("do_disk\n");
    info_data = 0;			/* remove a Lattice warning */
    cur_argc++;				/* Skip "DISK" keyword */
    ret_val = DIE_NOT_ENOUGH;

/*	-- test for enough arguments on the command line --	*/
    if ((cur_argc+1) >= gl_argc)
        return(DIE_BADARGS);

/*	-- test for the existence of the drive/volume --	*/
    old_ptr = (APTR) suppress_IO_err();	/* defeat "insert vol" requester */
    my_lock = Lock(argv[cur_argc], MODE_OLDFILE);
    allow_IO_err(old_ptr);		/* re-enable requesters. */
    cur_argc++;
    if (my_lock == 0) return(ret_val);

/*	-- get info about the drive --	*/
    info_data = (struct InfoData *) AllocMem(sizeof(*info_data), 0);
    if (info_data == 0) {
	UnLock(my_lock);
	return(ret_val);
    }

    result = Info(my_lock, info_data);
    if (!result) {
	UnLock(my_lock);
	FreeMem(info_data, sizeof(*info_data));
	return(ret_val);
    }
    

/*	-- get the amount of disk space needed --	*/
    sscanf(argv[cur_argc], "%d", &need);
    cur_argc++;
    if (need == 0) {
	UnLock(my_lock);
	FreeMem(info_data, sizeof(*info_data));
        return(DIE_BADARGS);
    }
    free = (info_data->id_NumBlocks - info_data->id_NumBlocksUsed) *
		 info_data->id_BytesPerBlock;

    UnLock(my_lock);
    FreeMem(info_data, sizeof(*info_data));
    if (free > (need*1024) ) ret_val = DIE_OK;
    return(ret_val);
    
    
}

/*	---------- do_exists() ------------------------------	*/
do_exists(argv)
    char	*argv[];
{
    LONG	my_lock;
    APTR	old_ptr;
    ROUTINE("do_exists\n");
    cur_argc++;
    old_ptr = (APTR) suppress_IO_err();	/* defeat "insert vol" requester */
    if (cur_argc >= gl_argc)
        return(DIE_BADARGS);
    my_lock = Lock(argv[cur_argc], MODE_OLDFILE);
    allow_IO_err(old_ptr);
    cur_argc++;
    if (my_lock == 0) return(DIE_NOT_ENOUGH);
    UnLock(my_lock);
    return(DIE_OK);
}


/*	====================================================	*/
/*	================== Subroutines =====================	*/
/*			    enough.h
/*	====================================================	*/

/*	---------- uc_copy() ------------------------------	*/
/*	Copy characters from one string to another, making	*/
/*	it upper case at it goes.				*/

uc_copy(to, from)
    char	*to;
    char	*from;
{
    ROUTINE("uc_copy\n");
    while (*to++ = toupper(*from++))
        ;
}

/*	---------- testbreak() ------------------------------	*/
/*	tests for a ^C (CTRL-C), calls cleanup() if found, 	*/
/*	otherwise returns.					*/

testbreak(argv)
    char	*argv[];
{
    LONG	newsigs;
    LONG	oldsigs;
    
    ROUTINE("testbreak\n");
    newsigs = 0;
    
	oldsigs = SetSignal(newsigs, SIGBREAKF_CTRL_C);
	if (oldsigs & (SIGBREAKF_CTRL_C) ) {
	    cleanup(argv, DIE_CTRL_C);
	}			/* end of if */

}				/* end of testbreak() */


/*		------------ cleanup(argv, cause) ------------	*/

cleanup(argv, cause)
    int		cause;
    char	*argv[];
{
    ROUTINE("cleanup\n");
/*
    kprintf ("cleanup # %ld, IoErr() = %ld\n", cause, IoErr());
*/
    switch (cause) {
	case DIE_OK:	
	case DIE_MEM:	
	case DIE_NOOUTPUT:
	case DIE_S_DIR:
	case DIE_D_DIR:	
	case DIE_S_FILE:
	case DIE_D_FILE:	
	case DIE_FIBOVERFLOW:	
	case DIE_FIBUNDERFLOW:
	case DIE_NOT_ENOUGH:
		break;
	case DIE_BADARGS: 
		printf("%s: Error --  Bad command line arguments.\n",
				argv[0]);
/*		enough 	*/
/*		   				*/
		printf("%s: Syntax is %s [{MEM|FAST|CHIP} nnn[K]]	[EXISTS file]\n",
				argv[0], argv[0]);
		printf("        [DISK drv: fff[K]]\n");
		printf("nnn is the number of K in RAM required, fff is the\n");
		printf("number of K on the disk \"drv:\" required, file is a\n");
		printf("path name you want to check for the existence of.\n");
		break;
	case DIE_CTRL_C:
		printf("%s: *Break*  Stopped by user.\n", argv[0]);
		break;
    }
    ROUTINE("exit\n");
    if (cause == DIE_OK)  exit(0);
    else if (cause == DIE_BADARGS)  exit(20);	/* syntax error!! */
    else exit(5);
    
	
}
