[comp.sources.unix] v10i091: A graphics editor, Part01/04

rs@uunet.UU.NET (Rich Salz) (08/06/87)

Submitted-by: "Alan W. Paeth" <awpaeth%watcgl.waterloo.edu@RELAY.CS.NET>
Posting-number: Volume 10, Issue 91
Archive-name: lemming/Part01

LEMMING is a complete interactive graphics editor which resembles PIC in
providing lines, boxes, circles, and text in various sizes and
emphases (bold, centered, dotted, etc). The implemtation has been proven
on the DEC GPX systems, SUN, and Ikonas Framebuffer. The code is completely
self-contained, and provides an extensive set of internal fonts.

Lemming makes no assumptions about the system hardware except that there
is (1) a mouse or tablet with at least one button and (2) there is a bitmap
display (at least one bit deep). The additional code (lemik.c) is a
representative Unix driver for use with an Ikonas framebuffer.


I am allowing complete public distribution and second party redistribution
of the software on an experimental, non-profit basis.  I maintain a
copyright against unauthorized sale or distribution for commercial or
product applications.

	Alan Paeth (awpaeth@watmath)
	c/o Computer Graphics Lab MC6080
	University of Waterloo
	Waterloo, Ontario N2L 3E5
	CANADA


[  I have not tried this program.  -r$  ]
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	.lemrc
#	lem.h
#	lemfont.h
#	lemalloc.c
#	lemalpha.c
#	lemattr.c
#	lembox.c
#	lemcut.c
#	lemedit.c
#	lemelli.c
#	lemfont.c
#	lemgeo.c
#	lemglobal.c
#	lemgroup.c
#	lemhelp.c
#	lemik.c
#	lemio.c
#	lemline.c
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
cat << \SHAR_EOF > 'Makefile'
CFLAGS = -g

OBJ =	lemalloc.o \
	lemalpha.o \
	lemattr.o \
	lembox.o \
	lemcut.o \
	lemedit.o \
	lemelli.o \
	lemfont.o \
	lemgeo.o \
	lemglobal.o \
	lemgroup.o \
	lemhelp.o \
	lemio.o \
	lemline.o \
	lemmain.o \
	lemmark.o \
	lemmisc.o \
	lemobj.o \
	lemobjsup.o \
	lemop.o \
	lempic.o \
	lemrc.o \
	lemselect.o \
	lemspecial.o \
	lemstart.o \
	lemstop.o \
	lemtext.o \
	lemtick.o \
	lemundo.o \
	lemvec.o

lemik::	$(OBJ) lemik.o
	cc $(CFLAGS) $(OBJ) lemik.o -lIkonas -lLocator -lm -o /u/awpaeth/bin/lemik

lemx::	$(OBJ) lemx.o
	cc $(CFLAGS) $(OBJ) lemx.o -lX -lm -o /u/awpaeth/bin/lemx
SHAR_EOF
chmod +x 'Makefile'
if test -f '.lemrc'
then
	echo shar: over-writing existing file "'.lemrc'"
fi
cat << \SHAR_EOF > '.lemrc'
.lemrc
Lemming .rc for default fonts (up to nine).
Data items are identified by a digit in the left-most column.

Note: substitue MR MB & MI for TR TB TI if you (*ugh*) must have ugly fonts.

	 |-----------------------  Fonts  ------------------------------|
Pnt Line |Display	Typeset			PostScript		|
Sz  Thkn		Rg/Bld/Itl		Rg/Bld/Itl
------------------------------------------------------------------------
12   1	TimesRoman	TR TB TI	Times-Bold Times-Bold Times-Bold
10   2	TimesRoman	TR TB TI	Times-Bold Times-Bold Times-Bold
18   3	TimesRoman	TR TB TI	Times-Bold Times-Bold Times-Bold
12   4	Helvetica	SR SB SI	Times-Bold Times-Bold Times-Bold
10   5	Helvetica	SR SB SI	Times-Bold Times-Bold Times-Bold
18   6	Helvetica	SR SB SI	Times-Bold Times-Bold Times-Bold
6    7	Helvetica	SR SB SI	Times-Bold Times-Bold Times-Bold
10   8	Gacha		CW CW CW	Times-Bold Times-Bold Times-Bold
12   9	Hippo 		GM GM GM	Times-Bold Times-Bold Times-Bold

Other popular entries (delete leading space):

 18 1	OldEnglish	oe oe oe	Times-Bold Times-Bold Times-Bold
SHAR_EOF
chmod +x '.lemrc'
if test -f 'lem.h'
then
	echo shar: over-writing existing file "'lem.h'"
fi
cat << \SHAR_EOF > 'lem.h'
/*
 * lem.h - lone include file for lem(ming) editor
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include <stdio.h>
#include <strings.h>
#include <ctype.h>

#define VERNO 1

/*
 * useful arithmetic functions
 */

#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define ABS(a) ((a)>0?(a):(-(a)))
#define C(a) ('a'&0x1f)
#define UC(c) (islower((c)) ? toupper((c)) : (c))

typedef struct
    {
    char stat;			/* DEL, UNDEL, SEL */
    char group;			/* group id (or zero) */
    char type;			/* LINE, TEXT, ELLI, BOX */
    char align;			/* ALIGNLEFT, ALIGNRGHT, ALIGNCENT */
    char emph;			/* EMPHNONE, EMPHBOLD, EMPHITAL */
    char size;			/* 1..10 */
    short x0, y0, x1, y1;	/* screen coordinates/bounding box */
    char *text;			/* string pointer if text */
    } *pel, el;

/*
 * object macros
 */

#define forobjects for(i=1; i<lastobj; i++)
#define forobjsrev for(i=lastobj-1; i>0; i--)
#define o objs[i]

/*
 * field access
 */

#define Ostat (o->stat)
#define Ogroup (o->group)
#define Otype (o->type)
#define Oalign (o->align)
#define Oemph (o->emph)
#define Osize (o->size)
#define Osizer ((Osize >= rclen) ? 1 : Osize)
#define Otext (o->text)
#define Oxs (o->x0)
#define Oys (o->y0)
#define Oxe (o->x1)
#define Oye (o->y1)

/*
 * derived field access
 */

#define Ox ((o->x0+o->x1+1)/2)
#define Oy ((o->y0+o->y1+1)/2)
#define Ow (o->x1-o->x0)
#define Oh (o->y1-o->y0)
#define Oxl (MIN(o->x0,o->x1))
#define Oyl (MIN(o->y0,o->y1))
#define Oxh (MAX(o->x0,o->x1))
#define Oyh (MAX(o->y0,o->y1))

#define Oxlt (Oalign==ALIGNCENT ? Oxs-Oxe/2:(Oalign==ALIGNLEFT ? Oxs:Oxs-Oxe))
#define Oylt (Oys-Oye/2)
/* (Oalign==ALIGNCENT ? Oyl : (Oalign==ALIGNLEFT ? Oy : Oy-Oh)) */
#define Oxht (Oxlt+Oxe)
#define Oyht (Oylt+Oye)
#define Oxcen (Otype==TEXT ? Oxs : Ox)
#define Oycen (Otype==TEXT ? Oys : Oy)

#define Osel (o->stat == SEL)
#define Oundel (o->stat == UNDEL)
#define Odel (o->stat == DEL)
#define Onotdel (o->stat != DEL)

/*
 * bounds limits
 */

#define MAXOBJS 2000
#define MAXCHAR 60

/*
 * .lemrc information
 */

typedef struct
    {
    int psize;
    int thick;
    char *dsp;
    char *tyr;
    char *tyb;
    char *tyi;
    char *psr;
    char *psb;
    char *psi;
    } *pfontdir, fontdir;


/*
 * file name (conventions)
 */
  
#define RCNAME  ".lemrc"
#define LEMEXTN "lem"

/*
 * initialization defaults (for .rc file in lemrc.c)
 */

#define RCLINE 120
#define RCLEN 10
#define RCWIDTH 9

#define DEFPSIZEFT 12
#define DEFDENSEFT 1.0
#define DEFIKRFT "TimesRoman"
#define DEFTYRFT "TR"
#define DEFTYBFT "TB"
#define DEFTYIFT "TB"
#define DEFPSRFT "Times-Roman"
#define DEFPSBFT "Times-Bold"
#define DEFPSIFT "Times-Italic"

/*
 * system color aliases
 */

#define DRAWCOL cwhite
#define SELECTCOL cred
#define ERASECOL cblack
#define MARKONOBJCOL cred
#define MARKONREGCOL cgreen
#define HELPCOL cgreen
#define MARKOFFCOL cblack
#define TICKONCOL cwhite
#define TICKOFFCOL cblack

/*
 * event types
 */

#define NOEVT 0
#define ALPHA 1
#define CNTRL 2
#define MOUSE 3

/*
 * geometric tolerances
 */

#define ENDTOL  5	/* near endpoints of lines */
#define MARKTOL 5	/* near a mark */
#define DRAGTOL 5	/* dragging otherwise */
#define FLATTOL 15	/* rectilinear lines */
#define SELTOL  15	/* near selection points */
#define SHRTTOL 5	/* lines may not be (entered) any shorter */
#define LINETOL 5	/* perp distance to a line */
#define TEXTTOL 0	/* text bounding box extra margins (usually no slop) */
#define SPLTTOL 3	/* do not split lines <^K> if made this short */

#define TUGPROX 2	/* when towing objects */
#define ARROWLEN 8	/* arrowhead length */
#define MINTICK 8	/* minimum VISIBLE tick spacing */
#define DEFCOPYWID 16	/* default copy width when gridding is off */

/*
 * type modes
 */

#define LINE 'L'
#define TEXT 'T'
#define ELLI 'E'
#define BOX  'B'

/*
 * status modes
 */

#define DEL 'D'
#define UNDEL 'U'
#define SEL 'S'

/*
 * align modes
 */

#define ALIGNLEFT 'L'
#define ALIGNRGHT 'R'
#define ALIGNCENT 'C'

/*
 * emphasis modes
 */

#define EMPHNONE 'N'
#define EMPHBOLD 'B'
#define EMPHITAL 'I'

/*
 * define system font (for help text and unknown fonts)
 */

#define SYSFONT 1

/*
 * generic object operations
 */

#define SELECT 1
#define DESELECT 2
#define DELETE 3
#define UNDELETE 4

/*
 * undo flags
 */
 
#define UNDOMOVE 'M'
#define UNDOTUG 'T'
#define UNDOAFF 'A'
#define UNDODEL 'D'
#define UNDONONE 'N'

/*
 * application specific
 */

#define MARKSIZE 2

/*
 * externals (see also lemglobal.c)
 */

extern char *firstfile;
extern int displayon;

extern int screenw, screenh, cred, cgreen, cblack, cwhite;
extern int changes, tickflag, ticksize, tickdot, tx, ty, txoff, tyoff;
extern int markx, marky, markon, markobj;
extern int anysel;
extern char gtype, galign, gemph, gsize;

extern char undo;
extern int unx, uny, unxe, unye;
extern float un11, un12, un21, un22;

extern int fontsize[RCLEN];
extern char *picfont[RCLEN], *postfont[RCLEN], *xfont[RCLEN], *ikfont[RCLEN];
extern float rval[RCLEN], gval[RCLEN], bval[RCLEN];

extern pel objs[MAXOBJS];
extern int lastobj;

extern fontdir lemfont[RCLEN];

extern int rclen;

extern char line[MAXCHAR], msgtext[MAXCHAR], prompttext[MAXCHAR];

/*
 * forward refenreces
 */

char *salloc(), *prompt(), getstroke();
SHAR_EOF
if test -f 'lemfont.h'
then
	echo shar: over-writing existing file "'lemfont.h'"
fi
cat << \SHAR_EOF > 'lemfont.h'
/* lemfont.c - routines to create and access binary level strike fonts
 *
 * copywrite (c) 1985, by Alan W. Paeth. All rights reserved
 * 
 * Programmed by Alan Paeth, University of Waterloo, February, 1984
 *
 * NOTE: these fonts began life as 16-bit integers, with opposite byte-
 * order conventions of the VAX. This explains the appearance of short
 * integers, and size counts done in terms of shorts.
 *
 * Also, fonts are represented as a pointer to a contiguous, variable-
 * length structure. Because the actual bitmap is the only data part
 * which varies from font to font, its declaration is ultimate in the
 * structure declaration. FONTHEADERSIZE is the short word offset to it.
 *
 * patched by Alan Paeth, May 1985, to deal with null print strings
 */

/* MAX WIDTH */

#define LEFT 0
#define RIGHT screenw
#define TOP screenh
#define BOTTOM 0

#define MAXWIDTH 1024

/* BFont structure - returned by BFontload() */

typedef struct BFont_type
    {
    short ascent;
    short descent;
    short mwidth;
    short rasterx;	/* strike scan line length expressed in short ints */
    short widths[257];  /* 257 boundaries between a strike of 256 chars */
    short glyphs[1];	/* var len glyphs starts after FONTHEADSIZE shorts */
    } *BFont;

BFont fontload();

/* offset to beginning of the glyphs */

#define FONTHEADERSIZE 261


extern BFont bfont[];
SHAR_EOF
if test -f 'lemalloc.c'
then
	echo shar: over-writing existing file "'lemalloc.c'"
fi
cat << \SHAR_EOF > 'lemalloc.c'
/*
 * lemalloc.c -- allocation routines useful to the whole lemming family
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

char *salloc(s)
    char *s;
    {
    char *out;
    out = (char*)(calloc(strlen(s)+1, sizeof(char)));
    strcpy(out, s);
    return(out);
    }
	
objfree(i)
    {
    if (Otext)
	{
	free(Otext);
	Otext = 0;
	}
    free(o);
    o = 0;
    }

objalloc(t)
    {
    int i;
    if (lastobj == MAXOBJS)
	{
	forobjects
	    {
	    if (Odel) break;
	    }
	if (i == lastobj) err("out of object space");
	objfree(i);
	}
    else
	{
	i = lastobj++;
	o = (pel)(calloc(1, sizeof(el)));
	}
    Otext = 0;
    Otype = t;
    Otype = t;
    Oalign= galign;
    Oemph = gemph;
    Osize = gsize;
    return(i);
    }

objcompress()
    {
    int i, j;
    forobjects
	{
	if (Onotdel) continue;	/* look for a hole */
	for(j=i+1; j<lastobj; j++)
	    {
	    pel tmp;
	    if (objs[j]->stat == DEL) continue;	/* look for non-hole */
	    tmp = objs[j];
	    objs[j] = objs[i];
	    objs[i] = tmp;
	    break;
	    }
	}
    forobjsrev
	{
	if (Odel) objfree(i);
	else break;
	}
    lastobj = i+1;
    }

objnew(i)
    {
    Ostat = DEL;
    Ogroup = 0;
    objectop(i, DEL, UNDEL);
    }
SHAR_EOF
if test -f 'lemalpha.c'
then
	echo shar: over-writing existing file "'lemalpha.c'"
fi
cat << \SHAR_EOF > 'lemalpha.c'
/*
 * lemalpha.c - text control
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

charadd(s, ch)
    char *s, ch;
    {
    int end;
    char str[2];
    str[0] = ch;
    str[1] = '\0';
    charshow(str);
    end = strlen(s);
    if (end < MAXCHAR-1)
	{
	s[end] = ch;
	s[end+1] = '\0';
	}
    }

chardel(s,n)
    char *s;
    {
    int end;
    end = strlen(s)-n;
    if (end >= 0)
	{
	charunshow(n);
	s[end] = '\0';
	}
    }

chardelall(s)
    char *s;
    {
    if (s) chardel(s, strlen(s));
    }

char getstroke()
    {
    int ev, t;
    char ch;
/*
 * get next alpha keystroke (null on other event)
 */
    do  {
	ev = getevent(&t, &t, &t, &t, &ch);
	} while ((ev == NOEVT) || ((ev == CNTRL) && (ch == '\0')));
    if ((ev == ALPHA) || (ev == CNTRL)) return(ch);
    return('\0');
    }

char *prompt(pstr)
    char *pstr;
    {
    char ch, pout[MAXCHAR], *rstr;
    pout[0] = '\0';
    strncpy(prompttext, pstr, MAXCHAR);
    msgclear();
    chardelall(line);
    charshow(prompttext);
    ch = '\0';
    while((ch != C(M)) && (ch != C(J)))
	{
	ch = getstroke();
	if (ch >= ' ') charadd(pout, ch);
	else if (ch == '\b') chardel(pout,1);
	}
    rstr = salloc(pout);
    chardelall(pout);
    chardelall(prompttext);
    return(rstr);
    }

msgpost(s)
    char *s;
    {
    msgclear();
    strncpy(msgtext, s, MAXCHAR);
    charshow(msgtext);
    }

msgclear()
    {
    chardelall(msgtext);
    }

stringadd()
    {
    textadd(markx, marky, line);
    if (line && strlen(line))
	{
	int hgt;
	hgt = fontleading(gsize);
	markupdate(markx, MAX(marky-hgt, hgt));
	}
    chardelall(line);
    }
	
fontheight(f)
    {
    return(lemfont[(f >= rclen) ? 1 : f].psize);
    }

fontleading(f)
    {
    return((fontheight(f)*6+2)/5);
    }
SHAR_EOF
if test -f 'lemattr.c'
then
	echo shar: over-writing existing file "'lemattr.c'"
fi
cat << \SHAR_EOF > 'lemattr.c'
/*
 * lemattr.c - change object attributes (and reset global defaults)
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

remake(newtype)
    {
    int i;
    gtype = newtype;
    forobjects
	{
	if (Osel && (Otype != newtype) && (Otype != TEXT))
	    {
	    objectop(i, SEL, DEL);
	    Otype = newtype;
	    objectop(i, DEL, SEL);
	    }
	}
    }

setattr(ch)
    char ch;
    {
    switch(UC(ch))
	{
	case 'B': gemph = EMPHBOLD; break;
	case 'I': gemph = EMPHITAL; break;
	case 'N': gemph = EMPHNONE; break;
	case 'L': galign = ALIGNLEFT; break;
	case 'R': galign = ALIGNRGHT; break;
	case 'C': galign = ALIGNCENT; break;
	case '0': gsize = 1; galign = ALIGNCENT; gemph = EMPHNONE; break;
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9': gsize = ch-'0'; break;
	default: return(0);		/* invalid char - fail */
	}
    return(1);	/* good char */
    }
/*
 * rewrite all objects with these attributes
 */

forceattr()
    {
    int i, salign, semph, ssize;
    char ch;
    ch = getstroke();
    if (setattr(ch))		/* set global attributes */
	{
	salign = galign;	/* save new global attributes */
	semph = gemph;
	ssize = gsize;
	forobjects
	    {
	    if (Osel)
		{
		objectop(i, SEL, DEL);	/* get object */
		galign = Oalign;	/* set matching global attribs, */
		gemph = Oemph;
		gsize = Osize;
		setattr(ch);		/* reset some new attribute(s) */
		Oalign = galign;	/* write back */
		Oemph = gemph;
		Osize = gsize;
		objresize(i);		/* in case this changes geometry */
		objectop(i, DEL, SEL);
		}
	    }
	galign = salign;	/* reset to new global attributes */
	gemph = semph;
	gsize = ssize;
	}
    }
SHAR_EOF
if test -f 'lembox.c'
then
	echo shar: over-writing existing file "'lembox.c'"
fi
cat << \SHAR_EOF > 'lembox.c'
/*
 * lembox.c - box primitives
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

boxresize(i)
    {
    }

boxnearpt(i, x, y)
    {
    int dx, dy;
    if (ptinrect(x, y, Oxl, Oyl, Oxh, Oyh, LINETOL))
        {
	dx = MIN(ABS(Ox-x), ABS(Oxh-x));	/* simplified for Iris C */
	dx = MIN(ABS(Oxl-x), dx);
	dy = MIN(ABS(Oy-y), ABS(Oyh-y));
	dy = MIN(ABS(Oyl-y), dy);
        if ((dx < ENDTOL) && (dy < 2*ENDTOL)) return(1);
        if ((dx < 2*ENDTOL) && (dy < ENDTOL)) return(1);
	}
    return(0);
    }

boxinrect(i, xl, yl, xh, yh)
    {
    return(objsupinrect(i, xl, yl, xh, yh));
    }

boxcantug(i, x, y)
    {
    return(objsupcantug(i, x, y));
    }

boxtug(i, xs, ys, xe, ye)
    {
    int lx, mx, hx, ly, my, hy;
    lx = ABS(Oxl-xs);
    mx = ABS(Ox-xs);
    hx = ABS(Oxh-xs);
    if (lx<mx && lx<hx) { if (Oxs<Oxe) Oxs = xe; else Oxe = xe; }
    if (hx<lx && hx<mx) { if (Oxs>Oxe) Oxs = xe; else Oxe = xe; }
    ly = ABS(Oyl-ys);
    my = ABS(Oy-ys);
    hy = ABS(Oyh-ys);
    if (ly<my && ly<hy) { if (Oys<Oye) Oys = ye; else Oye = ye; }
    if (hy<ly && hy<my) { if (Oys>Oye) Oys = ye; else Oye = ye; }
    if (mx<=hx && mx<=lx && my<=hy && my<=ly) boxmove(i, xe-xs, ye-ys);
    }

boxalign(i, x, y)
    int *x, *y;
    {
    int l, m, h;
    l = ABS(Oxl-*x);
    m = ABS(Ox-*x);
    h = ABS(Oxh-*x);
    if (l<m && l<h) *x = Oxl;
    if (m<h && m<l) *x = Ox;
    if (h<=l && h<=m) *x = Oxh;
    l = ABS(Oyl-*y);
    m = ABS(Oy-*y);
    h = ABS(Oyh-*y);
    if (l<m && l<h) *y = Oyl;
    if (m<h && m<l) *y = Oy;
    if (h<=l && h<=m) *y = Oyh;
    }

boxmove(i, x, y)
    {
    objsupmove(i, x, y);
    }

boxaffine(i, m11, m12, m21, m22)
    float m11, m12, m21, m22;
    {
    objsupaffine(i, m11, m12, m21, m22, 1);
    }

boxdraw(i, col)
    {
    int wid;
    wid = lemfont[Osizer].thick;
    drawvec(Oxs, Oys, Oxe, Oys, col, wid, Oemph);
    drawvec(Oxe, Oys, Oxe, Oye, col, wid, Oemph);
    drawvec(Oxe, Oye, Oxs, Oye, col, wid, Oemph);
    drawvec(Oxs, Oye, Oxs, Oys, col, wid, Oemph);
    }
SHAR_EOF
if test -f 'lemcut.c'
then
	echo shar: over-writing existing file "'lemcut.c'"
fi
cat << \SHAR_EOF > 'lemcut.c'
/*
 * lemcut.c - code for chopping against intersecting lines.
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

cutlines()
    {
    int i, x0, x1, y0, y1, x2, y2, x3, y3;
    forobjects
	{
	if (Osel && Otype == LINE)
	    {
	    x2 = Oxs;
	    y2 = Oys;
	    x3 = Oxe;
	    y3 = Oye;
		{
		int i, j, xs, ys;		/* new "i" variable */
		long det, det2, a, b;
		forobjects
		    {
		    if (Otype != LINE) continue;
		    if (Ostat != UNDEL) continue; /* don't cut sel lines */ 
		    x0 = Oxs;
		    y0 = Oys;
		    x1 = Oxe;
		    y1 = Oye;
		    if ((x0 == x2) && (y0 == y2)) continue; /* share endpnts */
		    if ((x1 == x2) && (y1 == y2)) continue;
		    if ((x0 == x3) && (y0 == y3)) continue;
		    if ((x1 == x3) && (y1 == y3)) continue;
		    det = (x1-x0)*(y3-y2) - (y1-y0)*(x3-x2);
		    if (det == 0) continue;
		    det2 = det/2;
		    a = ((y3-y2)*(x2-x0) + (x2-x3)*(y2-y0));
		    b = ((y1-y0)*(x2-x0) + (x0-x1)*(y2-y0));
		    if (a == 0) continue;
		    if ((a < 0) && (a <= det)) continue;
		    if ((a > 0) && (a >= det)) continue;
		    if ((b < 0) && (b <= det)) continue;
		    if ((b > 0) && (b >= det)) continue;
		    xs = x0 + (a*(x1-x0)+det2)/det;
		    ys = y0 + (a*(y1-y0)+det2)/det;
		    if (dist(x0, y0, xs, ys) <= SPLTTOL) continue;
		    if (dist(x1, y1, xs, ys) <= SPLTTOL) continue;
		    objectop(i, UNDEL, DEL);
		    j = objalloc(LINE);
		    copyattr(j, i);
		    lineupdate(i, x0, y0, xs, ys);
		    lineupdate(j, xs, ys, x1, y1);
		    objectop(i, DEL, UNDEL);
		    objectop(j, DEL, UNDEL);
		    }
		}
	    }
	}
    }
SHAR_EOF
if test -f 'lemedit.c'
then
	echo shar: over-writing existing file "'lemedit.c'"
fi
cat << \SHAR_EOF > 'lemedit.c'
/*
 * lemedit.c - object manipulation
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

moveselect(x, y)
    {
    int i;
/*
 * set flag and record last movement for undo
 */
    unx = x;
    uny = y;
    undo = UNDOMOVE;
/*
 * do the move
 */
    if (!anysel) return;
    forobjects
	{
	if (Osel)
	    {
	    objectop(i, SEL, DEL);
	    objmove(i, x, y);
	    objectop(i, DEL, SEL);
	    }
	}
    }

tugunselect(xs, ys, xe, ye)
    {
    int i;
/*
 * set flag and record last movement for undo
 */
    unx =  xs;
    uny =  ys;
    unxe = xe;
    unye = ye;
    undo = UNDOTUG;
/*
 * do the tug
 */
    if (anysel) return;
    forobjects
	{
	if (Oundel && objcantug(i, xs, ys))
	    {
	    objectop(i, UNDEL, DEL);
	    objtug(i, xs, ys, xe, ye);
	    objectop(i, DEL, UNDEL);
	    }
	}
    }

copyattr(j, i)
    {
    objs[j]->stat = Ostat;
    objs[j]->type = Otype;
    objs[j]->x0 = Oxs;
    objs[j]->y0 = Oys;
    objs[j]->x1 = Oxe;
    objs[j]->y1 = Oye;
    objs[j]->align = Oalign;
    objs[j]->emph = Oemph;
    objs[j]->size = Osize;
    objs[j]->group = Ogroup;
    if (Otext) objs[j]->text = salloc(Otext);
    }

copysel()
    {
    int i, j, g, dx, dy;
    if (!anysel) return;
    dx = tickflag ? tx : DEFCOPYWID;
    dy = tickflag ? ty : DEFCOPYWID;
    g = uniquegroup();
    forobjects
	{
	if (Osel)
	    {
	    j = objalloc(Otype);
	    copyattr(j, i);
	    objs[j]->x0 = Oxs+dx;
	    objs[j]->y0 = Oys+dy;
	    if (Otype != TEXT)
	        {
		objs[j]->x1 = Oxe+dx;
	        objs[j]->y1 = Oye+dy;
		}
	    objs[j]->group = g;
	    objs[j]->stat = DEL;
	    objectop(i, SEL, UNDEL);
	    objectop(j, DEL, UNDEL);
	    }
	}
    if (markobj) markupdate(markx+dx, marky+dy);
    }
SHAR_EOF
if test -f 'lemelli.c'
then
	echo shar: over-writing existing file "'lemelli.c'"
fi
cat << \SHAR_EOF > 'lemelli.c'
/*
 * lemselect.c - object selection and proximity testing
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

elliresize(i)
    {
    }

ellinearpt(i, x, y)
    {
    if (ptinrect(x, y, Oxl, Oyl, Oxh, Oyh, LINETOL))
	{
        if (dist(Ox,  Oyh, x, y) < ENDTOL) return(1);
        if (dist(Ox,  Oyl, x, y) < ENDTOL) return(1);
        if (dist(Oxl, Oy,  x, y) < ENDTOL) return(1);
        if (dist(Oxh, Oy,  x, y) < ENDTOL) return(1);
        if (dist(Ox,  Oy,  x, y) < ENDTOL) return(1);
	}
    return(0);
    }

elliinrect(i, xl, yl, xh, yh)
    {
    return(objsupinrect(i, xl, yl, xh, yh));
    }

ellicantug(i, x, y)
    {
    return(objsupcantug(i, x, y));
    }

ellitug(i, xs, ys, xe, ye)
    {
    int n, s, e, w, c;
    n = dist(Ox,  Oyh, xs, ys);
    s = dist(Ox,  Oyl, xs, ys);
    w = dist(Oxl, Oy,  xs, ys);
    e = dist(Oxh, Oy,  xs, ys);
    c = dist(Ox,  Oy,  xs, ys);
    if (n<s && n<e && n<w && n<c) { if (Oys>Oye) Oys = ye; else Oye = ye; }
    if (s<n && s<e && s<w && s<c) { if (Oys<Oye) Oys = ye; else Oye = ye; }
    if (e<w && e<n && e<s && e<c) { if (Oxs>Oxe) Oxs = xe; else Oxe = xe; }
    if (w<e && w<n && w<s && w<c) { if (Oxs<Oxe) Oxs = xe; else Oxe = xe; }
    if (c<=n && c<=s && c<=e && c<=w) ellimove(i, xe-xs, ye-ys);
    }

ellialign(i, x, y)
    int *x, *y;
    {
    int n, s, e, w, c;
    n = dist(Ox,  Oyh, *x, *y);
    s = dist(Ox,  Oyl, *x, *y);
    w = dist(Oxl, Oy,  *x, *y);
    e = dist(Oxh, Oy,  *x, *y);
    c = dist(Ox,  Oy,  *x, *y);
    *x = Ox;
    *y = Oy;
    if (n<s && n<e && n<w && n<c) *y = Oyh;
    if (s<n && s<e && s<w && s<c) *y = Oyl;
    if (e<w && e<n && e<s && e<c) *x = Oxh;
    if (w<=e && w<=n && w<=s && w<=c) *x = Oxl;
    }

ellimove(i, x, y)
    {
    objsupmove(i, x, y);
    }

elliaffine(i, m11, m12, m21, m22)
    float m11, m12, m21, m22;
    {
    objsupaffine(i, m11, m12, m21, m22, 1);
    }

ellidraw(i, col)
    {
    int wid, hw2, hh2, hw7, hh7;
    wid = lemfont[Osizer].thick;
    hw2 = ABS(Ow)/4;
    hh2 = ABS(Oh)/4;
    hw7 = ABS(Ow)*7/16;
    hh7 = ABS(Oh)*7/16;
    drawvec(Oxl,    Oy,     Ox-hw7, Oy+hh2, col, wid, Oemph);
    drawvec(Ox-hw7, Oy+hh2, Ox-hw2, Oy+hh7, col, wid, Oemph);
    drawvec(Ox-hw2, Oy+hh7, Ox,     Oyh,    col, wid, Oemph);
    drawvec(Ox,     Oyh,    Ox+hw2, Oy+hh7, col, wid, Oemph);
    drawvec(Ox+hw2, Oy+hh7, Ox+hw7, Oy+hh2, col, wid, Oemph);
    drawvec(Ox+hw7, Oy+hh2, Oxh,    Oy,     col, wid, Oemph);
    drawvec(Oxh,    Oy,     Ox+hw7, Oy-hh2, col, wid, Oemph);
    drawvec(Ox+hw7, Oy-hh2, Ox+hw2, Oy-hh7, col, wid, Oemph);
    drawvec(Ox+hw2, Oy-hh7, Ox,     Oyl,    col, wid, Oemph);
    drawvec(Ox,     Oyl,    Ox-hw2, Oy-hh7, col, wid, Oemph);
    drawvec(Ox-hw2, Oy-hh7, Ox-hw7, Oy-hh2, col, wid, Oemph);
    drawvec(Ox-hw7, Oy-hh2, Oxl,    Oy,     col, wid, Oemph);
    }
SHAR_EOF
if test -f 'lemfont.c'
then
	echo shar: over-writing existing file "'lemfont.c'"
fi
cat << \SHAR_EOF > 'lemfont.c'
/*
 * lemfont.c - routines to create and access binary level strike fonts
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 *
 * Programmed by Alan Paeth, University of Waterloo, February, 1984
 *
 * NOTE: these fonts began life as 16-bit integers, with opposite byte-
 * order conventions of the VAX. This explains the appearance of short
 * integers, and size counts done in terms of shorts.
 *
 * Also, fonts are represented as a pointer to a contiguous, variable-
 * length structure. Because the actual bitmap is the only data part
 * which varies from font to font, its declaration is ultimate in the
 * structure declaration. FONTHEADERSIZE is the short word offset to it.
 *
 * patched by Alan Paeth, May 1985, to deal with null print strings
 */

#include "lem.h"
#include "lemfont.h"

/* system constants */

#define NULL 0
#define READMODE 0
#define OPENFAIL -1

/* bit masking constants useful with non sign-extended shifts */

#define MAXPOS 0x77777777
#define MAXNEG 0x80000000

/* private tables to speed up bit test operations */

short intab[17] =
	{ 0x0000,
	  0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
	  0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 };

int outtab[33] =
	{ 0x00000000,
	  0x00000001, 0x00000002, 0x00000004, 0x00000008,
	  0x00000010, 0x00000020, 0x00000040, 0x00000080,
	  0x00000100, 0x00000200, 0x00000400, 0x00000800,
	  0x00001000, 0x00002000, 0x00004000, 0x00008000,
	  0x00010000, 0x00020000, 0x00040000, 0x00080000,
	  0x00100000, 0x00200000, 0x00400000, 0x00800000,
	  0x01000000, 0x02000000, 0x04000000, 0x08000000,
	  0x10000000, 0x20000000, 0x40000000, 0x80000000 };


/* PUBLIC PROCEDURES */

BFont fontload(filename)
char *filename;
    {
    BFont curfont;
    short xxx, minascii, maxascii, ascent;
    short mwidth, descent, rasterx, height;
    int i;
    long fd, readlen;

    if ((fd = open(filename, READMODE)) == OPENFAIL) return (NULL);

    sread(fd, &xxx, 2);		/* first word is a throwaway */
    sread(fd, &minascii, 2);
    sread(fd, &maxascii, 2);
    sread(fd, &mwidth, 2);
    sread(fd, &xxx, 2);		/* length is a throwaway */
    sread(fd, &ascent, 2);
    sread(fd, &descent, 2);
    sread(fd, &xxx, 2);		/* xoffset unused unless kerned fonts */
    sread(fd, &rasterx, 2);

    height = ascent + descent;

    curfont = (BFont)(calloc( rasterx*height + FONTHEADERSIZE , 2));
    if (curfont == NULL)
	{
	close(fd);
	return (NULL);
	}

    curfont->ascent = ascent;
    curfont->descent = descent;
    curfont->mwidth = mwidth;
    curfont->rasterx = rasterx;

    readlen = rasterx * height * 2;	/* convert shorts to bytes */
    if (sread(fd, &(curfont->glyphs[0]), readlen) != readlen)
	{
	close(fd);
	free(curfont);
	return (NULL);
	}

    for (i=0; i<256; i++) curfont->widths[i] = 0;

    readlen = (maxascii - minascii + 2) * 2;	/* n+1 widths (short ints) */
    if (sread(fd, &(curfont->widths[minascii]), readlen ) != readlen)
	{
	close(fd);
	free(curfont);
	return (NULL);
	}
    close(fd);
    return (curfont);
    }

fontfree(arg)
    BFont arg;
    {
    free(arg);
    }

fontmeasure(font, string, emph)
BFont font;
char *string;
    {
    int ch;
    int len = 0;
    if (font == NULL) err("font == NULL\n");
    while (ch = *(string++)) len += (font->widths[ch+1] - font->widths[ch]);
    if (len == 0) return(0);		/* no emphasis fudge if no string */
    if (emph == EMPHITAL) len += font->ascent / 4;
    if (emph == EMPHBOLD) ++len;
    return(len);
    }

fontwrite(font, x, y, string, emph, fontcol)
    {
    privfontwrite(bfont[font], x, y, string, emph, fontcol);
    }

privfontwrite(font, x, y, string, emph, fontcol)
BFont font;
int x, y;
char *string;
    {
    static long bitbuf[MAXWIDTH/32];

    int smeasure, bufsize, bufsizew, rows, inlen;
    char ch, *strcopy;
    short *inbase, *inaddr, *widthptr, inoffset;
    int i, curpos, skew, inmaski, outmaski;
    long *outaddr;

    y = screenh - y;
    smeasure = fontmeasure(font, string, emph);
    if (smeasure == 0) return;		/* QUICK RETURN: no string */
    bufsize = MIN(x + smeasure, RIGHT) - MAX(x, LEFT);

/* clip to physical resources */

    bufsize = MIN(bufsize, MAXWIDTH);

    bufsizew = (bufsize-1) / 32 + 1;	/* words to hold bits, rounded up */
    inbase = &(font->glyphs[0]);
    rows = font->ascent+font->descent;	/* +1 for predecrementing */
/* y adjust */
/*  y -= 0;					/* upper lh-corner */
/*  y -= font->ascent;				/* lh baseline */
/**/y -= (font->ascent+font->descent)/2;	/* lh center line */

    ++rows;
    while (--rows)			/* +1 for predecrementing speed */
	{
	if (bufsize > 0 && y >= BOTTOM && y < TOP)
	    {
	    if (emph == EMPHITAL)
		skew = rows / 4;
		else skew = 0;
	    curpos= MIN(x+skew-LEFT,0);	/* bitpos in output buffer */
	    i = bufsizew;
	    while (i) bitbuf[--i] = 0;	/* clear ALL output buffer */

	    strcopy = string;		/* set up for output */
	    outmaski = 32;
	    outaddr = bitbuf;

	    while (ch = *(strcopy++))	/* character loop */
		{
		widthptr = &(font->widths[ch]);
		inoffset = *widthptr;

/* inlen is min of (room left in buffer), (char width) */

		inlen = min(bufsize-skew-curpos, (*(++widthptr) - inoffset) );

		inaddr = inbase + inoffset/16;
		inmaski = 16 - (inoffset & 15);	/* 15+1 for predecrementing */
		++inlen;			/*   +1 for predecrementing */
		while (--inlen)			/* draw while char/room left */
		    {
		    if (++curpos > 0)		/* position at end of draw */
			{
			if (*inaddr&intab[inmaski]) *outaddr|=outtab[outmaski];
			if (!(--outmaski)) { outmaski = 32; ++outaddr; }
			}
		    if (!(--inmaski)) {  inmaski = 16; ++inaddr ; }
		    }
		}
	    if (emph == EMPHBOLD)
		{
		for(i = bufsizew - 1; i > 0; --i)
		    {
		    bitbuf[i] |= (bitbuf[i])>>1;
		    if (bitbuf[i-1]&1) bitbuf[i] |= MAXNEG;
		    }
		bitbuf[i] |= (bitbuf[i])>>1;
		}
/*
	    if ((emph == EMPHUNDERSCORE) && (rows == font->descent))
		{
		i = bufsizew;
		while (i) bitbuf[--i] = -1;
		}
*/
	    writescan( MAX(x+skew, LEFT), y, bufsize-skew, bitbuf, fontcol);
	    }
	++y;
	inbase += font->rasterx;
	}
    }

/* PRIVATE PROCEDURES */

static min(a,b)
    long a,b;
    {
    return( (a < b) ? a : b );
    }

/*
 * sread is analogous to unix read, but will swap bytes on machines with
 * byte order opposite that of the VAX. This makes the font files portable.
 */

sread(d, buf, nbytes)
    register char *buf;
    register int nbytes;
    {
    register char *test, l, r;
    short order = 1;
    int ret;
    test = (char*)(&order);
    ret = read(d, buf, nbytes);
    if (*test != '\001')
	{
	while( nbytes > 1)	/* non-vax: do byte swap */
	    {
	    l = *buf++;
	    r = *buf;
	    *buf = l;
	    *--buf = r;
	    buf += 2;
	    nbytes -= 2;
	    }
	}
    return(ret);
    }
SHAR_EOF
chmod +x 'lemfont.c'
if test -f 'lemgeo.c'
then
	echo shar: over-writing existing file "'lemgeo.c'"
fi
cat << \SHAR_EOF > 'lemgeo.c'
/*
 * lemgeo.c - low-level geometric routines
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

ptinrect(px, py, xl, yl, xh, yh, tol)
    {
    xl -= tol;
    yl -= tol;
    xh += tol;
    yh += tol;
    return((xl<=px) && (xh>=px) && (yl<=py) && (yh>=py));
    }

hypot(x, y)
    {
    x = ABS(x);
    y = ABS(y);
    if (x>y) return(x+y/2);
    return(y+x/2);
    }

dist(x0, y0, x1, y1)
    {
    return(hypot(x1-x0, y1-y0));
    }

spacealign(x, y)
    int *x, *y;
    {
    int dx, dy;
    dx = ABS(*x-markx);
    dy = ABS(*y-marky);
    if (dx > FLATTOL * dy) *y = marky;
    if (dy > FLATTOL * dx) *x = markx;
    tickalign(x, y);
    }
SHAR_EOF
if test -f 'lemglobal.c'
then
	echo shar: over-writing existing file "'lemglobal.c'"
fi
cat << \SHAR_EOF > 'lemglobal.c'
/*
 * lemglobal.c -- global variables
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"
#include "lemfont.h"

/* global object array */

pel objs[MAXOBJS];
int lastobj;

/* global font information */

fontdir lemfont[RCLEN];
BFont bfont[RCLEN];

int rclen;

/* command line globals */

char *firstfile;	/* name of first input dataset */
int displayon;		/* true if display is running */

/* global cursor and screen info */

int changes;		/* objects added/deleted since last write */
int tickflag, ticksize;	/* true if ticks turned on, tick size [0..6] */
int tx, ty;		/* tick x,y spacing */
int txoff, tyoff;	/* tick x,y offset */
int tickdot;		/* hwidth of tick dot: 0/1 for DEC/SUN X-windows */
int markx, marky;	/* current mark */
int markon;		/* if any mark is present */
int markobj;		/* object number if mark is present and on an object */
int anysel;		/* if at least one selection */

char gtype;		/* default object creation */
char galign;		/* default alignment */
char gemph;		/* default emphasis */
char gsize;		/* default size */

/* undo information */

char undo;		/* 'T' - transform 'M' - move 'U' - undelete */ 
int unx,uny, unxe,unye; /* translation and affine transformation values */
float un11, un12, un21, un22;

int screenw, screenh;			/* maximum screen size */
int cred, cgreen, cwhite, cblack;	/* system colors */
char line[MAXCHAR];			/* input text line */
char msgtext[MAXCHAR];			/* pending warning messages */
char prompttext[MAXCHAR];		/* messages to the user */
SHAR_EOF
if test -f 'lemgroup.c'
then
	echo shar: over-writing existing file "'lemgroup.c'"
fi
cat << \SHAR_EOF > 'lemgroup.c'
/*
 * lemgroup.c - object group maintenance
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

addgroup()
    {
    int i, g;
    g = uniquegroup();
    forobjects
	{
	if (Osel) Ogroup = g;
	}
    }

removegroup()
    {
    int i;
    forobjects
	{
	if (Ogroup) Ogroup = 0;
	}
    }

uniquegroup()
    {
    int i, groups[256];
    for(i=0; i<256; i++) groups[i] = 0;
    for(i=1; i<lastobj; i++) groups[Ogroup]++;
    for(i=1; i<256; i++)
	{
	if (groups[i] == 0) break;
	}
    return(groups[i] == 0 ? i : 0);
    }
SHAR_EOF
if test -f 'lemhelp.c'
then
	echo shar: over-writing existing file "'lemhelp.c'"
fi
cat << \SHAR_EOF > 'lemhelp.c'
/*
 * lemhelp.c - give menu of key functions
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"
#include "lemfont.h"

#define HELPCHARS "[IHMABCDEFGLNOPRSTUVWX^?"

help()
    {
    char c;
    msgpost("[help]: <space> - all; \"/\" - fonts; <key> - function: ");
    c = getstroke();
    if (c == ' ') helpall();
    else if (c == '/') helpfonts();
    else if (c != '\0') helpkey(c);
    }

char *helpmsg(c)
    char c;
    {
    char *s;
    if (c < ' ') c += ' ';	/* turn ^chars to upper case */
    switch(UC(c))
	{
	case '[': s = "ESC  Delete Mark; Deselect all"; break;
	case 'A': s = "^A   All select"; break;
	case 'B': s = "^B   Box-ify selections"; break;
	case 'C': s = "^C   Copy selections (in place)"; break;
	case 'D': s = "^D   Delete selections"; break;
	case 'E': s = "^E   Ellipse-ify selections"; break;
	case 'F': s = "^F   Force<+key>: 0=reset/1-9=size/Bld/Nrm/Itl/Lft/Rht/Cen";break;
	case 'G': s = "^G   Group selections"; break;
	case 'H': s = "BS   Backspace input text"; break;
	case 'I': s = "TAB  Select marked obj (cyclically)"; break;
	case 'L': s = "^L   Refresh display"; break;
	case 'J':
	case 'M': s = "CR   Add text (if present)"; break;
	case 'N': s = "^N   No select (deselect all)"; break;
	case 'O': s = "^O   Output PIC \"filename\""; break;
	case 'P': s = "^P   Pop (ungroup -- instantiate) selected groups"; break;
	case 'Q': s = "^Q   Quit"; break;
	case 'R': s = "^R   Read \"filename\""; break;
	case 'S': s = "^Sc  Special function escape"; break;
	case 'T': s = "^Td  Tickmarks (on/off)"; break;
	case 'U': s = "^U   Undo selections (undelete, untransform)"; break;
	case 'V': s = "^V   Vector-ify selections"; break;
	case 'W': s = "^W   Write \"filename\""; break;
	case 'X': s = "^X   Cut lines (selections scissor normal lines)"; break;
	case '^': s = "^^   Help"; break;
	case '?': s = "^^?  Help all"; break;
	default:  s = "    (undefined)"; break;
	}
    return(s);
    }

helpkey(c)
    char c;
    {
    msgpost(helpmsg(c));
    }

helpall()
    {
    int i, x, y;
    char c;
    erase();
    x = 10;
    y = screenh-fontleading(SYSFONT);
    for (i=0; i<strlen(HELPCHARS); i++)
	{
	int baseline;
	c = HELPCHARS[i];
	fontwrite(SYSFONT, x, y, helpmsg(c), EMPHNONE, HELPCOL);
	baseline = fontleading(SYSFONT);
	y -= baseline;
	if (y < baseline) break;
	}
    }

helpfonts()
    {
    int i, x, y;
    char fontmsg[50];
    erase();
    x = 10;
    y = screenh-fontleading(SYSFONT);
    fontwrite(SYSFONT, x, y, "Current Fonts", EMPHNONE, HELPCOL);
    y -= 2 * fontleading(SYSFONT);
    for (i=1; i<rclen; i++)
	{
	int baseline;
	sprintf(fontmsg, "%d    %s%d", i, lemfont[i].dsp, lemfont[i].psize);
	fontwrite(SYSFONT, x, y, fontmsg, EMPHNONE, HELPCOL);
	fontwrite(i, x+180, y, "regular", EMPHNONE, HELPCOL);
	fontwrite(i, x+280, y, "bold",    EMPHBOLD, HELPCOL);
	fontwrite(i, x+380, y, "italic",  EMPHITAL, HELPCOL);
	if (gsize == i)
	     {
	     char *S;
	     S = (galign==ALIGNLEFT)?"[L]" : ((gemph==ALIGNRGHT)?"[R]":"[C]");
	     if (gemph == EMPHNONE) fontwrite(i, x+160, y, S,EMPHNONE,HELPCOL);
	     if (gemph == EMPHBOLD) fontwrite(i, x+260, y, S,EMPHBOLD,HELPCOL);
	     if (gemph == EMPHITAL) fontwrite(i, x+360, y, S,EMPHITAL,HELPCOL);
	     }
	baseline = fontleading(SYSFONT);
	y -= 2 * baseline;
	if (y < baseline) break;
	}
    }
SHAR_EOF
if test -f 'lemik.c'
then
	echo shar: over-writing existing file "'lemik.c'"
fi
cat << \SHAR_EOF > 'lemik.c'
/*
 * lemik.c - ikonas driver for lemming software
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

#include <graphics/ik_const.h>
#include <local/Locator.h>
#include <errno.h>
#include <sys/time.h>
#include <sgtty.h>
#include <signal.h>

#define MASKREG 0
#define STDIN 0
#define OBITS 0xffffff
#define RED   0x0000ff
#define GREEN 0x00ff00
#define BLACK 0x000000
#define WHITE 0xffffff

struct In_config *Id, *Iopen();
struct In_state st;
char *inDevice, *getenv(), readchar();

/* cursor stuff */

#define CURLEN 32
#define CUROFFX 16
#define CUROFFY 16
#define LCLK 49
#define LWYOFF 33

#define SETCUR(x, y) cur[(y)] |= 1<<((x));
#define HL(a,b) (((a)<<16)+((b)&0xffff))

static int cur[CURLEN];

/*
 * external routines
 */

setpixelrunh(x, y, wid, val)
    {
    int i;
    for (i=0; i<wid; i++)
	Ik_diowr(IK_XY_ADDR, x+i, 511-y, val);
    }

setpixelrunv(x, y, wid, val)
    {
    int i;
    for (i=0; i<wid; i++)
	Ik_diowr(IK_XY_ADDR, x, 511-y+i, val);
    }

start()
    {
/*
 * system defaults
 */
    screenw = 512;
    screenh = 512;
    cred = RED;
    cgreen = GREEN;
    cblack = BLACK;
    cwhite = WHITE;
    tickdot = 1;
/*
 * initialization
 */
    startcbreak();
    Ik_open();
    Ik_init();
/* Ik_zoom_pan(0, 0, 508, 480, 0, 0, 1, 1, 0, 1); */ /* last for 1:1,not 4:3 */
    Ik_mask_set(MASKREG, OBITS);
    cursorenable();

    if( (inDevice = getenv("INPUT") ) == NULL )
    inDevice = "ikonas";
    if ( (Id = Iopen(inDevice, I_DEFAULT)) == NULL) err("can't open tablet");
    Iwindow( Id, 0, 511, 0, 511, 0, 32 );
    Ictl(Id, I_ENABLE, 0);	/* make the tablet free-running *sigh* */
    }

stop()
    {
    cursordisable();
    Iclose(Id);
    Ik_close();
    stopcbreak();
    }

getevent(xdown, ydown, xup, yup, ch)
    char *ch;
    int *xdown, *ydown, *xup, *yup;
    {
    int lastx, lasty, mousedesc, dev;
    mousedesc = fileno(Id->In_ifp);
    dev = checkevent(mousedesc, STDIN, 1);	/*  blocking (hah!) */
    if (dev == STDIN)
	{
	*ch = readchar();
	return(((*ch < ' ') || (*ch == '\177')) ? CNTRL : ALPHA);
	}
    if (dev == mousedesc)
	{
	Iread(Id, &st, COORDINATES);
	cursorplace(st.x, st.y);
	lastx = st.x;
	lasty = st.y;
	if (st.button == 0) return(NOEVT);
	else
	    {
	    *xdown = st.x;
	    *ydown = st.y;
	    do  {
		Iread(Id, &st, COORDINATES);
		*yup = st.y;
		*xup = st.x;
		if ((lastx != st.x) || (lasty != st.y)) cursorplace(st.x, st.y);
		lastx = st.x;
		lasty = st.y;
		} while (st.button != 0);
	    }
	return(MOUSE);
	}
    return(NOEVT);
    }

charshow(str)
    char *str;
    {
    fprintf(stdout, "%s", str);
    fflush(stdout);
    }

charunshow(n)
    {
    int i;
    for (i=0; i<n; i++) fprintf(stdout, "%c %c", '\b', '\b');
    fflush(stdout);
    }

drawvec(x0, y0, x1, y1, col, wid, emph)
    {
    drawline(x0, y0, x1, y1, wid, col, emph);
    }

erase()
    {
    Ik_clear();
    }

/*
 * internal routines
 */

cursorenable()
    {
    long i;
    int ncolor[IK_MAP_SIZE];
    Ik_set_mode( SET_DURING_RETRACE );
    Ik_mask_set(0, 0xffffff);
    Ik_dmard(IK_WD_ADDR, IK_COLOUR_MAPS, IK_MAP_SIZE*0, ncolor, IK_MAP_SIZE);
    for (i=0; i<IK_MAP_SIZE; i++) ncolor[i] = (-1) ^ ncolor[i];
    Ik_dmawr(IK_WD_ADDR, IK_COLOUR_MAPS, IK_MAP_SIZE*1, ncolor, IK_MAP_SIZE);
    Ik_dmawr(IK_WD_ADDR, IK_COLOUR_MAPS, IK_MAP_SIZE*3, ncolor, IK_MAP_SIZE);
    Ik_diowr( IK_WD_ADDR, IK_XBAR_SWITCH, 32, 32); /* guarantee incursor bit */
    for (i=0; i<CURLEN; i++) cur[i] = 0;	/* clear cursor */
    for (i=0; i<CURLEN/4; i++)			/* draw open + sign */
	{
	SETCUR(i+CURLEN/8,   CURLEN/2);
	SETCUR(7*CURLEN/8-i, CURLEN/2);
	SETCUR(CURLEN/2,     i+CURLEN/8);
	SETCUR(CURLEN/2,     7*CURLEN/8-i);
	}
    Ik_curs_map(cur, CURLEN/2, CURLEN/2);
    cursorplace(0, 0);
    }

cursordisable()
    {
    int i;
    for (i=0; i<CURLEN; i++) cur[i] = 0;
    Ik_curs_map(cur, 0, 0);
    Ik_diowr( IK_WD_ADDR, IK_FBC_REGS, FBC_MODE, HL(LCLK,  0x40));
    }

cursorplace(x, y)
    {
    Ik_diowr(IK_WD_ADDR, IK_FBC_REGS, FBC_CURSOR,
	HL((511-y)+LWYOFF-CUROFFY-5, x-CUROFFX));
    Ik_diowr( IK_WD_ADDR, IK_FBC_REGS, FBC_MODE, HL(LCLK,  0x44));
    }

/*
 * UNIX code to test for pending STDIN characters (in CBREAK mode)
 * and capture ^Z interruptions for the sake of CBREAK problems.
 */

int stopcatch();

stopcbreak()
    {
    struct sgttyb tty;
    ioctl(STDIN, TIOCGETP, &tty);
    tty.sg_flags &= ~CBREAK;
    tty.sg_flags |= ECHO;
    ioctl(STDIN, TIOCSETP, &tty);
    signal(SIGTSTP, SIG_DFL);
    }

startcbreak()
    {
    struct sgttyb tty;
    ioctl(STDIN, TIOCGETP, &tty);
    tty.sg_flags |= CBREAK;
    tty.sg_flags &= ~ECHO;
    ioctl(STDIN, TIOCSETP, &tty);
    signal(SIGTSTP, stopcatch);
    }

stopcatch()
    {
/* ^Z just typed.  */
    stopcbreak();
    sigsetmask (sigblock(0) & ~(1<<(SIGTSTP-1))); /* turn SIGTSTP on */
    kill(0, SIGTSTP);			/* STOP THYSELF! */
/* you just returned */
    startcbreak();			/* restore action for next time */
    }

checkevent(l, r, blockflag)
    {
    extern int errno;
    int rdesc, retcode, bits;
    struct timeval tv;
    do	{
	rdesc = (1<<l) | (1<<r);
	bits = (l > r) ? l+1 : r+1;
	bzero(&tv, sizeof tv);		/* zero timer -> poll, no waiting */
	retcode = select(bits, &rdesc, 0, 0, blockflag ? 0 : &tv);
	} while ((retcode < 0) && (errno == EINTR));
    if (retcode <= 0) return(-1);
    return((rdesc == (1<<l)) ? l : r);
    }

char readchar()
    {
    char ch;
    read(STDIN, &ch, 1);
    return(ch);
    }

writescan(x, y, pixels, outaddr, color)
    int x, y, pixels, *outaddr, color;
    {
    static int IKbuf[512];
    int words, *bufbase;

/* register */
    register int next, *wordbase, regfontcolor;

    if (pixels <= 0) return;		/* PARANOIA: should not ever happen */

    regfontcolor = color;		/* for a little speed */
    words = (pixels - 1) / 32 + 1;
    bufbase = IKbuf;
    Ik_dmard(IK_XY_ADDR, x, y, IKbuf, pixels);

    ++words;
    while (--words)
	{
	next = *outaddr;
	++outaddr;
	wordbase = bufbase;
	while (next)
	    {
	    if (next < 0) *wordbase = regfontcolor;
	    ++wordbase;
	    next<<=1;
	    }
	bufbase += 32;
	}
    Ik_dmawr(IK_XY_ADDR, x, y, IKbuf, pixels);
    }
SHAR_EOF
if test -f 'lemio.c'
then
	echo shar: over-writing existing file "'lemio.c'"
fi
cat << \SHAR_EOF > 'lemio.c'
/*
 * lemio.c - I/O routines
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

writefile()
    {
    int i;
    char *fname;
    FILE *f;
    if (lastobj == 1) return;	/* nothing on display -- fast return */
    fname = prompt("output file: ");
    f = (fname && (strlen(fname) > 1)) ? fopen(fname, "w") : 0;
    if (f)
	{
	fprintf(f, "LEMMING %d\n", VERNO);
	forobjects
	    {
	    if (Onotdel)
		{
		fprintf(f, "%c %d %d %d %d %d %c %c",
		  Otype, Oxs, Oys, Oxe, Oye, Osize, Oalign, Oemph);
		if (Otext && strlen(Otext)) fprintf(f, " \\%s", Otext);
		fprintf(f, "\n");
		}
	    }
	fclose(f);
	changes = 0;
	msgpost("output done");
	}
    else msgpost("output failed");
    free(fname);
    }

readfileint(fname)
    char *fname;
    {
    int i, g, ver;
    char *s, fline[MAXCHAR+50];
    FILE *f;
    f = 0;
    if (fname && (strlen(fname) > 0))
	{
	f = fopen(fname, "r");
	if (!f)
	    {
	    char filename[100];
	    sprintf(filename, "%s.%s", fname, LEMEXTN);
	    f = fopen(filename, "r");
	    }
	}
    if (f)
	{
	fgets(fline, sizeof(fline), f);
	if ((sscanf(fline, "LEMMING %d", &ver) == 1) && (ver == VERNO))
	    {
	    g = uniquegroup();
	    while (1)
		{
		int x0, y0, x1, y1, size;
		fgets(fline, sizeof(fline), f);
		if (feof(f)) break;
		i = objalloc(0);
		sscanf(fline, "%c %d %d %d %d %d %c %c", &Otype, &x0, &y0,
			&x1, &y1, &size, &Oalign, &Oemph);
		Oxs = x0;
		Oys = y0;
		Oxe = x1;
		Oye = y1;
		Osize = size;
/*
 * possible input text
 */
		s = fline;
		while ((*s) && (*s != '\\')) s++;
		if (*s == '\\') s++;
		if (*s) s[strlen(s)-1] = '\0';	/* snuff trailing CR */
		Otext = (s && strlen(s)) ? salloc(s) : 0;
/*
 * now assign attributes
 */
		Ogroup = g;
		Ostat = DEL;
		objresize(i);
		objectop(i, DEL, SEL);
		}
	    fclose(f);
	    msgpost("input done");
	    }
	else msgpost("bogus input file");
	}
    else msgpost("input not found");
    }

readfile()
    {
    char *fname;
    fname = prompt("input file: ");
    readfileint(fname);
    free(fname);
    }
SHAR_EOF
if test -f 'lemline.c'
then
	echo shar: over-writing existing file "'lemline.c'"
fi
cat << \SHAR_EOF > 'lemline.c'
/*
 * lemline.c - line primities
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

lineadd(x0, y0, x1, y1)
    {
    int i;
    if ((x0 == x1) && (y0 == y1)) return;
    i = objalloc(LINE);
    lineupdate(i, x0, y0, x1, y1);
    objnew(i);
    }

lineresize(i)
    {
    }
    
lineupdate(i, x0, y0, x1, y1)
    {
    Oxs = x0;
    Oys = y0;
    Oxe = x1;
    Oye = y1;
    }

linenearpt(i, x, y)
    {
    int tol, hy;
    if (ptinrect(x, y, Oxl, Oyl, Oxh, Oyh, LINETOL) == 0) return(0);
    hy = hypot(Ow, Oh);
    if (hy < SHRTTOL) return(1);
    tol = ABS(((x-Ox)*Oh - (y-Oy)*Ow)) / hy;
    return(LINETOL > tol);
    }

lineinrect(i, xl, yl, xh, yh)
    {
    return(ptinrect(Oxl, Oyl, xl, yl, xh, yh, LINETOL) &&
	ptinrect(Oxh, Oyh, xl, yl, xh, yh, LINETOL));
    }

linecantug(i, x, y)
    {
    return(linenearpt(i, x, y));
    }
    
linetug(i, xs, ys, xe, ye)
    {
    if (dist(Oxs, Oys, xs, ys) < TUGPROX) lineupdate(i, xe, ye, Oxe, Oye);
    else if (dist(Oxe, Oye, xs, ys) < TUGPROX) lineupdate(i, Oxs, Oys, xe, ye);
    else linemove(i, xe-xs, ye-ys);
    }

linealign(i, x, y)
    int *x, *y;
    {
    if (dist(Oxs, Oys, *x, *y) < ENDTOL)
	{
	*x = Oxs;
	*y = Oys;
	}
    else if (dist(Oxe, Oye, *x, *y) < ENDTOL)
	{
	*x = Oxe;
	*y = Oye;
	}
    else
	{
	int frac;
	frac = (ABS(Ow) > ABS(Oh)) ? (12*(*x-Oxs)+6)/Ow : (12*(*y-Oys)+6)/Oh;
	*x = ((12-frac)*Oxs + frac*Oxe)/12;
	*y = ((12-frac)*Oys + frac*Oye)/12;
	}
    }

linemove(i, x, y)
    {
    objsupmove(i, x, y);
    }

lineaffine(i, m11, m12, m21, m22)
    float m11, m12, m21, m22;
    {
    objsupaffine(i, m11, m12, m21, m22, 1);
    }
    
linedraw(i, col)
    {
    int wid;
    wid = lemfont[Osizer].thick;
    drawvec(Oxs, Oys, Oxe, Oye, col, wid, Oemph);
    if (Oalign == ALIGNLEFT)
	{
	int h, x, y, x1, y1;
	h = hypot(Ow, Oh)*13;
	x = Ow*ARROWLEN;
	y = Oh*ARROWLEN;
	x1 = ( x*12-y*5)/h;
	y1 = ( x*5+y*12)/h;
	drawvec(Oxs, Oys, Oxs+x1, Oys+y1, col, wid, EMPHNONE);
	x1 = ( x*12+y*5)/h;
	y1 = (-x*5+y*12)/h;
	drawvec(Oxs, Oys, Oxs+x1, Oys+y1, col, wid, EMPHNONE);
	}
    if (Oalign == ALIGNRGHT)
	{
	int h, x, y, x1, y1;
	h = hypot(Ow, Oh)*13;
	x = Ow*ARROWLEN;
	y = Oh*ARROWLEN;
	x1 = ( x*12-y*5)/h;
	y1 = ( x*5+y*12)/h;
	drawvec(Oxe, Oye, Oxe-x1, Oye-y1, col, wid, EMPHNONE);
	x1 = ( x*12+y*5)/h;
	y1 = (-x*5+y*12)/h;
	drawvec(Oxe, Oye, Oxe-x1, Oye-y1, col, wid, EMPHNONE);
	}
    }
SHAR_EOF
#	End of shell archive
exit 0


-- 

Rich $alz			"Anger is an energy"
Cronus Project, BBN Labs	rsalz@bbn.com
Moderator, comp.sources.unix	sources@uunet.uu.net