Newsgroups: comp.sources.unix
From: stevegru@welchlink.welch.jhu.edu (STEPHEN C GRUBB)
Subject: v29i093: copa - gui control panel kit for shell, C, perl - V1.0, Part06/08
References: <1.823324036.2981@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com

Submitted-By: stevegru@welchlink.welch.jhu.edu (STEPHEN C GRUBB)
Posting-Number: Volume 29, Issue 93
Archive-Name: copa/part06

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
# - - - - - - C U T   H E R E - - - - - - - - - - - - - - -
#!/bin/sh
#
# Part 6
#
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#		src/copa_init.c
#		src/copa_pop.c
#		src/copa_scroll.c
#		src/copa_setsel.c
#		src/copa_slider.c
#		src/copa_srv.c
#		src/copa_textbox.c
#		src/copa_txt.c
#		src/copa_value.c
#		src/edit.c
#		src/elib.d
#		src/elib.h
#		src/elib.x
#		src/err.c
echo src/copa_init.c
cat << \SHAR_EOF > src/copa_init.c
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any commercial product is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/



/* Initialize ZOOD and ELIB. */
#include "elib.x"

static char *home;

Einitall( name, dev, ux, uy, upleftx, uplefty )
char name[];
char dev;     /* 'x' for x11; 'p' for postscript */
double ux, uy;  /* size of window in inches.. */
int upleftx, uplefty; /* point (in native window system coords ) of upper-left corner of window */
{
char *getenv(), *cd, *cf;
char str[100];
FILE *fp;

  home = getenv( "COPA_HOME" );
  if( home == NULL ) {
       fprintf( stderr, "Error: cannot find COPA_HOME environment variable.\n" );
       fprintf( stderr, "Set COPA_HOME to contain the path name of the directory\n" );
       fprintf( stderr, "where copa files such as gui.def and presets.pan are located.\n" );
       exit(1);
       }

  Einit( name, dev, ux, uy, upleftx, uplefty ); /* initialize elib */

  /* read in defaults list.. */
  fp = NULL;
  EIinit();

  /* see if there's a private defaults file defined.. */
  cd = getenv( "COPA_DEF" );
  if( cd != NULL && strlen( cd ) > 0 ) {
	/* locate file.. */
	/* first check cd alone.. */
	strcpy( str, cd );
	fp = fopen( str, "r" );
	if( fp == NULL ) {
		/* now check COPA_FILES directory.. */
		cf = getenv( "COPA_FILES" );
		if( cf != NULL && strlen( cf ) > 0 ) { 
			sprintf( str, "%s/%s", cf, cd ); 
			fp = fopen( str, "r" ); 
			}
		if( fp == NULL ) {
			/* now check COPA_HOME directory.. */
			sprintf( str, "%s/%s", home, cd );
			fp = fopen( str, "r" );
			if( fp == NULL ) 
		   	  fprintf( stderr, 
			    "Can't find private defaults file. Using gui.def.\n", cd );
			}
		}
	}

  if( fp != NULL ) fclose( fp );
  else sprintf( str, "%s/gui.def", home );

  if( EIreaddeflist( str ) != 1 ) {
          fprintf( stderr, "Display server fatal error: error in %s.\n", str );
          exit(1);
          }
#ifdef PLOT
  sprintf( str, "%s/plot.def", home );
  if( EIreaddeflist( str ) != 1 ) {
          fprintf( stderr, "Display server fatal error: error in %s.\n", str );
          exit(1);
          }
  EPinit();
#endif

  EIsaveinitstate();
  
  cd = getenv( "COPA_FLASH" );
  if( cd != NULL ) {
	if( strlen( cd ) > 1 ) {
		sscanf( cd, "%ld", &Eflashdelay );
		Eflashdelay *= 10000; /* convert from n/100 sec to microsecs */
		}
	}

  /* read presets .. */
  Eload_presets();

return( 0 );
}


/* ================ */
Eload_presets()
{
char str[100];
char *fnm, *getenv();

fnm = getenv( "COPA_PRESETS" );
if( fnm == NULL ) sprintf( str, "%s/presets.pan", home );
else if( strlen( fnm ) < 1 )sprintf( str, "%s/presets.pan", home );
else strcpy( str, fnm );

if( EIreaduserlist( str ) != 1 ) {
      fprintf( stderr, "Error or missing presets file (%s).\n", str );
      exit(1);
      }
}
SHAR_EOF
############################

echo src/copa_pop.c
cat << \SHAR_EOF > src/copa_pop.c
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any commercial product is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/



/* ======================= */
/* present a pop-up with buttons and wait for user to press a button. */
/* modified Sept 95 scg: if menu is long enough, go to a second row 
		of buttons - p.s. this made the routine uglier!! */
#include "elib.x"
#define NONE ".!none"

/* copa_btnpop( char *s, char *menu, char *val ) */
copa_btnpop( s, menu, val )
char *s, *menu, *val;
{
int p, bp, bp2, j;
int secondrow;
char menu1[80], *menu2;
double x, y;
int selp, key;

p = EItaglookup( "_POP", E_NIL );
bp = EItaglookup( "_POPB1", E_NIL );
bp2 = EItaglookup( "_POPB2", E_NIL );
if( p < 0  || bp < 0  || bp2 < 0 ) return( 2100 );

/* Eexec( p, 0.0, 0.0, E_MESSAGE, "REINIT" ); */
EIraise( p );
EImodattr( p, "", "*/display", "x" );

copa_text( "_POP", s ); /* expand commands, put into zood */
/* replaces... EImodattr( p, "", "text", s ); */

Eexec( p, 0.0, 0.0, E_MESSAGE, "REINIT" );
Ealign( p );
Egen( p );

secondrow = 0;
if( strlen( menu ) > 0 ) {
	if( strlen( menu ) > 22 ) { /* break into two sets of buttons.. */
		for( j = 22; j < strlen( menu ); j++ ) if( menu[j] == ',' ) break;
		if( j < strlen( menu ) ) {
			strncpy( menu1, menu, j ); menu1[j] = '\0';
			menu2 = &menu[j+1];
			secondrow = 1;
			}
		}
	EIraise( bp );
	EImodattr( bp, "", "*/display", "x" );
	if( secondrow ) EImodattr( bp, "", "text", menu1 );
	else EImodattr( bp, "", "text", menu );
	Ealign( bp );
	Egen( bp );
	if( secondrow ) {
		EIraise( bp2 );
		EImodattr( bp2, "", "*/display", "x" );
		EImodattr( bp2, "", "text", menu2 );
		Ealign( bp2 );
		Egen( bp2 );
		}
	}

/* now get input.. */
strcpy( Eselection, NONE );
LOOP:
while( 1 ) {
	Egetkey( &x, &y, &key );

	if( key > 1000 ) {  
		selp = Ewhichobj( x, y );
		if( selp == bp ) break;
		if( secondrow && selp == bp2 ) break;
		if( selp == p ) Eexec( p, x, y, key, "" ); /* scroll text box.. */
		}
	}
Eexec( selp, x, y, key, "" );
if( strcmp( Eselection, ".!none" ) == 0 ) goto LOOP; /* shouldn't happen */

strcpy( val, Eselection );
 
/* now vanish.. */
EImodattr( p, "", "*/display", "" ); 
EImodattr( bp, "", "*/display", "" );
Eexec( p, 0.0, 0.0, E_MESSAGE, "RESET" );
Eexec( bp, 0.0, 0.0, E_MESSAGE, "RESET" );
if( secondrow ) {
	EImodattr( bp2, "", "*/display", "" );
	Eexec( bp2, 0.0, 0.0, E_MESSAGE, "RESET" );
	}
return( 0 );
}


/* ============================ */
/* Data entry popup */
/* copa_depop( char *s, char *def, char *len, char *val ) */
copa_depop( s, def, len, val )
char *s, *def, *len, *val;
{
int p, dp;

p = EItaglookup( "_POP", E_NIL );
dp = EItaglookup( "_POPD1", E_NIL );
if( p < 0  || dp < 0 ) return( 2100 );
EIraise( p );
EImodattr( p, "", "*/display", "x" );
copa_text( "_POP", s ); /* expand commands, put into zood */
Eexec( p, 0.0, 0.0, E_MESSAGE, "REINIT" );
Ealign( p );
Egen( p );


EIraise( dp );
EImodattr( dp, "", "*/display", "x" );
EImodattr( dp, "", "pick/value", def );
EImodattr( dp, "", "maxlength", len );
Ealign( dp );
Egen( dp );
strcpy( Eselection, NONE );

Eexec( dp, 0.0, 0.0, E_MOUSE_LEFT, "" );

strcpy( val, Eselection );
if( strlen( val ) < 1 ) strcpy( val, NONE );

EImodattr( p, "", "*/display", "" ); 
EImodattr( dp, "", "*/display", "" );
Eexec( p, 0.0, 0.0, E_MESSAGE, "RESET" );
Eexec( dp, 0.0, 0.0, E_MESSAGE, "RESET" );
return( 0 );
}
/* ============================ */
/* Listbox popup */
/* copa_lbpop( char *s, char *menu, char *buttons, char *val ) */
copa_lbpop( s, menu, buttons, val )
char *s, *menu, *buttons, *val;
{
int p, dp, bp;
double x, y;
int key, selp;

p = EItaglookup( "_POP", E_NIL );
dp = EItaglookup( "_POPL1", E_NIL );
bp = EItaglookup( "_POPB1", E_NIL );
if( p < 0  || dp < 0 || bp < 0 ) return( 2100 );

/* message box */
EIraise( p );
EImodattr( p, "", "*/display", "x" );
EImodattr( p, "", "box.marg_b", "3.2" );
copa_text( "_POP", s ); /* expand commands, put into zood */
Eexec( p, 0.0, 0.0, E_MESSAGE, "REINIT" );
Ealign( p );
Egen( p );

/* listbox */
EIraise( dp );
EImodattr( dp, "", "*/display", "x" );
copa_text( "_POPL1", menu ); /* expand commands, put into zood */
Ealign( dp );
Egen( dp );

/* buttons */
EIraise( bp );
EImodattr( bp, "", "*/display", "x" );
EImodattr( bp, "", "text", buttons );
Ealign( bp );
Egen( bp );



strcpy( Eselection, NONE );
LOOP:
while( 1 ) {
	Egetkey( &x, &y, &key );

	if( key > 1000 ) {  
		selp = Ewhichobj( x, y );
		if( selp == dp || selp == bp ) break;
		if( selp == p ) Eexec( p, x, y, key, "" ); /* scroll text box.. */
		}
	}
Eexec( selp, x, y, key, "" );
if( strcmp( Eselection, ".!none" ) == 0 ) goto LOOP; /* shouldn't happen */

strcpy( val, Eselection );

EImodattr( p, "", "*/display", "" ); 
EImodattr( p, "", "box.marg_b", "0.7" );
EImodattr( dp, "", "*/display", "" );
EImodattr( bp, "", "*/display", "" );
Eexec( p, 0.0, 0.0, E_MESSAGE, "RESET" );
Eexec( dp, 0.0, 0.0, E_MESSAGE, "RESET" );
Eexec( bp, 0.0, 0.0, E_MESSAGE, "RESET" );
return( 0 );
}
/* ============================ */
/* Message-only popup */
/* copa_mopop( char *msg, char *buttons ) */
copa_mopop( msg, buttons )
char *msg, *buttons;
{
int p, bp;
p = EItaglookup( "_POP", E_NIL );
if( p < 0 ) return( 2100 );
EIraise( p );
EImodattr( p, "", "*/display", "x" );
copa_text( "_POP", msg ); /* expand commands, put into zood */
Eexec( p, 0.0, 0.0, E_MESSAGE, "REINIT" );
Ealign( p );
Egen( p );

bp = EItaglookup( "_POPB1", E_NIL );
if( bp < 0 ) return( 2100 );
EIraise( bp );
EImodattr( bp, "", "*/display", "x" );
EImodattr( bp, "", "text", buttons );
Ealign( bp );
Egen( bp );

Eflush();
return( 0 );
}

/* ============================ */
/* Clear message-only popup */
copa_clpop( )
{
int p, bp;
p = EItaglookup( "_POP", E_NIL );
bp = EItaglookup( "_POPB1", E_NIL );
EImodattr( p, "", "*/display", "" ); 
EImodattr( bp, "", "*/display", "" ); 
Eexec( p, 0.0, 0.0, E_MESSAGE, "RESET" );
Eexec( bp, 0.0, 0.0, E_MESSAGE, "RESET" );
/* Eflush(); */
return( 0 );
}
SHAR_EOF
############################

echo src/copa_scroll.c
cat << \SHAR_EOF > src/copa_scroll.c
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any commercial product is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/





/* called by Egen after a textb has been drawn.  It determines whether to slap on
   a scroll controller. */

#include "elib.x"
#define W1 0.12
#define WW1 0.1
#define H1 0.05
#define HALFHEIGHT 0.9
#define GREY 0.9
#define SPACING 0.25    /* the spacing between triangles */
#define SP3 0.75
#define SP7 1.75
#define HALFSPACE 0.125
#define MINSIZEFORFULL 1.6

static int enable_right;


EAvscroller( p )
int p;
{
double x, y, y1, y2;
int len;
double *bb;
int *nlines;
int *firstline;
int *totallines;
int *startcol;
char sym[20];
double shade;
char *scrollcon;

bb = EIgetd( p, "", "*/bb", &len );
if( len != 4 ) return( 0 ); /* no bb */
EIgetc( p, "", "*/display", &len );
if( len < 1 ) return( 0 ); /* not visible */

firstline = EIgeti( p, "", "firstline", &len );
nlines = EIgeti( p, "", "nlines", &len );
totallines = EIgeti( p, "", "totallines", &len );

startcol = EIgeti( p, "", "startcol", &len );
scrollcon = EIgetc( p, "", "scrollcon", &len );

if( *nlines < 1 ) return( 1 ); /* not scrollable */
if( *nlines >= *totallines ) return( 1 ); /* not enough lines to require scrolling.. */

x = *(bb+2) - 0.2;
y1 = *(bb+1);
y2 = *(bb+3);
y = y1 + ((y2-y1)/2.0);   /* set y to midpoint */


/* if box is small, make a mini-control and return.. */
if( y2 - y1 < MINSIZEFORFULL || scrollcon[0] == 'M' ) {
	EAvminiscroller( x, y, *firstline, *nlines, *totallines );
	return( 0 );
	}

y -= SP3;

/* backing */
Eblock( x-W1, y, x+W1, y+(SP7), GREY, 0 );
Eblockdress( (x-W1)-0.1, y, x+W1+0.1, y+(SP7), 0.7, 0.95, 0.1, -1.0, -1.0 );
/* Eellipse( x, y+SP3, W1+0.15, SP3, GREY, 1 ); */

/* see if down controls should be active */
if( *firstline + *nlines > *totallines ) shade = GREY;
else shade = 1.0;
sprintf( sym, "sym2a%2.1f", shade );

/* to-bottom */
y += HALFSPACE;
Eblock( x-WW1, y-H1, x+WW1, y+H1, shade, 0 );
Elinetype( 0, 1.2, 1.0 );  
Emov( x-WW1, y+H1 ); Elin( x-WW1, y-H1 ); Elin( x+WW1, y-H1 ); Elin( x+WW1, y+H1 ); 
Enormline();

/* page down */
y += SPACING;
Emark( x, y, sym, 0.18 );

/* scroll down */
y += SPACING;
Emark( x, y, sym, 0.13 );

/* horizontal left/right */
y += SPACING;

/* left */
if( *startcol > 0 )strcpy( sym, "sym8a1.0" );
else strcpy( sym, "sym8a0.9 " );
Emark( x-WW1, y, sym, 0.13 ); 

/* right */
if( enable_right ) strcpy( sym, "sym7a1.0" );
else strcpy( sym, "sym7a0.9 " );
Emark( x+WW1, y, sym, 0.13 ); 

/* now see if up controls should be active.. */
if( *firstline <= 1 ) shade = GREY;
else shade = 1.0;
sprintf( sym, "sym1a%2.1f", shade );


/* scroll up */
y += SPACING;
Emark( x, y, sym, 0.13 );

/* page up */
y += SPACING;
Emark( x, y, sym, 0.18 );

/* to-top */
y += SPACING;
Eblock( x-WW1, y-H1, x+WW1, y+H1, shade, 0 );
Elinetype( 0, 1.2, 1.0 );
Emov( x-WW1, y-H1 ); Elin( x-WW1, y+H1 ); Elin( x+WW1, y+H1 ); Elin( x+WW1, y-H1 ); 
Enormline();

}
/* ==================================================== */
static int
/* EAvminiscroller( double x, double y, int firstline, int nlinesinbox, int totallines ) */
EAvminiscroller( x, y, firstline, nlinesinbox, totallines )
double x;
double y;
int firstline;
int nlinesinbox; 
int totallines;
{
double shade;
char sym[20];


y -= SPACING;

/* backing */
Eblock( x-W1, y, x+W1, y+SP3, GREY, 0 );
Eblockdress( (x-W1)-0.1, y, x+W1+0.1, y+SP3, 0.7, 0.95, 0.1, -1.0, -1.0 );
 
/* see if DOWN should be active */
if( firstline + nlinesinbox > totallines ) shade = GREY;
else shade = 1.0;
sprintf( sym, "sym2a%2.1f", shade );
 
/* page down */
y += SPACING;
Emark( x, y, sym, 0.2 );
 
/* see if UP should be active */
if( firstline <= 1 ) shade = GREY;
else shade = 1.0;
sprintf( sym, "sym1a%2.1f", shade );
 
/* page up */
y += SPACING;
Emark( x, y, sym, 0.2 );

return( 0 );
}



/* ==================================================== */
/* see if user pressed a scroll button.. */
EEcheckvscroller( message, p, x, y )
char message[]; 
int p;
double x, y; /* mouse position */
{
double *bb, x2, y1, y2, ylow, ycen, yhi, diff, *trl;
int len;
double b;
int mini;
char *scrollcon;


bb = EIgetd( p, "", "*/bb", &len ); 
x2 = *(bb+2); 
y1 = *(bb+1); 
y2 = *(bb+3); 
trl = EIgetd( p, "", "*/trl", &len );
x += (*(trl));  y += (*(trl+1)); /* remove translation */

scrollcon = EIgetc( p, "", "scrollcon", &len );

/* see if we're checking a mini control */
if( y2 - y1 < MINSIZEFORFULL || scrollcon[0] == 'M' ) {
	mini = 1;
	}
else mini = 0;

ycen = y1 + ((y2-y1)/2.0);
ylow = ycen - SP3;
yhi = ylow + SP7;

if( mini ) {
	ylow = ycen - SPACING;
	yhi = ycen + (SPACING*2);
	}

if( x > (x2-0.4) && x < x2 &&  y > ylow && y < yhi ) {
	diff = y - ylow;
	if( mini ) {
		b = .13; 
		if( diff < (b+SPACING) ) strcpy( message, "PAGE DOWN" );
		else strcpy( message, "PAGE UP" );
		return(0);
		}
		
	if( diff < SPACING ) strcpy( message, "BOTTOM" );
	else if( diff < (SPACING*2) ) strcpy( message, "PAGE DOWN" );
	else if( diff < (SPACING*3) ) strcpy( message, "BUMP DOWN" );
	else if( diff < (SPACING*4) && x < (x2-0.2) ) strcpy( message, "PAGE LEFT" );
	else if( diff < (SPACING*4) && x > (x2-0.2) ) strcpy( message, "PAGE RIGHT" );
	else if( diff < (SPACING*5) ) strcpy( message, "BUMP UP" );
	else if( diff < (SPACING*6) ) strcpy( message, "PAGE UP" );
	else strcpy( message, "TOP" );

	return( 1 );
	}
else return( 0 );
}

/* ================== */
EArightscrollable( mode )
int mode;
{
enable_right = mode;
return( 0 );
}
SHAR_EOF
############################

echo src/copa_setsel.c
cat << \SHAR_EOF > src/copa_setsel.c
/* handle setting of a mechanism's selection */
#include "elib.x"

copa_setsel( tag, value )
char *tag;
char *value;
{
int ip;
char *typ;
int i, ix, select;
char buf[E_SELECTION_LEN];
int *curselect, nlines, *size, totallines, firstline;
int status, len;
char *txt;

ip = Egetid( tag );
if( ip < 0 ) return( Eerrmsg( 2301, "Invalid tag.", tag ) );
typ = EIgetobjname( ip );

status = EImodattr( ip, "", "pick/value", value );
if( status < 1 ) return( Eerrmsg( 2302, "zood update failed", tag ));

/* these two types are easy.. */
if( strcmp( typ, "dataentry" )==0 || strcmp( typ, "slider" )==0 ) return( 0 );


else if( strcmp( typ, "button" )==0 ) {
	if( strlen( value ) < 1 ) {
		EImodattr( ip, "", "pick/hselect", "-1" );
		return( 0 );
		}
	/* we need to search the comma-delimited text list for the value */
	txt = EIgetc( ip, "", "text", &len );
	if( len < 1 ) return( Eerrmsg( 2303, "no button text found", tag ) );

	for ( i = 0, ix = 0, select = -1; ; i++ ) {
 		Egetchunk( buf, txt, &ix, "," );
        	if( strlen( buf ) < 1 ) break;
		if( strcmp( buf, value )==0 ) {
			select = i;
			break;
			}
		}
	if( select < 0 ) return( Eerrmsg( 2304, "no matching button found", value ) );
	else	{
		sprintf( buf, "%d", select );
		EImodattr( ip, "", "pick/hselect", buf );
		return( 0 );
		}
	}


else if( strcmp( typ, "textb" )==0 ) {
	if( strlen( value ) < 1 ) {
		EImodattr( ip, "", "pick/vselect", "0" );
		return( 0 );
		}
	/* we need to search the newline delimited text for the value.. */
	/* allow wild cards */
	/* begin at pick/vselect */
	/* vselect begins with 1 not 0.. */

	txt = EIgetc( ip, "", "text", &len );
	if( len < 1 ) return( Eerrmsg( 2305, "no textb text found", tag ) );

	/* get currently selected line, if any.. */
	curselect = EIgeti( ip, "", "pick/vselect", &len );
	if( len < 1 ) *curselect = 0;

	ix = 0; nlines = 0; select = -1;
	while( 1 ) {
                if( ix >= strlen( txt )) break;
                Egetln( buf, txt, &ix );
		if( nlines >= *curselect ) {
			status = Ewildcmp( buf, value, strlen( value ), 0 );
			if( status == 0 ) {
				select = nlines + 1;
				break;
				}
			}

                nlines++;
                }
	if( select < 1 && *curselect > 0 ) { /* still not found, retry from beginning..*/
		totallines = nlines;
		ix = 0; nlines = 0;
		while( 1 ) {
               		if( ix >= strlen( txt )) break;
                	Egetln( buf, txt, &ix );
			if( nlines > *curselect ) break; /* up to current line.. */
			status = Ewildcmp( buf, value, strlen( value ), 0 );
			if( status == 0 ) {
				select = nlines + 1;
				break;
				}
			nlines++;
			}
		}

	if( select > 0 ) {  /* a line was found, update vselect and firstline */
		size = EIgeti( ip, "", "nlines", &len );
		if( len < 1 ) *size = totallines;

		sprintf( buf, "%d", select );
		EImodattr( ip, "", "pick/vselect", buf );
		firstline = 1;
		if( select > *size ) firstline = select - ((*size) / 2);
		/* if( select > totallines - *size ) firstline = totallines - (*size); */

		/* update vselect.. */
		sprintf( buf, "%d", select );
		EImodattr( ip, "", "pick/vselect", buf );

		/* update firstline.. */
		sprintf( buf, "%d", firstline );
		EImodattr( ip, "", "firstline", buf );

		return( 0 );
		}

	else	{ /* nothing matching was found.. */
		return( 3000 );
		}
	}
}
SHAR_EOF
############################

echo src/copa_slider.c
cat << \SHAR_EOF > src/copa_slider.c
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any commercial product is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/





/* produces a horizontal slider */
#include "elib.x"

static int fastflag = 0;

EAslider( p, path )
int p;
char path[];
{
double *posx, *posy, x, y, *w, *h, x2, y2, *min, *max, promptlen, val, mark, *scalefact, *l;
double right, left, scfx;
char *pr, *fmt;
char str[20], newpath[100];
int len;

posx = EIgetd( p, path, "position", &len );
if( len != 2 ) { fprintf( stderr, "Position must be specified for slider.\n" ); return( 0 ); }
posy = posx + 1;
	
x = *posx; y = *posy;
	
pr = EIgetc( p, path, "prompt", &len );

if( len > 0 ) {
	sprintf( newpath, "%s/prompt", path );
	EAtext_props( p, newpath );
	}

promptlen = (strlen( pr )+1) * Ecurtextwidth;

w = EIgetd( p, path, "width", &len );
h = EIgetd( p, path, "height", &len );

/* backing box.. */
x2 = x + *w + promptlen; 
y2 = y + *h;
if( !fastflag ) {
	Eblock( x, y, x2, y2, 1.0, 0 );
	Esetlastbox( x, y, x2, y2 );
	
	/* rectangle dressing */
	EIgetc( p, path, "dress", &len );
	if( len > 0 ) {
		sprintf( newpath, "%s/dress", path );
		EArect_dress( p, newpath );
		}
	
	sprintf( newpath, "%s/text", path );
	EAtext_props( p, newpath );
	
	/* write the prompt.. */
	Emov( x+0.1, y+0.1 ); Etext( pr );
	}

min = EIgetd( p, path, "min", &len );
max = EIgetd( p, path, "max", &len );
fmt = EIgetc( p, path, "format", &len );

l = EIgetd( p, path, "left", &len );
if( len < 1 ) {
	left = x + promptlen + 0.1;
	sprintf( str, "%g", left );
	EImodattr( p, path, "left", str );
	}
else left = *l;

right = x2 - 0.1;

Etextsize( 7 );
Esetdrawcolor( E_WHITE );
Eblock( left, y+0.05, right, y2-0.05, 0.0, 0 ); /* draw background.. */
Emov( left, y+0.1 ); sprintf( str, "%g", *min ); Etext( str );
Emov( right, y+0.1 ); sprintf( str, "%g", *max ); Erightjust( str );

/* make scale */
scalefact = EIgetd( p, path, "scalefact", &len );
if( len < 1 ) {
	scfx = ( *max - *min ) / ( (right-0.1) - (left+0.1) );
	sprintf( str, "%g", scfx );
	EImodattr( p, path, "scalefact", str );
	}
else scfx = *scalefact;

val = atof( EIgetc( p, path, "pick/value", &len ) );
if( len < 1 ) val = *min;

/* now let user pick.. */
mark = left + 0.1 + (( val - *min ) / scfx);
Emark( mark, y+0.2, "sym1a1.0", 0.07 );
sprintf( str, fmt, val ); 
Emov( left + ((right-left)/2.0), y+0.1 ); 
Etextsize( 10 ); Ecentext( str ); /* value */
}

/* ============================== */
EEslider( p, x, y, e, message )
int p;
double x, y;
int e;
char message[];
{
double *min, *max, *left, *scalefact, val, *inc, norm, h;
int len;
char str[40], *fmt;

min = EIgetd( p, "", "min", &len );
max = EIgetd( p, "", "max", &len );
fmt = EIgetc( p, "", "format", &len );
left = EIgetd( p, "", "left", &len );
scalefact = EIgetd( p, "", "scalefact", &len );
inc = EIgetd( p, "", "increment", &len );

if( strcmp( message, "RESET" ) ==0 ) val = *min;
else val = (*min) + ( x - ( (*left) + 0.1 ) ) * (*scalefact);

if( val < (*min) ) val = *min;
else if( val > (*max) ) val = *max;

if( *inc != 0.0 ) {   /* set to increment */
	norm = 1.0 / *inc;
	h = (val+(*inc/2.0)) * norm;
	val = (int)h * (*inc);
	}
sprintf( str, fmt, val );
strcpy( Eselection, str );
EImodattr( p, "", "pick/value", str );

fastflag = 1;
Egen( p );
fastflag = 0;
}
SHAR_EOF
############################

echo src/copa_srv.c
cat << \SHAR_EOF > src/copa_srv.c
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any commercial product is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/





/* SRV - copa server, called copa_window.  Creates application window, then
   reads commands from FIFO file; calls appropriate api function which then makes 
   various elib calls.
 */
#include <stdio.h>
#include <fcntl.h>
#include "elib.x"
#include "bigbuf.h"

#define TMP_DIR "/usr/tmp"

extern int errno;
char Resultpipe[80];
char Eotchar[2];

char *Errflag = ".!error";
char *Okflag = ".!ok";
int Errcode = 0; /* the most recent error code.. */


main( argc, argv )
int argc;
char **argv;
{
char buf[ SELECTIONMAX + 1 ];
char smallbuf[80];
char *copa_pipe, *getenv();
char compipe[80];
int cfd, rfd, nbytes;
int stat;
int i, j, pos;
char *argp[10];
int nargs;
int len;
double atof();


sprintf( Eotchar, "%c", 18 );

/* build names for fifo files.. */
/* if COPA_PIPE defined, use username+copa_pipe; otherwise, just use username */
copa_pipe = getenv( "COPA_PIPE" );
if( copa_pipe == NULL ) sprintf( buf, "%d", geteuid() );
else if( strlen( copa_pipe ) < 1 )sprintf( buf, "%d", geteuid() );
else sprintf( buf, "%d%s", geteuid(), copa_pipe );
if( strlen( buf ) > 20 ) buf[20] = '\0'; /* truncate at length of 20 */
sprintf( compipe, "%s/copaC%s", TMP_DIR, buf );
sprintf( Resultpipe, "%s/copaR%s", TMP_DIR, buf );


/* unlink old fifos, in case they happen to be around.. */
unlink( compipe );
unlink( Resultpipe );

/* make new fifos..  permissions: read/write by user only */
stat = mkfifo( compipe, 00600 ); 
stat += mkfifo( Resultpipe, 00600 ); 

if( stat != 0 ) {
	Eerrmsg( 80, "Cannot make fifos", "" );
	exit(1);
	}
/* fprintf( stderr, "Fifos %s and %s created.\n", compipe, Resultpipe ); */

/* now open the pipes.. */
/* cfd = open( compipe, O_RDONLY | O_NONBLOCK ); */
cfd = open( compipe, O_RDONLY | O_NDELAY );
if( cfd == NULL ) {
	Eerrmsg( 81, "Cannot open pipe.", compipe );
	exit(1);
	}

Eservermode = 1;

/* now create the application window.. */
if( argc == 7 ) stat = copa_window( atoi( argv[1] ), atoi( argv[2] ), 
		  atof( argv[3] ), atof( argv[4] ), argv[5], atof( argv[6] ) );

else stat = copa_window( 10, 10, 7.0, 8.0, "untitled", 0.9 ); /* defaults */
	
if( stat != 0 ) exit(stat);
Eflush();


/* loop on a blocking read on the command pipe */
pos = 0;
while( 1 ) {
	nbytes = read( cfd, &Ebigbuf[ pos ], BIGBUFSIZE-(pos+1) );
	if( nbytes <=  0 ) {
		stat = Eusleep(  20000 ); /* sleep for 1/50 second.. */
		if( stat != 0 ) {
			sprintf( buf, "%d", stat );
			Eerrmsg( 82, "Srv sleep error", buf );
			exit(82);
			}
		continue;
		}
	if( Ebigbuf[ pos+(nbytes-1) ] != 18 ) { /* more to read.. */
		pos += nbytes;
		continue; 
		}
	Ebigbuf[ pos+(nbytes-1) ] = '\0';
	pos = 0;

	/* split up line into individual arguments.. */
	argp[0] = Ebigbuf;
	len = strlen( Ebigbuf );
	for( i =0, j = 1; i < len; i++ ) {
		if( Ebigbuf[i] == 17 ) {
			Ebigbuf[i] = '\0';
			argp[ j ] = &Ebigbuf[ i+1 ];
			j++;
			}
		else if( Ebigbuf[i] == 18 ) {
			Ebigbuf[i] = '\0';
			}
		}
	nargs = j;

	/* for( i = 0 ; i < nargs; i++ ) fprintf( stderr, "%s##", argp[i] ); */
	/* fprintf( stderr, "\n" ); fflush( stderr ); */

	if( nargs < 2 ) {
		fprintf( stderr, "Usage: copa command [args].\n" );
		sendback( Errflag );
		Errcode = 1;
		continue;
		}

	/* call requested function */
	if( strcmp( argp[1], "quit" )==0 ) {
		sendback( Okflag );
		copa_quit();
		close( cfd );
		exit( 0 );
		}


	else if( strcmp( argp[1], "pop" )==0 ) {
		if( nargs != 4 ) {
			Eerrmsg( 803, "arg count: copa pop message choicelist", "" );
			sendback( Errflag );
			Errcode = 803;
			continue;
			}
		stat = copa_pop( argp[2], argp[3], buf );
		sendback( buf );
		}

	else if( strcmp( argp[1], "poplist" )==0 ) {
		if( nargs < 4 || nargs > 5 ) {
			Eerrmsg( 804, "arg count: copa poplist message listtext buttons", "" );
			sendback( Errflag );
			Errcode = 804;
			continue;
			}
		/* allow buttons arg to be optional.. */
		if( nargs == 4 )
			stat = copa_poplist( argp[2], argp[3], "", buf );
		else
			stat = copa_poplist( argp[2], argp[3], argp[4], buf );
		sendback( buf );
		}

	else if( strcmp( argp[1], "popentry" )==0 ) {
		if( nargs < 4 || nargs > 5 ) {
			Eerrmsg( 805, "arg count: copa popentry message default length", "" );
			sendback( Errflag );
			Errcode = 805;
			continue;
			}

		/* allow length arg to be optional */
		if( nargs == 4 )
			stat = copa_popentry( argp[2], argp[3], 20, buf );
		else
			stat = copa_popentry( argp[2], argp[3], atoi( argp[4] ), buf );
		sendback( buf );
		}

	else if( strcmp( argp[1], "popmsg" )==0 ) {
		if( nargs < 3 || nargs > 4 ) {
			Eerrmsg( 806, "arg count: copa popmsg message buttons", "" );
			sendback( Errflag );
			Errcode = 806;
			continue;
			}
		/* allow buttons arg to be optional */
		if( nargs == 3 )
			stat = copa_popmsg( argp[2], "" );
		else 
			stat = copa_popmsg( argp[2], argp[3] );
		sendback( Okflag );
		}

	else if( strcmp( argp[1], "popclear" )==0 ) {
		if( nargs != 2 ) {
			Eerrmsg( 807, "arg count: copa popclear", "" );
			sendback( Errflag );
			Errcode = 807;
			continue;
			}
		stat = copa_popclear();
		sendback( Okflag );
		}

	else if( strcmp( argp[1], "panload" )==0 ) {
		if( nargs != 4 ) {
			Eerrmsg( 808, "arg count: copa panload panfile tag", "" );
			sendback( Errflag );
			Errcode = 808;
			continue;
			}
		Errcode = copa_panload( argp[2], argp[3] );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( Okflag );
		}

	else if( strcmp( argp[1], "panuse" )==0 ) {
		if( nargs != 3 ) {
			Eerrmsg( 809, "arg count: copa panuse tag", "" );
			sendback( Errflag );
			Errcode = 809;
			continue;
			}
		Errcode = copa_panuse( argp[2] );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( Okflag );
		}

	else if( strcmp( argp[1], "panadd" )==0 ) {
		if( nargs != 3 ) {
			Eerrmsg( 819, "arg count: copa panadd panfile", "" );
			sendback( Errflag );
			Errcode = 819;
			continue;
			}
		Errcode = copa_panadd( argp[2] );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( Okflag );
		}

	else if( strcmp( argp[1], "panquit" )==0 ) {
		if( nargs != 2 ) {
			Eerrmsg( 810, "arg count: copa panquit", "" );
			sendback( Errflag );
			Errcode = 810;
			continue;
			}
		Errcode = copa_panquit( );
		if( Errcode != 0 ) {
			fprintf( stderr, "Error %d.", Errcode );
			sendback( Errflag );
			}
		else sendback( Okflag );
		}

	else if( strcmp( argp[1], "text" )==0 ) {
		if( nargs != 4 ) {
			Eerrmsg( 811, "arg count: copa text tag text", "" );
			sendback( Errflag );
			Errcode = 811;
			continue;
			}
		Errcode = copa_text( argp[2], argp[3] );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( Okflag );
		}
	else if( strcmp( argp[1], "echo" )==0 ) {
		/* special case- command comes all in one:
		 * copa echo ".!begin TAG" "text" ".!end"
		 */
		if( nargs != 5 ) {
			Eerrmsg( 826, "echo: improper or missing begin/end construct", "" );
			sendback( Errflag );
			Errcode = 826;
			continue;
			}
		buf[0] = '\0';
		sscanf( argp[2], "%s %s", smallbuf, buf );
		if( strcmp( smallbuf, ".!begin" ) != 0 ) {
			Eerrmsg( 829, "Expecting echo .!begin", "" );
			sendback( Errflag );
			Errcode = 829;
			continue;
			}
		if( strlen( buf ) < 1 ) {
			Eerrmsg( 827, "Missing mechanism tag following .!begin", "" );
			sendback( Errflag );
			Errcode = 827;
			continue;
			}
		Errcode = copa_text( buf, argp[3] );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( Okflag );
		}

	else if( strcmp( argp[1], ".!end" )==0 ) {
		Eerrmsg( 828, "echo: improper or missing begin/end construct", "" );
		sendback( Errflag );
		Errcode = 828;
		continue;
		}

	else if( strcmp( argp[1], "get" )==0 ) {
		if( nargs != 2 ) {
			Eerrmsg( 812, "arg count: copa get", "" );
			sendback( Errflag );
			Errcode = 812;
			continue;
			}
		Errcode = copa_get( buf );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( buf );
		}

	else if( strcmp( argp[1], "mget" )==0 ) {
		if( nargs != 3 ) {
			Eerrmsg( 813, "arg count: copa get response_mode", "" );
			sendback( Errflag );
			Errcode = 813;
			continue;
			}
		Errcode = copa_mget( argp[2], buf );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( buf );
		}

	else if( strcmp( argp[1], "getentry" )==0 ) {
		if( nargs != 3 ) {
			Eerrmsg( 830, "arg count: copa getentry tag", "" );
			sendback( Errflag );
			Errcode = 830;
			continue;
			}
		Errcode = copa_getentry( argp[2], buf );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( buf );
		}

	else if( strcmp( argp[1], "rlimit" )==0 ) {
		if( nargs != 3 ) {
			Eerrmsg( 814, "arg count: copa rlimit taglist", "" );
			sendback( Errflag );
			Errcode = 814;
			continue;
			}
		Errcode = copa_rlimit( argp[2] );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( Okflag );
		}

	else if( strcmp( argp[1], "rinfo" )==0 ) {
		if( nargs != 3 ) {
			Eerrmsg( 815, "arg count: copa rinfo infotype", "" );
			sendback( Errflag );
			Errcode = 815;
			continue;
			}
		if( strcmp( argp[2], "errorcode" )==0 ) {
			sprintf( buf, "%d", Errcode );
			sendback( buf );
			continue;
			}
		Errcode = copa_rinfo( argp[2], buf );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( buf );
		}

	else if( strcmp( argp[1], "getvalue" )==0 ) {
		if( nargs != 3 ) {
			Eerrmsg( 821, "arg count: copa getvalue tag|.!all", "" );
			sendback( Errflag );
			Errcode = 821;
			continue;
			}
		Errcode = copa_getvalue( argp[2], buf );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( buf );
		}
	
	else if( strcmp( argp[1], "setvalue" )==0 ) {
		if( nargs != 4 ) {
			Eerrmsg( 822, "arg count: copa setvalue tag|.!file value|file", "" );
			sendback( Errflag );
			Errcode = 822;
			continue;
			}
		Errcode = copa_setvalue( argp[2], argp[3] );
		if( Errcode != 0 ) sendback( Errflag ); /* this includes #3000 (search failed) */
		else sendback( Okflag );
		}
			
	else if( strcmp( argp[1], "setmec" )==0 ) {
		if( nargs != 5 ) {
			Eerrmsg( 816, "arg count: copa setmec tag attribute value", "" );
			sendback( Errflag );
			Errcode = 816;
			continue;
			}
		Errcode = copa_setmec( argp[2], argp[3], argp[4] );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( Okflag );
		}

	else if( strcmp( argp[1], "getmec" )==0 ) {
		if( nargs != 4 ) {
			Eerrmsg( 817, "arg count: copa getmec tag attribute", "" );
			sendback( Errflag );
			Errcode = 817;
			continue;
			}
		Errcode = copa_getmec( argp[2], argp[3], buf );
		if( Errcode != 0 ) sendback( Errflag );
		else sendback( buf );
		}
	else if( strcmp( argp[1], "version" )==0 ) {
		copa_version();
		sendback( Okflag );
		}
		

	else if( strcmp( argp[1], "display" )==0 ) {
		if( nargs != 3 ) {
			Eerrmsg( 802, "arg count: copa display action", "" );
			sendback( Errflag );
			Errcode = 802;
			continue;
			}
		if( strcmp( argp[2], "ping" )==0 ) {
			sprintf( buf, "%d", getpid() );
			sendback( buf );
			}
		else	{
			stat = copa_display( argp[2] );
			sendback( Okflag );
			}
		}

	else if( strcmp( argp[1], "resize" )==0 ) {
		if( nargs != 7 ) {
			Eerrmsg( 801, "arg count: copa resize winx winy width height color", "" );
			sendback( Errflag );
			Errcode = 801;
			continue;
			}
		stat = copa_resize( atoi( argp[2] ), atoi( argp[3] ), 
			atof( argp[4] ), atof( argp[5] ), atof( argv[6] ) );
		sendback( Okflag );
		}

	else if( strcmp( argp[1], "ps" ) ==0 ) {
		if( nargs != 5 ) {
			Eerrmsg( 818, "arg count: copa ps title outfile paper","" );
			sendback( Errflag );
			Errcode = 818;
			continue;
			}
		stat = copa_ps( argp[2], argp[3], argp[4] );
		sendback( Okflag );
		}


	else	{
		Eerrmsg( 820, "Unrecognized command", argp[1] );
		Errcode = 820;
		sendback( Errflag );
		}
	}
}
/* ============================ */
/* send a string back to the client */
sendback( buf )
char *buf;
{
int rfd;

/* open results pipe */
rfd = open( Resultpipe, O_WRONLY );
if( rfd == NULL ) {
	Eerrmsg( 83, "Cannot open pipe", Resultpipe );
	exit(1);
	}
/* send back any results over the results pipe */
write( rfd, buf, strlen( buf ) );
write( rfd, Eotchar, 1 );
close( rfd );

Eflush(); 
return( 0 );
}

SHAR_EOF
############################

echo src/copa_textbox.c
cat << \SHAR_EOF > src/copa_textbox.c
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any commercial product is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/





#include "elib.x"

/* This file includes code for generating text and text boxes */
/* First, the actual subroutines which build the boxes, then the gen routine, 
   then the exec routine. */

static int Etxtparam = 0; /* tells Efiletext that the actual text is being sent instead of a file name */
static int Efastflag = 0; /* if 1, next regeneration does not need to do redraw trimming */

/* ===================================================== */
/* Print the text file fnm with upper left corner at x,y. */
/* Area that the text will occupy is erased first. */
/* fln is the first line (from the file) to print.  The first line is 1. */ 
/* nln is the number of lines to print. To print all lines use a very high number such as 9999.  */ 
/* If outline == 1 the text will be enclosed in a box. */
/* justify is "L" for left, "C" for center, "R" for right justification. */
/* If pickflag == 1 each line in the textbox will become an object. */
/* Width is the desired width in characters, excluding margin.  If 0, width of the longest line
   will be used. */
/* If x,y is negative, the text box will be centered in the middle of the screen */
/* Text attributes are set before this routine is called.. */
/* returns 1 on success, 0 on failure */
/* Note: picking lines won't work with align = 'C' or 'R' */
/* Efastflag: this flag may be set elsewhere in the application to indicate that the text box
     just needs a fast update.. */

Efiletext( fnm, x, y, width, marg, fln, nln, color, outline, justify, 
		spacing, rule, number, longest, totallines, flineselect,
		texttop, textbot, textleft, textright, charwidth, selectleft, selectright, 
		startcol, marg_l, marg_r, marg_b, marg_t )
		

char fnm[]; /* the file, or else the text itself */
double x, y;   /* position of the beginning of text */
int width;     /* width, in number of characters */
double marg;   /* size of margin do be created on all four sides of text (text will still be placed at x,y) */
int fln, nln;  /* first line to show; number of lines to show */
double color;  /* color of the backing box */
int outline;   /* outline the text box? 1=yes 0=no  */
char justify[]; /* alignment */
double *spacing; /* amount of space between lines.  (0.0 = normal, it will be returned) */
int rule;	/* 1 = draw ruling lines; 2 = draw 3d boxes; 0 = no rulings */
int number;	/* 1 = generate line numbers; 0 = don't */
int *longest;	/* length of the longest line (specify 0 if unknown, and it will be calculated) */
int *totallines; /* the total number of lines (specify 0 if unknown, and it will be calculated) */
int flineselect; /* the line number of a selected line (0 if none) */
double *texttop, *textbot;    /* returned- used for vertical pick info */
double *textleft, *textright, *charwidth; /* returned- used for horizontal pick info */
int selectleft, selectright;  /* character positions of highlight on/off (-1 = off) */
int startcol;   /* for horizontal scrolling (starts w/ 0).  If h. scrolling is off use 0 */
double marg_l, marg_r, marg_b, marg_t; /* explicit margin settings (these will override marg) */
{
int i;
FILE *fp;
char buf[E_GPBUF], buf2[E_GPBUF];
double px, py;
double h, w;
int iln;
int nlines;
int maxlength;
double awidth;
char oname[40];
int ix;
double linemarg, liney, oldliney;
char lineno[10];
double left, right;
double txtleft, txtright, txttop, txtbot;
double hilite_color;
int len;

/*
 * fprintf( stderr, "fln=%d nln=%d longest=%d totallns=%d flineselect=%d selectleft=%d selectright=%d\n",
 *  fln, nln, *longest, *totallines, flineselect, selectleft, selectright );
 */


if( *spacing <= 0.0 ) *spacing = Ecurtextheight;
*charwidth = Ecurtextwidth;

/* if unknown, scan file to get bounding box dimensions.. */
if( *totallines < 1 && *longest < 1 ) {
	if( Etxtparam == 0 ) {
		fp = fopen( fnm, "r" );
		if( fp == NULL ) { fprintf( stderr, "Efiletext: cannot open %s.\n", fnm ); return( 0 ); }
		}
	else ix = 0;
	
	/* count lines in file, since this may not be specified.. */
	/* also, find longest line */
	nlines = 0; maxlength = 0;
	while( 1 ) {
		if( Etxtparam == 0 ) {
			if( fgets( buf, E_GPBUF, fp ) == NULL ) break;
			}
		else if( Etxtparam == 1 ) {
			if( ix >= strlen( fnm )) break;
			Egetln( buf, fnm, &ix );
			}
		Eexpand_tabs( buf2, buf );
	
		if( strlen( buf2 ) > maxlength ) maxlength = strlen( buf2 );
		nlines++;
		}
	if( Etxtparam == 0 )fclose( fp );
	/* save return values */
	*totallines = nlines;
	*longest = maxlength;
	}

else 	{
	nlines = *totallines;
	maxlength = *longest;
	}

/* find omitted values.. */
if( nln == 0 ) nln = nlines;  /* we will auto-size.. */
if( fln > nlines ) fln = (nlines - nln); /* bottom of doc */
if( fln < 1 ) fln = 1;	/* top of doc */

if( width < 1 ) {
	width = maxlength;
	if( startcol > 0 ) {
		fprintf( stderr, "textb: width must be supplied if startcol is non-zero.\n" );
		startcol = 0;
		}
	}

/* find width of box.. */
if( Edev == 'p' ) awidth = width * Ecurtextheight * 0.4; /* fudge for postscript..*/
else awidth = width * (*charwidth);

/* auto center if x,y are negative */
if( x < 0.0 ) {
	x = (EWinx/2.0) - (awidth/2.0);
	y = (EWiny/2.0) + ((nln/2.0) * (*spacing));
	}

txttop = y + (*spacing);
txtleft = x;
txtright = x + awidth;
txtbot = y - ( (*spacing) * (nln - 1) );

/* add margins */
if( marg_l > 0.0 ) txtleft -= marg_l;
else txtleft-=marg;

if( marg_r > 0.0 ) txtright += marg_r;
txtright+=marg;

if( marg_b > 0.0 ) txtbot -= marg_b;
else txtbot-=marg;

if( marg_t > 0.0 ) txttop += marg_t;
else txttop+=marg;

/* draw the backing box.. */
if( !Efastflag )Eblock( txtleft, txtbot, txtright, txttop, color, outline );
Esetlastbox( txtleft, txtbot, txtright, txttop ); /* remember the coords of the box */

if( Etxtparam == 0 ) fp = fopen( fnm, "r" );

px = x; py = y;
*textleft = px; *textright = px + awidth; /* remember sides of text */

iln = 1;
ix = 0;
/* skip to first line.. */
if( Etxtparam == 0 && fln > 1 ) {
	while( fgets( buf, 255, fp ) != NULL ) {
		iln++;
		if( iln >= fln ) break;
		}
	}
else if( Etxtparam == 1 && fln > 1 ) {
	while( 1 ) {
		if( iln >= fln || ix >= strlen( fnm ) ) break;
		Egetln( buf, fnm, &ix );
		iln++;
		}
	}
linemarg = (*spacing) / 4.0;

/* draw top rule */
liney = py+((*spacing)-linemarg); 
if( rule == 1 ) { Emov( txtleft, liney ); Elin( txtright, liney ); }
oldliney = liney;

*texttop = py+((*spacing)-linemarg); /* remember top of text.. */

iln = 0;
EArightscrollable( 0 ); 

/* print the text.. */
while( 1 ) {
	if( Etxtparam == 0 ) {
		if( fgets( buf, 255, fp ) == NULL ) break;
		buf[ strlen( buf ) -1 ] = '\0';
		}
	if( Etxtparam == 1 ) {
		if( ix >= strlen( fnm )) break;
		Egetln( buf, fnm, &ix );
		}
	iln++;
	if( iln > nln ) { iln--; break; }
	Eexpand_tabs( buf2, buf );

	/* put horiz. scrolled portion into buf.. */
	if( startcol >= strlen( buf2 ) ) buf[0] = '\0';
	else strcpy( buf, &buf2[ startcol ] );

	if( strlen( buf ) > width ) {
		buf[width] = '\0'; /* truncate long lines */
		EArightscrollable( 1 ); /* tell scroll control to allow scroll to right */
		}

	liney = py-linemarg;
	/* if( Efastflag )Eblock( px, liney, px+awidth, oldliney, color, 0 ); */
	if( Efastflag )Eblock( txtleft, liney, txtright, oldliney, color, 0 ); /* scg 1-5-96*/

	/* ruling */
	if( rule == 0 ); /* do nothing.. */
	else if( rule == 1 ) { Emov( txtleft, oldliney ); Elin( txtright, oldliney ); }
	else if( rule == 2 ) 
		Eblockdress( txtleft, liney, txtright, oldliney, 0.9, 0.7, 0.06, -1.0, 0.0 );


	/* print the text.. */
	if( justify[0] == 'L' ) { Emov( px, py ); Etext( buf ); }
	else if( justify[0] == 'C' ) { Emov( px+(awidth/2), py ); Ecentext( buf ); }
	else if( justify[0] == 'R' ) { Emov( px+awidth, py ); Erightjust( buf ); }

	/* show "selected" line by printing it in reverse video.. */
	if( (iln+fln)-1 == flineselect ) {
		if( selectleft >= 0 && selectright >= 0 ) {
			selectleft -= startcol; /* adj for h. scrolling */
			selectright -= startcol;

			/* cases where highlighted block is straddling edge.. */
			if( selectleft < 0 ) {
				if( selectright > 0 ) selectleft = 0;
				else goto SKIP;
				}
			if( selectright > width ) {
				if( selectleft < width ) selectright = width;
				else goto SKIP;
				}
			left = (*textleft) + ((*charwidth) * selectleft);
			right = (*textleft) + ((*charwidth) * (selectright+1));
			}
		else 	{ 
			/* left = px; changed to below scg Nov 95 */
			left = txtleft;
			/* right = px + awidth; ** scg 1-5-96 */
			right = txtright;
			}

		if( color >= 0.9 ) hilite_color = 0.0;
		else hilite_color = 1.0;


		Eblock( left, liney, right, oldliney, hilite_color, 0 );
		Epenerase();
		if( selectleft >= 0 ) {
			strcpy( buf2, &buf[ selectleft ] );
			buf2[ (selectright-selectleft) +1 ] = '\0';
			Emov( left, py );
			Etext( buf2 );
			}
		else 	{
			if( justify[0] == 'L' ) { Emov( px, py ); Etext( buf ); }
			else if( justify[0] == 'C' ) { Emov( px+(awidth/2), py ); Ecentext( buf ); }
			else if( justify[0] == 'R' ) { Emov( px+awidth, py ); Erightjust( buf ); }
			}
		Epcode( 'R', (double)E_BLACK, (double)E_BLACK, "" );
		Ependraw(); /* turn off highlighting.. */
		SKIP:;

		}
		
	oldliney = liney;

	py -= (*spacing);
	if( py < 0.0 ) break; /* ran off bottom of page */
	}
if( Etxtparam == 0 )fclose( fp );

/* patch to do last line */
if( rule == 1 ) { Emov( txtleft, liney ); Elin( txtright, liney ); }

*textbot = (py-linemarg) + *spacing; /* save lowest pick info.. */

if( number ) {

	/* number the lines */
	Etextsize( 7 ); py = y;
	for( i = fln; i < (fln+iln); i++ ) {
		sprintf( lineno, "%4d.", i );
		Eblock( px-0.5, py, px-0.1, py+(*spacing), color, 0 );
		Emov( px-0.1, py ); Erightjust( lineno );
		py -= (*spacing);
		if( py < 0.0 ) break;
		}
	
	Eblock( px-0.5, py, px+0.2, py+0.1, color, 0 );Emov( px-0.1, py );
	/*
	 * if( (fln+iln) < *totallines ) Ecentext( "More.." );
	 * else Ecentext( "= End =" );
	 */
	}

return( 1 );
}

/* ================================================ */
/* same as Efiletext() except that multiline text is passed in as a string.. */
/* function returns number of lines in the text */
Eblocktext( s, x, y, width, marg, fln, nln, color, outline, justify, 
		spacing, rule, number, longest, totallines, flineselect,
		texttop, textbot, textleft, textright, charwidth, selectleft, selectright,
		startcol, marg_l, marg_r, marg_b, marg_t )
char s[];
double x, y;
int width;    /* width in number of characters */
double marg;
int fln;
int nln;
double color;
int outline;
char justify[];
double *spacing;
int rule;
int number;
int *longest;
int *totallines;
int flineselect;
double *texttop, *textbot, *textleft, *textright, *charwidth;
int selectleft, selectright;
int startcol;   /* for horizontal scrolling (starts w/ 0).  If h. scrolling is off use 0 */
double marg_l, marg_r, marg_b, marg_t; /* explicit margin settings (these will override marg) */
{
FILE *fp;
char str[100];
int stat;

Etxtparam = 1;

stat = Efiletext( s, x, y, width, marg, fln, nln, color, outline, justify, 
		spacing, rule, number, longest, totallines, flineselect,
		texttop, textbot, textleft, textright, charwidth, selectleft, selectright,
		startcol, marg_l, marg_r, marg_b, marg_t );

Etxtparam = 0;
return( stat );
}


/* ================================================ */
/* ================================================ */
/* The GEN routine. =============================== */
/* ================================================== */
EAtextb( p, path )
int p;
char path[];
{
int len;
char newpath[E_ANAMELEN];
char *txt, *align, *box, *dress;
double posx, posy, *d1, *d2, *boxmargin, *color;
int *boxwidth, *firstline, *nlines;
double *spacing;
int ruled;
char val[80];
int *sz, size;
int number;
char *rule;
int *lngst, longest;
int *flineselect;
int fromfile;
char *fnm;
char *title;
int pickable;
double texttop, textbot, textleft, textright;
double lineheight, charwidth;
int *selectleft, *selectright;
int *startcol;   /* for horizontal scrolling (starts w/ 0).  If h. scrolling is off use 0 */
double *marg_l, *marg_r, *marg_b, *marg_t; /* explicit margin settings (these will override marg) */
double *bb;

txt = EIgetc( p, path, "text", &len );

fnm = EIgetc( p, path, "file", &len );
if( len > 0 ) fromfile = 1; else fromfile = 0;

sprintf( newpath, "%s/text", path );
EAtext_props( p, newpath );
	
d1 = EIgetd( p, path, "position", &len ); d2 = d1; d2++;
if( len < 2 ) { posx = -1.0;  posy = -1.0; }
else { posx = *d1; posy = *d2; }

align = EIgetc( p, path, "align", &len );

spacing = EIgetd( p, path, "spacing", &len );
if( len > 0 ) lineheight = *spacing; else lineheight = 0;

rule=EIgetc( p, path, "ruled", &len );
if( len < 1 ) ruled = 0;
else if( *rule == 'L' ) ruled = 1; /* lines */
else if( *rule == 'B' ) ruled = 2; /* box */

EIgetc( p, path, "numbered", &len );
if( len > 0 ) number = 1; else number = 0;

EIgetc( p, path, "pick", &len );
if( len > 0 ) pickable = 1; else pickable = 0;

firstline = EIgeti( p, path, "firstline", &len );
nlines = EIgeti( p, path, "nlines", &len );

sz = EIgeti( p, path, "totallines", &len );
if( len > 0 ) size = *sz; else size = 0;

lngst = EIgeti( p, path, "longest", &len );
if( len > 0 ) longest = *lngst; else longest = 0;

startcol = EIgeti( p, path, "startcol", &len );

flineselect = EIgeti( p, path, "pick/vselect", &len );
selectleft = EIgeti( p, path, "pick/hselect", &len );
selectright = selectleft+1;


box = EIgetc( p, path, "box", &len );
/* text, no box */
if( strlen( box ) < 1 ) 
	if( fromfile ) Efiletext( fnm, posx, posy, 0, 0.0, *firstline, *nlines, -1.0, 0, align, 
		&lineheight, ruled, number, &longest, &size, *flineselect,
		&texttop, &textbot, &textleft, &textright, &charwidth, *selectleft, *selectright, 
		*startcol, -1.0, -1.0, -1.0, -1.0 );

	else Eblocktext( txt, posx, posy, 0, 0.0, *firstline, *nlines, -1.0, 0, align, 
		&lineheight, ruled, number, &longest, &size, *flineselect,
		&texttop, &textbot, &textleft, &textright, &charwidth, *selectleft, *selectright, 
		*startcol, -1.0, -1.0, -1.0, -1.0 );

/* text with box */
else	{
	boxwidth = EIgeti( p, path, "box.width", &len );
	boxmargin = EIgetd( p, path, "box.margin", &len );
	marg_l = EIgetd( p, path, "box.marg_l", &len );
	marg_r = EIgetd( p, path, "box.marg_r", &len );
	marg_b = EIgetd( p, path, "box.marg_b", &len );
	marg_t = EIgetd( p, path, "box.marg_t", &len );
	color = EIgetd( p, path, "box.color", &len );

	if( fromfile )Efiletext( fnm, posx, posy, *boxwidth, *boxmargin, *firstline, *nlines, 
		*color, 0, align, &lineheight, ruled, number, 
		&longest, &size, *flineselect,
		&texttop, &textbot, &textleft, &textright, &charwidth, *selectleft, *selectright,
		*startcol, *marg_l, *marg_r, *marg_b, *marg_t );

	else Eblocktext( txt, posx, posy, *boxwidth, *boxmargin, *firstline, *nlines, 
		*color, 0, align, &lineheight, ruled, number, 
		&longest, &size, *flineselect,
		&texttop, &textbot, &textleft, &textright, &charwidth, *selectleft, *selectright,
		*startcol, *marg_l, *marg_r, *marg_b, *marg_t );

	if( !Efastflag ) {
		dress = EIgetc( p, path, "dress", &len );
		if( strlen( dress ) > 0 ) {
			sprintf( newpath, "%s/dress", path );
			EArect_dress( p, newpath );
			}
		}
	}

/* update values that came back from Eblocktext.. */
if( !Efastflag ) {
	if( size != *sz ) {
		sprintf( val, "%d", size );
		EImodattr( p, path, "totallines", val ); 
		}
	if( longest != *lngst ) {
		sprintf( val, "%d", longest );
		EImodattr( p, path, "longest", val ); 
		}
	
	if( pickable ) {
		sprintf( val, "%g %g %g", textbot, texttop, lineheight );
		EImodattr( p, path, "pick/vzones", val ); /* not always necessary, but.. */
		sprintf( val, "%g %g %g", textleft, textright, charwidth );
		EImodattr( p, path, "pick/hzones", val );
		}
	}
}

/* ==================================================== */
/* ==================================================== */
/* =The EXEC routine. ================================= */
/* Get a text line, or scroll up/down */
/* ==================================================== */
EEtextb( p, x, y, e, msg )
int p;
double x, y;
int e;
char msg[];
{
int i, j, k, l, n, nlines, fromfile;
int len;
double *vlow, *vhi, *vinc, pz, oldpz;
double *hlow, *hhi, *hinc;
char *txt, *fnm;
char val[E_GPBUF], val2[E_GPBUF];
double *scr, u, v, r;
int *fln, *nln, *size, *oldpick;
int m;
int ix, oldix;
int pickable;
char *mode;
int selectleft, selectright;
int *oldline, *oldleft, *oldright;
int *startcol;
int *longest, *width;
int diff;
char *result_format, *delim_list;
char message[20];
char *unpick;
int *curln;
char *flashpick;

/* allow mouse clicks and messages */
if( e < 1000 ) return( 0 );

strcpy( message, msg );

mode = EIgetc( p, "", "pick.mode", &len );
unpick = EIgetc( p, "", "unpick", &len );

if( strcmp( message, "REINIT" )==0 ) {
	Enulloutbb( p );
	EImodattr( p, "", "firstline", "1" );
	EImodattr( p, "", "totallines", "0" );
	EImodattr( p, "", "longest", "0" );
	/* returns then, below. */
	}
if( Esmember( message, "RESET REINIT", " " )) {
	EImodattr( p, "", "pick/value", "" );
	EImodattr( p, "", "pick/vselect", "0" );
	if( *mode == 'W' || *mode == 'C' ) { EImodattr( p, "", "pick/hselect", "-1 -1" ); }
	return( 1 );
	}

fln = EIgeti( p, "", "firstline", &len );




nln = EIgeti( p, "", "nlines", &len );
size = EIgeti( p, "", "totallines", &len ); 
longest = EIgeti( p, "", "longest", &len );
startcol = EIgeti( p, "", "startcol", &len );
width = EIgeti( p, "", "box.width", &len );


/* see if user clicked on scroller.. */
/* if nln == 0 there will be no scrolling */
if( *nln > 0 )EEcheckvscroller( message, p, x, y ); 

if( strlen( message ) > 0 ) {

	if( strcmp( message, "NEXT" )==0 ) {
		curln = EIgeti( p, "", "pick/vselect", &len );
		if( *curln < 1 ) n = 0;
		else n = ( *curln - *fln ) + 1 ;
		n++; 
		if( n > *nln ) {
			Eexec( p, 0.0, 0.0, E_MESSAGE, "BUMP DOWN" ); /* recursion */
			n = *nln;
			}
		goto SECTION2;
		}

	else if( strcmp( message, "PREVIOUS" )==0 ) {
		curln = EIgeti( p, "", "pick/vselect", &len );
		if( *curln < 1 ) n = 2;
		else n = ( *curln - *fln ) + 1 ;
		n--;
		if( n < 1 ) {
			Eexec( p, 0.0, 0.0, E_MESSAGE, "BUMP UP" ); /* recursion */
			n = 1;
			}
		goto SECTION2;
		}
		
	else if( strcmp( message, "PAGE UP" )== 0 ) {
		m = *fln;
		if( m <= 1 ) return( 1 );
		m -= (*nln +1); /* leave an anchor line.. */
		if( m < 1 ) m = 1;
		sprintf( val, "%d", m ); EImodattr( p, "", "firstline", val );
		}
	else if( strcmp( message, "PAGE DOWN" )== 0 ) {
		m = *fln;
		/* if( m >= ((*size)-(*nln)) )return( 1 ); scg 11-7-95 */
		   if( m > ((*size)-(*nln)) )return( 1 ); 
		m += (*nln -1); /* leave an anchor line.. */
		if( m > (*size-*nln) ) m = (*size-*nln) +1;  /* bug fix */
		sprintf( val, "%d", m ); EImodattr( p, "", "firstline", val );
		}
	else if( strcmp( message, "TOP" )== 0 ) {
		if( *fln <= 1 ) return( 1 );
		EImodattr( p, "", "firstline", "1" );
		}
	else if( strcmp( message, "BOTTOM" )== 0 ) {
		/* if( *fln >= (*size)-(*nln)) return( 1 );scg 11-7-95 */
		   if( *fln > (*size)-(*nln)) return( 1 ); 
		sprintf( val, "%d", (*size - *nln)+1 ); /* bug fix */
	 	EImodattr( p, "", "firstline", val );
		}
	
	else if( strcmp( message, "BUMP UP" )==0 ) {
		if( *fln <= 1 ) return( 1 );
		sprintf( val, "%d", (*fln)-1 ); 
		EImodattr( p, "", "firstline", val );
		}
	else if( strcmp( message, "BUMP DOWN" )==0 ) {
		/* if( *fln + *nln >= *size )return( 1 ); scg 11-7-95 */
		   if( *fln + *nln > *size )return( 1 ); 
		sprintf( val, "%d", (*fln)+1 ); 
		EImodattr( p, "", "firstline", val );
		}
	else if( strcmp( message, "PAGE RIGHT" )==0 ) {
		diff = (*width) / 6;
		m = (*startcol);
		if( m >= ((*longest) - (*width) )) return( 1 );
		m += diff;
		if( m > ((*longest) - (*width)) ) m = (*longest) - (*width);
		sprintf( val, "%d", m );
		EImodattr( p, "", "startcol", val );
		}
	else if( strcmp( message, "PAGE LEFT" )==0 ) {
		diff = (*width) / 6;
		m = (*startcol);
		if( m <= 0 ) return( 1 );
		m -= diff;
		if( m < 0 ) m = 0;
		sprintf( val, "%d", m );
		EImodattr( p, "", "startcol", val );
		}
/*
 *	else if( strncmp( message, "SEARCH", 6 )==0 ) {
 *		curln = EIgeti( p, "", "pick/vselect", &len );
 *		txt = EIgetc( p, "", "text", &len );
 *		Esearch( curln, *size, txt, message );
 *		}
 */
	else fprintf( stderr, "textb does not recognize message (%s)\n", message );
	
	Efastflag = 1; Egen( p ); Efastflag = 0;
	return( 1 );
	}

	
EIgetc( p, "", "pick", &len );
if( len > 0 ) pickable = 1; else pickable = 0;

if( !pickable ) return( 0 );


vlow = EIgetd( p, "", "pick/vzones", &len );    /* vlow, vhi, vinc */
if( len != 3 ) return( 0 );
vhi = vlow + 1; vinc = vlow + 2;
if( *vhi < *vlow || (*vhi - *vlow) > 20.0 )
	{ fprintf( stderr, "EEtextb() internal v. pick error.\n" ); return( 0 ); }

/* find the vertical pick.. */
if( y >= *vlow && y <= *vhi ) {
	pz = *vhi;
	for( i = 0; ; i++ ) {
		if( y > pz ) break;
		pz -= (*vinc);
		}
	}
else 	{
	if( *mode == 'O' ) Eselection[0] = '\0';
	return( 0 );
	}

n = i;

SECTION2:
/* n now contains the on-screen number of the zone that was picked (first = 1) */

/* find the line of text that was pointed to (either from text or file).. */
txt = EIgetc( p, "", "text", &len );
fnm = EIgetc( p, "", "file", &len );
if( len > 0 ) fromfile =1; else fromfile = 0;

ix = 0;
nlines = 0;
while( 1 ) {
	nlines++;
	if( !fromfile )Egetln( val2, txt, &ix );
	if( ((nlines-*fln)+1) == n ) break;
	}
if( fromfile ) { 
	Efileline( fnm, nlines, val2 );
	val2[ strlen( val2 ) -1 ] = '\0';
	}
Eexpand_tabs( val, val2 );
/* we now have the line in val */



selectleft = -1; selectright = -1; i = 0;
if( *mode == 'W' || *mode == 'C' ) {   /* find the character or word being pointed to.. */
	hlow = EIgetd( p, "", "pick/hzones", &len );    /* hlow, hhi, hinc */
	if( len == 3 ) {
		hhi = hlow + 1;  hinc = hlow + 2;
		if( *hhi < *hlow || (*hhi - *hlow) > 20.0 ) 
			{ fprintf( stderr, "EEtextb() internal h. pick error.\n" ); return( 0 ); }
		
		/* find the horiz. pick.. */
		if( x >= *hlow && x <= *hhi ) {
			pz = *hlow;
			for( i = 0; ; i++ ) {
				if( x < pz ) break;
				pz += (*hinc);
				}
			}
		else return( 0 );
		if( i > strlen( val )) return( 0 );
		i--; /* adjust so that first character is position 0 */
		i += (*startcol); /* adjust for possible h. scrolling */
		/* i now contains the character pointed to.. */
		}
	else return( 0 );

	/* get the word or character.. */
	if( *mode == 'W' ) { /* word.. */
		if( val[i] == ' ' ) return( 0 );
		for( j = i; j > 0; j-- ) if( val[j] == ' ' ) { j++; break; }
		for( k = i; k < strlen( val ); k++ ) if( val[k] == ' ' ) { break; }
		k--;
		selectleft = j; selectright = k;
		for( l = j, m = 0; l <= k; l++ ) val2[ m++ ] = val[ l ];
		val2[ m ] = '\0';
		strcpy( val, val2 );
		}
	else if( *mode == 'C' ) { /* char.. */
		val[0] = val[i]; val[1] = '\0';
		selectleft = i; selectright = i;
		}
	}


/* see if an "already-picked" line was picked.. if so it becomes "un-picked".. */
oldline = EIgeti( p, "", "pick/vselect", &len );
oldleft = EIgeti( p, "", "pick/hselect", &len );
oldright = oldleft + 1;

result_format = EIgetc( p, "", "result.format", &len );
delim_list = EIgetc( p, "", "result.delim.list", &len );

/* if( nlines != *oldline || selectleft != *oldleft || selectright != *oldright ) { */

if( *unpick == 'x' && nlines == *oldline && selectleft == *oldleft &&
   selectright == *oldright ) { 
	EImodattr( p, "", "pick/vselect", "0" );
	Eselection[0] = '\0';
	EImodattr( p, "", "pick/value", Eselection );
	if( *mode == 'W' || *mode == 'C' ) { EImodattr( p, "", "pick/hselect", "-1 -1" ); }
	}

else	{

/* if( *unpick != 'x' ) {  */		/* scg 1-6-96 */

	if( *result_format != 'A' && *mode == 'L' ) {
		ix = 0;
		for( i = 0; i < atoi( result_format ); i++ ) {
			Egetchunk( Eselection, val, &ix, delim_list );
			}
		}
	else strcpy( Eselection, val ); /* save selection */
	EImodattr( p, "", "pick/value", Eselection );
	sprintf( val, "%d", nlines );
	EImodattr( p, "", "pick/vselect", val );
	if( *mode == 'W' || *mode == 'C' ) {
		sprintf( val, "%d %d", selectleft, selectright );
		EImodattr( p, "", "pick/hselect", val );
		}
	}


Efastflag = 1; Egen( p ); Efastflag = 0;

/* Do an immediate reset */
flashpick = EIgetc( p, "", "flashpick", &len );
if( len > 0 ) {
	Eflush();
	Eusleep( Eflashdelay ); 
	Eexec( p, 0.0, 0.0, E_MESSAGE, "RESET" ); 
	Egen( p );
	}


return( 1 );
}

SHAR_EOF
############################

echo src/copa_txt.c
cat << \SHAR_EOF > src/copa_txt.c
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any commercial product is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/





/* =========== COPA_FILLBUF (internal) =========== */
/* This is used to collect text from copa_txt calls into a large buffer */
/* This routine is called from C apps via copa_text() and from shell apps via copa_cli() */

/* Mode: 0 = fill buffer beginning at position 0 with given text   
	 1 = truncate buffer at postition 0 and return
	 2 = append given text to buffer, and add a trailing newline
 */
#include <stdio.h>

#include "bigbuf.h"


char *
/* copa_fillbuf( char *txt, int mode ) */
copa_fillbuf( txt, mode )
char *txt;
int mode;
{
int full;
char *c, *copa_txt();
int i;

if( mode < 2 ) {
	Ebigbuf[0] = '\0';
	if( mode == 1 ) return( NULL );
	}
full = 0;
for( i = 0; ; i++ ) {
	c = copa_txt( txt, i, Ebuf, LINEMAX ); /* get command results, if any */
	if( c == NULL ) break;
	else if( full );
	else	{
		if( strlen( c ) + strlen( Ebigbuf ) > BIGBUFSIZE ) full = 1;
		else 	{
			addb( Ebigbuf, c );
			if( mode == 2 ) addb( Ebigbuf, "\n" );
			}
		}
	}
if( full ) Eerrmsg( 55, "Warning: Too much text - results truncated.", "" );
return( Ebigbuf );
}


/* ============ COPA_TXT (internal) ============= */
/* This function is called by the client version of copa_text() which gets
   results and sends them via pipe to server; it is ALSO called by the
   the C api version of copa_text(), which gets results and appends them
   to a large buffer.

   This function evaluates a text string. Txt can be literal, !command, or 
   combination of the two.
   Called repeatedly; returns portions of results, until there are
   no more, in which case NULL is returned.

Args:
   count: First call for a given string: count = 0; otherwise count > 0.
   cbuf: is a char buffer which will be left alone between groups of
     calls to this function.
Notes:
   The txt argument will not be modified.
   This function will return pointers which access cbuf.
*/

#include <stdio.h>

static int doing_command; /* 1 when in the midst of getting command results, 0 otherwise */
static int done;   /* 1 when next call should return NULL immediately */
static int trail_txt; /* -1 == no trailing text; otherwise holds position of beginning
				of trailing text (literal text coming after command) */
static FILE *comfp;
static char combuf[ SELECTIONMAX ]; /* command goes here - note size limit.. */  /* LIMIT */

/* ======= */
char *
/* copa_txt( char *txt, int count, char *cbuf, int cbufsize ) */
copa_txt( txt, count, cbuf, cbufsize )
char *txt;
int count;
char *cbuf;
int cbufsize;
{
int i, len, comstart, comend;


/* first call: look for any imbedded commands (lines beginning with !) */
if( count == 0 ) {
	done = 0;
	doing_command = 0;
	trail_txt = -1;
	comstart = -1;
	len = strlen( txt );
	for( i = 0; i < len; i++ ) {
		if( i == 0 || txt[i-1] == '\n' ) {
			if( txt[i] == '!' ) { 
				comstart = i + 1;
				/* find end of command.. */
				for( ; i < len; i++ ) if( txt[i] == '\n' ) break;
				comend = i;
				strncpy( combuf, &txt[ comstart ], comend-comstart );
				combuf[ comend-comstart ] = '\0';
				break;
				}
			}
		}

	if( comstart == -1 ) {    /* no embedded commands.. just return text */
		done = 1; 
		return( txt ); 
		}

	if( comend + 1 < strlen( txt ) ) {   /* see if trailing text exists.. */
		trail_txt = comend + 1;
		}

	if( comstart > -1 ) {     /* popen the command.. */
		comfp = popen( combuf, "r" );
		if( comfp == NULL ) doing_command = 0;
		else doing_command = 1;
		}

	if( comstart > 1 ) {   		/* some text before command, return it */
		strcpy( cbuf, txt, comstart-1 );
		cbuf[ comstart - 1 ] = '\0';
		doing_command = 1; /* for next time.. */
		return( cbuf );
		}
	}

if( done ) return( NULL );

if( doing_command ) {
	if( fgets( cbuf, cbufsize, comfp ) == NULL ) { /* no more results.. */
		doing_command = 0;
		pclose( comfp );
		if( trail_txt > -1 ) return( &txt[ trail_txt ] );
		else return( NULL );
		}
	else 	{			/* more results still to come.. */
		doing_command = 1;
		return( cbuf ); /* return a line of the results */
		}
	}

return( NULL );
}



/* =============================== */
/* append str to buffer */
static int
addb( bb, str )
char bb[], str[];
{
int len;

len = strlen( bb );
sprintf( &bb[ len ], "%s", str );
}


/* ======== */
/* test module */
/*
 * main()
 * {
 * int i, j;
 * char *c;
 * char cbuf[512];
 * 
 * for( j = 0; j < 2; j++ ) {
 * for( i = 0; ; i++ ) {
 * 	c = copa_txt( "Choice A\nChoice B\n!ls\nBottom", i, cbuf, 512 );
 * 	if( c == NULL ) break;
 * 	printf( "%s", c );
 * 	}
 * }
 * }
 */
SHAR_EOF
############################

echo src/copa_value.c
cat << \SHAR_EOF > src/copa_value.c
/* VALUE.C - copa getvalue and setvalue */


SHAR_EOF
############################

echo src/edit.c
cat << \SHAR_EOF > src/edit.c
#include "elib.x"

/* ======================== */
/* ======================== */
/* ======================== */
/* edit the object or group */
/* ======================== */
Eeditobj( id, attr, value )
int id;
char attr[];
char value[];
{
int i, ip;

if( strcmp( EIgetobjname( id ), "group_begin" )==0 ) { /* update all objects in group.. */
	for( i = 0; ; i++ ) {
		if( i == 0 ) ip = Egetgroupobj( id, E_AT_BEGINNING );
		else ip = Egetgroupobj( id, E_NEXT );
		if( ip == E_NIL ) break;

		/* edit group begin,  don't edit group_end.  don't edit if attribute not legit.. */
		if( EIexists( ip, "", attr )) {
			EImodattr( ip, "", attr, value ); 
			Enulloutbb( ip );
			}
		}
	Egetgroupobj( id, E_DONE );
	}

else if( EIexists( id, "", attr )) {
	EImodattr( id, "", attr, value ); /* it's just a single object.. */
	Enulloutbb( id );
	}
else return( 0 );
return( 1 );
}

/* ====================== */
/* ====================== */
/* ====================== */
/* move an object or group */
/* ====================== */
Emoveobj( id, tx, ty )
int id;
double tx, ty; /* translation vector */
{
int i, len, ip;
char *name;

if( strcmp( EIgetobjname( id ), "group_begin" )==0 ) { /* update all objects in group.. */
	for( i = 0; ; i++ ) {
		if( i == 0 ) ip = Egetgroupobj( id, E_AT_BEGINNING );
		else ip = Egetgroupobj( id, E_NEXT );
		if( ip == E_NIL ) break;

		/* do a move on everything between (but not including) the begin and the end */
		name = EIgetobjname( ip );
		if( ! Esmember( name, "group_begin group_end", " " )) Edomov( ip, tx, ty );
		}
	Egetgroupobj( id, E_DONE );
	}
else Edomov( id, tx, ty ); /* it's just a single object.. */
return( 1 );
}

/* ==== */
static
Edomov( id, tx, ty )
int id;
double tx, ty; /* translation vector */
{
char value[100];
int n, k, len;
double *d1, *d2, *d3, *d4;

if( !EIexists( id, "*", "bb" )) return( 0 );
EIgetd( id, "*", "bb", &len );
if( len > 0 ) { 
	Enulloutbb( id );
	}

d1 = EIgetd( id, "*", "trl", &len );
if( len > 0 && EIwhere_was_it() == 1 ) { /* must be a user value, not inherited */
	d2 = d1 + 1;
	tx += *d1; ty += *d2;
	}
sprintf( value, "%g %g", tx, ty );
EImodattr( id, "", "*/trl", value );
return( 1 );
}

/* ====================== */
/* ====================== */
/* ====================== */
/* copy an object or group */
/* ====================== */
Ecopyobj( id, tx, ty )
int id;
double tx, ty; /* translation vector */
{
int i, len, ip;
char *name;

if( strcmp( EIgetobjname( id ), "group_begin" )==0 ) { 		/* copy all objects in group.. */
	for( i = 0; ; i++ ) {
		if( i == 0 ) ip = Egetgroupobj( id, E_AT_BEGINNING );
		else ip = Egetgroupobj( id, E_NEXT );
		if( ip == E_NIL ) break;

		/* copy everything, including begin and end */
		Edocopy( ip, tx, ty );
		}
	Egetgroupobj( id, E_DONE );
	}
else Edocopy( id, tx, ty ); /* it's just a single object.. */
return( 1 );
}

/* ================ */
static
Edocopy( id, tx, ty )
int id;
double tx, ty;
{
char value[100];
int newid;
int n, k, len;
double *d1, *d2, *d3, *d4;
char *name;

newid = EIcopy( id );
name = EIgetobjname( newid );

if( strcmp( name, "group_begin" )!=0 ) {
	if( !EIexists( id, "*", "trl" )) return( 0 );
	d1 = EIgetd( id, "*", "trl", &len ); 
	if( len > 0 && EIwhere_was_it() == 1 ) {
		d2 = d1 + 1;
		tx += *d1; ty += *d2;
		}
	
	sprintf( value, "%g %g", tx, ty );
	EImodattr( newid, "", "*/trl", value );
	}
Enulloutbb( newid );
}
/* ======================== */
/* ======================== */
/* ======================== */
/* delete an object or group */
/* ======================== */
Edelobj( id )
int id;
{
int i, len, ip;
char *name;

if( strcmp( EIgetobjname( id ), "group_begin" )==0 ) { /* update all objects in group.. */
	for( i = 0; ; i++ ) {
		if( i == 0 ) ip = Egetgroupobj( id, E_AT_BEGINNING );
		else ip = Egetgroupobj( id, E_NEXT );
		if( ip == E_NIL ) break;
	
		/* delete everything, including begin and end */
		Edodel( ip );
		}
	Egetgroupobj( id, E_DONE );
	}
else Edodel( id ); /* it's just a single object.. */
}
/* ======== */
static
Edodel( id )
int id;
{
Enulloutbb( id );
EIdelete( id );
}

/* ====================================================== */
/* ====================================================== */
/* ====================================================== */
/* This routine will return successive objects in a group */
/* starting with the group_begin and ending with the group_end. */
/* ============================================================ */
static
Egetgroupobj( group_procid, mode )
int group_procid;
int mode;
{
static int done = 0, *endid;
int len, i;

if( strcmp( EIgetobjname( group_procid ), "group_begin" ) !=0 ) return( E_NIL );

if( mode == E_AT_BEGINNING ) {
	endid = EIgeti( group_procid, "", "endid", &len );
	if( len < 1 ) { 
		fprintf( stderr, "id=%d: Matching group_end not found.\n", group_procid ); 
		return( E_NIL ); 
		}
	done = 0;
	EIgetnextobj( E_AT_BEGINNING, 0 ); /* initialize */
	while( 1 ) {
		i = EIgetnextobj( E_NEXT, 0 ); /* advance to current location in display list */
		if( i == group_procid ) break;
		else if( i == E_NIL ) { 
			fprintf( stderr, "Internal error. Source object not in order list.\n" ); 
			EIgetnextobj( E_DONE, 0 );
			return(0);
			}
		}
	return( i );
	}
else if( mode == E_NEXT ) {
	if( done ) return( E_NIL ); 
	i = EIgetnextobj( E_NEXT, 0 );
	if( i == *endid ) done = 1; 
	return( i );
	}
else if( mode == E_DONE ) {
	EIgetnextobj( E_DONE, 0 );
	return( E_NIL );
	}
else 	{
	fprintf( stderr, "Egetgroupobj: %d: Illegal mode\n", mode ); 
	return( E_NIL );
	}
}
SHAR_EOF
############################

echo src/elib.d
cat << \SHAR_EOF > src/elib.d
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any for-profit endeavor is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/




#include <stdio.h>
#include <math.h>

#define E_SELECTION_LEN 512 	/* max length of a selection */     /* LIMIT */
#define E_GPBUF 512		/* general purpose buffer size */   /* LIMIT */
#define E_ANAMELEN 80		/* max attribute name length */

#define E_WAITFOR_WM 200000	/* in certain situations such as after remapping
				the window or after resizing, a delay seems to be
				necessary before the window manager responds to
				subsequent instructions.. 
				This is in microseconds.
				*/

#define YES 1
#define NO 0
#define STDFONT "/Helvetica"

/* clear drawing area to the opposite of current drawing color */
#define Eclr()			Epcode( 'z', Eeraseshade, 0.0, "" )

/* dot at x, y */
#define Edot( x, y )		Epcode( '.', (double)x, (double)y, "" )
#define Edotu( x, y )		Epcode( '.', Eax((double)x), Eay((double)y), "" )

/* move to x, y absolute */
#define Emov( x , y )		Epcode( 'M', (double)x , (double)y, "" )

/* line to x, y absolute */
#define Elin( x , y )		Epcode( 'L', (double)x , (double)y, "" )

/* move to x, y data */
#define Emovu( x , y )		Epcode( 'M', Eax((double) x ) , Eay((double) y ), "" )

/* line to x, y data */
#define Elinu( x , y )		Epcode( 'L', Eax((double) x ) , Eay((double) y ), "" )

/* path to x, y absolute (form a polygon to be shaded later) */
#define Epath( x , y )		Epcode( 'P', (double)x , (double)y, "" )

/* path to x, y data (form a polygon to be shaded later) */
#define Epathu( x , y )		Epcode( 'P', Eax((double) x ) , Eay((double) y ), "" )

/* do shading, within the previously defined polygon path.. the shade can be 0 to 1 */
#define Eshade( x )		Epcode( 'S', (double)x , 0.0, "" )

/* text string s starting at the current location  */
#define Etext( s )		Epcode( 'T', 0.0, 0.0, s )


/* center text around current "pen" position.. */
#define Ecentext( s )		Epcode( 'C', 0.0 , 0.0, s )

/* right justify text such that right edge of text is at current "pen" position.. */
#define Erightjust( s )		Epcode( 'J', 0.0, 0.0, s )

/* scaling factor for text */
#define Escaletext( x )		Epcode( 'e', x, 0.0, "" )

/* Eprint() is same as Egetclick() */
#define Eprint()		Egetclick()

/* internal: eject page (printers), end-of-plot (screens) */
#define Eshow()			Epcode( 'Z', 0.0, 0.0, "" )

/* internal: wait for user input */
#define Esit()		 Epcode( 'W', 0.0, 0.0, "" )

/* cycle notifier when running asynchronously.. */
#define Easync()	 Epcode( 'w', 0.0, 0.0, "" )

/* these can go around repetitive drawing operations to improve efficiency (sunview only) */
#define Ebatch_on()		Epcode( 'B', 0.0, 0.0, "" )
#define Ebatch_off()		Epcode( 'b', 0.0, 0.0, "" )

/* display everything that's waiting..(x only) */
#define Eflush()		Epcode( 'U', 0.0, 0.0, "" )

/* define a circle center and radius, for the benefit of object/pick package.. */
/* x, y define the center and r the radius. */ 
/* #define Ecircledef( x, y, r )	Epcode( 'X', x, y, Eftoa( r ) ) */

/* remove window.. */
#define Ewinappear()		Epcode( 'a', 0.0, 0.0, "" )
#define Ewindisappear()		Epcode( 'd', 0.0, 0.0, "" )

/* terminate */
#define Eendoffile()		Epcode( 'Q', 0.0, 0.0, "" )

/* 
Graphics notes:
- Origin is in lower left corner of "paper", regardless of orientation of paper.
- Format of i-code will be: "a x y s\n", where a is an op code, x and y
   are coordinates in inches, and s is a variable length string (may be null).
*/

#define E_LINEAR 0
#define E_LOG 1
#define E_YYMM 2

#define E_WHITE 1
#define E_BLACK 0
extern double Eax(), Eay(), Eux(), Euy(), Egetvaluef(), atof(), sqrt();
extern char *Eftoa(), *Egetok(), *Egetobjparent();
extern int *Ewhichobjects();

#define E_MOUSE_LEFT 1001
#define E_MOUSE_MIDDLE 1002
#define E_MOUSE_RIGHT 1003
#define E_EXPOSE 1010  /* window has been exposed and needs to be redrawn */
#define E_RESIZE 1011  /* window has been resized */
#define E_MESSAGE 2000

#define E_RA 0.5  /* vertical size of the reserved area.. */

#define E_SAVE 0
#define E_RESTORE 1

#define E_PUSH 0
#define E_POP 1
#define E_PEEK 2

#define E_TMPFILENM "/usr/tmp/elib" 
#define E_TMPDIR "/usr/tmp"

/* ipl database defines.. */
extern char *EIgetobjname(), *EIgetnextattr(), *EIgetc(), *EIgetpackagename(), *EIgetval();
extern double *EIgetd();
extern int *EIgeti();

/* Egetnextobj sequences.. */
#define E_AT_BEGINNING 0
#define E_AT_END 2
#define E_NEXT 1
#define E_PREVIOUS -1
#define E_DONE 3

/* ipl nil */
#define E_NIL -1

/* convenience macros */ 
#define Egetid( t )  EItaglookup( t, E_NIL )
#define Eraise( p )  EIraise( p )
#define Elower( p )  EIlower( p )




SHAR_EOF
############################

echo src/elib.h
cat << \SHAR_EOF > src/elib.h
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any for-profit endeavor is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/





#include "elib.d"
/* window size.. */
double EWinx, EWiny;
/* original window size.. */
double EWinx_0, EWiny_0;
char Edev;
int  Epixelsinch;  /* number of pixels/inch */
char Estandardfont[60] = "";
char Ecurfont[60] = "";
int Ecurtextsize = 0;
double Ecurtextheight = 0.0;
double Ecurtextwidth = 0.0;
int Ecurtextdirection = 0;
int Ecurpaper = -1;
double Estandardlinewidth = -1.0;
double Ecurlinewidth = -1.0;
int Ecurlinetype = -1;
double Ecurpatternfactor = 0.0;
int Ecurcolor = -1;
int Eerasecolor = -1; /* same as below, used for comparisons with pen color.. */
double Eeraseshade = -1.0;
int Ecurpen = -1;
double Epsffactor = 1.0; /* compensate for prop. spaced fonts */

/* event information */
int EEvent;
double EEventx, EEventy;

char Eselection[E_SELECTION_LEN]; /* contents of button or text line that user just selected */
char Esource[40];     /* tag of object containing user's selection */

/* scaling.. */
double EXlo, EXhi, EYlo, EYhi;		/* graphic area bounds, absolute coords */
double EDXlo, EDXhi, EDYlo, EDYhi;		/* graphic area bounds, data coords */
double EScale_x = 1, EScale_y = 1; 		/* linear scaling factors in x and y */
int EScale_discipline_x = E_LINEAR;	/* either LINEAR or LOG */
int EScale_discipline_y = E_LINEAR;	/* either LINEAR or LOG */


double Ex1, Ey1; /* last moveto */
double Ex2, Ey2; /* last lineto */

/* bounding box mode */
int Ebbmode = 0;  /* 0 = contain nested objects, 1 = don't */

/* original color.. */
double Ebkcolor0 = 1.0;

int Eservermode = 0;
int Eresizingflag = 0;

long Eflashdelay = 150000; /* flashpick delay in microseconds */
int Eskipalign = 0; 
SHAR_EOF
############################

echo src/elib.x
cat << \SHAR_EOF > src/elib.x
/*
COPA 1.0 - gui control panel kit for shell, C, perl etc.  
*              **      **                              *
Copyright 1991-1996 by Stephen C. Grubb.

Permission is hereby granted to USE this software for free.
Permission is hereby granted to MODIFY and/or REDISTRIBUTE 
this software for free, provided that no monetary gain is 
realized, and all attached authorship and copyright notices 
are preserved.

Inclusion of any portion (or derivation) of this software, 
including ancillary files, in any for-profit endeavor is not 
allowed without prior written permission of the author.  

See also the file 'Copyright'. 
*/



#include "elib.d"
/* window size.. */
extern double EWinx, EWiny;
extern double EWinx_0, EWiny_0;

/* graphics parameters.. */
extern char Edev;
extern int  Epixelsinch;
extern char Estandardfont[];
extern char Ecurfont[];
extern int Ecurtextsize;
extern double Ecurtextheight;
extern double Ecurtextwidth;
extern int Ecurtextdirection;
extern int Ecurpaper;
extern double Estandardlinewidth;
extern double Ecurlinewidth;
extern int Ecurlinetype;
extern double Ecurpatternfactor;
extern int Ecurcolor;
extern int Eerasecolor;
extern double Eeraseshade;
extern int Ecurpen;
extern double Epsffactor;


/* current message */
extern char Ecurmessage[];

/* event information */
extern int EEvent;
extern double EEventx, EEventy;

extern char Eselection[];
extern char Esource[];

/* scaling.. */
extern double EXlo, EXhi, EYlo, EYhi;		/* graphic area bounds, absolute coords */
extern double EDXlo, EDXhi, EDYlo, EDYhi;	/* graphic area bounds, data coords */
extern double EScale_x, EScale_y; 		/* linear scaling factors in x and y */
extern int EScale_discipline_x;		/* either LINEAR or LOG */
extern int EScale_discipline_y;		/* either LINEAR or LOG */

/* last moveto and lineto */
extern double Ex1, Ey1, Ex2, Ey2;

/* bounding box mode */
extern int Ebbmode;

extern double Ebkcolor0;
extern int Eservermode;
extern int Eresizingflag;

extern long Eflashdelay;
extern int Eskipalign;
SHAR_EOF
############################

echo src/err.c
cat << \SHAR_EOF > src/err.c
#include <stdio.h>

/* ============= CERR ========================= */
/* Eerrmsg( int errno, char *msg, char *parm ) */
Eerrmsg( errno, msg, parm )
int errno;
char *msg;
char *parm;
{
fprintf( stderr, "COPA ERROR %d: %s (%s)\n", errno, msg, parm );
fflush( stderr );
return( errno );
}
SHAR_EOF
############################


