[comp.sys.amiga] MRBackup V1.3 Source, Part 5 of 5

mrr@softie.UUCP (09/26/87)

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file"
# Created Fri Sep 25 07:26:48 1987
#
# This archive contains:
#		FormatDisk.c
#		sendpkt.c
#		Speech.c
#		unixwild.c
echo "Creating FormatDisk.c"
cat > FormatDisk.c <<"***EOF 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)
 *
 * 08/26/87 -MRR- Modified FormatDisk to delay 5 seconds after
 *				  uninhibiting the drive.  This should give enough time
 *                for the validator to do its thing and prevent the
 *				  "Insert disk..." requester from rearing its ugly head
 *                if the application attempts to access the disk as
 *                soon as we return.
 */

#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 <intuition/intuition.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:
 *		drivename:	device name (DF0, etc.)
 *      name:		new volume name
 * 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;
	struct Process *myprocess;
	struct Window *mywindow;
	USHORT status = 0, i, retry, 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
		status = ERROR_INVALID_COMPONENT_NAME;	
		goto cleanup;
	}

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

	if (!(diskbuffer = 
		AllocMem((long) TRACKSIZE, MEMF_PUBLIC | MEMF_CHIP))) {
		status = 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
		status = 1;						/* is there a better error code? */
		goto cleanup;
	}

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

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

	if (status = 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 (status = 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 (status = 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 (status = 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 */

	Delay(3L * TICKS_PER_SECOND);		/* Give it a chance */

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

/* 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
***EOF FormatDisk.c***
echo "Creating sendpkt.c"
cat > sendpkt.c <<"***EOF 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);
}
***EOF sendpkt.c***
echo "Creating Speech.c"
cat > Speech.c <<"***EOF 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 = NULL;
ULONG narrator_status = -1L,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_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
***EOF Speech.c***
echo "Creating unixwild.c"
cat > unixwild.c <<"***EOF unixwild.c***"
/* unixwild.c
 * Unix (tm) wildcard support routines. 
 * Created on 08/07/87
 */

/* Text a filename for wildcard content.
 * Called with:
 *		name:		pathname
 * Returns:
 *		0 => no wild characters
 *		1 => 1 or more wild characters
 */
int
iswild(name)
	char *name;
{
	register char c, *s;

	for (s = name; c = *s++; )
		if (c == '*' || c == '?') return 1;

	return 0;
}


/*
 * Compare a wild card name with a normal name.
 * Called with:
 *		wild:		name with "wild" content
 *		name:		"normal" name
 * Returns:
 *		0 => names don't match
 *		1 => names match
 *
 * This source was lifted from Steve Drew's version of Matt Dillon's
 * shell, version 2.06m.
 * 
 */

#define MAXB   8

int
wildcmp(wild,name)
	char *wild,*name;
{
	register char  *w = wild;
	register char  *n = name;
	char   *back[MAXB][2];
	register char   s1,s2;
	int     bi = 0;

	while (*n || *w){
		switch (*w){
			case '*': 
				if (bi == MAXB){
#ifdef DEBUG
					printf("Too many levels of '*'\n");
#endif
					return (0);
				}
				back[bi][0]= w;
				back[bi][1]= n;
				++bi;
				++w;
				continue;
		goback: 
				--bi;
				while (bi >= 0 && *back[bi][1]== '\0')
					--bi;
				if (bi < 0)
					return (0);
				w = back[bi][0]+ 1;
				n = ++back[bi][1];
				++bi;
				continue;
			case '?': 
				if (!*n){
					if (bi)
						goto goback;
					return (0);
				}
				break;
			default: 
				s1 = (*n >= 'A' && *n <= 'Z')?*n - 'A' + 'a' :*n;
				s2 = (*w >= 'A' && *w <= 'Z')?*w - 'A' + 'a' :*w;
				if (s1 != s2){
					if (bi)
						goto goback;
					return (0);
				}
				break;
		}
		if (*n)
			++n;
		if (*w)
			++w;
	}
	return (1);
}
#ifdef DEBUG
char normal[81], wild[81];
main()
{
	puts("Terminate this program by entering 'quit'");
	for (;;) {
		puts("Enter the non-wild pathname:");
		gets(normal);
		if (!strcmp(normal,"quit")) break;
		if (iswild(normal)) {
			puts("No, idiot!  Enter a non-wild filename!");
			continue;
		}
		puts("Enter a wild pathname:");
		gets(wild);
		if (wildcmp(wild,normal))
			puts("Yup, they match.");
		else
			puts("No match here.");
	}
}
#endif
***EOF unixwild.c***
-- 
< Mark R. Rinfret,        mrr@softie, ..rayssd!unisec!softie!mrr             >
< SofTech, Inc.           Home: 401-846-7639                                 >
< 1 Silva Lane,           Work: 401-849-4174                                 >
< Middletown, RI 02840    "The name has changed but I'm still guilty."       >