[net.micro.amiga] enough, a new CLI utility

bruceb@amiga.UUCP (Bruce Barrett) (05/13/86)

/*
Ever wonder if the system you're running on has enough system
resources for you to do what you would like too (or need to)
do?  Ever want to use the same CLI or workbench diskette to 
boot a 256k, 512k, and 8.5 meg system, and take advantage of 
the extra memory if it's available?  Well your prayers have
just been answered.

Introducing "enough" (a CLI execute file command).

Enough will test to see if you have enough RAM memory, disk
(DF0:, DF1:, ...) memory or if a file, directory or device
exists.  Any combination of tests may be done at once.  For
example, if you need c:copy, c:assign, and 200k of RAM in
order to copy your C: directory to RAM disk you can test for
this in your startup-sequence execute file as follows:

	failat 10			{optional}
	ENOUGH MEM 200k EXISTS c:copy EXISTS c:assign
	if NOT warn
	  copy c: ram:
	  assign c: ram:
	  endif
	echo "ready."

The advantage of using:
	enough exists foo:bar
	if NOT warn 
	    :
over:
	if exists foo:bar
	    :
is that enough prevents the "Please insert volume foo in any drive"
requester.  So your batch file can check for the existence of a 
volume without "help" from the user.  For example you can say:
	enough exists MY-C-VOL:
	if NOT warn
	   cd My-C-Vol:
	   endif

Anyway, I hope this gives you some ideas for a few creative execute
files.  If you add additional keywords please send your code to me
and I will coordinate updates.  Thank you.

The source code that follows compiles under Lattice V3.03 without
warnings or errors.

	Bruce Barrett
	Commodore-Amiga
	Software QA.
*/

/*	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);
    
	
}