[comp.unix.sysv386] Screen packages in general

anton@bkj386.uucp (Anton Aylward) (11/28/90)

I've looked at a lot of screen packages and am very  unhapy  with
them.   Almost  all  turn areound and say "we aren't going to use
the  UNIX standard   /etc/termcap  or  /usr/lib/terminfo",  we're
going to re- invent the wheel.

This really burns me.  it may be OK for in house  developers  and
hackers who can waste time cutting new things like VVTERMCAP etc,
but for us who have to shift product or  install  at  a  customer
site its the pits.  We get paid for results, not for wasting time
hacking about.

Now CURSES may not be perfect.  it may be  bloated  and  only  do
80-90%  of  the  job, but it is there.  it is also a standard, as
far as the TERMCAP/TERMINFO side goes.

So how can we criticise it?

Two ways, both of which go fully into the hands of ISC SCO  INTEL
etc:

	1) it lacks colour ...... etc
	   Yes it does/no it doesn't.

	   NO it doesn't.  I've been using ATT WGS machines with 
	   SVR3.2.  They have colour capability in CURSES.  If SCO
	   etc choose not to implement this for their own reasons
	   that's their problem.   Go buy your UNIX from someone who
	   adhere's to the standard.

	2) it can't do <insert your favourite....>

	   My "favourite" is ledger lines.  
	   I'm in the process of converting an application from ATT
	   equipment (3B & WGS) to SCO XENIX.  It was written for
	   TERMINFO.   The SCO TERMINFO lacks many features that
	   were introduced in SVR2.0.  In fact most of the SCO XENIX 
	   implemetation of TERMINFO & utilities is riddled with
	   bugs.  We're basically having to re-write CURSES, or the
	   facilities we need!

	   The stock solution is being told to upgrade to SCO UNIX
	   (or something like that).  This is fine for us,
	   developing with the latest, most feature-full release.
	   But what about customers buying the package from sortes
	   and other outlets?

	   To put this in persspective, would you consider buying,
	   say, Norton Tools for DOS, if they were written so that
	   they used the '286 & '386 extended instructions and the
	   features of the VGA ?    I mean this in the sense that
	   you HAVE to upgrade to use the program at all!

	   We're trying to make a design which will work if you
	   haven't been obsesive about keeping up with new
	   technology, if you don't have a colour screen (I'm a
	   Brit, i spel funy!) if you don't have a VT220 with 16
	   functions keys and 8 display levels.....

	   We're also trying to produce a product which can be
	   installed without being an expert in TERMCAP or TERMINFO
	   and without having to RTFM.   One of our support group
	   made the comment

		"If you have to _read_ the manual, its too complex"

	   OK, maybe its a bit extreeme for you and me as
	   developers, but the end users do have that attitude.


So (flame down), can someone tell the net of a good, easy to use
screen pacakge which does follow the UNIX standards ?

/anton aylward				Analysis Synthesis Consulting Inc
					anton@analsyn.uucp
					"12 Years with UNIX"

staceyc@sco.COM (Stacey Campbell) (12/06/90)

In article <1990Nov27.165132.1335@bkj386.uucp> anton@analsyn.UUCP writes:
>Now CURSES may not be perfect.  it may be  bloated  and  only  do
>80-90%  of  the  job, but it is there.  it is also a standard, as
>far as the TERMCAP/TERMINFO side goes.

Agreed.  Even if curses doesn't directly support some feature it will
just take a little work to add the required top layer, which can then
be used for other applications' development.

>	   SVR3.2.  They have colour capability in CURSES.  If SCO
>	   etc choose not to implement this for their own reasons
>	   that's their problem.   Go buy your UNIX from someone who
>	   adhere's to the standard.

Just so it is clear, SCO Unix V 3.2 (all versions) supports the
stock AT&T System V 3.2 color curses.  Anton is almost certainly
referring to SCO Xenix.  I've tossed in a fun little curses color
demo at the bottom of this post, so anybody with any System V 3.2
Development System can give it a spin.

>	   The SCO TERMINFO lacks many features that
>	   were introduced in SVR2.0.  In fact most of the SCO XENIX 
>	   implemetation of TERMINFO & utilities is riddled with
>	   bugs.

SCO Xenix comes with System V 3.[01] curses, not Sys V 2 (the clue is
ACS character defines in /usr/include/tinfo.h).  Historically SCO
Xenix was based mostly around termcap curses simply because in
the good old days BSD termcap curses was much more robust and useful
than System V curses.  IMHO System V 3.2 curses, and even to a degree
System V 3.1 curses, are far and away better than BSD curses.

>	   But what about customers buying the package from sortes
>	   and other outlets?
>
>	   To put this in persspective, would you consider buying,
>	   say, Norton Tools for DOS, if they were written so that
>	   they used the '286 & '386 extended instructions and the
>	   features of the VGA ?    I mean this in the sense that
>	   you HAVE to upgrade to use the program at all!

System V 3.2 curses applications execute correctly on Xenix machines,
terminfo files are backward compatible, though it is much nicer to
use Unix terminfo files when on Xenix.  There is no real system
dependent issues when running a 386 Unix curses application on Xenix.
The application only requires a working terminfo file.

>	   We're also trying to produce a product which can be
>	   installed without being an expert in TERMCAP or TERMINFO
>	   and without having to RTFM.

The terminfo(4) man page is a bit daunting.  There is a reasonable
Nutshell book that deals with both termcap and terminfo.

Here's the demo program;

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    212 -rw------- Makefile
#   6631 -rw-rw-r-- fire.c
#
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
CC= cc
CFLAGS= -O -DM_TERMINFO -UM_TERMCAP
LDFLAGS= -O
OBJS= fire.o
X
#Unix
LDLIBS= -lcurses -lm
X
#Xenix
# LDLIBS= -ltinfo -lm
X
fire: $(OBJS)
X	$(CC) $(LDFLAGS) fire.o -o fire $(LDLIBS)
X
clean:
X	rm -f $(OBJS) fire
SHAR_EOF
chmod 0600 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 212 -eq "$Wc_c" ||
	echo 'Makefile: original size 212, current size' "$Wc_c"
fi
# ============= fire.c ==============
if test -f 'fire.c' -a X"$1" != X"-c"; then
	echo 'x - skipping fire.c (File already exists)'
else
echo 'x - extracting fire.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'fire.c' &&
#include <sys/types.h>
#include <math.h>
#include <curses.h>
#include <string.h>
X
#ifndef COLOR_BLACK
#define start_color()
#define COLOR_PAIR(a) 0
#endif
X
extern double drand48();
extern void srand48();
extern long lrand48();
extern time_t time();
extern char *malloc();
extern void free();
extern unsigned int sleep();
X
#define PART_COUNT 10
#define PART_VARIANCE 5
#define SIN_TABLE_SIZE 350
#define COLOR_MIXED -1
#define TABLE_SCALE(val) ((int)(val / M_PI * SIN_TABLE_SIZE))
#define BOUNDCHAR(win, y, x, char) \
X	(((y) >= 0 && (y) < LINES && (x) >= 0 && (x) < COLS) ? \
X		mvwaddch((win), (y), (x), (char)) : 0)
#define PAT_RAND_SEQ	0x01
X
typedef struct particle_t {
X	double y_scale;
X	double x_scale;
X	double x_inc;
X	double x;
X	int old_y, old_x;
X	int direction;
X	int color;
X	int sequence;
X	int pattern_inc;
} particle_t;
X
typedef struct pattern_t {
X	char *string;
X	int mask;
} pattern_t;
X
typedef struct object_t {
X	int rel_y, rel_x;
X	int part_count;
X	pattern_t *pattern;
X	int pat_cycle;
X	int color;
X	int done_count;
X	int life;
X	double y_mag, x_mag;
X	particle_t *particles;
} object_t;
X
typedef struct object_list_t {
X	object_t *object;
X	struct object_list_t *next;
} object_list_t;
X
static pattern_t Patterns[] = {
X	{"......+++++++******@@@@@@@", 0},
X	{"|\\-/", PAT_RAND_SEQ},
X	{".......ooooOOOOoooo", 0},
X	{".........****.......", 0},
X	{"*", 0}
};
X
#define PATTERN_SIZE (sizeof(Patterns) / sizeof(Patterns[0]))
X
static int ColorId = 1;
#define RAND_COLOR() (lrand48() % ColorId + 1)
X
static void DoSinTable();
static void DisplayObject();
static void BuildParticles();
static object_t *BuildObject();
static void InitColors();
static void AddObject();
static void DoObjectList();
static void DeleteObject();
static void FreeMemory();
X
int main(argc, argv)
X
int argc;
char *argv[];
X
{
X	double sin_table[SIN_TABLE_SIZE];
X	object_list_t *top;
X	time_t show_over;
X
X	nice(4);
X	printf("wait.");
X	fflush(stdout);
X	DoSinTable(sin_table);
X	srand48((long)time((time_t *)0));
X	initscr();
X	start_color();
X	curs_set(FALSE);
X	InitColors();
X	top = (object_list_t *)malloc(sizeof(object_list_t));
X	top->object = BuildObject();
X	top->next = 0;
X	show_over = time((time_t *)0) + 10000 * 60;
X	while (time((time_t *)0) < show_over)
X	{
X		if (! (lrand48() % 20))
X			AddObject(&top);
X		else
X			if (! top)
X			{
X				sleep(1);
X				AddObject(&top);
X			}
X		DoObjectList(stdscr, sin_table, &top);
X		wrefresh(stdscr);
X	}
X	endwin();
X	return 0;
}
X
static void DoObjectList(win, sin_table, top)
X
WINDOW *win;
double *sin_table;
object_list_t **top;
X
{
X	object_list_t *now, *old;
X
X	now = *top;
X	while (now)
X	{
X		DisplayObject(win, sin_table, now->object);
X		old = now;
X		now = now->next;
X		if (old->object->done_count >= old->object->part_count ||
X		    old->object->life < 0)
X			DeleteObject(old, top);
X	}
}
X
static void DeleteObject(zap, top)
X
object_list_t *zap;
object_list_t **top;
X
{
X	object_list_t *new, *last;
X
X	if (zap == *top)
X	{
X		new = zap->next;
X		FreeMemory(zap);
X		*top = new;
X		return;
X	}
X	new = *top;
X	while (new != zap)
X	{
X		last = new;
X		new = new->next;
X	}
X	last->next = zap->next;
X	FreeMemory(zap);
}
X
static void FreeMemory(item)
X
object_list_t *item;
X
{
X	free((char *)item->object->particles);
X	free((char *)item->object);
X	free((char *)item);
}
X
static void AddObject(top)
X
object_list_t **top;
X
{
X	object_list_t *new_top;
X
X	new_top = (object_list_t *)malloc(sizeof(object_list_t));
X	new_top->object = BuildObject();
X	new_top->next = *top;
X	*top = new_top;
}
X
static object_t *BuildObject()
X
{
X	object_t *object;
X
X	object = (object_t *)malloc(sizeof(object_t));
X	object->part_count = lrand48() % PART_VARIANCE + PART_COUNT;
X	object->particles = (particle_t *)malloc(object->part_count *
X	    sizeof(particle_t));
X	object->pattern = &Patterns[lrand48() % PATTERN_SIZE];
X	object->pat_cycle = strlen(object->pattern->string);
X	object->rel_y = LINES - lrand48() % 15;
X	object->rel_x = lrand48() % (COLS / 4 * 3) + COLS / 4 * 1 / 2;
X	object->color = lrand48() % 4 ? RAND_COLOR() : COLOR_MIXED;
X	object->done_count = 0;
X	object->y_mag = drand48() * 0.9 + 0.5;
X	object->x_mag = drand48() * 0.9 + 0.5;
X	object->life = lrand48() % 15 + 10;
X	BuildParticles(object);
X
X	return object;
}
X
static void DisplayObject(win, sin_table, object)
X
WINDOW *win;
double *sin_table;
object_t *object;
X
{
X	int i;
X	int draw_y, draw_x;
X	particle_t *p;
X	double y;
X	int sym;
X
X	if (--object->life < 0)
X	{
X		for (i = 0; i < object->part_count; ++i)
X		{
X			p = &object->particles[i];
X			BOUNDCHAR(win, p->old_y, p->old_x, ' ');
X		}
X		return;
X	}
X	for (i = 0; i < object->part_count; ++i)
X	{
X		p = &object->particles[i];
X		if (p->x < M_PI)
X		{
X			BOUNDCHAR(win, p->old_y, p->old_x, ' ');
X			y = sin_table[TABLE_SCALE(p->x)] * p->y_scale;
X			draw_y = object->rel_y - y;
X			draw_x = object->rel_x + p->direction * p->x *
X			    p->x_scale;
X			p->sequence += p->pattern_inc;
X			if (p->sequence < 0)
X				p->sequence = object->pat_cycle - 1;
X			else
X				if (p->sequence >= object->pat_cycle)
X					p->sequence = 0;
X			sym = object->pattern->string[p->sequence];
X			BOUNDCHAR(win, draw_y, draw_x,
X			    sym | COLOR_PAIR(p->color));
X			p->old_y = draw_y;
X			p->old_x = draw_x;
X			p->x += p->x_inc;
X			if (p->x >= M_PI)
X			{
X				BOUNDCHAR(win, draw_y, draw_x, ' ');
X				++object->done_count;
X			}
X		}
X	}
}
X
static void DoSinTable(table)
X
double *table;
X
{
X	int i;
X	double inc;
X	double current;
X
X	inc = M_PI / SIN_TABLE_SIZE;
X	for (i = 0, current = 0.0; i < SIN_TABLE_SIZE; ++i, current += inc)
X	{
X		table[i] = sin(current);
X		if (! (i % 66))
X		{
X			putchar('.');
X			fflush(stdout);
X		}
X	}
}
X
static void BuildParticles(object)
X
object_t *object;
X
{
X	int i;
X	particle_t *p;
X
X	for (i = 0; i < object->part_count; ++i)
X	{
X		p = &object->particles[i];
X		p->y_scale = drand48() * (LINES - 1) * object->y_mag;
X		p->x_scale = drand48() * COLS / 6.0 * object->x_mag;
X		p->x_inc = drand48() * 0.05 + 0.1;
X		p->x = 0.0;
X		p->old_y = 0;
X		p->old_x = 0;
X		p->direction = lrand48() & 1 ? -1 : 1;
X		if (object->pattern->mask & PAT_RAND_SEQ)
X		{
X			p->sequence = lrand48() % object->pat_cycle;
X			p->pattern_inc = -p->direction;
X		}
X		else
X		{
X			p->sequence = 0;
X			p->pattern_inc = 1;
X		}
X		if (object->color == COLOR_MIXED)
X			p->color = RAND_COLOR();
X		else
X			p->color = object->color;
X	}
}
X
static void InitColors()
X
{
#ifdef COLOR_BLACK
X	init_pair(ColorId++, COLOR_RED, COLOR_BLACK);
X	init_pair(ColorId++, COLOR_GREEN, COLOR_BLACK);
X	init_pair(ColorId++, COLOR_YELLOW, COLOR_BLACK);
X	init_pair(ColorId++, COLOR_BLUE, COLOR_BLACK);
X	init_pair(ColorId++, COLOR_MAGENTA, COLOR_BLACK);
X	init_pair(ColorId++, COLOR_CYAN, COLOR_BLACK);
X	init_pair(ColorId, COLOR_WHITE, COLOR_BLACK);
#endif
}
X
SHAR_EOF
chmod 0664 fire.c ||
echo 'restore of fire.c failed'
Wc_c="`wc -c < 'fire.c'`"
test 6631 -eq "$Wc_c" ||
	echo 'fire.c: original size 6631, current size' "$Wc_c"
fi
exit 0
-- 
Stacey Campbell       staceyc@sco.com
{uunet,decwrl,ucscc,att,sq,altos,lotus,phoenix,sun,microsoft,xbs}!sco!staceyc