[comp.sources.amiga] v02i025: MRBackUp

mark@s.cc.purdue.edu.UUCP (09/17/87)

!!!!!  Note:  If you are using my unshar program, at this point in time,
!!!!!  You MUST create the directory 'misc' before unshar'ing this
!!!!!  file!

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
# This archive created: Wed Sep 16 20:52:10 1987
# By: Craig Norborg (Purdue University Computing Center)
#	Run the following text with /bin/sh to create:
#	misc
#	misc/CopyFile.c
#	misc/DateRequest.c
#	misc/Dates.c
#	misc/DiskMisc.c
#	misc/FileMisc.c
#	misc/RenameDisk.c
#	misc/Speech.c
#	misc/formatdisk.c
#	misc/sendpkt.c
mkdir misc
cat << \SHAR_EOF > misc/CopyFile.c
/* 
 * Copy file, preserving date.  
 * Depends upon file date routines in FileMisc.c 
 * Original author: Jeff Lydiatt, Vancouver, Canada
 */

#include <stdio.h>
#include <exec/types.h>
#include <libraries/dos.h>
#include <exec/memory.h>
#include <functions.h>

#define BUFMAX 32768
#define MAXSTR 127
 
extern char *malloc();
extern long Chk_Abort();
extern BOOL GetFileDate(), SetFileDate();
extern long IoErr();

/* Copy the last modified date from one file to another.
 * Called with:
 *		from:		name of source file
 *		to:			name of destination file
 * Returns:
 *		0 => success, 1 => failure
 * Note:
 *		Dynamic memory allocation of the DateStamp struction is
 *		necessary to insure longword alignment.
 */

BOOL CopyFileDate(from,to)
	char *from, *to;
{
	struct DateStamp *date;
	int status = 1;				/* default is fail code */

	if (date = (struct DateStamp *) 
		AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC)) {
		if (GetFileDate(from,date))
			if (SetFileDate(to,date))
				status = 0;
		FreeMem(date,(long) sizeof(struct DateStamp));
	}
	return status;
}

int     CopyFile(from,to)
char   *from,*to;
{
	char   *buffer;
	char	errmsg[256];
	long    status,count,bufsize;
	struct FileHandle  *fin,*fout;
static char *errfmt = "I/O error %ld, file %s";

	if ((fin = Open(from,MODE_OLDFILE ))== NULL ){
		status = IoErr();
#ifdef DEBUG
		sprintf(errmsg,errfmt,status, from);
print_err:
		puts(errmsg);
#endif
		return status;
	}

	if ((fout = Open(to,MODE_NEWFILE ))== NULL ){
		status = IoErr();
		Close(fin );
#ifdef DEBUG
		sprintf(errmsg,errfmt,IoErr(),to);
		goto print_err;
#endif
		return status;
	}

	for (bufsize = BUFMAX; bufsize > 2048; bufsize -= 2048 )
		if ((buffer = malloc((unsigned int)bufsize))!= NULL )
			break;

	if (bufsize <= 2048 ){
		Close(fin );
		Close(fout );
#ifdef DEBUG
		puts("CopyFile: Not enough memory." );
#endif
		return ERROR_NO_FREE_STORE;
	}

	status = 1;
	while(status > 0 && (count = Read(fin,buffer,bufsize ))== bufsize )
		if (Chk_Abort())
			status = -1;
		else
			status = Write(fout,buffer,count );

	if (status > 0 && count > 0 )
		status = Write(fout,buffer,count );

	Close(fin );
	Close(fout);
	free(buffer);

	if (status < 0 || count < 0 ){
		unlink(to);
		return 1;
	}
	return CopyFileDate(from, to);
}
SHAR_EOF
cat << \SHAR_EOF > misc/DateRequest.c
/* Date Requester Package
 * Author:		Mark R. Rinfret
 * Description:
 *		This source file contains a canned date requester routine which
 * supports time and date entry in MM/DD/YY HH:MM:SS notation (time is
 * optional) to a DateStamp structure.  This package is dependent upon
 * the package "dates.c" (same author) for DateStamp/string conversions.
 *
 * History:		(most recent change first)
 *
 * 07/20/87 -MRR- Created this file.
 */


#include <intuition/intuition.h> 
#include <intuition/intuitionbase.h> 
#include <libraries/dosextens.h> 
#include <graphics/gfxbase.h> 
#include <graphics/gfx.h> 
#include <graphics/display.h> 

#include <graphics/text.h> 
#include <functions.h>

#include <ctype.h> 

/**********************************************************************
 *                    Gadget Structure Definitions
 * 
 * The following structures were defined using EGAD! (by the Programmer's
 * Network) and further modified by the author.
 * 
 **********************************************************************/
/*  Definitions for Gadget ID numbers */ 
#define DATEGAD 0

/**********************************************************************
 *  Text attribute structures used in rendering IntuiTexts
 **********************************************************************/


static char def_font[] ="topaz.font";

static struct TextAttr TxtAt_Plain = { 
	(UBYTE *)def_font, 8, FS_NORMAL, FPF_ROMFONT
	};



/**********************************************************************
 *  Border Definitions for dategad gadget
 **********************************************************************/

static SHORT dategad_Pairs_1[] = {
  0,     0,   
  150,   0,   
  150,   9,   
  0,     9,   
  0,     0    
};

/**********************************************************************
 *  String information for the dategad string gadget.
 **********************************************************************/

static UBYTE dategad_sbuf_1[19] = "00/00/00 00:00:00";
static UBYTE dategad_ubuf_1[19];

static struct StringInfo dategad_txstr_1 = {
  dategad_sbuf_1, dategad_ubuf_1, 	/* Buffer, UndoBuffer  */
  0, 18, 0,  						/* BufferPos, MaxChars, DispPos   */
  0, 18,      						/* UndoPos, NumChars */
  0, 0, 0,  						/* DispCount, CLeft, CTop */
  0x0, 0,   						/* LayerPtr, LongInt */
  0x0        						/* AltKeyMap */
};


/**********************************************************************
 *  Gadget Structure definition for the dategad gadget.
 **********************************************************************/

static struct Gadget dategad = {
  NULL,     /* NextGadget pointer */
  64, 40,    /* LeftEdge, TopEdge  */
  150, 9,    /* Width, Height      */
  /* Gadget Flags */
   GADGHCOMP,
  /* Activation Flags */
	RELVERIFY /* | ENDGADGET */,
  /* GadgetType */
  REQGADGET | STRGADGET,		/* string gadget belongs to requester */
	NULL,						/* GadgetRender - no border */
  NULL,    						/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  (APTR)&dategad_txstr_1,   	/* SpecialInfo */
  DATEGAD,    					/* GadgetID */
  NULL							/* UserData Pointer */
};


static struct Requester daterequest;	/* requester for the date */

static SHORT datereq_pairs1[] = {
  30,  10,   
  230, 10,   
  250, 30,   
  250, 50,   
  230, 70,
  30,  70,
  10,  50,
  10,  30,
  30,  10
};

static struct Border datereq_bord1 = {
  -1,  -1,       /* LeftEdge, TopEdge */
  2,  1,  JAM2,  /* FrontPen, BackPen, DrawMode*/
  9,             /* Count of XY pairs */  
  (SHORT *)&datereq_pairs1, /* XY pairs */
  NULL           /* Next Border */
};

static struct IntuiText datereqtext = {
	2, 1,						/* FrontPen / BackPen */
	JAM2,						/* DrawMode */
	20,							/* LeftEdge */
	30,							/* TopEdge */
	&TxtAt_Plain,				/* ITextFont */
	(UBYTE *) "Enter date:",	/* IText */
	NULL						/* NextText */
	};

static initialized = 0;			/* set to 1 after initialization */

static InitDateRequest()
{
	InitRequester(&daterequest);
	daterequest.LeftEdge = 60;
	daterequest.TopEdge = 10;
	daterequest.Width = 260;
	daterequest.Height = 80;
	daterequest.ReqGadget = &dategad;
	daterequest.ReqText = &datereqtext;
	daterequest.ReqBorder = &datereq_bord1;
	daterequest.BackFill = 0;
	++initialized;
}

/* Request a date from the user.
 * Called with:
 *		window:			pointer to window structure
 *		prompt:			string to be used as the prompt text
 *		default_date:	pointer to default date or NULL
 *		date:			pointer to date result (returned)
 * Returns:
 *		status code:	0 => success, 1 => failure
 *		(actually, always returns 0 - can't leave without good date)
 */

DateRequest(window,prompt,default_date,date)
	struct Window *window; char *prompt; 
	struct DateStamp *default_date,*date;
{
	ULONG class;				/* message class */
	USHORT code;				/* message code */
	USHORT gadgid;				/* gadget ID */
	APTR Iadr;					/* address field from message */
	struct IntuiMessage *msg;	/* Intuition message pointer */
	SHORT x,y;					/* mouse x and y position */

	if (!initialized)
		InitDateRequest();
	datereqtext.IText = prompt;
	if (default_date)			/* write default date in requester? */
		DS2Str(dategad_sbuf_1,"%02m/%02d/%02y %02h:%02n:%02s",
			default_date);
	else
		*dategad_sbuf_1 = '\0';

	Request(&daterequest, window);

	for (;;) {
		Wait(1L << window->UserPort->mp_SigBit);
		while (msg = GetMsg(window->UserPort)) {
			class = msg->Class;
			code = msg->Code;
			Iadr = (APTR) msg->IAddress;
			x = msg->MouseX;
			y = msg->MouseY;
			ReplyMsg(msg);		/* acknowledge the message */

			switch (class) {

			case REQSET: 
				ActivateGadget(&dategad,window,&daterequest);
				break;
			
			case GADGETUP:
				if ( ! Str2DS(dategad_sbuf_1, date) ) {
					EndRequest(&daterequest, window);
					return 0;
				}
				else
					DisplayBeep(window->WScreen); /* bad conversion */
				break;

			default:
				break;			/* ignore the rest */
			}					/* end switch(class) */
		}
	}
}

/* #define DEBUG */

#ifdef DEBUG

/* --- Only compiled in the debug version --- */

#include <exec/memory.h>

/* New window structure */

struct NewWindow newwindow = {
	0,0,640,200,0,1,

/* IDCMP Flags */

	MOUSEMOVE | MENUPICK | MOUSEBUTTONS | 
	CLOSEWINDOW | GADGETDOWN | GADGETUP | REQSET, 

/* Flags */
	WINDOWCLOSE | WINDOWDEPTH | ACTIVATE | RMBTRAP | REPORTMOUSE,

	NULL,							/* First gadget */
	NULL,							/* Checkmark */
	(UBYTE *)"Date Requester Test Program",	/* Window title */
	NULL,							/* No custom streen */
	NULL,							/* Not a super bitmap window */
	0,0,640,200,					/* Not used, but set up anyway */
	WBENCHSCREEN
};
struct IntuitionBase *IntuitionBase;
struct Window *mywindow;
struct DateStamp *ds;

static struct IntuiText MoreText = {
	AUTOFRONTPEN,				/* FrontPen */
	AUTOBACKPEN,				/* BackPen */
	JAM2,						/* DrawMode */
	AUTOLEFTEDGE,				/* LeftEdge */
	AUTOTOPEDGE,				/* TopEdge */
	AUTOITEXTFONT,				/* ITextFont */
	(UBYTE *) "Want to play some more?", /* IText */
	NULL						/* NextText */
	};

static struct IntuiText YesText = {
	AUTOFRONTPEN,				/* FrontPen */
	AUTOBACKPEN,				/* BackPen */
	AUTODRAWMODE,				/* DrawMode */
	AUTOLEFTEDGE,				/* LeftEdge */
	AUTOTOPEDGE,				/* TopEdge */
	AUTOITEXTFONT,				/* ITextFont */
	(UBYTE *) "Sure!", 			/* IText */
	NULL						/* NextText */
	};

static struct IntuiText NoText = {
	AUTOFRONTPEN,				/* FrontPen */
	AUTOBACKPEN,				/* BackPen */
	JAM2,						/* DrawMode */
	AUTOLEFTEDGE,				/* LeftEdge */
	AUTOTOPEDGE,				/* TopEdge */
	AUTOITEXTFONT,				/* ITextFont */
	(UBYTE *) "Nope!", 			/* IText */
	NULL						/* NextText */
	};

main()
{
	short keep_going;

	if (!(IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library",33L))) {
		puts("Failed to open Intuition library!");
		exit(1);
	}

	ds = (struct DateStamp *)
		AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);
	DateStamp(ds);				/* get current date/time */

	mywindow = OpenWindow(&newwindow);

	do {
		DateRequest(mywindow, "Enter date and time", ds, ds);
		keep_going = AutoRequest(mywindow, &MoreText, &YesText, &NoText,
						NULL, NULL, 220L, 50L);
	} while (keep_going);

	if (mywindow)
		CloseWindow(mywindow);

	if (IntuitionBase)
		CloseLibrary(IntuitionBase);
}

#endif
SHAR_EOF
cat << \SHAR_EOF > misc/Dates.c

/* General routines to provide date support for the DateStamp
 * date format.
 *
 * Author:		Mark R. Rinfret	(mark@unisec.usi.com)
 * Date:		07/18/87
 *
 * This source is released to the public domain by the author, without
 * restrictions.  However, it is requested that you give credit where
 * credit is due and share any bug fixes or enhancements with the author.
 */

#include <libraries/dos.h>
#include <exec/memory.h>
#include <ctype.h>
#include <functions.h>

/* #define DEBUG */

typedef struct {
	unsigned short year,month,day,hour,minute,second;
	} unpacked_date;

static char *daynames[] = {
	"Sunday", "Monday", "Tuesday", "Wednesday", 
	"Thursday", "Friday", "Saturday"
	};

static USHORT monthdays[12] =  {0,31,59,90,120,151,181,212,243,273,304,334};

static char *monthnames[12] = {
	"January", "February", "March", "April", "May", "June",
	"July", "August", "September", "October", "November", "December"
	};

/* Compare two DateStamp values.
 * Called with:
 *		d1,d2:		pointers to DateStamp structs
 * 
 * Returns:
 *		< 0 => d1 < d2
 *		  0 => d1 == d2
 *		> 0 => d1 > d2
 *
 * Note:
 *		This routine makes an assumption about the DateStamp structure,
 *		specifically that it can be viewed as an array of 3 long integers
 *		in days, minutes and ticks order.
 */

int 
CompareDS(d1, d2)
	long *d1, *d2;
{
	USHORT i;
	long compare;

	for (i = 0; i < 3; ++i) {
		if (compare = (d1[i] - d2[i])) {
			if (compare < 0) return -1;
			return 1;
		}
	}
	return 0;						/* dates match */
}

/* Convert a DateStamp to a formatted string.
 * Called with:
 *		fmt:	format string
 *			The format of the format string is very similar to that
 *			for printf, with the exception that the following letters
 *			have special significance:
 *				y => year minus 1900
 *				Y => full year value
 *				m => month value as integer
 *				M => month name
 *				d => day of month (1..31)
 *				D => day name ("Monday".."Sunday")
 *				h => hour in twenty-four hour notation
 *				H => hour in twelve hour notation
 *				i => 12 hour indicator for H notation (AM or PM)
 *				I => same as i
 *				n => minutes	(sorry...conflict with m = months)
 *				N => same as n
 *				s => seconds
 *				S => same as s
 *
 *			All other characters are passed through as part of the normal
 *			formatting process.  The following are some examples with
 *			Saturday, July 18, 1987, 13:53 as an input date:
 *
 *				"%y/%m/%d"			=> 87/7/18
 *				"%02m/%02d/%2y"		=> 07/18/87
 *				"%D, %M %d, %Y"		=> Saturday, July 18, 1987
 *				"%02H:%02m i"		=> 01:53 PM
 *				"Time now: %h%m"	=> Time now: 13:53
 *
 *		str:	string to write date on
 *		d:		pointer to DateStamp structure
 *		
 */
void
DS2Str(str,fmt,d)
	char *str, *fmt; struct DateStamp *d;
{
	unpacked_date date;
	char fc,*fs,*out;
	USHORT ivalue;
	char new_fmt[256];			/* make it big to be "safe" */
	USHORT new_fmt_lng;
	char *svalue;

	UnpackDS(d, &date);			/* convert DateStamp to unpacked format */

	*str = '\0';				/* insure output is empty */
	out = str;
	fs = fmt;					/* make copy of format string pointer */

	while (fc = *fs++) {		/* get format characters */
		if (fc == '%') {		/* formatting meta-character? */
			new_fmt_lng = 0;
			new_fmt[new_fmt_lng++] = fc;
			/* copy width information */
			while (isdigit(fc = *fs++) || fc == '-')
				new_fmt[new_fmt_lng++] = fc;

			switch (fc) {		/* what are we trying to do? */
			case 'y':			/* year - 1980 */
				ivalue = date.year - 1900;
write_int:
				new_fmt[new_fmt_lng++] = 'd';
				new_fmt[new_fmt_lng] = '\0';
				sprintf(out,new_fmt,ivalue);
				out = str + strlen(str);
				break;
			case 'Y':			/* full year value */
				ivalue = date.year;
				goto write_int;

			case 'm':			/* month */
				ivalue = date.month;
				goto write_int;

			case 'M':			/* month name */
				svalue = monthnames[date.month - 1];
write_str:
				new_fmt[new_fmt_lng++] = 's';
				new_fmt[new_fmt_lng] = '\0';
				sprintf(out,new_fmt,svalue);
				out = str + strlen(str);
				break;

			case 'd':			/* day */
				ivalue = date.day;
				goto write_int;

			case 'D':			/* day name */
				svalue = daynames[d->ds_Days % 7];
				goto write_str;

			case 'h':			/* hour */
				ivalue = date.hour;
				goto write_int;

			case 'H':			/* hour in 12 hour notation */
				ivalue = date.hour;
				if (ivalue >= 12) ivalue -= 12;
				goto write_int;

			case 'i':			/* AM/PM indicator */
			case 'I':
				if (date.hour >= 12)
					svalue = "PM";
				else
					svalue = "AM";
				goto write_str;

			case 'n':			/* minutes */
			case 'N':
				ivalue = date.minute;
				goto write_int;

			case 's':			/* seconds */
			case 'S':
				ivalue = date.second;
				goto write_int;

			default:
				/* We are in deep caca - don't know what to do with this
				 * format character.  Copy the raw format string to the
				 * output as debugging information.
				 */
				new_fmt[new_fmt_lng++] = fc;
				new_fmt[new_fmt_lng] = '\0';
				strcat(out, new_fmt);
				out = out + strlen(out);	/* advance string pointer */
				break;
			}
		}
		else
			*out++ = fc;		/* copy literal character */
	}
	*out = '\0';				/* terminating null */
}

/* Convert a string to a DateStamp.
 * Called with:
 *		str:	string containing date in MM/DD/YY format		
 *		d:		pointer to DateStamp structure
 * Returns:
 *	    status code (0 => success, 1 => failure)
 */

int
Str2DS(str, d)
	char *str; struct DateStamp *d;
{
	register char c;
	int count;
	int i, item;
	char *s;

	int values[3];
	int value;
	int years,months,days,hours,minutes,seconds;

	s = str;
	for (item = 0; item < 2; ++item) {	/* item = date, then time */
		for (i = 0; i < 3; ++i) values[i] = 0;
		count = 0;
		while (c = *s++) {			/* get date value */
			if (c <= ' ') 
				break;

			if (isdigit(c)) {
				value = 0;
				do {
					value = value*10 + c - '0';
					c = *s++;
				} while (isdigit(c));
				if (count == 3) {
	bad_value:
#ifdef DEBUG
					puts("Error in date-time format.\n");
					printf("at %s: values(%d) = %d, %d, %d\n",
						s, count, values[0], values[1], values[2]);
#endif
					return 1;
				}
				values[count++] = value;
				if (c <= ' ')
					break;
			}
		}							/* end while */
		if (item) {					/* getting time? */
			hours = values[0];
			minutes = values[1];
			seconds = values[2];
		}
		else {						/* getting date? */
			if (count != 3)
				goto bad_value;
			months = values[0];
			days = values[1];
			years = values[2];
		}
	}								/* end for */
	SetDateStamp(d,years,months,days,hours,minutes,seconds);
	return 0;
}


/* Set a DateStamp structure, given the date/time components.
 * Called with:
 *		d:			pointer to DateStamp
 *		years:		may be 19xx or just xx
 *		months:		1..12
 *		days:		1..31
 *		minutes: 	0..59
 *		seconds: 	0..59
 */
SetDateStamp(d,years,months,days,hours,minutes,seconds)
	struct DateStamp *d; int years,months,days,hours,minutes,seconds;
{
	USHORT leapyear;

	if (years > 1900)
		years = years - 1900;

	leapyear = (years % 4 ? 0 : 1);

	years = years - 78;
	if (months < 1 || months > 12)	/* somebody goofed? */
		months = 1;

	days = days - 1 + monthdays[months-1];
	if (leapyear && (months > 2))
		++days;

	d->ds_Days = years * 365 + (years + 1) / 4 + days ;
	d->ds_Minute = hours * 60 + minutes;
	d->ds_Tick = seconds * TICKS_PER_SECOND;
}

/* Unpack a DateStamp structure into an unpacked_date structure. 
 * Called with:
 *		ds:		pointer to DateStamp structure
 *		du:		pointer to unpacked_date structure
 */
UnpackDS(ds, du)
	struct DateStamp *ds; unpacked_date *du;
{
	USHORT i, leap_years, leap, temp, test_value;

	du->year = ds->ds_Days / 365 + 1978;
	
	/* is current year a leapyear? */
	leap = ( (du->year % 4) == 0); 

	/* how many leap years since "beginning of time"? */
	leap_years = (du->year - 1976 - 1) / 4;

	/* get days remaining in year */
	temp = ds->ds_Days % 365 - leap_years;

	/* find month */

	du->month = 0;
	du->day = 0;
	for (i = 11; i >= 0; --i) {
		test_value = monthdays[i];
		if (i > 2) test_value += leap;
		if (temp >= test_value) {
			du->month = i + 1;
			du->day = temp - test_value + 1;
			break;
		}
	}

	du->hour = ds->ds_Minute / 60;
	du->minute = ds->ds_Minute % 60;
	du->second = ds->ds_Tick / TICKS_PER_SECOND;
}


#ifdef DEBUG
main()
{
	int compflag;
	char datestr[81], instr[81];
	struct DateStamp *ds, *now;
	unpacked_date du;

	now = (struct DateStamp *) 
		AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);

	ds = (struct DateStamp *) 
		AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);

	puts("Enter a date string and I will convert it.  To quit, hit RETURN");
	while (1) {
		DateStamp(now);
		UnpackDS(now, &du);

		printf("\nCurrent date and time: %02d/%02d/%02d %02d:%02d:%02d\n",
			du.month,du.day,du.year,du.hour,du.minute,du.second);

		puts("\nEnter the date [and time]:");
		gets(instr);
		if (*instr == '\0') break;
		if (Str2DS(instr,ds))
			puts("Error encountered in input string");
		else {
			DS2Str(datestr, "%02m/%02d/%02y %02h:%02n:%02s", ds);
			puts(datestr);

			DS2Str(datestr, "%D, %M %d, %Y", ds);
			puts(datestr);

			DS2Str(datestr, "The time entered is %02H:%02N %i", ds);
			puts(datestr);

			compflag = CompareDS(ds,now);
			printf("The date input is ");
			if (compflag < 0)
				printf("earlier than");
			else if (compflag == 0)
				printf("the same as");
			else
				printf("later than");
			puts(" the current date.");
		}
	}

	FreeMem(ds, (long) sizeof(struct DateStamp));
	FreeMem(now, (long) sizeof(struct DateStamp));
}
#endif
SHAR_EOF
cat << \SHAR_EOF > misc/DiskMisc.c
/* DiskMisc.c - miscellaneous disk support routines.
 * Mark Rinfret (et al), 1987
 */

/*#define DEBUG*/

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <libraries/dosextens.h>
#include <functions.h>

extern LONG 	sendpkt();

/* This routine returns the number of disk blocks remaining on the
 * drive specified by 'name'.  Though 'name' would typically be the
 * drive name or volume name, it can also be the name of any file
 * on the disk drive.
 * Called with:
 *		name:		disk device or volume name
 * Returns:
 *		> 0 => number of blocks available
 *		< 0 => error status
 */

long DiskBlocks(name)
	char *name;
{
	struct FileLock *lock = NULL;
	struct InfoData *info = NULL;
	long int blocks = -1L;
	long IoErr();

	if (lock = (struct FileLock *) Lock(name,ACCESS_READ)) {
		if (info = AllocMem((long)sizeof(struct InfoData),MEMF_PUBLIC)) {
			if (Info(lock,info)) {
				blocks = info->id_NumBlocks - info->id_NumBlocksUsed;
			}
			else {
				blocks = -IoErr();
#ifdef DEBUG
				printf("DiskBlocks: can't get Info on %s; error %ld\n",
					name, blocks);
#endif
				}
		}
		else {
			blocks = -ERROR_NO_FREE_STORE;
#ifdef DEBUG
			puts("DiskBlocks: no memory!");
#endif
		}
	}
	else {
		blocks = -IoErr();
#ifdef DEBUG
		printf("DiskBlocks: can't lock %s; error %ld\n",name,blocks);
#endif
	}

	if (lock)	UnLock(lock);
	if (info)	FreeMem(info,(long)sizeof(struct InfoData));
	return blocks;					/* bad status indicator */
}

/* Disk ACTION_INHIBIT support routine.
 * Author:		Mark R. Rinfret
 * Date:		06/29/87
 * 
 * This routine provides support for user-written disk formatting, copy
 * operations which benefit from suppressing/restoring disk validation.
 */

int
Inhibit(drivename, code)
	char *drivename; int code;
{
	struct MsgPort     *task;
	LONG 	arg[2];
	LONG 	rc;

	if (!(task=(struct MsgPort *) DeviceProc(drivename))) 
		return 1;						/* fail, darn it! */

	arg[0] = code;

	/* Now, cross all your fingers and toes... */

	return ( !sendpkt(task,ACTION_INHIBIT,arg,1));
}

#ifdef DEBUG
main()
{
	long blocks;

	blocks = DiskBlocks("df0:");
	if (blocks == -1L)
		puts("Bad status from DiskBlocks()");
	else
		printf("Disk blocks left on df0: %ld\n",blocks);
}
#endif
SHAR_EOF
cat << \SHAR_EOF > misc/FileMisc.c
/* File date routines.
 * Filename:	FileDates.c
 */

#include "exec/types.h"
#include "exec/ports.h"
#include "exec/io.h"
#include "exec/memory.h"
#include "libraries/dosextens.h"
#include <stdio.h>
#define AZTEC 1
#ifdef AZTEC
#include "functions.h"				/* aztec C include */
#endif

#define ACTION_SETDATE_MODE 34L		/* Set creation date on file */
#define DOSTRUE 	    -1L			/* AmigaDos TRUE */
#define MAXARGS          7L			/* limit in packet structure
									   (dosextens.h) */
#define NARGS		     4L			/* Number of args for setdate */

long    sendpkt();

^L
/*---------------------------------------------------------------------*/
/*  GetFileDate: get the datestamp the given file.			       	   */
/*---------------------------------------------------------------------*/

BOOL GetFileDate(name, date)
char   *name;
register struct DateStamp  *date;
{
	struct FileInfoBlock   *Fib;
	ULONG   FLock;
	int     result;
	register struct DateStamp  *d;

	if ((FLock = (ULONG)Lock(name,(long)(ACCESS_READ)))== NULL)
		return FALSE;

	Fib = (struct FileInfoBlock *)
		AllocMem((long)sizeof(struct FileInfoBlock),
					(long)(MEMF_CHIP|MEMF_PUBLIC));

	if (Fib == NULL )
		result = FALSE;
	else{
		if (!Examine(FLock,Fib ))
			result = FALSE;
		else 
			if (Fib->fib_DirEntryType > 0 )
				result = FALSE;		/* It's a directory */
			else{
				d = &Fib->fib_Date;
				date->ds_Days = d->ds_Days;
				date->ds_Minute = d->ds_Minute;
				date->ds_Tick = d->ds_Tick;
				result = TRUE;
			}
		FreeMem((void *)Fib,(long)sizeof(struct FileInfoBlock));
	}

	UnLock(FLock);
	return result;
}
^L
/* Examine a pathname to determine if it is a device or directory name.
 * Called with:
 *		name:		pathname specification
 * Returns:
 *		0 =>		no
 *		1 => 		yes
 *	   <0 =>		-<system error number>
 */
int
IsDir(name)
	char *name;
{
	struct FileInfoBlock   *FIB = NULL;
    struct Lock *lock = NULL;	
	int status;


	if (!(FIB =
		AllocMem((long)sizeof(struct FileInfoBlock),
				 MEMF_CHIP|MEMF_CLEAR))) {
		return -ERROR_NO_FREE_STORE;
	}

	if (!(lock=Lock(name,SHARED_LOCK))) {
		status = -IoErr();
		goto done;
	}

	if ((Examine(lock,FIB))==0){
		status = -IoErr();
		goto done;
	}

	status = (FIB->fib_DirEntryType > 0);
done:
	if (FIB)
		FreeMem(FIB, (long) sizeof(struct FileInfoBlock));
	UnLock(lock);
	return status;
}
^L
/*---------------------------------------------------------------------*/
/*  SetFileDate: datestamp the given file with the given date.	       */
/*---------------------------------------------------------------------*/

BOOL SetFileDate(name,date )
char   *name;
struct DateStamp   *date;
{
	struct MsgPort     *task;		/* for process id handler */
	ULONG   arg[4];					/* array of arguments     */
	char   *bstr, *strcpy();		/* of file to be set      */
	long    rc;
	char   *strchr();
	int     strlen();

	rc = 0;

	if (!(bstr = (char *)AllocMem(68L,(long)(MEMF_PUBLIC))))
		goto exit2;

	if (!(task = (struct MsgPort *)DeviceProc(name )))
		goto exit1;

 /* Dos Packet needs the filename in Bstring format */

	(void)strcpy(bstr+1,name );
	*bstr = strlen(name );

	arg[0]= (ULONG)NULL;
	arg[1]= (ULONG)IoErr();			/* lock on parent director set by
									   DeviceProc() */
	arg[2]= (ULONG)bstr >> 2;
	arg[3]= (ULONG)date;
	rc = sendpkt(task,ACTION_SETDATE_MODE,arg,4L );

exit1: if (bstr )
		FreeMem((void *)bstr,68L );
exit2: if (rc == DOSTRUE )
		return TRUE;
	else
		return FALSE;
}
SHAR_EOF
cat << \SHAR_EOF > misc/RenameDisk.c
/* Rename a disk.
 * Author:		Mark R. Rinfret
 * Date:		06/27/87
 *
 * This package was derived from "touch.c", written by Andy Finkel
 * and Phil Lindsay of Commodore-Amiga.  I wrote RenameDisk as a
 * support routine for my hard disk backup utility.
 */

/* Enable the next #define if you want to do testing.  This will cause
 * generation of a main program.  For practical use, the RELABEL command
 * in the C: directory is much more efficient.
 */

/* #define STAND_ALONE */

#include "exec/types.h"
#include "exec/ports.h"
#include "exec/io.h"
#include "exec/memory.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"

#ifdef AZTEC_C
#include <functions.h>
#endif

extern LONG 	sendpkt();

#ifndef AZTEC_C
extern int      strcpy();
extern int      strlen();
#endif

#define DOSTRUE 	    -1
#define MAX_NAME		30L	

#ifdef STAND_ALONE
main(argc,argv)
int     argc;
char   *argv[];
{
	unsigned code = 0;

	if(argc!=3){
		puts("Bad arguments\n");
	}
	else
		if (RenameDisk(argv[1], argv[2]))
			code = 20;

	exit(code);
}
#endif

int
RenameDisk(oldname, newname)
	char *oldname, *newname;
{
	struct MsgPort     *task;
	LONG 	arg[4];
	LONG 	rc;
	USHORT  fail = 0;
	ULONG   lock;
	ULONG   plock;
	UBYTE  *pointer;

	if (strlen(newname) >= MAX_NAME) 	/* name too long? */
		return 1;

	if(!(pointer= (UBYTE *) AllocMem(MAX_NAME,MEMF_PUBLIC))) {
		++fail;
		goto cleanup;
	}

	if (!(task=(struct MsgPort *) DeviceProc(oldname))) {
		++fail;
		goto cleanup;
	}

	/* Make sure that the old name is valid. */

	if(!(lock = (ULONG) Lock(oldname,SHARED_LOCK))) {
		++fail;
		goto cleanup;
	}
	UnLock(lock);

	/* Convert the nice C string to an ugly BSTR :-) */

	strcpy((pointer + 1),newname);
	*pointer = strlen(newname);
	arg[0]= (ULONG) &pointer[0]>> 2;	/* BSTR of filename */

	/* Now, cross all your fingers and toes... */
	rc = sendpkt(task,ACTION_RENAME_DISK,arg,1);
	if(!rc)
		++fail;
cleanup:
	if (pointer)
		FreeMem(pointer, MAX_NAME);
	return fail;
}

/* This is the actual workhorse which tells DOS what to do.  Aztec C
 * has a new function, "dos_packet", but I prefer this one.  Thanks,
 * Phil and Andy!
 */

LONG 
sendpkt(id,type,args,nargs)
struct MsgPort     *id;				/* process indentifier ... (handler's
									   message port ) */
LONG type,							/* packet type ... (what you want 
									   handler to do )   */
args[],								/* a pointer to argument list */
nargs;								/* number of arguments in list  */
{

	struct MsgPort     *replyport;
	struct StandardPacket  *packet;

	LONG count,*pargs,res1=NULL;


	if (!(replyport = (struct MsgPort   *) CreatePort(NULL,NULL)))
		return(NULL);

	packet = (struct StandardPacket *)
	           AllocMem((LONG)sizeof(*packet),MEMF_PUBLIC|MEMF_CLEAR);

	if (packet) {
		packet->sp_Msg.mn_Node.ln_Name = &(packet->sp_Pkt);/* link packet */
		packet->sp_Pkt.dp_Link = &(packet->sp_Msg);/* to message    */
		packet->sp_Pkt.dp_Port = replyport;/* set-up reply port   */
		packet->sp_Pkt.dp_Type = type;/* what to do... */

	/* move all the arguments to the packet */
		pargs = &(packet->sp_Pkt.dp_Arg1);/* address of first argument */
		for (count=0; (count < nargs) && (count < 7); count++)
			pargs[count] = args[count];

		PutMsg(id,packet);			/* send packet */
		WaitPort(replyport);		/* wait for packet to come back */
		GetMsg(replyport);			/* pull message */

		res1 = packet->sp_Pkt.dp_Res1;/* get result */
		FreeMem(packet,(LONG)sizeof(*packet));

	}
	DeletePort(replyport);
	return(res1);
}

/* Functions strcpy, strlen are defined by Aztec C library. */

#ifndef AZTEC_C
int
        strcpy(to,from )
register char  *to,*from;
{
	do {
		*to++= *from;
	}while(*from++);
}

int
        strlen(s )
register char  *s;
{
	register    i = 0;

	while(*s++)
		i++;

	return(i );
}
#endif
/* eof */
SHAR_EOF
cat << \SHAR_EOF > misc/Speech.c

/* Minimal-capability speech support package.
 * Author:		Mark R. Rinfret
 * Date:		07/30/87
 * Description:
 *
 *		This package provides a quick and dirty means for adding
 *		speech to C language programs.  In order to use it, observe
 *		the following:
 *
 *			1. Call SpeechOn - return parameter of 0 => success.
 *			2. Call Say(<your message in English>) as often as the
 *			   application requires.
 *			3. Call SpeechOff to close libraries/ports/devices.
 */

#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <devices/narrator.h>
#include <libraries/translator.h>
#include <functions.h>

/*#define DEBUG */


#define PHONEME_MAX 1024L		/* size of phoneme buffer */

/* Which audio channels to use */

BYTE audio_chan[] = {3, 5, 10, 12};

struct Library *TranslatorBase = NULL;
struct narrator_rb voice_io;	/* Narrator I/O request block */
struct MsgPort *voice_port;
ULONG narrator_status,translate_error;

UBYTE Phonemes[PHONEME_MAX];	/* Phoneme text buffer */

/******************
 *    ROUTINES    *
 ******************/

/* Enable speech capability. */

SpeechOn(on)
	int on;
{

   if (!(TranslatorBase = (struct Library *)
    	OpenLibrary("translator.library", (long) LIBRARY_VERSION))) {
#ifdef DEBUG
      	DebugWrite("Can't open the translator library!\n");
#endif
fail:
	    SpeechOff();			/* close whatever's open */
      	return 1;
   }

	/* Open a reply port for the narrator. */

	if (!(voice_port = CreatePort(0L, 0L))) {
#ifdef DEBUG
		DebugWrite("Can't create narrator reply port!\n");
#endif
		goto fail;
	}

	voice_io.message.io_Message.mn_ReplyPort = voice_port;

   /* Open the device */
   if ((narrator_status = 
   			OpenDevice("narrator.device", 0L, &voice_io, 0L))) {
#ifdef DEBUG
      DebugWrite("Can't open the Narrator device!\n");
#endif
      goto fail;
   }


   return 0;
}

SpeechOff()
{
	if (voice_port) 
		DeletePort(voice_port);

   	if (!narrator_status)
      	CloseDevice(&voice_io);

   	if (TranslatorBase)
      	CloseLibrary(TranslatorBase);

   	return(0);
}

Say(English)
	char *English;
{
	if (!TranslatorBase) {
		if (SpeechOn())	return 1;
	}

    if (translate_error = 
		Translate(English, (long) strlen(English), 
				  Phonemes, PHONEME_MAX)) {
#ifdef DEBUG
         DebugWrite("Translator error!\n");
#endif
      }

/* Set up the write channel information */

	voice_io.ch_masks = (UBYTE *) (audio_chan);
	voice_io.nm_masks = sizeof(audio_chan);
	voice_io.mouths = 0;
	/*voice_io.message.io_Message.mn_ReplyPort = NULL;*/
	voice_io.message.io_Command = CMD_WRITE;
	voice_io.message.io_Offset = 0;
	voice_io.message.io_Data = (APTR)Phonemes;
	voice_io.message.io_Message.mn_Length = sizeof(voice_io);
	voice_io.message.io_Length = strlen(Phonemes);
	DoIO(&voice_io);
} 


#ifdef DEBUG
DebugWrite(msg)
	char *msg;
{
	puts(msg);
}

main()
{
	short i;
 	char *s;

static char *text[] = {
	"I am an Amiga computer.  I am currently testing my voice ability.",
	"This is pretty incredible, don't you agree?  I thought you would.",
	"This package is really a set of routines to be used by an application.",
	"All you have to do is call Speech On first, ",
	"then call Say as often as you like.",
	NULL
	};

	SpeechOn();
	for (i = 0;s = text[i]; ++i) {
		Say(s);
		Delay(30L);
	}
	SpeechOff();
}
#endif
SHAR_EOF
cat << \SHAR_EOF > misc/formatdisk.c
/* Format a floppy disk (880k drive).
 * Author:		Mark R. Rinfret
 * Date:		06/28/87
 * Description:
 *		This set of routines may be incorporated into a program which
 *	has need of formatting a floppy disk.  I wrote it to support my
 *	hard disk backup utility.
 *
 * History:		(most recent change first)
 */

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <exec/io.h>
#include <exec/tasks.h>
#include <exec/execbase.h>
#include <exec/devices.h>
#include <devices/trackdisk.h>
#include <libraries/dosextens.h>
#include <functions.h>

extern struct IOExtTD *CreateExtIO();

static int CkIOErr();

/* #define DEBUG */
#define MAX_NAME	30L
#define TD_WRITE	CMD_WRITE
#define TRACKSIZE	NUMSECS * TD_SECTOR


/* Format a floppy disk - hardwired for the 3.5" 880k floppy drives.
 * Called with:
 *		unit:		drive number (0 - NUMUNITS-1)
 * Returns:
 *		Zero on success, 1 on failure
 * Note:
 *		This routine does not currently perform a verification, as
 *		recommended by the RKM.  Perhaps later...
 *		I also discovered that there's some erroneous crap in 
 *		"The Amiga Programmer's Workbook, Vol. II", by 
 *		Eugene P. Mortimore.  On page 339, he states that only 512
 *		bytes of track data are required for formatting.  The RKM
 *		correctly states that a "track's worth of data" is required.
 *		It took some playing with DiskEd to discover this error.
 */

int FormatDisk(drivename,name)
	char *drivename; char *name;
{

	long checksum;
	char *dos_id = "DOS";
	long dosword = 0;
	SHORT error;
	struct MsgPort *diskport = NULL;
	struct IOExtTD *diskreq = NULL;
	ULONG diskchangecount;
	USHORT fail = 0, i, track;
	int unit; 
	char *volname;

	char *diskbuffer;
	ULONG *diskblock;			/* alias for diskbuffer, ULONG type */

	if (strlen(name) >= MAX_NAME) {
#ifdef DEBUG
		printf("Disk name is too long!\n");
#endif
		fail = ERROR_INVALID_COMPONENT_NAME;	
		goto cleanup;
	}

	if ((unit = (drivename[2]-'0')) < 0 || unit >= NUMUNITS) {
#ifdef DEBUG
		printf("FormatDisk: invalid drive specification!\n");
#endif
		fail = ERROR_INVALID_COMPONENT_NAME;
		goto cleanup;
	}

	if (!(diskbuffer = 
		AllocMem((long) TRACKSIZE, MEMF_PUBLIC | MEMF_CHIP))) {
		fail = ERROR_NO_FREE_STORE;
		goto cleanup;
	}

	/* Store DOS "magic word" in disk block to be written during
	 * formatting. 
	 */
	diskblock = (ULONG *) diskbuffer;/* we'll need this later */
	for (i = 0; i < 3; ++i)
		dosword = (dosword << 8) | dos_id[i];
	dosword = dosword << 8;

#ifdef DEBUG
	printf("dosword is %lx\n",dosword);
#endif
	for (i = 0; i < TRACKSIZE / 4; ++i)
		diskblock[i] = (dosword | (long) (i & 0xff));

	if ((diskport = CreatePort(0L, 0L)) == NULL) {
#ifdef DEBUG
		printf("FormatDisk can't create port!\n");
#endif
		fail = 1;						/* is there a better error code? */
		goto cleanup;
	}

	if (!(diskreq = (struct IOExtTD *) 
		CreateExtIO(diskport, (long) sizeof(struct IOExtTD)))) {
		fail = 1;
		goto cleanup;
	}

	if (fail = OpenDevice(TD_NAME, (long) unit, diskreq, 0L)) {
#ifdef DEBUG
		printf("FormatDisk: OpenDevice error: %d\n",error);
#endif
		goto cleanup;
	}

	if (fail = Inhibit(drivename, 1)) {
#ifdef DEBUG
		printf("FormatDisk: unable to inhibit drive!\n");
#endif
		goto cleanup;
	}

/* Get the current disk change count.  This allows the trackdisk
 * driver to detect unwanted disk changes later on.
 */

	diskreq->iotd_Req.io_Command = TD_CHANGENUM;
	DoIO(diskreq);

/* Save a copy of the disk change count. */

	diskchangecount = diskreq->iotd_Req.io_Actual;

#ifdef DEBUG
	printf("Current disk change count is %ld\n", diskchangecount);
#endif


	/* Format the disk, one track at a time. */

	for (track = 0; track < NUMTRACKS; ++track) {
		diskreq->iotd_Req.io_Command = TD_FORMAT;
		diskreq->iotd_Req.io_Flags = 0;
		diskreq->iotd_Req.io_Data = (APTR) diskbuffer;
		diskreq->iotd_Count = diskchangecount;
		diskreq->iotd_Req.io_Length = NUMSECS * TD_SECTOR; 
		diskreq->iotd_Req.io_Offset = track * NUMSECS * TD_SECTOR;
		DoIO(diskreq);

		if (fail = CkIOErr(diskreq,"Formatting error")) {
#ifdef DEBUG
			printf("  Track: %d\n",track);
#endif
			goto cleanup;
		}
	}

	/* Now comes some real KLUDGING.  Fill in the root block and the
	 * first hash block.  The information for this was gathered from
	 * the "AmigaDos Technical Reference Manual" and some sleuthing
	 * with DiskEd.
	 */

	for (i = 0; i < 128; ++i)
		diskblock[i] = 0;

	diskblock[0] = 2;			/* T.SHORT (type) */
	diskblock[3] = 128 - 56;	/* hashtable size */
	diskblock[78] = 0xffffffff; /* BMFLAG */
	diskblock[79] = 881;		/* first bitmap block */
	DateStamp(&diskblock[105]);	/* volume last altered date/time */
	DateStamp(&diskblock[121]); /* volume creation date/time */
	volname = (char *) &diskblock[108];
	/* convert input name to BSTR */
	*volname = strlen(name);
	for (i = 0; i < *volname; ++i)
		*(volname + 1 + i) = *(name + i);

	diskblock[127] = 1;			/* ST.ROOT (secondary type) */

	checksum = 0;
	for (i = 0; i < 128; ++i)
		checksum += diskblock[i];

	diskblock[5] = - checksum;

	/* Write the root block out to the disk. */

	diskreq->iotd_Req.io_Command = TD_WRITE;
	diskreq->iotd_Req.io_Length = TD_SECTOR;
	diskreq->iotd_Req.io_Offset = TD_SECTOR * 880L;
	DoIO(diskreq);
	if (fail = CkIOErr(diskreq, "Error writing root block")) {
		goto cleanup;
	}

	/* Write the first bitmap block. */

	for (i = 0; i < 56; ++i)
		diskblock[i] = 0xffffffff;

	for (i = 56; i < 128; ++i)
		diskblock[i] = 0;

	diskblock[0] = 0xc000c037;	/* hint: x37 = 55 (last word of map?) */
	diskblock[28] = 0xffff3fff; /* blocks 880, 881 used */
	diskblock[55] = 0x3fffffff; /* blocks 1760, 1761 used? */

	diskreq->iotd_Req.io_Length = TD_SECTOR;
	diskreq->iotd_Req.io_Offset = 881L * TD_SECTOR;
	DoIO(diskreq);					/* write out the bitmap */
	if (fail = CkIOErr(diskreq, "Error writing bitmap")) {
		goto cleanup;
	}

	diskreq->iotd_Req.io_Command = ETD_UPDATE;
	diskreq->iotd_Req.io_Flags = 0;
	DoIO(diskreq);

	/* Turn the disk motor off. */

	diskreq->iotd_Req.io_Command = TD_MOTOR;
	diskreq->iotd_Req.io_Length = 0;
	DoIO(diskreq);
	Inhibit(drivename, 0);				/* enable disk validator */

cleanup:
	CloseDevice(diskreq);
	if (diskbuffer) FreeMem(diskbuffer, (long) TRACKSIZE);
	if (diskreq) DeleteExtIO(diskreq, (long) sizeof(*diskreq));
	if (diskport) DeletePort(diskport);
	return fail;
}

/* Check the disk request block for an error code.  If an error
 * occurred, print the argument string.
 * Called with:
 *		req:	pointer to I/O request structure
 *		msg:	error message string
 * Returns:
 *		error code from request structure
 */
static int CkIOErr(req, msg)
	struct IOStdReq *req; char *msg;
{
	register int code;

	if (code = req->io_Error) {
#ifdef DEBUG
		printf("%s, code: %d\n",msg,code);
#endif
	}
	return code;
}

#ifdef DEBUG
main(argc, argv)
	int argc; char *argv[];
{
	char *diskname;
	char *volname;

	int unit;

	if (argc < 3)
		volname = "GoodJob!";
	else
		volname = argv[2];

	if (argc < 2)
		diskname = "DF1:";
	else {
		diskname = argv[1];
		if (strlen(diskname) != 4 || 
			(strncmp(diskname,"df",2) && strncmp(diskname,"DF",2))) {
bad_drive:
			printf("Drive name may only be df0: through df3:!\n");
			exit(1);
		}
		if ((unit = (diskname[2] - '0')) < 0 || unit > 3)
			goto bad_drive;

	}
	printf("Insert disk in %s, then hit return\n",diskname);
	while (getchar() != '\n');
	if (FormatDisk(diskname,volname))
		printf("FormatDisk failed\n");
	else {
		printf("FormatDisk succeeded\n");
	}
}
#endif
SHAR_EOF
cat << \SHAR_EOF > misc/sendpkt.c
/* Filename:	sendpkt.c
 * Authors:		Andy Finkel, Phil Lindsay, Commodore-Amiga
 * Date:		06/29/87
 *
 * This package was derived from "touch.c", written by Andy Finkel
 * and Phil Lindsay of Commodore-Amiga.  
 */

#include "exec/types.h"
#include "exec/ports.h"
#include "exec/io.h"
#include "exec/memory.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"

#ifdef AZTEC_C
#include <functions.h>
#endif

LONG 
sendpkt(id,type,args,nargs)
struct MsgPort     *id;				/* process indentifier ... (handler's
									   message port ) */
LONG type,							/* packet type ... (what you want 
									   handler to do )   */
args[],								/* a pointer to argument list */
nargs;								/* number of arguments in list  */
{

	struct MsgPort     *replyport;
	struct StandardPacket  *packet;

	LONG count,*pargs,res1=NULL;

	if (!(replyport = (struct MsgPort   *) CreatePort(NULL,NULL)))
		return(NULL);

	packet = (struct StandardPacket *)
	           AllocMem((LONG)sizeof(*packet),MEMF_PUBLIC|MEMF_CLEAR);

	if (packet) {
		packet->sp_Msg.mn_Node.ln_Name = &(packet->sp_Pkt);/* link packet */
		packet->sp_Pkt.dp_Link = &(packet->sp_Msg);/* to message    */
		packet->sp_Pkt.dp_Port = replyport;/* set-up reply port   */
		packet->sp_Pkt.dp_Type = type;/* what to do... */

	/* move all the arguments to the packet */
		pargs = &(packet->sp_Pkt.dp_Arg1);/* address of first argument */
		for (count=0; (count < nargs) && (count < 7); count++)
			pargs[count] = args[count];

		PutMsg(id,packet);			/* send packet */
		WaitPort(replyport);		/* wait for packet to come back */
		GetMsg(replyport);			/* pull message */

		res1 = packet->sp_Pkt.dp_Res1;/* get result */
		FreeMem(packet,(LONG)sizeof(*packet));

	}
	DeletePort(replyport);
	return(res1);
}
SHAR_EOF