[comp.sources.amiga] v02i079: gimme.lib - misc library routines, Part06/07

page@swan.ulowell.edu (Bob Page) (12/02/88)

Submitted-by: oscvax!jan@uunet.UU.NET (Jan Sven Trabandt)
Posting-number: Volume 2, Issue 79
Archive-name: libraries/gimme.6

#	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
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	picture.c
#	postext.c
#	requester.c
#	screen.c
#	scrollbar.c
#	sound.c
#	stdstuff.c
#	subtask.c
#	subtinit.c
#	timer.c
#	timerstuff.c
#	window.c
# This archive created: Thu Dec  1 19:52:33 1988
cat << \SHAR_EOF > picture.c
/*
 *  FILE: picture.c
 *  Support routines for reading IFF/ILBM files.
 *
 *  Public Domain, but keep our names in it as the original authors.
 *  08-Dec-87	Rico Mariani	    original code (modified by JST)
 *  31-Aug-88	Jan Sven Trabandt   first release version
 */


#define I_AM_PICTURE
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/picture.h"
#include "gimmelib/postext.h"
#include "gimmelib/minterm.h"
#include <stdio.h>


#define GET(iffile)         getc( iffile )

#define getId		    getLong
#define getLen		    getLong
#define getByte 	    GET
#define skip(len, file)     fseek(file, (long)(len), 1)

#define getBMH(bmh, file)   fread(bmh, sizeof(BitMapHeader), 1, file)

/* requires an existent variable 'char *errmsg' and a label 'failure_return' */
#define fail_and_return(msg)    {errmsg = msg; goto failure_return;}

/* forward declarations */
static LONG getLong();
static WORD getWord();
static ULONG makeBM();

static char noMemMsg[] = "insufficient memory\n";
static char badFileMsg[] = "corrupt or incomplete file\n";


PICTURE *gimmePicture( filename, myflags )
    UBYTE   *filename;
    ULONG   myflags;
{
    LONG    len, id;
    PICTURE *pic = NULL;
    BYTE    *p;
    void    *mh = NULL;
    FILE    *file = NULL;
    char    *errmsg = " ";
    SHORT   i;

    if( !(file = fopen(filename, "r")) ) {
	fail_and_return( "unable to open iff picture file for read\n" );
    }
    if( getId(file) != ID_FORM ) {
	fail_and_return( "not IFF format\n" );
    }
    getLen( file );
    if( getId(file) != ID_ILBM ) {
	fail_and_return( "not ILBM format\n" );
    }
    for( ;; ) {
	getChunk( &id, &len, file );
	if( ferror(file) || feof(file) ) {
	    fail_and_return( badFileMsg );
	}
	switch( id ) {
	  case ID_BMHD:
	    pic = chainAllocMem( &mh, (ULONG)sizeof(PICTURE),
				    MEMF_PUBLIC | MEMF_CLEAR );
	    if( !pic ) {
	       fail_and_return( noMemMsg );
	    }
	    getBMH( &pic->bmh, file );
	    if( len & 1 ) {
		GET(file);
	    }
	    break;
	  case ID_CMAP:
	    if( getLut(pic, len, file) ) {
		fail_and_return( "unable to get color table\n" );
	    }
	    break;
	  case ID_BODY:
	    if( !pic ) {
		fail_and_return( "didn't find BMHD chunk\n" );
		return( NULL );
	    }
	    switch( pic->bmh.masking ) {
	      case mskNone:
	      case mskLasso:
	      case mskHasTranCol:
		break;
	      default:
		printf("Error, unsupported masking type\n");
		return( NULL );
	    } /* switch */

	    pic->xsize = pic->bmh.w;
	    if( (pic->myflags = makeBM(pic, myflags)) == GBP_ERROR ) {
		return( NULL );
	    }
	    switch( pic->bmh.compression ) {
	      case cmpNone:
		if( getBody(pic->bm, pic->myflags, file) ) {
		    fail_and_return( "error in uncompressed body\n" );
		}
		break;
	      case cmpByteRun1:
		if( getCmpBody(pic->bm, file) ) {
		    fail_and_return( "error in compressed body\n" );
		}
		break;
	      default:
		fail_and_return( "unknown compression form\n" );
		return( NULL );
	    } /* switch */
	    if( ferror(file) ) {
		fail_and_return( badFileMsg );
	    }
	    pic->memhead = mh;
	    fclose( file );
	    return( pic );
	    break;
	  case ID_DEST:
	  case ID_SPRT:
	  case ID_CAMG:
	  case ID_CRNG:
	  case ID_CCRT:
	  default:		/* unimplemented chunk type */
	    skip( EVEN(len), file );
	    break;
	} /* switch */
    } /* for */
failure_return: {}
    if( Output() ) {
	Write( Output(), errmsg, (ULONG)strlen(errmsg) );
    }
    if( mh ) {
	chainFreeMem( mh );
    }
    if( file ) {
	fclose( file );
    }
    return( NULL );
} /* gimmePicture */


static ULONG makeBM( pic, myflags )
    register PICTURE	*pic;
    ULONG		myflags;
{
    UBYTE *plane;

    if( !(pic->bm = AllocMem((ULONG)sizeof(struct BitMap), MEMF_PUBLIC)) ) {
	return( GBP_ERROR );
    }
    InitBitMap( pic->bm, (long) pic->bmh.nPlanes, (long) pic->bmh.w,
		    (long) pic->bmh.h );
    return( gimmeBitPlanes(pic->bm, myflags) );
} /* makeBM */


short getRidOfPicture( picture )
    PICTURE   *picture;
{
#ifdef GIMME_WIMPY
    if( picture ) {
	return( -1 );
    }
#endif
    if( picture->colormap.ColorTable ) {
	FreeMem( picture->colormap.ColorTable,
		    (ULONG) picture->colormap.Count * sizeof(USHORT) );
    }
    if( picture->bm ) {
	getRidOfBitPlanes( picture->bm, picture->myflags );
	FreeMem( picture->bm, (ULONG)sizeof(struct BitMap) );
    }
    chainFreeMem( picture->memhead );
    return( 0 );
} /* getRidOfPicture */


short positionPicture( rp, myflags, pic, minterm, x, y )
    struct RastPort *rp;
    ULONG	    myflags;
    PICTURE	    *pic;
    SHORT	    minterm;
    register SHORT  x, y;
{
    SHORT	    left, top;
    SHORT	    width, height;
    SHORT	    temp;
    struct BitMap   *bm;

#ifdef GIMME_WIMPY
    if( !pic || !rp ) {
	return( -1 );
    }
#endif
    left = top = 0;
    width = pic->bmh.w;
    height = pic->bmh.h;
    bm = rp->BitMap;
    switch( myflags & GPT_XFLAGS ) {
      case GPT_XCENTRE:
	x -= width >> 1;
	break;
      case GPT_XRIGHT:
	x -= width;
	break;
      case GPT_XLEFT:
      default:
	break;
    } /* switch */
    switch( myflags & GPT_YFLAGS ) {
      case GPT_YBOTTOM:
      case GPT_YBASELINE:
	y -= height;
	break;
      case GPT_YCENTRE:
      case GPT_YCENTREBASE:
	y -= height >> 1;
	break;
      case GPT_YTOP:
      default:
	break;
    } /* switch */
    if( minterm != GIM_MINTERM_DEST ) {
	if( x < 0 ) {
	    width += x;
	    left -= x;
	    x = 0;
	} else if( (temp = x + width - (bm->BytesPerRow << 3)) > 0 ) {
	    width -= temp;
	}
	if( y < 0 ) {
	    height += y;
	    top -= y;
	    y = 0;
	} else if( (temp = y + height - bm->Rows) > 0 ) {
	    height -= temp;
	}
	if( width > 0 && height > 0 ) {
	    BltBitMapRastPort( pic->bm, (long) left, (long) top, rp,
				(long) x, (long) y,
				(long) width, (long) height, (long) minterm );
	}
    }
    return( 0 );
} /* positionPicture */


short usePictureColors( pic, screen )
    register PICTURE *pic;
    struct Screen    *screen;
{
#ifdef GIMME_WIMPY
    if( !pic || !screen ) {
	return( -1 );
    }
#endif
    return( setColors(screen, pic->colormap.ColorTable,
			(SHORT) pic->colormap.Count) );
} /* usePictureColors */


/* read an IFF Id */
static LONG getLong( file )
    FILE    *file;
{
    register UBYTE  p[4];

    p[0] = GET(file);
    p[1] = GET(file);
    p[2] = GET(file);
    p[3] = GET(file);
    return( (LONG) Mk(p[0],p[1],p[2],p[3]) );
} /* getLong */


/* read an IFF chunk header */
static getChunk( id, len, file )
    LONG    *id, *len;
    FILE    *file;
{
    *id = getId( file );
    *len = getLen( file );
} /* getChunk */


/* get len bytes from the file and put them into memory */
static memget( p, len, file )
    UBYTE   *p;
    LONG    len;
    FILE    *file;
{
    for( ; len > 0L; len -= 0x07fffL, p += 0x07fffL ) {
	fread( p, (int) (len & 0x07fffL), 1, file );
    } /* for */
} /* memget */


/* get a word */
static WORD getWord( file )
    FILE    *file;
{
    WORD    v;

    v = GET(file) << 8;
    return( v | GET(file) );
} /* getWord */


static int getCmpBody( bm, file )
    struct BitMap   *bm;
    FILE	    *file;
{
    register short  x;
    short	    y, pl;
    UBYTE	    *plane;
    UBYTE	    run_len, verb_len, run_byte;
    BYTE	    v;
    register BYTE   mybyte;

    verb_len = run_len = 0;
    /* note: the bit-planes should be clear already */
    for( y = 0; y < bm->Rows; ++y ) {
	for( pl = 0; pl < bm->Depth; ++pl ) {
	    plane = bm->Planes[pl] + y * bm->BytesPerRow;
	    for( x = 0; x < bm->BytesPerRow; ++x ) {
		if( run_len ) {
		    --run_len;
		    mybyte = run_byte;
		} else if( verb_len ) {
		    --verb_len;
		    mybyte = GET(file);
		} else if( (v = GET(file)) >= 0 ) {
		    verb_len = v;
		    mybyte = GET(file);
		} else {
		    run_len = -v;
		    mybyte = run_byte = GET(file);
		}
		plane[x] = mybyte;
	    } /* for */
	} /* for */
    } /* for */
    return( 0 );
} /* getCmpBody */


static int getBody( bm, flags, file )
    register struct BitMap *bm;
    ULONG   flags;
    FILE    *file;
{
    register short  i;

    if( flags & GBP_CONTIGUOUS ) {
	memget( bm->Planes[0], (ULONG)(bm->Depth) * bm->Rows * bm->BytesPerRow,
		    file );
    } else {
	for( i = 0; i < bm->Depth; ++i ) {
	    memget( bm->Planes[i], (ULONG)(bm->Rows) * bm->BytesPerRow, file );
	} /* for */
    }
    return( 0 );
} /* getBody */


static int getLut( pic, len, file )
    PICTURE *pic;
    LONG    len;
    FILE    *file;
{
    SHORT   i, ncols;
    USHORT  red, green, blue;
    USHORT   *lut;

    pic->colormap.Flags = pic->colormap.Type = 0;
    ncols = len / 3;
    lut = (USHORT *) AllocMem( (ULONG) ncols * sizeof(USHORT), MEMF_PUBLIC );
    if( !lut ) {
	return( -1 );
    }
    for( i = 0; i < ncols; ++i ) {
	red = GET(file) >> 4;
	green = GET(file) >> 4;
	blue = GET(file) >> 4;
	lut[i] = (red << 8) | (green << 4) | blue;
    } /* for */
    if( len & 1 ) {
	GET(file);
    }
    pic->colormap.Count = ncols;
    pic->colormap.ColorTable = (APTR) lut;
    return( 0 );
} /* getLut */
SHAR_EOF
cat << \SHAR_EOF > postext.c
/*
 *  FILE: postext.c
 *  Support routines for writing text (or a number) in a rastport,
 *  with flexible text location specification (eg any corner, centre).
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Aug-88	Jan Sven Trabandt   first release version
 */


#define I_AM_POSTEXT
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/postext.h"


SHORT positionText( rp, myflags, s, num, x, y )
    register struct RastPort	*rp;
    register ULONG		myflags;
    UBYTE   *s;
    LONG    num;
    SHORT   x, y;
{
    register SHORT  i, j;
    SHORT	    len, rastlen, maxrastlen;
    SHORT	    maxbit, lowi;
    SHORT	    dest, temp;
    SHORT	    height, baseline;
    struct RastPort myrp;
    UBYTE	    buf[12];		/* big enough for max ULONG + '\0' */


#ifdef GIMME_WIMPY
    if( !rp ) {
	return( -1 );
    }
#endif
    if( s ) {
	len = strlen( s );
    } else {
	len = sprintf( buf, "%1ld", num );
	s = buf;
    }
    maxrastlen = len * (rp->TxWidth + rp->TxSpacing);
    rastlen = TextLength( rp, s, (long) len );

    if( myflags & (GPT_YUPWARDS | GPT_YDOWNWARDS) ) {
	myrp = *rp;			/* copy struct */
	myrp.BitMap = gimmeBitMap( rp->BitMap->Depth, rastlen, myrp.TxHeight );
	if( !myrp.BitMap ) {
	    return( -1 );
	}
	myrp.Layer = NULL;		/* make sure no layer else trouble */
	myrp.GelsInfo = NULL;
	Move( &myrp, 0L, (long) myrp.TxBaseline );
	Text( &myrp, s, (long) len );

	maxbit = rastlen - 1;
	switch( myflags & GPT_XFLAGS ) {
	  case GPT_XRIGHT:
	    if( myflags & GPT_YDOWNWARDS ) {
		y -= maxbit;
	    }
	    break;
	  case GPT_XCENTRE:
	    y -= rastlen >> 1;
	    break;
	  case GPT_XLEFT:
	  default:
	    if( myflags & GPT_YUPWARDS ) {
		y -= maxbit;
	    }
	    break;
	} /* switch */

	if( myflags & GPT_XTHICKEN ) {              /* if double thickness */
	    height = (myrp.TxHeight << 1) - 1;
	    baseline = (myrp.TxBaseline << 1);
	} else {
	    height = myrp.TxHeight - 1;
	    baseline = myrp.TxBaseline;
	}

	switch( myflags & GPT_YFLAGS ) {        /* make x top of char */
	  case GPT_YBOTTOM:
	    if( myflags & GPT_YUPWARDS ) {
		x -= height;
	    }
	    break;
	  case GPT_YCENTRE:			/* skew to top of char */
	    if( myflags & GPT_YDOWNWARDS ) {
		/* x += (height >> 1) - height; */
		x -= (height + 1) >> 1;
	    } else {
		x -= height >> 1;
	    }
	    break;
	  case GPT_YCENTREBASE: 		/* skew to bottom of char */
	    if( myflags & GPT_YDOWNWARDS ) {
		x += ((baseline + 1) >> 1) - height;
	    } else {
		x -= (baseline + 1) >> 1;
	    }
	    break;
	  case GPT_YTOP:
	    if( myflags & GPT_YDOWNWARDS ) {
		x -= height;
	    }
	    break;
	  case GPT_YBASELINE:
	  default:
	    if( myflags & GPT_YDOWNWARDS ) {
		x += baseline - height;
	    } else {
		x -= baseline;
	    }
	    break;
	} /* switch */

	if( y < 0 ) {
	    rastlen += y;
	    y = 0;
	}
	lowi = rastlen - rp->BitMap->Rows;
	if( lowi > 0 ) {
	    rastlen -= lowi;
	} else {
	    lowi = 0;
	}
	maxbit = rastlen - 1;
	if( myflags & GPT_YDOWNWARDS ) {
	    if( lowi ) {
		maxbit -= lowi;
		lowi = 0;
	    }
	    temp = x + height;
	    for( j = myrp.TxHeight - 1; j >= 0; --j ) {
		if( GPT_XTHICKEN ) {
		    dest = temp - (j << 1) - 1;
		} else {
		    dest = temp - j;
		}
		for( i = maxbit; i >= lowi; --i ) {
		    /* if no error and not background colour */
		    if( ReadPixel(&myrp, (long) i, (long) j) > 0L ) {
			WritePixel( rp, (long) dest, (long) y + i );
			if( myflags & GPT_XTHICKEN ) {
			    WritePixel( rp, (long) dest + 1, (long) y + i );
			}
		    }
		} /* for */
	    } /* for */
	} else {		/* else upwards */
	    for( i = maxbit; i >= lowi; --i ) {
		dest = y + maxbit - i;
		for( j = myrp.TxHeight - 1; j >= 0; --j ) {
		    /* if no error and not background colour */
		    if( ReadPixel(&myrp, (long) i, (long) j) > 0L ) {
			if( myflags & GPT_XTHICKEN ) {
			    temp = j << 1;
			    WritePixel( rp, (long) x + temp + 1, (long) dest );
			    WritePixel( rp, (long) x + temp, (long) dest );
			} else {
			    WritePixel( rp, (long) x + j, (long) dest );
			}
		    }
		} /* for */
	    } /* for */
	}
	getRidOfBitMap( myrp.BitMap );
    } else {
	switch( myflags & GPT_XFLAGS ) {
	  case GPT_XRIGHT:
	    x -= rastlen - 1;
	    break;
	  case GPT_XCENTRE:
	    x -= rastlen >> 1;
	    break;
	  case GPT_XLEFT:
	  default:
	    break;
	} /* switch */

	switch( myflags & GPT_YFLAGS ) {        /* make y top of char */
	  case GPT_YBOTTOM:
	    y -= rp->TxHeight - 1;
	    break;
	  case GPT_YCENTRE:
	    y -= (rp->TxHeight - 1) >> 1;       /* skew to top of char */
	    break;
	  case GPT_YCENTREBASE:
	    y -= (rp->TxBaseline + 1) >> 1;     /* skew to bottom of char */
	    break;
	  case GPT_YTOP:
	    break;
	  case GPT_YBASELINE:
	  default:
	    y -= rp->TxBaseline;
	    break;
	} /* switch */
	y += rp->TxBaseline;		/* adjust top to baseline for Text() */
	/* note rp's TxBaseline is offset from top pixel of character */

	Move( rp, (long) x, (long) y );
	Text( rp, s, (long) len );
    }
    return( maxrastlen );
} /* positionText */
SHAR_EOF
cat << \SHAR_EOF > requester.c
/*
 *  FILE: requester.c
 *  Support routines for putting up an Auto Request or creating a Requester.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Aug-88	Jan Sven Trabandt   first release version
 *  31-Oct-88	Jan Sven Trabandt   added more functionality to gimmeRequester
 */


#define I_AM_REQUESTER
#include <clib/macros.h>
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/requester.h"
#include "gimmelib/macros.h"

extern struct GfxBase *GfxBase;


SHORT gimmeAutoRequest( window, s, textattr )
    struct Window   *window;
    UBYTE	    *s;
    struct TextAttr *textattr;
{
    struct IntuiText	itext, ptext, ntext;
    SHORT		xsize, ysize, width;

    if( !s ) {
	s = (UBYTE *) GAR_DUMMY_TEXT;
    }
    itext.FrontPen  = AUTOFRONTPEN;
    itext.BackPen   = AUTOBACKPEN;
    itext.DrawMode  = AUTODRAWMODE;
    itext.LeftEdge  = AUTOLEFTEDGE;
    itext.TopEdge   = AUTOTOPEDGE;
    itext.ITextFont = textattr;
    itext.IText     = s;
    itext.NextText  = AUTONEXTTEXT;

    ptext = itext;	    /* struct copy */
    ntext = itext;	    /* struct copy */
    ptext.IText = gimAutReqPostext;
    ntext.IText = gimAutReqNegtext;
    xsize = 0;
    if( textattr ) {
	ysize = textattr->ta_YSize;
    } else if( window ) {
	ysize = window->RPort->TxHeight;
	xsize = window->RPort->TxWidth;
    } else {
	ysize = GfxBase->DefaultFont->tf_YSize;
    }
    if( !xsize ) {
	xsize = GfxBase->DefaultFont->tf_XSize;
    }
    width = MAX(IntuiTextLength(&itext),
		IntuiTextLength(&ptext) + IntuiTextLength(&ntext) + 3*xsize);
    return (
	    AutoRequest( window, &itext, &ptext, &ntext, ENDGADGET, ENDGADGET,
			(ULONG) width + xsize * GAR_BORDER_WIDTH,
			(ULONG) ysize * GAR_HEIGHT )
	);
} /* gimmeAutoRequest */


#define XLEEWAY     8	    /* border space */
#define YLEEWAY     4
#define MIN_WIDTH   50	    /* minimum dimensions if calculating dimension(s) */
#define MIN_HEIGHT  20	    /* not counting y leeways */

struct Requester *gimmeRequester( mh, left, top, width, height, backfill,
				    gp, s, textattr, flags )
    void	    **mh;
    SHORT	    left, top;
    SHORT	    width, height;
    UBYTE	    backfill;
    struct Gadget   *gp;
    UBYTE	    *s;
    struct TextAttr *textattr;
    ULONG	    flags;
{
    register struct Requester	*req;
    register struct Border	*bp;
    struct Gadget   *gadg;
    SHORT   len, extra;
    void    *mymh = NULL;

    GUESS
	QUIF( !mh );
	req = chainAllocMem( &mymh, (ULONG)sizeof(struct Requester),
				MEMF_PUBLIC | MEMF_CLEAR );
	QUIF( !req );
	if( flags & POINTREL ) {
	    req->RelLeft = left;
	    req->RelTop = top;
	}
	req->LeftEdge = left;
	req->TopEdge = top;
	req->ReqGadget = gp;
	req->ReqText = gimmeIntuiText( &mymh, s != NULL ? s : (UBYTE *)"",
					textattr, 0 );
	QUIF( !req->ReqText );
	req->ReqText->TopEdge = YLEEWAY;
	req->ReqText->LeftEdge = XLEEWAY;
	req->ReqText->BackPen = backfill;
	req->Flags = flags;
	req->BackFill = backfill;
	if( width <= 0 ) {
	    width = IntuiTextLength( req->ReqText );
	    extra = 0;
	    for( gadg = gp; gadg; gadg = gadg->NextGadget ) {
		if( gadg->Flags & GRELRIGHT ) {
		    len = -gadg->LeftEdge;
		} else {
		    len = gadg->LeftEdge;
		}
		if( !(gadg->Flags & GRELWIDTH) ) {
		    len += gadg->Width;
		}
		if( len > width ) {
		    width = len;
		} else if( gadg->Activation & (RIGHTBORDER | LEFTBORDER) ) {
		    if( len > extra ) {
			extra = gadg->Width;
		    }
		}
	    } /* for */
	    width += extra + XLEEWAY;
	    if( width <= 0 ) {
		width = MIN_WIDTH;
	    }
	}
	req->Width = width;
	if( height <= 0 ) {
	    if( textattr ) {
		height = textattr->ta_YSize;
	    } else {
		height = MIN_HEIGHT;
	    }
	    extra = 0;
	    for( gadg = gp; gadg; gadg = gadg->NextGadget ) {
		if( gadg->Flags & GRELBOTTOM ) {
		    len = -gadg->TopEdge;
		} else {
		    len = gadg->TopEdge;
		}
		if( !(gadg->Flags & GRELHEIGHT) ) {
		    len += gadg->Height;
		}
		if( len > height ) {
		    height = len;
		} else if( gadg->Activation & (BOTTOMBORDER | TOPBORDER) ) {
		    if( len > extra ) {
			extra = gadg->Height;
		    }
		}
	    } /* for */
	    height += extra + YLEEWAY;
	}
	req->Height = height;
	bp = gimmeBorder( &mymh, width - 4, height - 2 );
	if( bp ) {
	    bp->LeftEdge = 2;
	    bp->TopEdge = 1;
	    bp->FrontPen = ~backfill;
	    req->ReqBorder = bp;
	    /* double thickness vertical lines */
	    bp = gimmeBorder( &mymh, width - 6, height - 2 );
	    if( bp ) {
		bp->LeftEdge = 3;
		bp->TopEdge = 1;
		bp->FrontPen = ~backfill;
		req->ReqBorder->NextBorder = bp;
	    }
	}
	linkChainMem( mh, mymh );
	return( req );
    ENDGUESS
    if( mymh ) {
	chainFreeMem( mymh );
    }
    return( NULL );
} /* gimmeRequester */
SHAR_EOF
cat << \SHAR_EOF > screen.c
/*
 *  FILE: screen.c
 *  Support for Intuition screen stuff.
 *
 *  Public Domain, but keep our names in it as the original authors.
 *  31-Aug-88	Jan Sven Trabandt   first release version
 *  30-Sep-88	Jan Sven Trabandt   gimmeNewScreen checks width more closely
 */


#define I_AM_SCREEN
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/window.h"
#include "gimmelib/globals.h"

extern struct GfxBase *GfxBase;


struct NewScreen *gimmeNewScreen( modes, type, depth, title, textattr )
    ULONG	    modes, type;
    SHORT	    depth;
    UBYTE	    *title;
    struct TextAttr *textattr;
{
    register struct NewScreen	*ns;

#ifdef GIMME_WIMPY
    if( depth < 1 || depth > 8 ) {
	return( NULL );
    }
#endif
    ns = (struct NewScreen *) AllocMem( (ULONG)sizeof(struct NewScreen),
					    MEMF_PUBLIC | MEMF_CLEAR );
    if( ns ) {
	ns->Width = GfxBase->NormalDisplayColumns;
	if( modes & HIRES ) {
	    if( ns->Width <= 350 ) {
		ns->Width <<= 1;
	    }
	} else {
	    if( ns->Width > 350 ) {
		ns->Width >>= 1;
	    }
	}
	ns->Height = STDSCREENHEIGHT;
	ns->Depth = depth;
	ns->BlockPen = 1;
	ns->ViewModes = modes;
	ns->Type = type;
	ns->Font = textattr;
	ns->DefaultTitle = title;
    }
    return( ns );
} /* gimmeNewScreen */


short getRidOfNewScreen( ns )
    struct NewScreen	*ns;
{
#ifdef GIMME_WIMPY
    if( !ns ) {
	return( -1 );
    }
#endif
    FreeMem( ns, (ULONG)sizeof(struct NewScreen) );
    return( 0 );
} /* getRidOfNewScreen */


struct Screen *gimmeScreen( ns, winptr, depth, IDCMPflags, winflags )
    struct NewScreen	*ns;
    struct Window	**winptr;
    SHORT		depth;
    ULONG		IDCMPflags, winflags;
{
    struct Screen	*screen;
    struct NewWindow	*nw;
    struct NewScreen	*myns;

    if( !(myns = ns) ) {
	ns = gimmeNewScreen( HIRES, CUSTOMSCREEN, depth, NULL, &gimMyFont );
    }
    if( ns ) {
	screen = OpenScreen( ns );
	if( screen && winptr ) {
	    nw = gimmeNewWindow( NULL, screen, 0, 1, IDCMPflags, winflags );
	    if( !nw ) {
		*winptr = NULL;
	    } else {
		*winptr = gimmeWindow( nw, 0, 0, 0 );
		getRidOfNewWindow( nw );
		if( !*winptr ) {
		    getRidOfScreen( screen, NULL );
		    screen = NULL;
		} else {
		    ShowTitle( screen, FALSE );     /* hide screen title */
		}
	    }
	}
    }
    if( !myns && ns ) {
	getRidOfNewScreen( ns );
    }
    return( screen );
} /* gimmeScreen */


struct Screen *gimmeScreenLazy( ns, winptr, depth )
    struct NewScreen	*ns;
    struct Window	**winptr;
    SHORT		depth;
{
    return( gimmeScreen(ns, winptr, depth, IDCMP_DEFAULT, FLAGS_DEFAULT) );
} /* gimmeScreenLazy */


short getRidOfScreen( screen, window )
    struct Screen   *screen;
    struct Window   *window;
{
    if( window ) {
	getRidOfWindow( window );
    }
    if( screen ) {
	CloseScreen( screen );
    }
    return( 0 );
} /* getRidOfScreen */


short lowerScreen( screen, toheight )
    struct Screen   *screen;
    SHORT	    toheight;
{
    register SHORT  i;

#ifdef GIMME_WIMPY
    if( !screen ) {
	return( -1 );
    }
#endif
    for( i = screen->TopEdge | 1; i < toheight; i += 2 ) {
	MoveScreen( screen, 0L, 2L );
    } /* for */
    return( 0 );
} /* lowerScreen */


short raiseScreen( screen, toheight )
    struct Screen   *screen;
    SHORT	    toheight;
{
    register SHORT  i;

#ifdef GIMME_WIMPY
    if( !screen ) {
	return( -1 );
    }
#endif
    for( i = screen->TopEdge & (~1); i >= toheight; i -= 2 ) {
	MoveScreen( screen, 0L, -2L );
    } /* for */
    return( 0 );
} /* raiseScreen */
SHAR_EOF
cat << \SHAR_EOF > scrollbar.c
/*
 *  FILE: scrollbar.c
 *  Support routines for making scroll-bar and -button gadgets.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Aug-88	Jan Sven Trabandt   first release version
 *  30-Sep-88	Jan Sven Trabandt   keep up with changes to gadget.c
 */


#define I_AM_SCROLLBAR
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/scrollbar.h"
#include "gimmelib/macros.h"


struct Gadget *gimmeOneScroll( window, id, dirflags, myflags )
    struct Window   *window;
    USHORT	    id;
    ULONG	    dirflags, myflags;
{
    register struct Gadget  *gp;
    void    *gadgmh = NULL;
    USHORT  *data;
    USHORT  *imagedata;

    GUESS
	QUIF( !id );
	gp = chainAllocMem( &gadgmh, (ULONG)sizeof(struct Gadget),
				MEMF_CLEAR | MEMF_PUBLIC );
	QUIF( !gp );
	gp->GadgetType = BOOLGADGET;
	gp->GadgetRender = (APTR) gimmeImage( &gadgmh, GOS_BITDEPTH,
						GOS_BITWIDTH, GOS_BITHEIGHT );
	QUIF( !gp->GadgetRender );

	if( dirflags & FREEVERT ) {
	    gp->LeftEdge = -(GOS_BITWIDTH -1);
	    gp->Width = GOS_BITWIDTH;
	    gp->Height = GOS_BITHEIGHT;
	    if( myflags & GOS_TOP ) {
		if( window ) {
		    gp->TopEdge = window->BorderTop - 1;
		} else {
		    gp->TopEdge = GIM_DFLT_TBHEIGHT;
		}
		gp->Flags = GADGIMAGE | GADGHCOMP | GRELRIGHT;
		imagedata = gimDataOneScrollUp;
	    } else {
		gp->TopEdge = -GIM_SZHEIGHT - (GOS_BITHEIGHT -1);
		gp->Flags = GADGIMAGE | GADGHCOMP | GRELRIGHT | GRELBOTTOM;
		imagedata = gimDataOneScrollDown;
	    }
	    gp->Activation = RELVERIFY | RIGHTBORDER;
	} else {		/* otherwise we have FREEHORIZ */
	    gp->TopEdge = -(GOS_BITHEIGHT -1);
	    gp->Width = GOS_BITWIDTH;
	    gp->Height = GOS_BITHEIGHT;
	    if( myflags & GOS_LEFT ) {
		gp->LeftEdge = 0;
		gp->Flags = GADGIMAGE | GADGHCOMP | GRELBOTTOM;
		imagedata = gimDataOneScrollLeft;
	    } else {
		gp->LeftEdge = -GIM_SZWIDTH - (GOS_BITWIDTH - 1);
		gp->Flags = GADGIMAGE | GADGHCOMP | GRELBOTTOM | GRELRIGHT;
		imagedata = gimDataOneScrollRight;
	    }
	    gp->Activation = RELVERIFY | BOTTOMBORDER;
	}
	copyDataImage( imagedata, (struct Image *) gp->GadgetRender );
	if( window ) {
	    if( window->Flags & GIMMEZEROZERO ) {
		gp->GadgetType |= GZZGADGET;
	    }
	}
	gp->GadgetID = id;
	gp->UserData = gadgmh;
	return( gp );
    ENDGUESS
    if( gadgmh ) {
	chainFreeMem( gadgmh );
	return( NULL );
    }
} /* gimmeOneScroll */


struct Gadget *gimmeScrollBar( window, id, propflags, myflags )
    struct Window   *window;
    USHORT	    id;
    ULONG	    propflags, myflags;
{
    register struct Gadget  *gp;
    SHORT   ones_size = 0;
    SHORT   left, top, width, height;
    ULONG   gadgflags, activation;
    void    *gadgmh = NULL;

    GUESS
	QUIF( !id );
	if( propflags & FREEVERT ) {
	    propflags &= ~FREEHORIZ;
	    if( myflags & GSB_ONE_SCROLL ) {
		ones_size = GOS_BITHEIGHT;
	    }
	    left = - (GOS_BITWIDTH -1);
	    top  = ones_size;
	    if( !(myflags & GSB_NO_TITLEBAR) ) {
		if( window ) {
		    top += window->BorderTop - 1;
		} else {
		    top += GIM_DFLT_TBHEIGHT;
		}
	    }
	    width  = GOS_BITWIDTH;
	    height = -top - ones_size - GIM_SZHEIGHT;
	    gadgflags  = GADGHCOMP | GADGIMAGE | GRELRIGHT | GRELHEIGHT;
	    activation = RELVERIFY | RIGHTBORDER;
	} else {		/* otherwise we have FREEHORIZ */
	    propflags &= ~FREEVERT;
	    if( myflags & GSB_ONE_SCROLL ) {
		ones_size = GOS_BITWIDTH;
	    }
	    left = ones_size;
	    top  = - (GOS_BITHEIGHT -1);
	    width  = -GIM_SZWIDTH - (ones_size<<1);
	    height = GOS_BITHEIGHT;
	    gadgflags  = GADGHCOMP | GADGIMAGE | GRELBOTTOM | GRELWIDTH;
	    activation = RELVERIFY | BOTTOMBORDER;
	}
	gp = gimmePropGadget( window, id, left, top, width, height, NULL,
				NULL, activation, propflags );
	QUIF( !gp );
	gp->Flags = gadgflags;
	if( window ) {
	    ((struct PropInfo *)gp->SpecialInfo)->VertBody =
				0x0FFFFL * window->Height / window->MaxHeight;
	    ((struct PropInfo *)gp->SpecialInfo)->HorizBody =
				0x0FFFFL * window->Width / window->MaxWidth;
	}
	linkChainMem( &gp->UserData, gadgmh );
	return( gp );
    ENDGUESS
    if( gadgmh ) {
	chainFreeMem( gadgmh );
	return( NULL );
    }
} /* gimmeScrollBar */


struct Gadget *gimmeFullScrollBar( window, id, propflags, myflags, id1, id2 )
    struct Window   *window;
    USHORT	    id;
    ULONG	    propflags, myflags;
    USHORT	    id1, id2;
{
    register struct Gadget  *gp;

    GUESS
	QUIF( !id );
	gp = gimmeScrollBar( window, id, propflags, myflags | GSB_ONE_SCROLL );
	QUIF( !gp );
	/* top or left one-scroll */
	gp->NextGadget = gimmeOneScroll( window, id1, propflags,
					    GOS_TOP | GOS_LEFT );
	QUIF( !gp->NextGadget );
	/* bottom or right one-scroll */
	gp->NextGadget->NextGadget = gimmeOneScroll( window, id2, propflags,
					    GOS_BOT | GOS_RIGHT );
	QUIF( !gp->NextGadget->NextGadget );
	return( gp );
    ENDGUESS
    if( gp ) {
	getRidOfGadgets( gp );
    }
    return( NULL );
} /* gimmeFullScrollBar */
SHAR_EOF
cat << \SHAR_EOF > sound.c
/*
 *  FILE: sound.c
 *  Support routines for reading IFF/8SVX files.
 *
 *  Public Domain, but keep our names in it as the original authors.
 *  09-Dec-87	Rico Mariani	    original code (modified by JST)
 *  31-Aug-88	Jan Sven Trabandt   first release version
 */


#define I_AM_SOUND
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/sound.h"
#include <stdio.h>


#define GET(iffile)         getc( iffile )

#define getId		    getLong
#define getLen		    getLong
#define getByte 	    GET
#define skip(len, file)     fseek(file, (long)(len), 1)

#define getV8H(v8h, file)   fread(v8h, sizeof(Voice8Header), 1, file)

/* requires an existent variable 'char *errmsg' and a label 'failure_return' */
#define fail_and_return(msg)    {errmsg = msg; goto failure_return;}

/* forward declarations */
static LONG getLong();
static WORD getWord();

static char noMemMsg[] = "insufficient memory\n";
static char badFileMsg[] = "corrupt or incomplete file\n";


SOUND *gimmeSound( filename )
    UBYTE   *filename;
{
    LONG    len, id;
    SOUND   *snd = NULL;
    BYTE    *p;
    void    *mh = NULL;
    FILE    *file = NULL;
    char    *errmsg = " ";
    SHORT   i;

    if( !(file = fopen(filename, "r")) ) {
	fail_and_return( "unable to open iff sound file for read\n" );
    }
    if( getId(file) != ID_FORM ) {
	fail_and_return( "not IFF format\n" );
    }
    getLen( file );
    if( getId(file) != ID_8SVX ) {
	fail_and_return( "not 8SVX format\n" );
    }
    for( ;; ) {
	getChunk( &id, &len, file );
	if( ferror(file) || feof(file) ) {
	    fail_and_return( badFileMsg );
	}
	switch( id ) {
	  case ID_VHDR:
	    snd = chainAllocMem( &mh, (ULONG)sizeof(SOUND),
				    MEMF_PUBLIC | MEMF_CLEAR );
	    if( !snd ) {
	       fail_and_return( noMemMsg );
	    }
	    getV8H( &snd->vh, file );
	    if( len & 1 ) {
		GET(file);
	    }
	    break;
	  case ID_BODY:
	    if( !snd ) {
		fail_and_return( "didn't find VHDR chunk\n" );
	    }
	    switch( snd->vh.sCompression ) {
	      case sCmpNone:
		snd->bodylen = len;
		snd->body = chainAllocMem( &mh, len, MEMF_CHIP );
		if( !snd->body ) {
		    fail_and_return( noMemMsg );
		}
		memget( snd->body, len, file );
		break;
	      case sCmpFibDelta:
		snd->bodylen = len << 1;
		snd->body = chainAllocMem( &mh, (ULONG) snd->bodylen,
					    MEMF_CHIP );
		if( !snd->body ) {
		    fail_and_return( noMemMsg );
		}
		p = AllocMem( len, MEMF_PUBLIC );
		if( !p ) {
		    fail_and_return( noMemMsg );
		}
		memget( p, len, file );
		DUnpack( p, len, snd->body );
		FreeMem( p, len );
		break;
	      default:
		fail_and_return( "unknown compression form\n" );
		break;
	    } /* switch */
	    if( len & 1 ) {
		GET(file);
	    }
	    if( ferror(file) ) {
		fail_and_return( badFileMsg );
	    }
	    snd->memhead = mh;
	    fclose( file );
	    return( snd );
	    break;
	  case ID_NAME:
	  case ID_AUTH:
	  case ID_COPY:
	  case ID_ANNO:
	  case ID_ATAK:
	  case ID_RLSE:
	  default:		/* unimplemented chunk type */
	    skip( EVEN(len), file );
	    break;
	} /* switch */
    } /* for */
failure_return: {}
    if( Output() ) {
	Write( Output(), errmsg, (ULONG)strlen(errmsg) );
    }
    if( mh ) {
	chainFreeMem( mh );
    }
    if( file ) {
	fclose( file );
    }
    return( NULL );
} /* gimmeSound */


short getRidOfSound( sound )
    SOUND   *sound;
{
#ifdef GIMME_WIMPY
    if( !sound ) {
	return( -1 );
    }
#endif
    chainFreeMem( sound->memhead );
    return( 0 );
} /* getRidOfSound */


/* read an IFF Id */
static LONG getLong( file )
    FILE    *file;
{
    register UBYTE  p[4];

    p[0] = GET(file);
    p[1] = GET(file);
    p[2] = GET(file);
    p[3] = GET(file);
    return( (LONG) Mk(p[0],p[1],p[2],p[3]) );
} /* getLong */


/* read an IFF chunk header */
static getChunk( id, len, file )
    LONG    *id, *len;
    FILE    *file;
{
    *id = getId( file );
    *len = getLen( file );
} /* getChunk */


/* get len bytes from the file and put them into memory */
static memget( p, len, file )
    UBYTE   *p;
    LONG    len;
    FILE    *file;
{
    for( ; len > 0L; len -= 0x07fffL, p += 0x07fffL ) {
	fread( p, (int) (len & 0x07fffL), 1, file );
    } /* for */
} /* memget */


/* get a word */
static WORD getWord( file )
    FILE    *file;
{
    WORD    v;

    v = GET(file) << 8;
    return( v | GET(file) );
} /* getWord */


/* get the EGPoint info */
static getEGPoint( pnt, file )
    EGPoint *pnt;
    FILE    *file;
{
    pnt->duration = getWord( file );
    pnt->dest = getLong( file );
} /* getEGPoint */


static BYTE codeToDelta[] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};

/* unpack a part of a fibonacci delta encoded sound sample */
static BYTE D1Unpack( source, n, dest, x )
    BYTE    *source;
    LONG    n;
    BYTE    *dest;
    BYTE    x;
{
    UBYTE   d;
    LONG    i, lim;

    lim = n << 1;
    for( i = 0; i < lim; ++i ) {
	d = source[i>>1];
	if( i & 1 ) {
	    d &= 0xf;
	} else {
	    d >>= 4;
	}
	x += codeToDelta[d];
	dest[i] = x;
    } /* for */
    return( x );                /* return last data value */
} /* D1Unpack */


/* unpack a fibonacci delta encoded sound sample */
static DUnpack( source, n, dest )
    BYTE    *source;
    LONG    n;
    BYTE    *dest;
{
    D1Unpack( source + 2, n - 2, dest, source[1] );
} /* DUnpack */
SHAR_EOF
cat << \SHAR_EOF > stdstuff.c
/*
 *  FILE: stdstuff.c
 *  Support routines for creating and dealing with standard libraries
 *  and devices.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  30-Sep-88	Jan Sven Trabandt   added to gimme.lib
 *  31-Oct-88	Jan Sven Trabandt   added new options
 *				    made getRidOfStdStuff more controllable
 */


#define I_AM_STDSTUFF
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/stdstuff.h"

#ifdef AZTEC_C
extern int Enable_Abort;
#endif AZTEC_C

struct IntuitionBase	*IntuitionBase = NULL;
struct GfxBase		*GfxBase = NULL;
struct DiskfontBase	*DiskfontBase = NULL;
struct Device		*TimerBase = NULL;

struct MsgPort	    *gimTimerPort = NULL;
struct timerequest  *gimMasterTR = NULL;
struct timerequest  *gimSlaveTR = NULL;

struct MsgPort	    *gimMainPort = NULL;
SHORT		    gimSubTasks = 0;

void		    *gimChainMem = NULL;


ULONG gimmeStdStuff( myflags, rev )
    ULONG   myflags;
    SHORT   rev;
{
    if( myflags & GSS_DISABLEABORT ) {
#ifdef AZTEC_C
	Enable_Abort = 0;
#endif
    }
    if( myflags & GSS_INTUITION ) {
	if( !(IntuitionBase = (struct IntuitionBase *)
			    OpenLibrary("intuition.library", (long) rev)) ) {
	    return( GSS_INTUITION );
	}
    }
    if( myflags & GSS_GFX ) {
	if( !(GfxBase = (struct GfxBase *)
			    OpenLibrary("graphics.library", (long) rev)) ) {
	    return( GSS_GFX );
	}
    }
    if( myflags & GSS_CLOSEWBENCH ) {
	if( CloseWorkBench() ) {
	    return( GSS_CLOSEWBENCH );
	}
    }
    if( myflags & GSS_DISKFONT ) {
	if( !(DiskfontBase = (struct DiskfontBase *)
			    OpenLibrary("diskfont.library", (long) rev)) ) {
	    return( GSS_DISKFONT );
	}
    }
    if( myflags & GSS_TIMER ) {
	if( !(gimMasterTR = accessTimer(UNIT_MICROHZ, &gimTimerPort)) ) {
	    return( GSS_TIMER );
	}
	if( !(gimSlaveTR = gimmeTimeRequest(gimMasterTR)) ) {
	    return( GSS_TIMER );
	}
    }
    if( myflags & GSS_SUBTASK ) {
	if( initSubTasker(&gimSubTasks, &gimMainPort) ) {
	    return( GSS_SUBTASK );
	}
    }
    return( 0L );
} /* gimmeStdStuff */


ULONG getRidOfStdStuff( myflags )
    ULONG   myflags;
{
    if( myflags & GSS_MEMCHAIN ) {
	if( gimChainMem ) {
	    chainFreeMem( gimChainMem );
	    gimChainMem = NULL;
	}
    }
    if( myflags & GSS_SUBTASK ) {
	if( gimMainPort ) {
	    handleSpecialSubTaskMsg( &gimSubTasks, &gimMainPort );
	    if( doneSubTasker(&gimSubTasks, &gimMainPort)
			&& !(myflags & GSS_RUTHLESS) ) {
		return( GSS_SUBTASK );
	    }
	    gimSubTasks = 0;
	    gimMainPort = NULL;
	}
    }
    if( myflags & GSS_TIMER ) {
	if( gimSlaveTR ) {
	    if( getRidOfTimeRequest(gimSlaveTR) && !(myflags & GSS_RUTHLESS) ) {
		return( GSS_TIMER );
	    }
	    gimSlaveTR = NULL;
	}
	if( gimMasterTR ) {
	    if( releaseTimer(gimMasterTR, NULL) && !(myflags & GSS_RUTHLESS) ) {
		return( GSS_TIMER );
	    }
	    gimMasterTR = NULL;
	    gimTimerPort = NULL;
	}
    }
    if( myflags & GSS_DISKFONT ) {
	if( DiskfontBase ) {
	    CloseLibrary( DiskfontBase );
	    DiskfontBase = NULL;
	}
    }
    if( myflags & GSS_OPENWBENCH ) {
	if( OpenWorkBench() && !(myflags & GSS_RUTHLESS) ) {
	    return( GSS_OPENWBENCH );
	}
    }
    if( myflags & GSS_GFX ) {
	if( GfxBase ) {
	    CloseLibrary( GfxBase );
	    GfxBase = NULL;
	}
    }
    if( myflags & GSS_INTUITION ) {
	if( IntuitionBase ) {
	    CloseLibrary( IntuitionBase );
	    IntuitionBase = NULL;
	}
    }
    if( myflags & GSS_ENABLEABORT ) {
#ifdef AZTEC_C
	Enable_Abort = 1;
#endif
    }
    return( 0L );
} /* getRidOfStdStuff */
SHAR_EOF
cat << \SHAR_EOF > subtask.c
/*
 *  FILE: subtask.c
 *  Support routines for spawning subtasks (not processes).
 *  This means the subtask shares the same memory space as its parent task.
 *
 *  Note: this "library" is re-entrant, so any task can spawn and keep track
 *  of its own subtasks independantly of other users of this "library".
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Aug-88	Jan Sven Trabandt   first release version
 *  31-Oct-88	Jan Sven Trabandt   (de)initialize routines moved to subtinit.c
 *				      so that minimal routines need to be
 *				      linked in when using stdstuff.c
 *				    renamed getRidOfSubTask to killSubTask
 */


#define I_AM_SUBTASK
#include "gimmelib/gimmefuncs.h"


#define MIN_STACK   100L

#define MIN_COUNT   2
#define MAX_EXTRA   2


typedef struct {
    struct Message msg;
    ULONG flags;
    APTR  ptr;
} DONEMSG;

#define DONEFLAG    ((1L << 31) + 1857329L)


/* internal use only!!
 *
 * NAME:	a4get, a4put
 *
 * SYNOPSIS:	a4value = a4get();
 *		a4put( a4value );
 *		LONG a4value;
 *
 * DESCRIPTION: Get or put a value into register A4.	MANX specific!!!!
 *		These two functions are support routines for task creation.
 *		BECAUSE A4 GETS CLEARED IN THE SUBTASK
 *		and Manx needs it as a base pointer in small-code model.
 *		Manx's geta4() won't work if its code is too far away,
 *		so this ensures a4 is set up.
 *		I'm not sure if this is only in small code and/or small data.
 *

static LONG a4get();
static VOID a4put();

#asm
	cseg
_a4get:
	move.l	a4,d0
	rts

_a4put:
	move.l	4(a7),a4
	rts
#endasm


struct Task *gimmeSubTask( countptr, portptr, stack_size, data_size,
			    myportptr )
    SHORT	    *countptr;
    struct MsgPort  **portptr;
    LONG	    stack_size, data_size;
    struct MsgPort  **myportptr;
{
    struct Task     *task;
    DONEMSG	    *msg = NULL;
    struct MemList  *mymemlist;
    struct myneeds {
	struct MemList mn_head; 	    /* 1 MemEntry in the head */
	struct MemEntry mn_body[MIN_COUNT+MAX_EXTRA-1];
    } myneeds;
    UWORD	    count = 0;

    myneeds.mn_head.ml_Node.ln_Type = NT_MEMORY;
    myneeds.mn_head.ml_Node.ln_Pri  = 0;
    myneeds.mn_head.ml_Node.ln_Name = NULL;

    if( data_size > 0L ) {
	myneeds.mn_head.ml_me[count].me_Reqs = MEMF_PUBLIC | MEMF_CLEAR;
	myneeds.mn_head.ml_me[count].me_Length = data_size;
	++count;
    }
    if( myportptr && portptr ) {
	myneeds.mn_head.ml_me[count].me_Reqs = MEMF_PUBLIC | MEMF_CLEAR;
	myneeds.mn_head.ml_me[count].me_Length = (LONG) sizeof(DONEMSG);
	++count;
    }

    /* leave stack and struct Task as last two memory blocks */

    if( stack_size < MIN_STACK ) {
	stack_size = MIN_STACK;
    }
    myneeds.mn_head.ml_me[count].me_Reqs = MEMF_PUBLIC;
    myneeds.mn_head.ml_me[count].me_Length = stack_size;
    ++count;
    myneeds.mn_head.ml_me[count].me_Reqs = MEMF_PUBLIC | MEMF_CLEAR;
    myneeds.mn_head.ml_me[count].me_Length = (LONG) sizeof(struct Task);
    ++count;

    myneeds.mn_head.ml_NumEntries = count;
    mymemlist = (struct MemList *) AllocEntry( &myneeds );
    if( (ULONG)(mymemlist) & (1L<<31) ) {
	return( NULL );
    }

    --count;
    task = (struct Task *) mymemlist->ml_me[count].me_Addr;
    NewList( &task->tc_MemEntry );
    AddTail( &task->tc_MemEntry, mymemlist );

    --count;
    task->tc_SPLower = mymemlist->ml_me[count].me_Addr;     /* stack */
    task->tc_SPUpper = (APTR) (stack_size + (ULONG) task->tc_SPLower);
    task->tc_SPReg = task->tc_SPUpper;
    task->tc_Node.ln_Type = NT_TASK;

    if( myportptr && portptr ) {
	--count;
	msg = (DONEMSG *) mymemlist->ml_me[count].me_Addr;
	msg->msg.mn_Length = mymemlist->ml_me[count].me_Length;
	msg->msg.mn_Node.ln_Type = NT_MESSAGE;
	msg->ptr = (APTR) *portptr;     /* save subtask monitoring port */
	msg->flags = DONEFLAG;
    } /* endif */
    pushTaskStack( task, msg );

    if( data_size > 0L ) {
	--count;
	task->tc_UserData = mymemlist->ml_me[count].me_Addr;
    }
    pushTaskStack( task, task->tc_UserData );
    pushTaskStack( task, myportptr );
    pushTaskStack( task, countptr );

    return( task );
} /* gimmeSubTask */


/* internal use only!!
 *
 * pushTaskStack : push a long value onto the subtask's stack
 * task struct and stack must already be initialized,
 * task must not have been started yet.
static pushTaskStack( task, val )
    struct Task *task;
    LONG	val;
{
    --((LONG *)task->tc_SPReg);
    *((LONG *)task->tc_SPReg) = val;
} /* pushTaskStack */


/* internal use only!!
 *
 * popTaskStack : pop a long value off the subtask's stack
 * task struct and stack must already be initialized,
 * task must not have been started yet.
static LONG popTaskStack( task )
    struct Task *task;
{
    return( *((LONG *)task->tc_SPReg)++ );
} /* popTaskStack */


VOID undoGimmeSubTask( task )
    struct Task *task;
{
    if( task ) {
	FreeEntry( task->tc_MemEntry.lh_Head );
    }
} /* undoGimmeSubTask */


VOID killSubTask( countptr, portptr, task )
    SHORT	    *countptr;
    struct MsgPort  **portptr;
    struct Task     *task;
{
    struct MsgPort  *myport;

    if( portptr && (myport = *portptr) ) {
	*portptr = NULL;
	DeletePort( myport );
    }
    /*	It is permissible to do a Forbid() and RemTask(NULL) [kill myself]
     *	even though the following Permit() statement would not get executed
     *	since the OS will take care of things just fine.
    */
    Forbid();
    if( countptr ) {
	--(*countptr);
    }
    RemTask( task );
    Permit();
} /* killSubTask */


/*  internal use only!!
 *
 *  getRidOfMyself
 *  what's actually on the stack:
 *	func	a4	countptr   myport   data    msg  -> see bridgeSubTask
 *  what getRidOfMyself thinks is there:
 *	ret-addr dum	[countptr] [myport] [data]  [msg]
 *  note it doesn't actually know about data, msg and port.
 *  thus countptr is 1 long past dum, etc.
static VOID getRidOfMyself( dum )
    LONG    dum;
{
    LONG	    *parm;
    DONEMSG	    *msg;
    struct MsgPort  *mp, *myport;

    parm = &dum;
    msg = (DONEMSG *) *(parm + 4);
    if( msg && (myport = (struct MsgPort *) *(parm + 2)) ) {
	mp = (struct MsgPort *) msg->ptr;
	msg->ptr = (APTR) FindTask( NULL );
	msg->msg.mn_ReplyPort = myport;
	PutMsg( mp, msg );
	for( ;; ) {
	    WaitPort( myport );
	    while ( msg = (DONEMSG *) GetMsg(myport) ) {
		if( msg->msg.mn_Node.ln_Type != NT_REPLYMSG ) {
		    ReplyMsg( msg );
		} else if( msg->flags == DONEFLAG ) {
		    goto gromyself_done;
		}
	    } /* while */
	} /* for */
    }
gromyself_done:
    killSubTask( *(parm + 1), parm + 2, NULL );
} /* getRidOfMyself */


/*  internal use only!!
 *
 *  bridgeSubTask
 *  Used as the actual initialPC for the subtask, it gets a message port
 *  if necessary and calls the real subtask routine.
 *  Also increments the subtask counter!!!!
 *  Also changes portptr on the stack to port (ie a pointer to a port, not
 *  a pointer to a pointer) so things are kosher for getRidOfMyself.
 *  startSubTask does the set-up so that the new subtask starts executing
 *  with this routine.
static VOID bridgeSubTask( func, a4, countptr, myportptr, data, msg )
    long	    (*func)();
    LONG	    a4;
    SHORT	    *countptr;
    struct MsgPort  **myportptr;
    APTR	    data;
    DONEMSG	    *msg;
{
    a4put( a4 );
    if( countptr ) {
	Forbid();
	++(*countptr);
	Permit();
    }
    if( myportptr ) {
	*myportptr = CreatePort( NULL, 0L );
	if( !*myportptr ) {
	    return;
	}
	*((struct MsgPort **)&myportptr) = *myportptr;
    }
    func( data );
} /* bridgeSubTask */


short startSubTask( task, name, pri, initialpc, finalpc )
    struct Task *task;
    char	*name;
    BYTE	pri;
    void	(*initialpc)(), (*finalpc)();
{
    if( !task || !initialpc ) {
	return( -1 );
    }
    task->tc_Node.ln_Name = name;
    task->tc_Node.ln_Pri  = pri;
    pushTaskStack( task, a4get() );
    pushTaskStack( task, initialpc );
    if( !finalpc ) {
	(APTR) finalpc = (APTR) getRidOfMyself;
    }
    AddTask( task, bridgeSubTask, finalpc );
    return( 0 );
} /* startSubTask */
SHAR_EOF
cat << \SHAR_EOF > subtinit.c
/*
 *  FILE: subtinit.c
 *  Support routines for spawning subtasks (not processes).
 *  This means the subtask shares the same memory space as its parent task.
 *
 *  Note: this "library" is re-entrant, so any task can spawn and keep track
 *  of its own subtasks independantly of other users of this "library".
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Oct-88	Jan Sven Trabandt   split from subtask.c
 */


#define I_AM_SUBTINIT
#include "gimmelib/gimmefuncs.h"
#define GIM_BUILTIN
#include "gimmelib/macros.h"


short initSubTasker( countptr, portptr )
    SHORT	    *countptr;
    struct MsgPort  **portptr;
{
    if( countptr ) {
	*countptr = 0;
    }
    if( portptr ) {
	*portptr = CreatePort( NULL, 0L );
	if( !*portptr ) {
	    return( -1 );
	}
    }
    return( 0 );
} /* initSubTasker */


short doneSubTasker( countptr, portptr )
    SHORT	    *countptr;
    struct MsgPort  **portptr;
{
    struct MsgPort  *myport;

    if( countptr && *countptr ) {
	return( -1 );
    }
    if( portptr && (myport = *portptr) ) {
	*portptr = NULL;
	DeletePort( myport );
    }
    return( 0 );
} /* doneSubTasker */


/****************************************************************/
/* routines to handle printing messages from subtasks to Output()

extern struct Message *gimmeMessage();

struct print_msg {
    struct Message msg;
    ULONG flags;
    UBYTE buf[164];
};
typedef struct print_msg PRINTMSG;

#define PRINTMSG_FLAG	218572L


short doPrintf( port, replyport, s, p1, p2, p3, p4 )
    struct MsgPort  *port, *replyport;
    UBYTE	    *s;
    LONG	    p1, p2;
    double	    p3, p4;
{
    PRINTMSG	*pmsg;

    if( !port || !s ) {
	return( -1 );
    }
    pmsg = (PRINTMSG *) gimmeMessage( (ULONG)sizeof(PRINTMSG), replyport );
    if( !pmsg ) {
	return( -1 );
    }
    pmsg->flags = PRINTMSG_FLAG;
    sprintf( pmsg->buf, s, p1, p2, p3, p4 );
    PutMsg( port, pmsg );
    if( replyport ) {
	WaitPort( replyport );
	pmsg = (PRINTMSG *) GetMsg( port );
/***
	if( pmsg->msg.mn_Node.ln_Type != NT_REPLYMSG
	     || pmsg->flags != PRINTMSG_FLAG ) {
	}
***/
	getRidOfMessage( pmsg );
    } /* endif */
    return( 0 );
} /* doPrintf */


SHORT handleSpecialSubTaskMsg( countptr, portptr )
    SHORT	    *countptr;
    struct MsgPort  **portptr;
{
    PRINTMSG	*msg;
    SHORT	died = 0;

    if( !portptr || !*portptr ) {
	return( died );
    }
    while( msg = (PRINTMSG *) GetMsg(*portptr) ) {
	if( msg->flags == PRINTMSG_FLAG ) {
	    if( Output() ) {
		Forbid();
		Write( Output(), msg->buf, (ULONG)strlen(msg->buf) );
		Permit();
	    }
	    if( !msg->msg.mn_ReplyPort ) {
		getRidOfMessage( msg );
	    } else {
		ReplyMsg( msg );
	    }
	} else {	/* otherwise its a DONEMSG (see subtask.c) */
	    ReplyMsg( msg );
	    ++died;
	} /* endif */
    } /* while */
    return( died );
} /* handleSpecialSubTaskMsg */
SHAR_EOF
cat << \SHAR_EOF > timer.c
/*
 *  FILE: timer.c
 *  Support routines for dealing with the timer device.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Aug-88	Jan Sven Trabandt   first release version
 *  31-Oct-88	Jan Sven Trabandt   most routines moved to timerstuff.c
 *				      so that minimal routines need to be
 *				      linked in when using stdstuff.c
 */


#define I_AM_TIMER
#include "gimmelib/gimmefuncs.h"

extern struct Device *TimerBase;


struct timerequest *accessTimer( unit, portptr )
    ULONG	    unit;
    struct MsgPort  **portptr;
{
    struct MsgPort	*timerport = NULL;
    struct timerequest	*tr;

#ifdef GIMME_WIMPY
    if( unit != UNIT_VBLANK && unit != UNIT_MICROHZ ) {
	return( NULL );
    }
#endif
    if( portptr && *portptr ) {
	timerport = *portptr;
    } else {
	timerport = CreatePort( NULL, 0L );
	if( portptr ) {
	    *portptr = timerport;
	}
    }
    if( !timerport ) {
	return( NULL );
    }
    tr = CreateExtIO( timerport, (ULONG)sizeof(struct timerequest) );
    if( !tr ) {
	DeletePort( timerport );
    } else {
	if( OpenDevice(TIMERNAME, unit, tr, 0L) ) {
	    DeleteExtIO( tr, (ULONG)sizeof(struct timerequest) );
	    DeletePort( timerport );
	    return( NULL );
	}
    }
    TimerBase = tr->tr_node.io_Device;
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    return( tr );
} /* accessTimer */


LONG releaseTimer( tr, saveport )
    register struct timerequest *tr;
    struct MsgPort  *saveport;
{
    struct MsgPort  *tport;
    LONG	    err;

#ifdef GIMME_WIMPY
    if( !tr ) {
	return( 0L );
    }
#endif
    tport = tr->tr_node.io_Message.mn_ReplyPort;
    if( tr->tr_node.io_Message.mn_Node.ln_Type == NT_MESSAGE ) {
	if( err = AbortIO(tr) ) {
	    return( err );
	}
	Remove( tr );
    }
    CloseDevice( tr );
    DeleteExtIO( tr, (ULONG)sizeof(struct timerequest) );
    if( !saveport && tport ) {
	DeletePort( tport );
    }
    return( 0L );
} /* releaseTimer */


struct timerequest *gimmeTimeRequest( trmaster )
    struct timerequest	*trmaster;
{
    register struct timerequest *tr;

#ifdef GIMME_WIMPY
    if( !trmaster ) {
	return( NULL );
    }
#endif
    tr = CreateExtIO( trmaster->tr_node.io_Message.mn_ReplyPort,
			(ULONG)sizeof(struct timerequest) );
    if( tr ) {
	tr->tr_node.io_Device = trmaster->tr_node.io_Device;
	tr->tr_node.io_Unit   = trmaster->tr_node.io_Unit;
	tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    }
    return( tr );
} /* gimmeTimeRequest */


LONG getRidOfTimeRequest( tr )
    register struct timerequest *tr;
{
    LONG    err;

#ifdef GIMME_WIMPY
    if( !tr ) {
	return( 0L );
    }
#endif
    Forbid();
    tr->tr_node.io_Message.mn_ReplyPort = NULL;
    if( tr->tr_node.io_Message.mn_Node.ln_Type == NT_MESSAGE ) {
	if( err = AbortIO(tr) ) {
	    Permit();
	    return( err );
	}
	Remove( tr );
	tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    }
    Permit();
    DeleteExtIO( tr, (ULONG)sizeof(struct timerequest) );
    return( 0L );
} /* getRidOfTimeRequest */
SHAR_EOF
cat << \SHAR_EOF > timerstuff.c
/*
 *  FILE: timerstuff.c
 *  Support routines for dealing with timerequests and additional timer support.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Oct-88	Jan Sven Trabandt   split from timer.c
 */


#define I_AM_TIMERSTUFF
#include "gimmelib/gimmefuncs.h"

extern struct Device *TimerBase;


LONG timeDelay( secs, micros, unit, mytr )
    ULONG		secs, micros;
    ULONG		unit;
    struct timerequest	*mytr;
{
    register struct timerequest *tr;
    LONG    err;

    if( !secs && !micros ) {
	return( 0L );           /* so we don't crash, return right away */
    }
    if( mytr ) {
	tr = mytr;
    } else {
#ifdef GIMME_WIMPY
	if( unit != UNIT_VBLANK && unit != UNIT_MICROHZ ) {
	    return( -1L );
	}
#endif
	if( !secs ) {
	    unit = UNIT_MICROHZ;	    /* force more efficient method */
	}
	if( !(tr = accessTimer(unit, NULL)) ) {
	    return( -1L );
	}
    }
    tr->tr_node.io_Command = TR_ADDREQUEST;
    tr->tr_time.tv_secs = secs;
    tr->tr_time.tv_micro = micros;
    err = DoIO( tr );
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    if( !mytr ) {
	releaseTimer( tr, NULL );
    }
    return( err );
} /* timeDelay */


struct timerequest *timeDelayAsync( secs, micros, unit, tr )
    ULONG   secs, micros;
    ULONG   unit;
    register struct timerequest *tr;
{
    if( !tr ) {
#ifdef GIMME_WIMPY
	if( unit != UNIT_VBLANK && unit != UNIT_MICROHZ ) {
	    return( NULL );
	}
#endif
	if( !secs ) {
	    unit = UNIT_MICROHZ;	    /* force more efficient method */
	}
	if( !(tr = accessTimer(unit, NULL)) ) {
	    return( NULL );
	}
    }
    if( !secs && !micros ) {
	micros = 1L;			/* so we don't crash on zero-delay */
    }
    tr->tr_node.io_Command = TR_ADDREQUEST;
    tr->tr_time.tv_secs = secs;
    tr->tr_time.tv_micro = micros;
    SendIO( tr );
    return( tr );
} /* timeDelayAsync */


LONG waitTimer( tr )
    struct timerequest	*tr;
{
    LONG    err = 0L;

#ifdef GIMME_WIMPY
    if( !tr ) {
	return( err );
    }
#endif
    err = WaitIO( tr );
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    return( err );
} /* waitTimer */


LONG killTimeDelay( tr )
    register struct timerequest *tr;
{
    LONG    err;

#ifdef GIMME_WIMPY
    if( !tr ) {
	return( 0L );
    }
#endif
    Forbid();
    if( tr->tr_node.io_Message.mn_Node.ln_Type == NT_MESSAGE ) {
	if( err = AbortIO(tr) ) {
	    Permit();
	    return( err );
	}
	Remove( tr );
	tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    }
    Permit();
    return( 0L );
} /* killTimeDelay */


short getSysTime( secs, micros, mytr )
    ULONG		*secs, *micros;
    struct timerequest	*mytr;
{
    register struct timerequest *tr;

    if( mytr ) {
	tr = mytr;
    } else {
	if( !(tr = accessTimer(UNIT_MICROHZ, NULL)) ) {
	    return( -1 );
	}
    }
    tr->tr_node.io_Command = TR_GETSYSTIME;
    DoIO( tr );
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    if( secs ) {
	*secs = tr->tr_time.tv_secs;
    }
    if( micros ) {
	*micros = tr->tr_time.tv_micro;
    }
    if( !mytr ) {
	releaseTimer( tr, NULL );
    }
    return( 0 );
} /* getSysTime */


short setSysTime( secs, micros, mytr )
    ULONG		secs, micros;
    struct timerequest	*mytr;
{
    register struct timerequest *tr;

    if( mytr ) {
	tr = mytr;
    } else {
	if( !(tr = accessTimer(UNIT_MICROHZ, NULL)) ) {
	    return( -1 );
	}
    }
    tr->tr_node.io_Command = TR_SETSYSTIME;
    tr->tr_time.tv_secs = secs;
    tr->tr_time.tv_micro = micros;
    DoIO( tr );
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    if( !mytr ) {
	releaseTimer( tr, NULL );
    }
    return( 0 );
} /* setSysTime */
SHAR_EOF
cat << \SHAR_EOF > window.c
/*
 *  FILE: window.c
 *  Support routines for dynamic (de)allocation of (new)windows.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Aug-88	Jan Sven Trabandt   first release version
 */


#define I_AM_WINDOW
#include "gimmelib/gimmefuncs.h"
#include "gimmelib/window.h"
#include <graphics/gfxbase.h>

extern struct GfxBase *GfxBase;


struct NewWindow *gimmeNewWindow( title, screen, leftedge, topedge,
				    IDCMPflags, flags )
    UBYTE	    *title;
    struct Screen   *screen;
    SHORT	    leftedge, topedge;
    ULONG	    IDCMPflags, flags;
{
    register struct NewWindow	*nw;

    nw = (struct NewWindow *) AllocMem( (ULONG)sizeof(struct NewWindow),
					MEMF_PUBLIC | MEMF_CLEAR );
    if( !nw ) {
	return( NULL );
    }
    nw->DetailPen = GNW_DETAIL_PEN;
    nw->BlockPen  = GNW_BLOCK_PEN;
    nw->IDCMPFlags= IDCMPflags;
    nw->Flags	  = flags;
    nw->Title	  = title;
    nw->MinWidth  = GNW_MIN_WIDTH;
    nw->MinHeight = GNW_MIN_HEIGHT;
    nw->LeftEdge  = leftedge;
    nw->TopEdge   = topedge;
    if( screen ) {
	nw->Type = CUSTOMSCREEN;
	nw->Screen = screen;
	nw->MaxWidth  = screen->Width;
	nw->MaxHeight = screen->Height;
    } else {
	nw->Type = WBENCHSCREEN;
	nw->MaxWidth  = GfxBase->NormalDisplayColumns;
	nw->MaxHeight = GfxBase->NormalDisplayRows;
    }
    nw->Width  = nw->MaxWidth - nw->LeftEdge;
    nw->Height = nw->MaxHeight - nw->TopEdge;
    return( nw );
} /* gimmeNewWindow */


short getRidOfNewWindow( nw )
    struct NewWindow	*nw;
{
#ifdef GIMME_WIMPY
    if( !nw ) {
	return( -1 );
    }
#endif
    FreeMem( nw, (ULONG)sizeof(struct NewWindow) );
    return( 0 );
} /* getRidOfNewWindow */


struct Window *gimmeWindow( nw, depth, width, height )
    struct NewWindow	*nw;
    SHORT   depth, width, height;
{
    struct Window	*window;
    struct NewWindow	*mynw;

    if( !(mynw = nw) ) {
	nw = gimmeNewWindow( NULL, NULL, 0, 1, IDCMP_DEFAULT, FLAGS_DEFAULT );
    }
    for( ;; ) {         /* dummy loop with break at end */
	if( nw ) {
	    if( nw->Flags & SUPER_BITMAP ) {
		if( !(nw->BitMap = gimmeBitMap(depth, width, height)) ) {
		    break;
		}
	    }
	    window = OpenWindow( nw );
	    if( !window ) {
		if( nw->Flags & SUPER_BITMAP ) {
		    getRidOfBitMap( nw->BitMap );
		}
	    } else {
		window->UserData = (BYTE *) nw->BitMap;
	    }
	}
	break;
    } /* for */
    if( !mynw && nw ) {
	getRidOfNewWindow( nw );
    }
    return( window );
} /* gimmeWindow */


short getRidOfWindow( window )
    struct Window   *window;
{
    struct BitMap	*bm = NULL;
    struct IntuiMessage *imsg;

#ifdef GIMME_WIMPY
    if( !window ) {
	return( -1 );
    }
#endif
    if( window->Flags & SUPER_BITMAP ) {
	bm = (struct BitMap *) window->UserData;
    }
    if( window->MenuStrip ) {
	ClearMenuStrip( window );
    }
    while( imsg = (struct IntuiMessage *) GetMsg(window->UserPort) ) {
	ReplyMsg( imsg );
    } /* while */
    CloseWindow( window );
    if( bm ) {
	getRidOfBitMap( bm );
    }
} /* getRidOfWindow */
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.