[net.micro.amiga] fm.c

ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) (09/17/86)

[ The line eating bug is dead, but these are still fun, anyway. ]

	Am I the first one to write something like this?  Hmmm....

	Will someone (read: Neil Katin) at Amiga please tell me if I did
this right?  The DOS docs provided only enough information to allow me to
scratch my head a lot.

					Enjoy!
					Schwab

#################### Apply particle beam here. #####################
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	Makefile
#	things.h
#	fm.c
#	file.c
#	misc.c
#	includes.c
# This archive created: Tue Sep 16 21:57:30 1986
# By:	Leo 'Bols Ewhac' Schwab ()
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
	This little toy is designed to allow you to examine the sector
allocation on your disks.  Instead of using the DOS to find files, it uses
the trackdisk.device and examines the sectors directly, traversing the
filesystem "by hand."

	This is written for the Manx compiler; conversion to Lettuce may
or may not be trivial.  To make this beastie, first download all the files,
then do this:

1> make

	Simple, isn't it?

SYNOPSIS
	fm [device [file]]

DESCRIPTION
	fm is a utility that allows you to examine the sector allocation of
files on your disk.

	Unallocated sectors are the background color; file control blocks
are rendered in color 1; data blocks are color 2; and sectors allocated by
other things show up as color 3.

	Files to be examined are entered in the filename gadget.  All
filenames must be a full path from the root.  When entered, the program will
then attempt to find the file and display its allocation on the screen.  If
an error occurs, the program will inform you.  Errors may or may not be
fatal.  However, the program does clean up after itself rather well.

	To change devices, enter a new device name in the device gadget.
The program will then load the bitmap off the new device and display it.  If
you wish to examine a different disk in the same device, you *must* hit the
device gadget and then press RETURN.  Failing to do this causes (non-
destructive) problems, since the bitmap sector number is cached.

	To re-display the current device/file, hit the refresh gadget.  This
is useful if another task is running concurrently and writing to the disk.
Hitting refresh allows you to see the changes made to the disk.

--------

	Enjoy!

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 ________		 ___
	   \		/___--__		Leo L. Schwab
  ___  ___ /\		    ---##\		ihnp4!ptsfa!well!ewhac
      /   X  \_____    |  __ _---))			..or..
     /   /_\--    -----+==____\ // \  _		well ---\
___ (   o---+------------------O/   \/ \	dual ----> !unicom!ewhac
     \     /		    ___ \_  (`o )	hplabs -/       ("AE-wack")
 ____ \___/                          \_/
	      Recumbent Bikes:			"Work FOR?  I don't work FOR
	    The _O_n_l_y Way To Fly!		anybody!  I'm just having fun."
SHAR_EOF
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#  :ts=8 bk=0
# My first Makefile ever.  Please excuse any verbosity.
#
fm:	fm.o misc.o file.o
	ln fm.o misc.o file.o -lc -o fm

fm.o:	fm.c structs.b
	cc +istructs.b fm.c

misc.o:	misc.c structs.b
	cc +istructs.b misc.c

file.o:	file.c structs.b
	cc +istructs.b file.c

structs.b: includes.c
	cc -a +hstructs.b includes.c
	delete includes.asm
SHAR_EOF
fi
if test -f 'things.h'
then
	echo shar: "will not over-write existing file 'things.h'"
else
cat << \SHAR_EOF > 'things.h'
/*  :ts=8 bk=0
 * Lotsa defines and a few global externals.
 */

#define	REV		0L
#define BLOCKSIZE	TD_SECTOR
#define NUMBLOCKS	(NUMCYLS * NUMHEADS * NUMSECS)
#define ROOTBLOCK	(NUMBLOCKS / 2)
#define BITMAPINDEX	79
#define NUMLONGS	(NUMBLOCKS / 32)
#define XX		6L
#define	YY		5L
#define XOFF		30L
#define YOFF		25L
#define BRKOVER		(NUMSECS * YY + YOFF)
#define SEP		6
#define LABEL_Y		(2*NUMSECS*YY+SEP+YOFF+10)
#define ever		(;;)

/*	Offsets into interesting fields in disk blocks	*/
#define SIZE		(BLOCKSIZE/4)
#define NAME		(SIZE-20)
#define HASHCHAIN	(SIZE-4)
#define EXTENSION	(SIZE-2)
#define TYPE		0
#define HEADER_KEY	1
#define SECONDARY_TYPE	(SIZE-1)
#define DIR_HASHTAB	6
#define FH_BLOCKLIST	(SIZE-51)
#define FH_ENDLIST	6

/*	Type definitions (coerced from the DOS using DISKED)	*/
#define T_SHORT		2
#define T_DATA		8
#define T_LIST		16
#define ST_ROOT		1
#define ST_DIR		2
#define ST_FILE		-3


extern void	*OpenLibrary(), *OpenWindow(), *AllocMem(), *Lock(), *Info(),
		*CreatePort(), *CreateExtIO(), *GetMsg(), *index();
extern long	TextLength(), OpenDevice(), ReadPixel();
SHAR_EOF
fi
if test -f 'fm.c'
then
	echo shar: "will not over-write existing file 'fm.c'"
else
cat << \SHAR_EOF > 'fm.c'
/*  :ts=8 bk=0
 * File mapper.  Uses trackdisk.device to grab sectors and traverse the
 * filesystem the hard way to find out what sectors a particular file
 * occupies.
 *
 * Crufted together by Leo Schwab while waiting for an open line on the WELL.
 *	8608.19
 * Finally finished:	8609.16
 * I could have done it quicker if I hadn't started working for Wendy's.
 *
 * Note: This program is only valid for 3.5" floppy drives.
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <devices/trackdisk.h>
#include "things.h"


extern struct NewWindow	windef;
extern struct IntuiText	errmsg, ok;
extern struct Gadget	gad[];
extern char		filename[], devname[];

struct Window	*win;
struct RastPort *rp;
struct InfoData *id;
struct IOExtTD	*diskreq;
struct MsgPort	*diskport;
ULONG		diskchangecount, *diskbuffer, bitmap[SIZE];
int		bmsect;
void		*IntuitionBase, *GfxBase, *lok;


main (ac, av)
char *av[];
{
	struct IntuiMessage *msg;
	struct Gadget *ptr;
	int class;

	if (ac) {
		ac--;  av++;
		if (ac) {
			strcpy (devname, *av);
			ac--;  av++;
		} else
			strcpy (devname, "df0:");

		if (ac)
			strcpy (filename, *av);
		else
			strcpy (filename, ":");
	}
	openstuff ();
	drawgrid ();
	setdev ();

	/*  Process IntuiEvents  */
	for ever {
		WaitPort (win -> UserPort);
		msg = GetMsg (win -> UserPort);
		class = msg -> Class;
		ptr = (struct Gadget *) msg -> IAddress;
		ReplyMsg (msg);
		if (class == CLOSEWINDOW)
			break;
		else if (class == GADGETUP) {
			if (ptr == gad) {		/*  New filename  */
				drawbitmap ();
				findfile (filename);
			} else if (ptr == &gad[1])	/*  New device  */
				setdev ();
			else if (ptr == &gad[2]) {	/*  Refresh screen  */
				getbitmap ();
				drawbitmap ();
				findfile (filename);
			}
		}
	}
	closestuff ();
}


setdev ()
{
	int unit;

	/*
	 * This rather lengthy series of DOS calls is needed to turn DOS
	 * device names into unit numbers that OpenDevice() can deal with.
	 */
	if (!(lok = Lock (devname, ACCESS_READ)))
		die ("Can't obtain lock for specified device.");

	if (!(id = AllocMem ((long) sizeof (*id), MEMF_CLEAR)))
		die ("Can't get InfoData memory.");

	if (!Info (lok, id))
		die ("Call to Info() failed.");

	if (id -> id_DiskType == ID_NO_DISK_PRESENT)
		die ("No disk in drive.");

	unit = id -> id_UnitNumber;
	FreeMem (id, (long) sizeof (*id));  id = NULL;
	UnLock (lok);  lok = NULL;
	opendisk (unit);
	getbitmap ();
	drawbitmap ();
}

getbitmap ()
{
	register int i;

	MotorOn ();
	GetSector ((long) ROOTBLOCK);
	bmsect = diskbuffer [BITMAPINDEX];
	GetSector ((long) bmsect);
	MotorOff ();
	for (i=0; i<SIZE; i++)
		bitmap [i] = diskbuffer [i];
}

drawbitmap ()
{
	register int i, n, l, p;
	int free = NUMBLOCKS-2;
	long k, x, y;
	char buf[80];

	SetDrMd (rp, JAM1);
	SetAPen (rp, 3L);

	/*  Show sectors 0 and 1 (always allocated)  */
	RectFill (rp, XOFF+1, YOFF+1, XX+XOFF-1, YY+YY+YOFF-1);
	l = 2;
	for (i=1; i<=NUMLONGS; i++) {
		k = bitmap[i];
		for (n=0; n<32; n++) {
			/*  Bits progress from low to high order  */
			if (i<NUMLONGS || n<30) {	/*  Ignore last two  */
				/*  Perform icky conversion  */
				x = (l / 22) * XX + XOFF;
				y = (l % 22) * YY + YOFF;
				if (y >= BRKOVER)
					y += SEP;

				/*
				 * The following incantation basically means,
				 * don't draw sectors that don't need to be
				 * drawn.
				 */
				p = ReadPixel (rp, x+1, y+1);
				if (~k & 1) {
					free--;
					if (p != 3) {
						SetAPen (rp, 3L);
						RectFill (rp, x+1, y+1,
							  x+XX-1, y+YY-1);
					}
				} else if (p) {
					SetAPen (rp, 0L);
					RectFill
					 (rp, x+1, y+1, x+XX-1, y+YY-1);
				}
				k >>= 1;
			}
			l++;	/*  Increment sector number  */
		}
	}

	/*  Do labels  */
	SetAPen (rp, 1L);
	SetBPen (rp, 0L);
	SetDrMd (rp, JAM2);
	sprintf (buf, "Bitmap on sector %-4d", bmsect);
	Move (rp, XOFF, LABEL_Y);
	Text (rp, buf, (long) strlen (buf));
	sprintf (buf, "Sectors free: %-4d", free);
	Move (rp, 250L, LABEL_Y);
	Text (rp, buf, (long) strlen (buf));
	sprintf (buf, "Allocated: %-4d", (int) NUMBLOCKS-free);
	Move (rp, 450L, LABEL_Y);
	Text (rp, buf, (long) strlen (buf));
	Move (rp, NUMCYLS*XX+XOFF+10, NUMSECS*YY/2+YOFF+2);
	Text (rp, "Surface 0", 9L);
	Move (rp, NUMCYLS*XX+XOFF+10, NUMSECS*YY/2+BRKOVER+SEP+2);
	Text (rp, "Surface 1", 9L);
}

drawgrid ()	/*  Draw grid and labels so we can see  */
{
	long x, y;

	SetDrMd (rp, JAM1);
	SetAPen (rp, 1L);
	for (x=XOFF; x<=80*XX+XOFF; x += XX) {
		Move (rp, x, YOFF);
		Draw (rp, x, YOFF+11*YY);
		Move (rp, x, BRKOVER+SEP);
		Draw (rp, x, BRKOVER+SEP+11*YY);
	}
	for (y=0; y<=11*YY; y += YY) {
		Move (rp, XOFF, y+YOFF);
		Draw (rp, XOFF+80*XX, y+YOFF);
		Move (rp, XOFF, y+SEP+BRKOVER);
		Draw (rp, XOFF+80*XX, y+SEP+BRKOVER);
	}

	/*  Draw map markings  */
	Move (rp, XOFF+XX/2, YOFF);	  Draw (rp, XOFF+XX/2, YOFF-3);
	Move (rp, XOFF+80*XX-XX/2, YOFF); Draw (rp, XOFF+80*XX-XX/2, YOFF-3);
	Move (rp, XOFF, YOFF+YY/2);	  Draw (rp, XOFF-3, YOFF+YY/2);
	Move (rp, XOFF, YOFF+YY*10+YY/2); Draw (rp, XOFF-3, YOFF+YY*10+YY/2);
	Move (rp, XOFF-1, YOFF-4);	  Text (rp, "0", 1L);
	Move (rp, XOFF+79*XX-1, YOFF-4);  Text (rp, "79", 2L);
	Move (rp, XOFF-12, YOFF+6);	  Text (rp, "0", 1L);
	Move (rp, XOFF-20, YOFF+11*YY);   Text (rp, "10", 2L);
}

marksector (n, color)
long n;
int color;
{
	register int x, y;

	x = (n / 22) * XX + XOFF;
	y = (n % 22) * YY + YOFF;
	if (y >= BRKOVER)
		y += SEP;
	SetAPen (rp, (long) color);
	RectFill (rp, x+1L, y+1L, x+XX-1L, y+YY-1L);
}

openstuff ()
{
	if (!(IntuitionBase = OpenLibrary ("intuition.library", REV))) {
		/*
		 * If we can't open Intuition, then we can't use
		 * AutoRequest ()
		 */
		printf ("Intuition failed; you'll have to use logic.\n");
		closestuff ();
		exit (100);
	}

	if (!(GfxBase = OpenLibrary ("graphics.library", REV))) {
		printf ("Art shop closed.\n");
		closestuff ();
		exit (100);
	}

	if (!(win = OpenWindow (&windef))) {
		printf ("Window painted shut.\n");
		closestuff ();
		exit (100);
	}
	rp = win -> RPort;

	if (!(diskport = CreatePort (NULL, NULL)))
		die ("No port.");

	if (!(diskreq = CreateExtIO (diskport, (long) sizeof (*diskreq))))
		die ("Can't make IO block.");

	if (!(diskbuffer = AllocMem (BLOCKSIZE, MEMF_CLEAR | MEMF_CHIP)))
		die ("Can't allocate disk buffer.");
}

opendisk (unit)
int unit;
{
	long err;
	char *buf[80];

	/*  We may be changing units, so close it if it's open  */
	if (diskreq -> iotd_Req.io_Device) {
		CloseDevice (diskreq);
		diskreq -> iotd_Req.io_Device = NULL;
	}

	if (err = OpenDevice (TD_NAME, (long) unit, diskreq, NULL)) {
		sprintf (buf, "Can't get at disk; err = %ld.", err);
		die (buf);
	}

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

closestuff ()
{
	if (lok)
		UnLock (lok);
	if (diskreq) {
		/*
		 * Apparently, if OpenDevice() fails, it fills in the
		 * io_Device field with -1.  This pretty much blows all
		 * my previous code out of the water, which assumed it got
		 * filled in with 0.  Sigh.  Why don't they tell us these
		 * things?
		 */
		if ((long) diskreq -> iotd_Req.io_Device != -1L)
			CloseDevice (diskreq);
		DeleteExtIO (diskreq, (long) sizeof (*diskreq));
	}

	if (diskbuffer)
		FreeMem (diskbuffer, (long) BLOCKSIZE);
	if (id)
		FreeMem (id, (long) sizeof (*id));
	if (diskport)
		DeletePort (diskport);
	if (win)
		CloseWindow (win);
	if (GfxBase)
		CloseLibrary (GfxBase);
	if (IntuitionBase)
		CloseLibrary (IntuitionBase);
}

notice (str)	/*  For non-fatal errors  */
UBYTE *str;
{
	MotorOff ();
	errmsg.IText = str;
	AutoRequest (win, &errmsg, NULL, &ok, NULL, NULL,
		     TextLength (rp, str, (long) strlen (str)) + 40, 46L);
}

die (str)	/*  For fatal errors  */
UBYTE *str;
{
	errmsg.IText = str;
	AutoRequest (win, &errmsg, NULL, &ok, NULL, NULL,
		     TextLength (rp, str, (long) strlen (str)) + 40, 46L);
	closestuff ();
	exit (100);
}

/*	Guess....
debug (str)
char *str;
{
	printf (str);
	getchar ();

}
*/
SHAR_EOF
fi
if test -f 'file.c'
then
	echo shar: "will not over-write existing file 'file.c'"
else
cat << \SHAR_EOF > 'file.c'
/*  :ts=8 bk=0
 * Filesystem routines (or, How To Find A File The Hard Way)
 */
#include <exec/types.h>
#include <devices/trackdisk.h>
#include "things.h"

extern struct IOExtTD	*diskreq;
extern ULONG		diskchangecount, *diskbuffer;


findfile (name)		/*  Traverse the filesystem the hard way  */
char *name;
{
	register int err;
	register char *b, *e;
	char str[80];

	strcpy (str, name);
	if (b = index (str, ':'))	/*  Ignore device names  */
		b++;
	else
		b = str;

	while (*b == '/')	/*  Ignore leading slashes  */
		b++;
	if (!*b) {		/*  Don't do anything if string is empty  */
		notice ("Badly formed filename.");
		return (0);
	}

	e = b;
	MotorOn ();
	GetSector (ROOTBLOCK);	/*  All paths are relative to the root  */
	while (e) {
		if (!*b) {
			notice ("Badly formed filename.");
			return (0);
		}

		if (e = index (b, '/'))
			*e = '\0';

		if ((err = traverse (b, hash (b))) < 0) {
			switch (err) {
			case -1:
				notice ("Badly formed path.");
				break;
			case -2:
				notice ("File not found.");
				break;
			}
			return (0);
		}

		if (e) {
skip:			b = e+1;
			while (*b == '/')
				b++;
		}
	}
	drawfile ();
	MotorOff ();
	return (1);
}

traverse (str, hash)	/*  Indirect through the disk blocks  */
char *str;
int hash;
{
	register int block;
	register char *file = (char *) &diskbuffer [NAME];

	if (diskbuffer [TYPE] == T_SHORT &&
	    diskbuffer [SECONDARY_TYPE] == ST_FILE)
		/*  Can't indirect out of a file  */
		return (-1);

	strupper (str);
	block = diskbuffer [hash];
	for ever {
		if (!block)
			return (-2);	/*  No such file  */
		GetSector ((long) block);
		/*  Force null termination in case BCPL doesn't do it  */
		file [*file + 1] = '\0';
		strupper (file+1);	/*  Force to all upper case  */
		if (!strcmp (str, file+1))	/*  Is this it?  */
			break;
		/*  This ain't it; traverse hash chain  */
		block = diskbuffer [HASHCHAIN];
	}
	return (1);
}

drawfile ()	/*  Draw file's allocated sectors  */
{
	register int i;

	/*
	 * File control blocks are marked with pen 1, data blocks with pen 2.
	 */
	marksector (diskbuffer [HEADER_KEY], 1);

	if (diskbuffer [TYPE] == T_SHORT &&
	    diskbuffer [SECONDARY_TYPE] == ST_FILE)
		for ever {
			for (i=FH_BLOCKLIST; i>=FH_ENDLIST; i--)
				if (diskbuffer [i])
					marksector (diskbuffer [i], 2);
			if (diskbuffer [EXTENSION]) {
				marksector (diskbuffer [EXTENSION], 1);
				GetSector (diskbuffer [EXTENSION]);
			} else
				break;
		}
}

strupper (str)
register char *str;
{
	while (*str) {
		*str = toupper (*str);
		str++;
	}
}


/*
 * The following routines were stolen from an RKM example by Bob Peck and
 * hacked up a bit.
 */

GetSector (sector)
long sector;
{
	LONG offset = sector * BLOCKSIZE;

	diskreq -> iotd_Req.io_Length = BLOCKSIZE;      
	diskreq -> iotd_Req.io_Data = (APTR) diskbuffer;	
		/* show where to put the data when read */
	diskreq -> iotd_Req.io_Command = ETD_READ;
		/* check that disk not changed before reading */
	diskreq -> iotd_Count = diskchangecount;
	
	/* convert from cylinder, head, sector to byte-offset value to get
   	 * right one (as dos and everyone else sees it)...*/
	
	/* driver reads one CYLINDER at a time (head does not move for
	 * 22 sequential sector reads, or better-put, head doesnt move for
	 * 2 sequential full track reads.)
	 */
	
	diskreq -> iotd_Req.io_Offset = offset;
	DoIO (diskreq);
	return (0);
}

MotorOn()
{
	/* TURN ON DISK MOTOR ... old motor state is returned in io_Actual */
	diskreq -> iotd_Req.io_Length = 1;
	/* this says motor is to be turned on */
	diskreq -> iotd_Req.io_Command = TD_MOTOR;
	/* do something with the motor */
	DoIO (diskreq);
	return (0);
}

MotorOff()
{
	diskreq -> iotd_Req.io_Length = 0;	
	/* says that motor is to be turned on */
	diskreq -> iotd_Req.io_Command = TD_MOTOR;	
	/* do something with the motor */
	DoIO (diskreq);
	return (0);
}


/*
 * The following code segment was thrown at the USENET by Neil Katin.
 * Thanks, Neil.
 */

hash (str)
unsigned char *str;
{
	int res;
	unsigned char *sp;
	unsigned c;

	res = strlen (str);

	for (sp = str; *sp; sp++) {
		c = *sp;
		if (c >= 'a' && c <= 'z')
			c = c - 'a' + 'A';
		res = ((res * 13 + c) & 0x7ff);
	}
	return (res % 72 + DIR_HASHTAB);
}
SHAR_EOF
fi
if test -f 'misc.c'
then
	echo shar: "will not over-write existing file 'misc.c'"
else
cat << \SHAR_EOF > 'misc.c'
/*  :ts=8 bk=0
 * Static structure definitions (mostly for Intuition).
 */

#include <exec/types.h>
#include <intuition/intuition.h>
#include <devices/trackdisk.h>
#include "things.h"


/*
 * IntuiText structures for AutoRequestors
 */
struct IntuiText ok = {
	AUTOFRONTPEN, AUTOBACKPEN,
	AUTODRAWMODE, AUTOLEFTEDGE, AUTOTOPEDGE,
	AUTOITEXTFONT,
	(UBYTE *) "OK",
	AUTONEXTTEXT
};

struct IntuiText errmsg = {
	AUTOFRONTPEN, AUTOBACKPEN,
	AUTODRAWMODE, AUTOLEFTEDGE, AUTOTOPEDGE,
	AUTOITEXTFONT,
	NULL,	/*  Gets filled in later  */
	AUTONEXTTEXT
};


/*
 * Gadgets 'n stuff.
 */

SHORT filebox[] = {	/*  Coordinates for box surrounding gadget  */
	-2, 9,
	-2, -2,
	401, -2,
	401, 9,
	-1, 9,
	-1, -2,
	400, -2,
	400, 9
};

SHORT devbox[] = {
	-2, 9,
	-2, -2,
	41, -2,
	41, 9,
	-1, 9,
	-1, -2,
	40, -2,
	40, 9
};

SHORT redrawbox[] = {
	-2, 10,
	-2, -1,
	65, -1,
	65, 10,
	-1, 10,
	-1, -1,
	64, -1,
	64, 10
};


struct Border bord[] = {	/*  Borders for gadgets  */
 {
 	0, 0,
	1, 0, JAM1,
	8,
	filebox,
	NULL
 }, {
 	0, 0,
	1, 0, JAM1,
	8,
	devbox,
	NULL
 }, {
 	0, 0,
	1, 0, JAM1,
	8,
	redrawbox,
	NULL
 }
};


struct IntuiText rdtext = {	/*  Text for redraw gadget  */
 	1, 0, JAM1,
	4, 1,
	NULL,
	"Refresh",
	NULL
};

struct IntuiText fnametxt = {	/*  Text for filename gadget  */
 	1, 0, JAM1,
	0, -10,
	NULL,
	"Filename",
	NULL
};

struct IntuiText devnamtxt = {	/*  Text for device name gadget  */
 	1, 0, JAM1,
	0, -10,
	NULL,
	"Device",
	NULL
};


/*
 * Filename gadget special info.
 */
char filename[80], ufilename[80];
struct StringInfo filenamegad = {
	filename, ufilename,
	0, 80, 0,
	0, 0, 0, 0, 0, 0, 0, 0
};

char devname[10], udevname[10];
struct StringInfo devnamegad = {
	devname, udevname,
	0, 10, 0,
	0, 0, 0, 0, 0, 0, 0, 0
};


/*
 * List of gadgets for window.
 */
struct Gadget gad[] = {
 {		/*  Filename  */
	&gad[1],
	XOFF, LABEL_Y+15, 50*8, 10,
	GADGHCOMP,
	RELVERIFY,
	STRGADGET,
	&bord[0], NULL,
	&fnametxt,
	0,
	&filenamegad,
	0, 0
 }, {		/*  Device  */
	&gad[2],
	XOFF+XOFF+50*8+20, LABEL_Y+15, 5*8, 10,
	GADGHCOMP,
	RELVERIFY,
	STRGADGET,
	&bord[1], NULL,
	&devnamtxt,
	0,
	&devnamegad,
	1, 0
 }, {		/*  Refresh  */
	NULL,
	XOFF+NUMCYLS*XX+20, BRKOVER, 64, 10,
	GADGHCOMP,
	RELVERIFY,
	BOOLGADGET,
	&bord[2], NULL,
	&rdtext,
	0, 0, 2, 0
 }
};


/*
 * Window definition
 */
struct NewWindow windef = {
	0, 0, 640, 180,
	-1, -1,
	CLOSEWINDOW | GADGETUP,
	WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | ACTIVATE,
	&gad[0],
	NULL,
	(UBYTE *) "File Allocation Map",
	NULL, NULL, 0, 0, 0, 0,
	WBENCHSCREEN
};
SHAR_EOF
fi
if test -f 'includes.c'
then
	echo shar: "will not over-write existing file 'includes.c'"
else
cat << \SHAR_EOF > 'includes.c'
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <devices/trackdisk.h>
#include "things.h"
SHAR_EOF
fi
exit 0
#	End of shell archive