[comp.sources.amiga] v89i127: backdrop - put pattern behind cli windows

page%swap@Sun.COM (Bob Page) (05/11/89)

Submitted-by: ecarroll@vax1.tcd.ie (Eddy Carroll)
Posting-number: Volume 89, Issue 127
Archive-name: util/backdrop.1

Backdrop puts a pattern in the area behind the CLI windows.  The only
program I had which would give a similar effect was DropCloth by Eric
Lavitsky, but this requires Workbench to be loaded.  Backdrop won't
work very well with Workbench, which suits me fine since I hardly ever
use Workbench.

[uuencoded exectuable included.  ..bob]

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	README
#	backdrop.c
#	atoi.a
#	res.a
#	tiny.a
#	Makefile
#	Sys-Conf.uu
#	backdrop.uu
#	backdrop.n
# This is archive 1 of a 1-part kit.
# This archive created: Thu May 11 00:35:34 1989
echo "extracting README"
sed 's/^X//' << \SHAR_EOF > README
XThis archive includes all the files necessary to recreate a working copy
Xof Backdrop, a utility which puts a pattern in the area behind the CLI
Xwindow. See Backdrop.n for more information.
X
XAlso included is a System-Configuration file which you can copy into the
XDEVS directory of your system disk. It makes your Amiga boot up with an
Xinterlaced overscan workbench, giving you an resolution of around 704x562
X(on a PAL screen). When used with Backdrop, this can make for a very
Xdisplay which looks like those seen on expensive workstations (and Macs).
XFor best effect, turn the contrast and brightness down to prevent flicker
X(unless you are fortunate enough to have a Flicker Fixer). It's not really
Xthat usable on a normal monitor, but it looks impressive.
SHAR_EOF
echo "extracting backdrop.c"
sed 's/^X//' << \SHAR_EOF > backdrop.c
X/*
X * Backdrop (C) Copyright Eddy Carroll 1989, may be Freely Redistributed
X *
X * Backdrop allows you to define a pattern which will then be displayed
X * in the empty screen area behind all the windows (who said Macintosh? :-)
X *
X * Usage: Backdrop { -a# | -b# | -f | -p# | -q | -s | B1B2B3B4B5B6B7B8}
X *
X * If no parameters are given, the default is a half tone grey pattern.
X *
X * -a or -b followed by a number sets the foreground or background colour
X * to the corresponding pen number (0 - 3)
X *
X * -f and -s select either a SMART_REFRESH or SIMPLE_REFRESH window to
X * display the backdrop pattern in. The former gives fast screen updates,
X * but uses up quite a bit of memory, whereas the latter uses up very
X * little memory but is slower at updating the screen.
X *
X * -p followed by a number selects the built in pattern corresponding to that
X * number. If you try and select a pattern number not available, you get
X * the default.
X *
X * -q kills the background copy of Backdrop currently installed, if any.
X *
X * A list of 16 hex digits will be interpreted as a user defined pattern,
X * which should be viewed as an 8x8 grid.
X *
X * The first time you run Backdrop, it installs itself in memory. Future
X * invocations of Backdrop will merely tell this first copy about any
X * changes in parameters, until the -q option is used to remove it. Note
X * that all the parameters, including window type, can be changed even
X * while Backdrop is currently running.
X *
X * Compiles under Lattice C V4.0
X *
X */
X
X#include <exec/types.h>
X#include <graphics/gfxbase.h>
X#include <graphics/gfxmacros.h>
X#include <intuition/intuition.h>
X#include <intuition/intuitionbase.h>
X#include <libraries/dos.h>
X#include <proto/exec.h>
X#include <proto/graphics.h>
X#include <proto/dos.h>
X#include <proto/intuition.h>
X#include <string.h>
X
X#define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) + 'a' - 'A' : (c))
X#define YES		1
X#define NO		0
X#define NUMPATS	19		/* Number of predefined patterns available		*/
X#define REPEAT  9999	/* Special return value indicates reopen window */
X#define UNSET	-1		/* Indicates a parameter is currently unset		*/
X
X#define htoi(c) (((c) - '0' - 7 * ((c) >= 'A')) & 0x0F)	/* Hex to int */
X
Xstruct IntuitionBase *IntuitionBase;
Xstruct GfxBase *GfxBase;
XULONG BackGroundIO = 0;
X
Xchar usage1[] = "\
XBackdrop (C) Copyright Eddy Carroll 1989, adds backdrop to Workbench screen\n",
Xusage2[] = "\
XUsage: Backdrop {-f | -p# | -q | -s | B1B2B3B4B5B6B7B8}\n\
X\n\
X		-a# - Set foreground colour to specified pen #\n\
X		-b# - Set background colour to specified pen #\n",
Xusage3[] = "\
X		-f  - Enable fast update (uses more memory)\n\
X		-p# - Use specified pattern # (1-5)\n\
X		-q  - Remove backdrop from memory\n\
X		-s  - Enable slow update\n\
X   B1B2B3B4B5B6B7B8 - 16 hex digits defining an 8x8 pattern\n\
X\n> ";
X
Xchar Portname[] = "Backdrop";
X
Xstruct Pattern {
X	UWORD value[8];
X} Patterns[] = {
X	{ 0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA }, /* Check */
X	{ 0xFFFF,0x4040,0x4040,0x4040,0xFFFF,0x0404,0x0404,0x0404 }, /* Brick */
X	{ 0x8888,0x0000,0x0000,0x0000,0x8888,0x0000,0x0000,0x0000 },
X	{ 0x8888,0x0000,0x2222,0x0000,0x8888,0x0000,0x2222,0x0000 },
X	{ 0xAAAA,0x0000,0xAAAA,0x0000,0xAAAA,0x0000,0xAAAA,0x0000 },
X	{ 0xAAAA,0x0000,0x5555,0x0000,0xAAAA,0x0000,0x5555,0x0000 },
X	{ 0x8888,0x2222,0x8888,0x2222,0x8888,0x2222,0x8888,0x2222 },
X	{ 0xAAAA,0xAAAA,0x5555,0x5555,0xAAAA,0xAAAA,0x5555,0x5555 },
X	{ 0xCCCC,0x3333,0xCCCC,0x3333,0xCCCC,0x3333,0xCCCC,0x3333 },
X	{ 0xFFFF,0x8181,0xBDBD,0xA5A5,0xA5A5,0xBDBD,0x8181,0xFFFF },
X	{ 0xFEFE,0x8282,0xBABA,0xAAAA,0xBABA,0x8282,0xFEFE,0x0000 },
X	{ 0x9999,0xCCCC,0x6666,0x3333,0x9999,0xCCCC,0x6666,0x3333 },
X	{ 0x9999,0x3333,0x6666,0xCCCC,0x9999,0x3333,0x6666,0xCCCC },
X	{ 0x0000,0x4444,0x2828,0x1010,0x2828,0x4444,0x0000,0x0000 },
X	{ 0x0000,0x5454,0x0202,0x5858,0x1A1A,0x4040,0x2A2A,0x0000 },
X	{ 0xAAAA,0x4444,0xAAAA,0x0000,0xAAAA,0x4444,0xAAAA,0x0000 },
X	{ 0xC3C3,0x6666,0x3C3C,0x1818,0x3C3C,0x6666,0xC3C3,0x8181 },
X	{ 0xDBDB,0x6666,0x3C3C,0x9999,0x9999,0x3C3C,0x6666,0xDBDB },
X	{ 0x6666,0xF0F0,0x9999,0x0F0F,0x6666,0xF0F0,0x9999,0x0F0F },
X	{ 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF }
X};
X
Xstruct MyMsgPort {
X	struct MsgPort mp;				/* A genuine message port	*/
X	struct Pattern pat;				/* Current pattern			*/
X	ULONG  windowflags;				/* Flags for our window		*/
X	UBYTE  foreground,background;	/* Colours for window		*/
X} port;
X
Xtypedef struct MessagePort	MP;
Xtypedef struct MyMsgPort	MyMP;
Xtypedef struct IntuiMessage	IM;
X
X#define WINDOWFLAGS	(BORDERLESS | BACKDROP)
X
Xstruct NewWindow nw = {
X	0,0,
X	320,200,	/* Max dimensions will be filled in at run time */
X	0,1,		/* These colours are also filled in at run time */
X	REFRESHWINDOW,
X	NULL,	/* Window flags will be filled in at run time */
X	NULL, NULL,
X	NULL,
X	NULL, NULL,
X	0,0,0,0,
X	WBENCHSCREEN
X};
X
X/*
X * The start of the program. All main does is interpret the command line
X * parameters, and then determine whether there is already a copy of Backdrop
X * running or not. If there isn't, a public message port is set up for
X * future reference, else the other copy of Backdrop is informed of the
X * changes to the parameters.
X *
X */
X
Xvoid main(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	int quit = NO, error = NO;
X	UWORD n,i,j;
X	MyMP *myport;
X	struct Task *FindTask(), *othertask;
X	char *p;
X	int doback();
X	void resloop();
X	BPTR stdout;
X
X	stdout = Output();
X	Write(stdout,usage1,sizeof(usage1));
X
X	/*   Check to see if we are already running. If we are, initialise
X	 *   contents of our local port structure with the current contents,
X	 *   else initialise them to default values.
X	 */
X
X	if ((myport = (MyMP *)FindPort(Portname)) == NULL) {
X		/* --- First time being run --- */
X		port.foreground = 1;					 /* Default pen colour     */
X		port.background = 0;					 /* Default background col */
X		port.windowflags = SMART_REFRESH | WINDOWFLAGS;	 /* Window type    */
X		port.pat = Patterns[0];					 /* Default pattern        */
X		port.mp.mp_Node.ln_Name = Portname;      /* Set the port name      */
X		port.mp.mp_SigBit = AllocSignal(-1L);	 /* Get signal # for port  */
X	} else {
X		/* --- Already running a copy --- */
X		port = *myport;	/* Get copy of current contents */
X	}
X
X	/* Now parse command line, updating parameters as necessary */
X
X	while (argc > 1) {
X		if (argv[1][0] == '-') {
X			n = atoi(&argv[1][2]);	/* Get possible second parameter */
X			switch (tolower(argv[1][1])) {
X				case 'a':
X					port.foreground = n;
X					break;
X				case 'b':
X					port.background = n;
X					break;
X				case 'p':
X					if (n < 0 || n > NUMPATS-1)
X						n = 0;
X					port.pat = Patterns[n];
X					break;
X				case 'q':
X					quit = YES;
X					break;
X				case 'f':
X					port.windowflags = WINDOWFLAGS | SMART_REFRESH;
X					break;
X				case 's':
X					port.windowflags = WINDOWFLAGS | SIMPLE_REFRESH;
X					break;
X				default:
X					error = YES;
X					break;
X			}
X		} else if ((strlen(p = argv[1])) == 16) {
X			/* Convert 16 digit hex value into pattern */
X			for (i = 0; i < 8; i++) {
X				for (n = 0, j = 0; j < 2; j++,p++) {
X					n = n<<4 | htoi(*p);
X				}
X				port.pat.value[i] = n<<8 | n;
X			}
X		} else
X			error = YES;
X
X		if (error) {
X			Write(stdout,usage2,sizeof(usage2));
X			Write(stdout,usage3,sizeof(usage3));
X			exit(10);
X		}
X		argv++;
X		argc--;
X	}
X
X	/*   Now local copy of port contains an up-to-date copy of the
X	 *   current settings
X	 */
X
X	if (myport == NULL) {
X		/* --- First time being run --- */
X		if (quit)
X			exit(10);	/* No work to do if backdrop not active already */
X		AddPort(&port);							 /* Make our port public  */
X		/* Detach this process from CLI, and setup process ID in port	*/
X		if (!res("Backdrop",4,resloop,4000))
X			RemPort(&port);
X		exit(0);
X	} else {
X		othertask = myport->mp.mp_SigTask;
X
X		/* If quit, tell the other copy to quit */
X		if (quit) {
X			Signal(othertask, SIGBREAKF_CTRL_C);
X			exit(0);
X		}
X
X		/* Else we have a new pattern to install */
X		Forbid();	/* Stop other copy trying to access the array */
X		*myport = port; /* Copy updated parameters back to global store */
X		Permit();
X		Signal(othertask, SIGBREAKF_CTRL_F); /* Force screen update */
X		exit(0);
X	}
X}
X
X/*
X * This is the main loop. It just keeps looping around, until it is told
X * to exit (via a special return value from doback()). When it returns,
X * it actually is returning to AmigaDOS() which will then remove it from
X * the system.
X *
X */
Xvoid resloop()
X{
X	port.mp.mp_SigTask = FindTask(0L);	/* Set pointer to our task */
X	while (doback() == REPEAT)		 /* Do intuition stuff	  */
X		;
X	/* We got some kind of exit code, so clean up */
X	RemPort(&port);	/* Kill our public port  */
X}
X
X/*
X * This routine is where all the actual work gets done. A backdrop window
X * is opened on the workbench screen, and filled with the current pattern.
X * Then it waits for messages from Intuition saying the window needs to be
X * refreshed, and for signals from other invocations of Backdrop. A CTRL-C
X * signal causes Backdrop to remove itself, and CTRL-F forces the screen
X * to be updated. The return value is an error code, in case some resources
X * couldn't be allocated (0 or 10).
X *
X */
X
X#define OLIB(a,b) ((a = (struct a *)OpenLibrary(b,33L)) == NULL)
X
Xint doback()
X{
X	struct Window *win;
X	struct RastPort *rp;
X	struct Screen *scr;
X	IM *msg;
X	int err = 10, xmax, ymax,;
X	ULONG signal,lock;
X
X	if (OLIB(IntuitionBase,"intuition.library"))
X		goto err1;
X
X	if (OLIB(GfxBase,"graphics.library"))
X		goto err2;
X
X	/* Now find the maximum size for our window by peeking at the dimensions
X	 * of the Workbench screen. If no workbench screen is open, we exit.
X	 */
X	lock = LockIBase(0L);
X	for (scr = IntuitionBase->FirstScreen; scr; scr = scr->NextScreen) {
X		if ((scr->Flags & SCREENTYPE) == WBENCHSCREEN) {
X			xmax = scr->Width;
X			ymax = scr->Height;
X			break;
X		}
X	}
X	UnlockIBase(lock);
X
X	if (scr == NULL)
X		goto err2;	/* If couldn't find workbench screen, we fail */
X
X	nw.Width  = xmax;
X	nw.Height = ymax;
X	nw.Flags  = port.windowflags;
X
X	if ((win = OpenWindow(&nw)) == NULL)
X		goto err3;
X
X	err = 0;	/* Everything opened ok, so indicate no error */
X	rp = win->RPort;
X	SetDrMd(rp,JAM2);
X	SetAfPt(rp,&port.pat.value[0],3);	/* Set area pattern */
X
X
X#define IDCMPMASK (1<<win->UserPort->mp_SigBit)
X#define CTRL_C (SIGBREAKF_CTRL_C)
X#define CTRL_F (SIGBREAKF_CTRL_F)
X
X	while (1) {
X		SetAPen(rp,port.foreground);
X		SetBPen(rp,port.background);
X		RectFill(rp,0,0,xmax,ymax);
X		signal = Wait(CTRL_C | CTRL_F | IDCMPMASK);
X
X		/* If we got a CTRL_C, break out of this loop */
X		if (signal & CTRL_C)
X			break;
X
X		/* Else was CTRL_F or a refresh event from Intuition */
X
X		if (signal & IDCMPMASK) {
X			/* Flush Intuition messages */
X			while ((msg = (IM *)GetMsg(win->UserPort)) != NULL)
X				ReplyMsg((APTR)msg);
X		}
X
X		/* Now check if user wants a different sort of window type */
X
X		if (nw.Flags != port.windowflags) {
X			err = REPEAT;	/* Indicate we want to reopen window */
X			break;
X		}
X		/* Else loop back to start, and force redraw of window */
X	}
X
X	/* We get down to here if a CTRL_C is received */
X
X	err4:
X		CloseWindow(win);
X
X	err3:
X		CloseLibrary(GfxBase);
X
X	err2:
X		CloseLibrary(IntuitionBase);
X
X	err1:
X		return(err);
X}
X
X/*
X *   These definitions just stop the corresponding library routines getting
X *   pulled in, which helps keep the code size down.
X */
X
Xint brk(){return(0);}
Xvoid MemCleanup(){}
Xvoid chkabort(){}
SHAR_EOF
echo "extracting atoi.a"
sed 's/^X//' << \SHAR_EOF > atoi.a
X* :ts=8
X*
X* A very simple function which simply converts an ASCII string to its numeric
X* equivalent. It is MUCH smaller than it's equivalent in the Lattice
X* library.
X*
X
X	xdef	atoi
X
X	csect   text,0,0,1,2
X
Xatoi:
X	moveq	#0,d0			; Initialise integer to 0
X	moveq	#0,d1			; Initialise temporary variable
X	move.l	4(a7),a0		; Get pointer to string
Xloop:
X	move.b	(a0)+,d1		; Get next character from string
X	subi.b	#$30,d1			; Convert to range 0-9
X	cmpi.b	#10,d1			; If outside range,
X	bhi.s	exit			; then return to caller
X	mulu	#10,d0			; Update count
X	add.l	d1,d0			; Add in new digit
X	bra.s	loop			; And go back for next digit
Xexit:
X	rts				; Return with number in D0
X
X	end
SHAR_EOF
echo "extracting res.a"
sed 's/^X//' << \SHAR_EOF > res.a
X*:ts=8
X*****************************************************************************
X*                                                                           *
X* RES.A                                    (C) Copyright Eddy Carroll 1989  *
X*                                                                           *
X* This module allows you to make a duplicate copy of your current process.  *
X* In fact, both processes actually share the same code. However, the        *
X* seglist pointer of the current process is modified so that when the       *
X* process terminates, the memory doesn't get freed (if it did, the new      *
X* process would suddenly find itself deallocated. Hello guru...)            *
X* This code only works when called from CLI processes.                      *
X*                                                                           *
X* The parameters passed are similar to those for CreateProc(), with the     *
X* difference that instead of passing a BPTR to a seglist, you pass the      *
X* address of the function the new process should start executing at.        *
X*                                                                           *
X* When the new process returns from this function, it will be removed from  *
X* the system, and its memory (finally) deallocated.                         *
X*                                                                           *
X* The typical use for a function like this is to allow a program to detach  *
X* itself from a CLI (completely, with no trailing console handles etc.)     *
X* when it is run. This is a convenient feature for the user, if the program *
X* is of the sort designed to sit in the background the whole time, rather   *
X* than do something immediately, then exit.                                 *
X*                                                                           *
X* Lattice provide cback.o which on first look would seem to provide a       *
X* similar solution. However, cback.o makes it difficult to print error      *
X* messages to the console if there is an error on the command line - by     *
X* the time you spot the error, the CLI prompt has already been printed      *
X* and your error message is printed after it. This looks very messy.        *
X* In addition, cback.o doesn't let you shut the CLI window after detaching  *
X* a process, which can be annoying. res doesn't suffer from any such        *
X* inhibitions.                                                              *
X*                                                                           *
X* From C, you call it as follows:                                           *
X*                                                                           *
X* pid = res(name,pri,func,stacksize)                                        *
X*                                                                           *
X* name         - pointer to null terminated string                          *
X* pri          - integer, priority of the new process                       *
X* func         - pointer to the function for new process to call            *
X* stacksize    - integer, size of the stack for the new process             *
X*                                                                           *
X* pid          - Process ID of new process, or 0 if none created            *
X*                                                                           *
X*****************************************************************************
X
X	INCLUDE "exec/types.i"
X        INCLUDE "exec/alerts.i"
X        INCLUDE "exec/nodes.i"
X        INCLUDE "exec/lists.i"
X        INCLUDE "exec/ports.i"
X        INCLUDE "exec/libraries.i"
X        INCLUDE "exec/tasks.i"
X        INCLUDE "libraries/dos.i"
X        INCLUDE "libraries/dosextens.i"
X        INCLUDE "workbench/startup.i"
X        INCLUDE "exec/funcdef.i"
X        INCLUDE "exec/exec_lib.i"
X        INCLUDE "libraries/dos_lib.i"
X
X	xref	SysBase
X	xref	DOSBase
X	xdef	res
X
XAbsExecBase	equ	4
Xsegsize		equ	36		; Size of fake seg. (code = 28 bytes)
X
X        csect   text,0,0,1,2		* xref's after this are 16-bit reloc
X
X	xref	exit
X
Xcallsys macro
X        CALLLIB _LVO\1
X	endm
X
X
Xres:
X	movem.l	d2-d4/a2/a3/a6,-(a7)	; Save registers
X	move.l	AbsExecBase.w,a6	; Get base of Exec library
X	moveq	#0,d1			; Any sort of memory will do
X	moveq	#segsize,d0		; Get size of fake segment
X	callsys	AllocMem		; Grab some memory
X	tst.l	d0			; Did we get any?
X	beq	fatal			; If not, abort immediately!
X	move.l	d0,a3			; Save pointer to memory
X	sub.l	a1,a1			; NULL pointer indicates our process
X	callsys	FindTask		; Get pointer to our process block
X	move.l	d0,a2			; Save it
X	move.l	pr_CLI(A2),a0		; Get BPTR to our process's segarray
X	add.l	a0,a0			; Convert BPTR to address
X	add.l	a0,a0			; 
X	move.l	cli_Module(a0),4(a3)	; Make fake segment point to our code
X	clr.l	cli_Module(a0)		; Remove process seg. from CLI seglist
X	move.l	#segsize,(a3)		; Set size of fake seglist
X	lea.l	8(a3),a2		; Get pointer to first code byte
X
X;
X; Now a tiny machine code program is constructed. It looks like this:
X;
X;	move.l	#$xxxxxx,A4	; Initialise A4
X;	jsr	$xxxxxx		; Call user program
X;	move.l	#$xxxxxx,A6	; Load DOSbase into A6
X;	move.l	#$xxxxxx,d1	; Get BPTR to this segment 
X;	jmp	UnLoadSeg(A6)	; Unload our process from memory
X;
X; It's built "on the fly" so to speak, to keep code size down, and also
X; because it's a convenient way of initialising all the variables.
X; Note that a potential problem exists if DOSBase should somehow alter or
X; disappear. We'll assume it will remain relatively stable for the next
X; few years anyway :-)
X;
X
X	move.l	DOSBase,a6		; Prepare for DOS call
X	move.w	#$287C,(a2)+		; Store MOVE.L $xxxxxx,A4 instruction
X	move.l	a4,(a2)+		; Output value of A4 to initialise to
X	move.w	#$4EB9,(a2)+		; Store JSR $xxxxxx
X	move.l	36(a7),(a2)+		; followed by address of user function
X	move.w	#$2C7C,(a2)+		; Store MOVE.L $xxxxxx,A6 instruction
X	move.l	a6,(a2)+		; followeds by current DOSbase
X;
X	lea	4(a3),a3		; Now get seglist ptr to fake segment
X	move.l	a3,d3			; and convert it to BPTR
X	lsr.l	#2,d3			; D3 now has seglist ptr to fake seg
X	move.w	#$223C,(a2)+		; Store MOVE.L $xxxxxx,D1 instruction
X	move.l	d3,(a2)+		; Followed by BPTR to the segment
X	move.l	#$4EEEFF64,(a2)+	; Store JMP UnLoadSeg(A6)
X;
X	move.l	28(A7),d1		; Get pointer to name
X	move.l	32(A7),d2		; Get process priority
X	move.l	40(A7),d4		; Get stacksize
X	move.l	d1,$03f0
X	callsys	CreateProc		; Create new process
X	movem.l	(a7)+,d2-d4/a2/a3/a6	; Pop registers
X	rts				; Return
Xfatal:
X	moveq	#120,d0			; Set error exit code
X	jmp	exit			; And exit
X
X	end
SHAR_EOF
echo "extracting tiny.a"
sed 's/^X//' << \SHAR_EOF > tiny.a
X*:ts=8
X****************************************************************************
X*                                                                          *
X* TINY.A                                  (C) Copyright Eddy Carroll 1989  *
X* ~~~~~~                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
X*                                                                          *
X* This is a rewrite of the startup code provided with Lattice C V4.0.      *
X* It is a "bare bones" version, which is substantially smaller, and also   *
X* allows programs to be linked without needing to access lc.lib (unless    *
X* of course they are using functions in lc.lib). Only CLI programs are     *
X* supported, and no default i/o channels or other lattice-specific stuff   *
X* are initialised. exit() doesn't automatically clean up any more, so      *
X* don't use things like malloc() and fopen() unless you call free() and    *
X* fclose() yourself. This replacement is designed for programs that go     *
X* directly to AmigaDOS and Exec, rather than through the Unix-like Lattice *
X* functions.                                                               *
X*                                                                          *
X* All in all, this version shaves around 1500 bytes off the size of a C    *
X* program. No guarantees are supplied as regards its suitability for any   *
X* particular use, other than it works for me.                              *
X*                                                                          *
X* Using it is very simple: Simply modify the command line for BLINK from   *
X* BLINK FROM LIB:C.O+.... to BLINK FROM TINY.O+... and leave everything    *
X* else the same.                                                           *
X*                                                                          *
X* Note that when assembling this, make sure to specify the -u switch on    *
X* the Lattice assembler's command line. This adds a '_' to all symbols     *
X* defined. If you are using a different assembler, you need to add a '_'   *
X* manually yourself.                                                       *
X*                                                                          *
X****************************************************************************
X
X        INCLUDE "exec/types.i"
X        INCLUDE "exec/alerts.i"
X        INCLUDE "exec/nodes.i"
X        INCLUDE "exec/lists.i"
X        INCLUDE "exec/ports.i"
X        INCLUDE "exec/libraries.i"
X        INCLUDE "exec/tasks.i"
X        INCLUDE "libraries/dos.i"
X        INCLUDE "libraries/dosextens.i"
X        INCLUDE "workbench/startup.i"
X        INCLUDE "exec/funcdef.i"
X        INCLUDE "exec/exec_lib.i"
X        INCLUDE "libraries/dos_lib.i"
X
XMAXARGS	    EQU 32	; Maximum number of command line arguments from CLI
XAbsExecBase EQU 4	; Welcome to the only fixed point in the universe
X
X* A useful macro to let us call library routines
Xcallsys macro
X        CALLLIB _LVO\1
X        endm
X        
X        xdef    XCEXIT			* exit(code) is standard way to exit C.
X	xdef	exit                    *
X
X        xref    LinkerDB        	* linker defined base value
X        xref    _BSSBAS			* linker defined base of BSS
X        xref    _BSSLEN			* linker defined length of BSS
X
X*       library references
X
X        csect   text,0,0,1,2		* xref's after this are 16-bit reloc
X
X        xref    main			* Name of C program to start with.
X
Xstart:
X        movem.l d1-d6/a0-a6,-(a7)
XREGSIZE EQU     (6+7)*4
X        lea     REGSIZE(a7),A5         * Determine old stack pointer
X        move.l  a0,a2                  * Save command pointer
X        move.l  d0,d2                  * and command length
X        lea     LinkerDB,a4            * Load base register
X
X        move.l  AbsExecBase.W,a6
X        move.l  a6,SysBase(A4)
X        move.l  a7,_StackPtr(A4)       * Save stack ptr
X
X	suba.l	a1,a1
X	callsys	FindTask	       * Find out our task ID
X	move.l	d0,a3
X
X*=======================================================================
X*====== CLI Startup Code ===============================================
X*=======================================================================
X*
X* Entry: D2 = command length
X*        A2 = Command pointer
XfromCLI:
X        move.l  a5,D0           * get top of stack
X        sub.l   4(a5),D0        * compute bottom 
X        add.l   #128,D0         * allow for parms overflow
X        move.l  D0,_base(A4)    * save for stack checking
X*-----------------------------------------------------------------------
X*  Open the DOS library:
X
XopenDOS
X	lea     DOSName(A4),A1
X	moveq.l #0,D0
X	callsys OpenLibrary
X	move.l  D0,DOSBase(A4)
X	bne	getcom
XnoDOS:
X	moveq.l #100,d0
X	bra     exit2
X
X*------ find command name:
Xgetcom:
X	move.l  pr_CLI(a3),a0
X        add.l   a0,a0           * bcpl pointer conversion
X        add.l   a0,a0
X        move.l  cli_CommandName(a0),a1
X        add.l   a1,a1           * bcpl pointer conversion
X        add.l   a1,a1
X
X*------ collect parameters:
X        move.l  d2,d0                   * get command line length
X        moveq.l #0,d1
X        move.b  (a1)+,d1
X        move.l  a1,_ProgramName(A4)
X        add.l   d1,d0                   * add length of command name
X        addq.l  #1,d0                   * allow for space after command 
X
X        clr.w   -(A7)                   * set null terminator for command line
X        addq.l  #1,D0                   * force to even number of bytes
X        andi.w  #$fffe,D0               * (round up)
X        sub.l   D0,A7                   * make room on stack for command line
X        subq.l  #2,D0
X        clr.w   0(A7,D0)
X
X*------ copy command line onto stack
X        move.l  d2,d0                   * get command line length
X        subq.l  #1,d0
X        add.l   d1,d2
X
Xcopy_line:
X        move.b  0(A2,D0.W),0(A7,D2.W)   * copy command line to stack
X        subq.l  #1,d2
X        dbf     d0,copy_line
X        move.b  #' ',0(a7,d2.w)         * add space between command and parms
X        subq.l  #1,d2
X
Xcopy_cmd:
X        move.b  0(a1,d2.w),0(a7,d2.w)	* copy command name to stack
X        dbf     d2,copy_cmd
X	move.l	a7,a1			* Get pointer to new command line
X
X	sub.l	#(MAXARGS*4),a7		* Reserve space for argv[]
X	move.l	a7,a2			* Initialise base into array
X	move.l	a2,a3			* Save base of argv
X	moveq	#0,d2			* Initialise argc
X
X*
X* From here on down, A1 is pointer into command line
X*
Xbuild_argv:
X	bsr.s	getnext			* Read next character from line
X	bcs.s	doquote			* If quote, handle
X	beq.s	build_argv		* If white space, skip over it
X
X	lea	-1(a1),a0		* Get address of this parameter
X	bsr.s	bumpargv		* Store it to argv[] array
Xbuild_2:
X	bsr.s	getnext			* Get next character
X	bne.s	build_2			* If not white space, keep looking
X	clr.b	-1(a1)			* Zero-terminate current argument
X	bra.s	build_argv		* And go back to get next argument
X
Xdoquote:
X	move.l	a1,a0			* Get pointer to this argument
X	bsr.s	bumpargv		* Output it to argv[]
Xquote_2:
X	bsr.s	getnext			* Get next character
X	bcc.s	quote_2			* If not quote, keep looking
X	clr.b	-1(a1)			* Zero-terminate current argument
Xquote_3:
X	bsr.s	getnext			* Get next character
X	bne.s	quote_3			* Skip until space reached
X	beq.s	build_argv		* Go back and read next argument
X
Xbumpargv:
X	move.l	a0,(a2)+		* Output ptr to current argument
X	addq	#1,d2			* Increment argc
X	cmpi	#MAXARGS,d2		* Used up all our arguments yet?
X	bls.s	qrts			* If not, then return
X	moveq	#110,d0			* Else set return code
X	bra.s	exit2			* And exit
X
X*
X* Reads next character from command line. If zero, never returns, but
X* drops into call to main. Else, returns, with C=1 if character is quote,
X* Z=1 if character is white space.
X*
Xgetnext:
X	move.b	(a1)+,d0		* Get character from command line
X	beq.s	get_2			* Exit if end of line
X	cmp.b	#34,d0			* Check if quote
X	beq.s	isquote			* 
X	cmp.b	#32,d0			* Check if space
X	beq.s	isspace			*
X	cmp.b	#9,d0			* Or tab
X	beq.s	isspace			*
X	cmp.b	#10,d0			* Or end of line
Xisspace:
X	andi	#$1E,ccr		* Clear carry flag, retaining Z
Xqrts	rts
X
Xisquote:
X	ori	#1,ccr			* Set carry flag
X	andi	#$FB,ccr		* Clear zero flag
X	rts				* And return
X
Xget_2:
X	move.l	a3,-(a7)		* Push argv onto stack
X	move.l	d2,-(a7)		* Push argc onto stack
X
X        lea     _BSSBAS,a3      	* get base of BSS
X        moveq   #0,d1
X        move.l  #_BSSLEN,d0     	* get length of BSS in longwords
X        bra.s   clr_lp          	* and clear for length given
Xclr_bss move.l  d1,(a3)+
Xclr_lp  dbf     d0,clr_bss
X
Xdomain:
X	jsr	main(PC)		* Call main(argc,argv)
X        moveq.l #0,d0           	* Set successful status
X        bra.s   exit2
X
Xexit:
X_exit:
XXCEXIT:
X        move.l  4(SP),d0		* Extract return code
Xexit2:
X        move.l  d0,-(a7)
X        move.l  AbsExecBase.W,a6
X        move.l  DOSBase(A4),a1
X        callsys CloseLibrary            * Close Dos library
X
X*------ this rts sends us back to DOS:
XexitToDOS:
X        MOVE.L  (A7)+,D0
X        movea.l _StackPtr(a4),SP        * Restore stack ptr
X        movem.l (a7)+,d1-d6/a0-a6
X        rts
X
X*-----------------------------------------------------------------------
X* Global definitions
X*
X        csect   __MERGED,1,,2,2
X*
X        xdef    NULL,SysBase,LoadAddress,DOSBase
X        xdef    _oserr,_OSERR,_ONBREAK
X        xdef    _ProgramName,_StackPtr,_base
X*
XNULL           dc.l    0
X_base          dc.l    0
X_oserr         equ     *
X_OSERR         dc.l    0
X_ONBREAK       dc.l    0
XSysBase        dc.l    0
XLoadAddress    dc.l    0
X_StackPtr      dc.l    0
XDOSBase        dc.l    0
X_ProgramName   dc.l    0
XDOSName        dc.b    'dos.library',0
X
X        END
SHAR_EOF
echo "extracting Makefile"
sed 's/^X//' << \SHAR_EOF > Makefile
X#
X# Aztec Make makefile, for Lattice C V4.0 :-)
X#
X# Backdrop (C) Copyright Eddy Carroll, April 1989
X#
X
XZOOEXE = backdrop backdrop.doc README System-Configuration
XZOOSRC = backdrop.c backdrop.n tiny.a res.a atoi.a tiny.o res.o atoi.o makefile
XOBJS   = tiny.o res.o atoi.o backdrop.o
X
X
X.c.o:
X	lc -s -v $*.c
X.a.o:
X	sys:lattice/c/asm -isys:include/ -u $*.a
X.n.doc:
X	nro >$*.doc -ms:an $*.n
X
X
Xall: backdrop backdrop.doc
X
Xbackdrop: $(OBJS)
X    blink from $(OBJS) to backdrop sc sd nd map ram:map lib lib:amiga.lib
X
Xtiny.o:	tiny.a
Xres.o:	res.a
Xatoi.o:	atoi.a
X
Xbackdrop.o:	  backdrop.c
Xbackdrop.doc: backdrop.n
X
Xzoo:	backdrop.zoo
Xzoosrc: backdropsrc.zoo
X
Xbackdrop.zoo: $(ZOOEXE)
X	-delete Backdrop.zoo
X	zoo a Backdrop.zoo $(ZOOEXE)
X
Xbackdropsrc.zoo: $(ZOOSRC)
X	-delete BackdropSrc.zoo
X	zoo a BackdropSrc.zoo $(ZOOSRC)
X
Xclean:
X	-delete "#?.bak"
SHAR_EOF
echo "extracting Sys-Conf.uu"
sed 's/^X//' << \SHAR_EOF > Sys-Conf.uu
X
Xbegin 644 System-Configuration
XM"````@```````)'U```````([)(````!``>A(````````/P`?`#^`'P`A@!X/
XM`(P`?`"&`&X`DP`'`&F``X`$P`'``F``@`%`````@```````````````````J
XM`````````````/\````&9@S,``$%50```S,$1.CO`($`+`````!%<'-O;EA;8
XM0T)-7TU04RTQ,C4P70```````````````````````0!0```````!``(```!")
XM````0``I17!S;VY86T-"35]-4%,M,3(U,%T`````````````&$`9(``````'L
X'`````````'!SC
X``
Xend
Xsize 232
SHAR_EOF
echo "extracting backdrop.uu"
sed 's/^X//' << \SHAR_EOF > backdrop.uu
X
Xbegin 644 backdrop
XM```#\P`````````"``````````$```'P````]@```^D```'P2.=^_DOO`#0DZ
XM2"0`2?D`````+'@`!"E.`!`I3P`8D\E.KO[:)D`@#9"M``0&@````(`I0``$D
XM0^P`)'``3J[]V"E``!QF```(<&1@``#H(&L`K-'(T<@B:``0T\G3R2`"<@`2$
XM&2E)`"#0@5*`0F=2@`)`__Z?P%6`0G<(`"`"4X#4@1^R```@`%."4<C_]A^\V
XM`"`@`%."'[$@`"``4<K_^")/G_P```"`)$\F2G0`831E$F?Z0>G__V$<82AF;
XM_$(I__]@ZB!)80YA&F3\0BG__V$29OQGV"3(4D(,0@`@8R)P;F!0$!EG)@P`B
XM`")G%@P``"!G"@P```EG!`P```H"/``>3G4`/``!`CP`^TYU+PLO`D?Y```#8
XMF'(`(#P````08`(FP5'(__Q.N@#6<`!@!"`O``0O`"QX``0B;``<3J[^8B`?T
XM+FP`&$S??WY.=0``2.<X,BQX``1R`'`D3J[_.DJ`9P``<B9`D\E.KO[:)$`@6
XM:@"LT<C1R"=H`#P`!$*H`#PFO````"1%ZP`(+'D````<-/PH?"3,-/Q.N23O*
XM`"0T_"Q\),Y'ZP`$)@ODBS3\(CPDPR3\3N[_9"(O`!PD+P`@*"\`*"/!```#^
XM\$ZN_W9,WTP<3G5P>$[Y```!,```<`!R`"!O``02&`0!`#`,`0`*8@C`_``*R
XMT(%@[$YU``!.5?_B2.<P`G``*T#_^"M`__PL;``<3J[_Q"M`_^(B+?_B0>P`9
XM-"0(=DTL;``<3J[_T$/L`?`L>``$3J[^>BM`_^Y*K?_N9CH9?``!`]9"+`/7Q
XM*7P```D``])![`'Z0^P#PB+8(M@BV"+80>P!\"E(`ZIP_RQX``1.KOZV&4`#F
XMKV`0(&W_[D/L`Z!P#2+84<C__`RM`````0`(;P`"`B)M``P@:0`$$!`,```ML
XM9@`!`%2(+PA.NO\J6$\B;0`,(&D`!")(4HD2$3M`__8,`0!!;1@,`0!:;A(BN
XM2%*)$!%(@$C`!H`````@8`A2B!`02(!(P'(P!$$`"&L``*JPNQ`(9O).^Q`&J
XM````<V```(P```!F8```>````'%@``!F````<&```"H```!B8```%@```&%@G
XM```","W_]AE``]9@``$2,"W_]AE``]=@``$&,BW_]@Q!``!E!@Q!`!)C!G``I
XM.T#_]C`M__9(P.F`0>P!^M'`0^P#PB+8(M@BV"+88```TG`!*T#__&```,@IB
XM?```"0`#TF```+PI?```"4`#TF```+!P`2M`__A@``"F(FT`#"!I``0B2$H97
XM9OQ3B9/(*TC_YK+\`!!F``""0FW_]`QM``C_]&1Z<``[0/_R.T#_]@QM``+_1
XM\F1"<``P+?_VZ8`@;?_F$A!(@4C!#!``05S"1`)(@DC")@+GBY:"DH,$@0``*
XM`#`"@0````^`@3M`__92;?_R4JW_YF"V,"W_]$C`T(!![`/"T<`P+?_V(@#A=
XM08)`,(%2;?_T8(1P`2M`__A*K?_X9SHB+?_B0>P`@20()CP```"<+&P`'$ZND
XM_]`B+?_B0>P!'20()CP```#3+&P`'$ZN_]!(>``*3KK\HEA/6*T`#%.M``A@Z
XM`/WV2JW_[F9.2JW__&<*2'@`"DZZ_(!83T/L`Z`L>``$3J[^GDAX#Z!(>@":`
XM2'@`!$AL`VI.NOQ^3^\`$$J`9@Q#[`.@+'@`!$ZN_IA"ITZZ_$183V!F(FW_I
XM[B!I`!`K2/_J2JW__&<:(FW_ZB`\```0`"QX``1.KOZ\0J=.NOP66$\L>``$J
XM3J[_?$'L`Z`B;?_N<`TBV%'(__PL>``$3J[_=B)M_^H@/```@``L>``$3J[^=
XMO$*G3KK[W%A/3-]`#$Y=3G5(YP`"D\DL>``$3J[^VBE``[!A&@R````G#V?V/
XM0^P#H"QX``1.KOZ83-]``$YU3E7_V$CG(`)P"BM`_^Q#[`-T<"$L>``$3J[]M
XMV"E``YA*K`.89P`!V$/L`X9P(2QX``1.KOW8*4`#G$JL`YQG``&R<``L;`.8)
XM3J[^8BM`_]P@;`.8*V@`//_T2JW_]&<P(&W_]#`H`!0"0``/4T!F%C`H``Q($
XMP#(H``Y(P2M`_^@K0?_D8`H@;?_T*U#_]&#*(&W_W"QL`YA.KOY<2JW_]&<`6
XM`5`@+?_H.4`#/B`M_^0Y0`-`*6P#T@-(0>P#.BQL`YA.KO\T*T#__$JM__QGK
XM``$60JW_[")M__P@:0`R*TC_^")M__AP`2QL`YQ.KOZ>0>P#PB)M__@C2``(1
XM$WP``P`=<``0+`/6+T``"")M__@@+P`(+&P#G$ZN_JIP`!`L`]<O0``((FW_N
XM^"`O``@L;`.<3J[^I"\M_^0O+?_H<``O`"\`+RW_^$ZZ`,A/[P`4(FW__"!I\
XM`%9P`!`H``]R`20!X:(`@@``D``@`BQX``1.KO["*T#_X`@M``3_XF9:(FW_R
XM_"!I`%9P`!`H``]R`>&A("W_X,"!2H!G*")M__P@:0!6+'@`!$ZN_HPK0/_P^
XM2JW_\&<.(FW_\"QX``1.KOZ&8-@B+`-(LJP#TF<`_S0K?```)P__[$YQ(&W_R
XM_"QL`YA.KO^X(FP#G"QX``1.KOYB(FP#F"QX``1.KOYB("W_[$S?0`1.74YU5
XM<`!.=4YU3G5(YS`"+'D```.<(F\`$$SO``\`%$ZN_LY,WT`,3G4``````^P`.
XM```!`````````=H````$`````0``!Z8```&.```!%`````X````````#\@``U
XM`^H```#F````````````````````````````````````````````````9&]S9
XM+FQI8G)A<GD``````$)A8VMD<F]P("A#*2!#;W!Y<FEG:'0@161D>2!#87)RD
XM;VQL(#$Y.#DL(&%D9',@8F%C:V1R;W`@=&\@5V]R:V)E;F-H('-C<F5E;@H``
XM57-A9V4Z($)A8VMD<F]P('LM9B!\("UP(R!\("UQ('P@+7,@?"!",4(R0C-"O
XM-$(U0C9"-T(X?0H*"0DM82,@+2!3970@9F]R96=R;W5N9"!C;VQO=7(@=&\@U
XM<W!E8VEF:65D('!E;B`C"@D)+6(C("T@4V5T(&)A8VMG<F]U;F0@8V]L;W5RM
XM('1O('-P96-I9FEE9"!P96X@(PH`"0DM9B`@+2!%;F%B;&4@9F%S="!U<&1A0
XM=&4@*'5S97,@;6]R92!M96UO<GDI"@D)+7`C("T@57-E('-P96-I9FEE9"!PH
XM871T97)N(",@*#$M-2D*"0DM<2`@+2!296UO=F4@8F%C:V1R;W`@9G)O;2!M1
XM96UO<GD*"0DM<R`@+2!%;F%B;&4@<VQO=R!U<&1A=&4*("`@0C%",D(S0C1""
XM-4(V0C="."`M(#$V(&AE>"!D:6=I=',@9&5F:6YI;F<@86X@.'@X('!A='1E6
XM<FX*"CX@`$)A8VMD<F]P``!55:JJ556JJE55JJI55:JJ__]`0$!`0$#__P0$T
XM!`0$!(B(````````B(@```````"(B```(B(``(B(```B(@``JJH``*JJ``"JJ
XMJ@``JJH``*JJ``!550``JJH``%55``"(B"(BB(@B(HB((B*(B"(BJJJJJE55<
XM556JJJJJ55555<S,,S/,S#,SS,PS,\S,,S/__X&!O;VEI:6EO;V!@?___OZ"D
XM@KJZJJJZNH*"_OX``)F9S,QF9C,SF9G,S&9F,S.9F3,S9F;,S)F9,S-F9LS,N
XM``!$1"@H$!`H*$1$````````5%0"`EA8&AI`0"HJ``"JJD1$JJH``*JJ1$2JJ
XMJ@``P\-F9CP\&!@\/&9FP\.!@=O;9F8\/)F9F9D\/&9FV]MF9O#PF9D/#V9F0
XM\/"9F0\/_____________________P`````!0`#(``$````$````````````N
XM`````````````````````````````````4)A8VMD<F]P``!I;G1U:71I;VXNX
X>;&EB<F%R>0!G<F%P:&EC<RYL:6)R87)Y``````/R>
X``
Xend
Xsize 3000
SHAR_EOF
echo "extracting backdrop.n"
sed 's/^X//' << \SHAR_EOF > backdrop.n
X.TH BACKDROP 1 "AMIGA Programmer's Manual" "Copyright Eddy Carroll 1989"
X.SH NAME
Xbackdrop - adds a backdrop behind workbench windows
X.SH SYNOPSIS
Xbackdrop {-a# | -b# | -f | -p# | -q | -s | b1b2b3b4b5b6b7b8}
X.SH DESCRIPTION
XBackdrop allows you to define a pattern which will then be displayed on
Xthe workbench screen in the normally empty area behind all the windows.
XI originally wrote it because I was experimenting an overscan interlaced
Xworkbench, and I wanted to get that 'workstation' look. The only program
XI had which would give a similar effect was DropCloth by Eric Lavitsky,
Xbut this requires Workbench to be loaded. Backdrop will not
Xcohabit very well with Workbench, which suits me fine since I hardly
Xever use Workbench.
X
XThe first time you run Backdrop, it detaches itself from the CLI and
Xhangs around in memory until you tell it to quit. You can change the
Xcurrent settings by running Backdrop again with different options.
XOnly those options you specify will be altered, all the others will remain
Xunchanged.
X
XThe following options can be specified:
X
X-a followed by a number sets the foreground colour used to
Xplot the pattern to the pen number specified
X(normally 0 to 3). Similarly, -b sets the background colour.
X
X-f and -s select the window type used by Backdrop. -f uses a SMART_REFRESH
Xwindow, which results in fast updating of the screen, but can use up to 64K of
Xchip memory (in interlace mode). -s uses a SIMPLE_REFRESH window, which
Xgives slower updating of the screen but doesn't use up any chip memory.
XIf you can afford the memory, -f looks much more professional.
X
X-p followed by a number selects one of the built in patterns for display.
XPattern 0 is the default pattern. Numbers from 1 upwards select other
Xpatterns. If you try to select a non-existant pattern, you get the
Xdefault pattern.
X
X-q tells any copy of Backdrop already resident in memory to remove itself,
Xand restore the screen back to normality. If Backdrop isn't already resident,
Xthen this option has no effect.
X
XFinally, you can define your own unique pattern by giving a list of 16 hex
Xdigits. These are interpreted as 8 bytes, with each byte corresponding to
Xone row of an 8x8 grid. This grid is then replicated over the entire screen
Xto form the pattern. Try experimenting with random values to generate some
Xunique patterns.
X
XAny or all of these options may be present on the command line, and
Xorder is not important. You can get a summary of these options by invoking
XBackdrop with -h (or any other invalid option).
X.SH CAVEATS
XIf you try running this when Workbench is running, Workbench will disappear
X(this could be viewed as a benefit :-) You can quite easily recover
XWorkbench by telling Backdrop to quit with the -q option.
X.SH DISTRIBUTION
XAlthough I retain copyright of Backdrop, it may be freely redistributed
Xas long as no charge is made other than to cover distribution costs.
X.SH EXAMPLES
X.bo "Backdrop
Xinstalls a simple backdrop pattern
X.br
X.bo "Backdrop -a0 -b3 -p1
Xinstalls a red brick wall pattern
X.br
X.bo "Backdrop -a2 cccc666633339999
Xinstalls dark stripes pattern
X.SH AUTHOR
XEddy Carroll
X.br
XThe Old Rectory,
X.br
XDelgany, Co. Wicklow,
X.br
XIreland.
X
XEMAIL: ecarroll@@cs.tcd.ie
SHAR_EOF
echo "End of archive 1 (of 1)"
# if you want to concatenate archives, remove anything after this line
exit