Bizarre program
Chris Torek
chris at umcp-cs.UUCP
Tue Jul 9 09:33:24 AEST 1985
I don't know what net.bizarre is supposed to be for, but as long
as it's here, I might as well exercise it :-), so here's a truly
bizarre program. (It actually has some useful code embedded in
it too.)
---------------------------------------------------------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Making directory "floop"'
mkdir floop
/bin/echo 'Extracting floop/Makefile'
sed 's/^X//' <<'//go.sysin dd *' >floop/Makefile
#
# Makefile for floop
#
# Copyright (c) 1985 University of Maryland Computer Science Department
# Author: Chris Torek
CFLAGS= -O
LIBS= -ltermlib
floop: floop.o cm.o
cc -o floop floop.o cm.o $(LIBS)
clean:
rm -f floop floop.o cm.o
floop.o: cm.h
cm.o: cm.h
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 floop/Makefile
/bin/echo -n ' '; /bin/ls -ld floop/Makefile
fi
/bin/echo 'Extracting floop/cm.c'
sed 's/^X//' <<'//go.sysin dd *' >floop/cm.c
X/*
* cm -- Cursor Motion subroutines
*
* Copyright (c) 1985 University of Maryland Computer Science Department
*/
#include <stdio.h>
#include <sgtty.h>
#include "cm.h"
#define BIG 2000
char *malloc (), *tgoto (), *getenv (), *tgetstr ();
static int cost; /* sums up costs */
static evalcost (c) char c; {
cost++;
}
static put (c) char c; {
putchar (c);
}
X/* NEXT TWO ARE DONE WITH MACROS */
#if 0
X/*
* Assume the cursor is at row row, column col. Normally used only after
* clearing the screen, when the cursor is at (0, 0), but what the heck,
* let's let the guy put it anywhere.
*/
static
at (row, col) {
curY = row;
curX = col;
}
X/*
* Add n columns to the current cursor position.
*/
static
addcol (n) {
curX += n;
/*
* If cursor hit edge of screen, what happened?
* N.B.: DO NOT!! write past edge of screen. If you do, you
* deserve what you get. Furthermore, on terminals with
* autowrap (but not magicwrap), don't write in the last column
* of the last line.
*/
if (curX == Wcm.cm_cols) {
/*
* Well, if magicwrap, still there, past the edge of the
* screen (!). If autowrap, on the col 0 of the next line.
* Otherwise on last column.
*/
if (Wcm.cm_magicwrap)
; /* "limbo" */
else if (Wcm.cm_autowrap) {
curX = 0;
curY++; /* Beware end of screen! */
}
else
curX--;
}
}
#endif
X/*
* (Re)Initialize the cost factors, given the output speed of the terminal
* in the variable ospeed. (Note: this holds B300, B9600, etc -- ie stuff
* out of <sgtty.h>.)
*/
static
costinit () {
#define COST(x) (x ? (cost = 0, tputs (x, 1, evalcost), cost) : BIG)
Wcm.cc_up = COST (Wcm.cm_up);
Wcm.cc_down = COST (Wcm.cm_down);
Wcm.cc_left = COST (Wcm.cm_left);
Wcm.cc_right = COST (Wcm.cm_right);
Wcm.cc_home = COST (Wcm.cm_home);
Wcm.cc_cr = COST (Wcm.cm_cr);
Wcm.cc_ll = COST (Wcm.cm_ll);
Wcm.cc_tab = Wcm.cm_tabwidth ? COST (Wcm.cm_tab) : BIG;
/*
* These last three are actually minimum costs. When (if) they are
* candidates for the least-cost motion, the real cost is computed.
* (Note that "0" is the assumed to generate the minimum cost.
* While this is not necessarily true, I have yet to see a terminal
* for which is not; all the terminals that have variable-cost
* cursor motion seem to take straight numeric values. --ACT)
*/
#undef COST
#define COST(x) (x ? (cost = 0, tputs (tgoto (x, 0, 0), 1, evalcost),\
cost) : BIG)
Wcm.cc_abs = COST (Wcm.cm_abs);
Wcm.cc_habs = COST (Wcm.cm_habs);
Wcm.cc_vabs = COST (Wcm.cm_vabs);
#undef COST
}
X/*
* Calculate the cost to move from (srcy, srcx) to (dsty, dstx) using
* up and down, and left and right, motions, and tabs. If doit is set
* actually perform the motion.
*/
static
calccost (srcy, srcx, dsty, dstx, doit) {
register int deltay, deltax, c, totalcost;
int ntabs, n2tabs,
tabx, tab2x,
tabcost;
register char *p;
totalcost = 0;
if ((deltay = dsty - srcy) == 0)
goto x;
if (deltay < 0)
p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay;
else
p = Wcm.cm_down, c = Wcm.cc_down;
if (c == BIG) { /* caint get thar from here */
if (doit)
printf ("OOPS");
return c;
}
totalcost = c * deltay;
if (doit)
while (--deltay >= 0)
tputs (p, 1, put);
x:
if ((deltax = dstx - srcx) == 0)
goto done;
if (deltax < 0) {
p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
goto dodelta; /* skip all the tab junk */
}
/* Tabs (the toughie) */
if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs)
goto olddelta; /* forget it! */
/*
* ntabs is # tabs towards but not past dstx; n2tabs is one more
* (ie past dstx), but this is only valid if that is not past the
* right edge of the screen. We can check that at the same time
* as we figure out where we would be if we use the tabs (which
* we will put into tabx (for ntabs) and tab2x (for n2tabs)).
*/
ntabs = deltax / Wcm.cm_tabwidth;
n2tabs = ntabs + 1;
tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth;
tab2x = tabx + Wcm.cm_tabwidth;
if (tab2x >= Wcm.cm_cols)/* too far (past edge) */
n2tabs = 0;
/*
* Now set tabcost to the cost for using ntabs, and c to the cost
* for using n2tabs, then pick the minimum.
*/
/* cost for ntabs + cost for right motion */
tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right
: BIG;
/* cost for n2tabs + cost for left motion */
c = n2tabs ? n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left
: BIG;
if (c < tabcost) /* then cheaper to overshoot & back up */
ntabs = n2tabs, tabcost = c, tabx = tab2x;
if (tabcost >= BIG) /* caint use tabs */
goto newdelta;
/*
* See if tabcost is less than just moving right
*/
if (tabcost < (deltax * Wcm.cc_right)) {
totalcost += tabcost;/* use the tabs */
if (doit)
while (--ntabs >= 0)
tputs (Wcm.cm_tab, 1, put);
srcx = tabx;
}
/*
* Now might as well just recompute the delta.
*/
newdelta:
if ((deltax = dstx - srcx) == 0)
goto done;
olddelta:
if (deltax > 0)
p = Wcm.cm_right, c = Wcm.cc_right;
else
p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
dodelta:
if (c == BIG) { /* caint get thar from here */
if (doit)
printf ("OOPS");
return c;
}
totalcost += c * deltax;
if (doit)
while (--deltax >= 0)
tputs (p, 1, put);
done:
return totalcost;
}
#define USEREL 0
#define USEHOME 1
#define USELL 2
#define USECR 3
static
xgoto (row, col) {
int homecost, crcost, llcost, relcost, directcost;
int use;
char *p, *dcm;
/* First the degenerate case */
if (row == curY && col == curX)/* already there */
return;
/*
* Pick least-cost motions
*/
relcost = calccost (curY, curX, row, col, 0);
use = USEREL;
if ((homecost = Wcm.cc_home) < BIG)
homecost += calccost (0, 0, row, col, 0);
if (homecost < relcost)
relcost = homecost, use = USEHOME;
if ((llcost = Wcm.cc_ll) < BIG)
llcost += calccost (Wcm.cm_rows - 1, 0, row, col, 0);
if (llcost < relcost)
relcost = llcost, use = USELL;
if ((crcost = Wcm.cc_cr) < BIG) {
if (Wcm.cm_autolf)
if (curY + 1 >= Wcm.cm_rows)
crcost = BIG;
else
crcost += calccost (curY + 1, 0, row, col, 0);
else
crcost += calccost (curY, 0, row, col, 0);
}
if (crcost < relcost)
relcost = crcost, use = USECR;
directcost = Wcm.cc_abs, dcm = Wcm.cm_abs;
if (row == curY && Wcm.cc_habs < BIG)
directcost = Wcm.cc_habs, dcm = Wcm.cm_habs;
else if (col == curX && Wcm.cc_vabs < BIG)
directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs;
/*
* In the following comparison, the = in <= is because when the costs
* are the same, it looks nicer (I think) to move directly there.
*/
if (directcost <= relcost) {
/* compute REAL direct cost */
cost = 0;
p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) :
tgoto (dcm, col, row);
tputs (p, 1, evalcost);
if (cost <= relcost) { /* really is cheaper */
tputs (p, 1, put);
curY = row, curX = col;
return;
}
}
switch (use) {
case USEHOME:
tputs (Wcm.cm_home, 1, put);
curY = 0, curX = 0;
break;
case USELL:
tputs (Wcm.cm_ll, 1, put);
curY = Wcm.cm_rows - 1, curX = 0;
break;
case USECR:
tputs (Wcm.cm_cr, 1, put);
if (Wcm.cm_autolf)
curY++;
curX = 0;
break;
}
calccost (curY, curX, row, col, 1);
curY = row, curX = col;
}
X/*
* Read the interesting things out of termcap
* Return 0 if can do CM.
*/
Wcm_init (fill) char **fill; {
char *p, *term;
Wcm.cx_put = put;
Wcm.cx_costinit = costinit;
Wcm.cx_goto = xgoto;
if (fill == 0) /* assume Wcm stuff is already set up */
goto done;
/*
* If *fill == 0, he has not got the termcap stuff yet, so allocate a
* buffer and set *fill. Otherwise assume he already set everything
* up and we merely have to suck in the capabilities.
*/
if (*fill == 0) {
term = getenv ("TERM");
if (!term)
return -1;
/*
* Magic constants, yucko! Termcap should have #defines
* for these.
*/
p = malloc (2048);
if (!p)
return -1;
if (tgetent (&p[1024], term) <= 0) {
free (p);
return -1;
}
*fill = p;
}
if (tgetflag ("bs"))
Wcm.cm_left = "\b";
else
Wcm.cm_left = tgetstr ("bc", fill);
Wcm.cm_up = tgetstr ("up", fill);
Wcm.cm_down = tgetstr ("nl", fill);
Wcm.cm_right = tgetstr ("nd", fill);
Wcm.cm_home = tgetstr ("ho", fill);
Wcm.cm_cr = tgetstr ("cr", fill);
Wcm.cm_ll = tgetstr ("ll", fill);
Wcm.cm_abs = tgetstr ("cm", fill);
Wcm.cm_habs = tgetstr ("ch", fill);
Wcm.cm_vabs = tgetstr ("cv", fill);
Wcm.cm_tab = tgetstr ("ta", fill);
Wcm.cm_tabwidth = tgetnum ("tw");
if (Wcm.cm_tabwidth < 0)
Wcm.cm_tabwidth = 8;
Wcm.cm_cols = tgetnum ("co");
Wcm.cm_rows = tgetnum ("li");
Wcm.cm_autowrap = tgetflag ("am");
Wcm.cm_magicwrap = tgetflag ("xn");
Wcm.cm_autolf = tgetflag ("rn");
#define DEFAULT(x,y) if (!x) x = y
DEFAULT (Wcm.cm_down, "\n");
DEFAULT (Wcm.cm_cr, "\r");
DEFAULT (Wcm.cm_tab, "\t");
#undef DEFAULT
if (tgetflag ("nc"))
Wcm.cm_cr = 0;
if (tgetflag ("nn"))
Wcm.cm_down = 0;
if (tgetflag ("xt"))
Wcm.cm_tab = 0;
p = tgetstr ("pc", fill);
if (p)
PC = *p;
done:
/* Check that we know the size of the screen.... */
if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0)
return -1;
/* Require up and left, and, if no absolute, down and right */
if (!Wcm.cm_up || !Wcm.cm_left)
return -1;
if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right))
return -1;
return 0;
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 floop/cm.c
/bin/echo -n ' '; /bin/ls -ld floop/cm.c
fi
/bin/echo 'Extracting floop/cm.h'
sed 's/^X//' <<'//go.sysin dd *' >floop/cm.h
X/* Copyright (c) 1985 University of Maryland Computer Science Department */
X/*
* This structure holds everything needed to do cursor motion except the pad
* character (PC) and the output speed of the terminal (ospeed), which
* termcap wants in global variables.
*/
struct cm {
/* Cursor position */
int cm_curY, /* current row */
cm_curX; /* current column */
/* Capabilities from termcap(5) (including extensions) */
char *cm_up, /* up (up) */
*cm_down, /* down (do) */
*cm_left, /* left (bs) */
*cm_right, /* right (nd) */
*cm_home, /* home (ho) */
*cm_cr, /* carriage return (cr) */
*cm_ll, /* last line (ll) */
*cm_abs, /* absolute (cm) */
*cm_habs, /* horizontal absolute (ch) */
*cm_vabs, /* vertical absolute (cv) */
*cm_tab; /* tab (ta) */
int cm_tabwidth, /* tab width (tw) */
cm_cols, /* Number of cols on screen (co) */
cm_rows, /* Number of rows on screen (li) */
cm_autowrap:1, /* autowrap flag (am) */
cm_magicwrap:1, /* vt100s: cursor stays in last col but
will wrap if next char is printing (xn) */
cm_usetabs:1, /* if set, use tabs */
cm_autolf:1; /* \r performs a \r\n (rn) */
/* Costs */
int cc_up, /* cost for up */
cc_down, /* etc */
cc_left,
cc_right,
cc_home,
cc_cr,
cc_ll,
cc_abs, /* abs costs are actually min costs */
cc_habs,
cc_vabs,
cc_tab;
/* Functions */
int (*cx_costinit) (),/* initialize cost factors */
(*cx_goto) (), /* (*cx_goto) (row, col) moves cursor to
specified coordinates (0 origin!!) */
(*cx_put) (); /* points to putc function (for tputs) */
} Wcm;
char PC; /* Pad character */
short ospeed; /* Output speed (from sg_ospeed) */
X/* Shorthand */
#ifndef NoCMShortHand
#define curY Wcm.cm_curY
#define curX Wcm.cm_curX
#define Up Wcm.cm_up
#define Down Wcm.cm_down
#define Left Wcm.cm_left
#define Right Wcm.cm_right
#define Home Wcm.cm_home
#define CR Wcm.cm_cr
#define LastLine Wcm.cm_ll
#define Tab Wcm.cm_tab
#define TabWidth Wcm.cm_tabwidth
#define AbsPosition Wcm.cm_abs
#define ColPosition Wcm.cm_habs
#define RowPosition Wcm.cm_vabs
#define AutoWrap Wcm.cm_autowrap
#define MagicWrap Wcm.cm_magicwrap
#define UseTabs Wcm.cm_usetabs
#define AutoLF Wcm.cm_autolf
#define ScreenRows Wcm.cm_rows
#define ScreenCols Wcm.cm_cols
#define cmcostinit() (*Wcm.cx_costinit) ()
#define cmgoto(row,col) (*Wcm.cx_goto) (row, col)
#define cmat(row,col) (curY = (row), curX = (col))
#define cmplus(n) {if ((curX += (n)) >= ScreenCols && !MagicWrap)\
if (AutoWrap) curX = 0, curY++; else curX--;}
#define cmputc Wcm.cx_put
#endif
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 floop/cm.h
/bin/echo -n ' '; /bin/ls -ld floop/cm.h
fi
/bin/echo 'Extracting floop/floop.c'
sed 's/^X//' <<'//go.sysin dd *' >floop/floop.c
X/* Copyright (c) 1985 Computer Science Department University of Maryland */
X/*
* floop
*/
#include <stdio.h>
#include <sgtty.h>
#include <signal.h>
#include "cm.h"
struct sgttyb old;
int in_fd;
char *tgetstr(), *malloc ();
intrup () {
stty (in_fd, &old);
exit (1);
}
main (argc, argv) char **argv; {
register int i, j, line, n, c;
register char *cp;
register int r;
char *p = 0, *cl, *ce, **buf2;
int maxcol = 0, col = 0;
long time (); /* no see */
FILE *fp, *popen ();
struct sgttyb sg2;
if (gtty (in_fd = 0, &old))
gtty (in_fd = 1, &old);
if (Wcm_init (&p) || (cl = tgetstr ("cl", &p)) == 0) {
fprintf (stderr, "terminal too dumb\n");
exit (1);
}
ce = tgetstr ("ce", &p);
if (makebuf (&buf2)) {
fprintf (stderr, "out of memory!\n");
exit (1);
}
fp = in_fd == 0 ? popen ("who", "r") : stdin;
if (fp == NULL) {
fprintf (stderr, "popen(\"who\") failed\n");
exit (1);
}
cp = buf2[0];
line = 0;
r = ScreenRows - 1;
while ((i = getc (fp)) != EOF) {
if (line >= r || col >= ScreenCols)
continue;
if (i == '\n') {
if (col > maxcol)
maxcol = col;
if (++line >= r)
continue;
cp = buf2[line];
col = 0;
}
else if (i == '\t')
col = (col & ~7) + 8;
else
cp[col++] = i;
}
if (col > maxcol)
maxcol = col;
if (maxcol > ScreenCols)
maxcol = ScreenCols;
if (fp != stdin)
pclose (fp);
ospeed = old.sg_ospeed;
if ((old.sg_flags & TBDELAY) == TAB0)
UseTabs = 1;
sg2 = old;
sg2.sg_flags &= ~CRMOD;
signal (SIGINT, intrup);
stty (in_fd, &sg2);
cmcostinit ();
tputs (cl, 1, cmputc);
cmat (0, 0);
srand (time ((long *) 0));
#define rnd() (rand()>>16)
n = 3 * maxcol * line;
while (--n >= 0) {
i = rnd () % line;
j = rnd () % maxcol;
c = buf2[i][j];
if (c == ' ' || c == 0)
continue;
cmgoto (i, j);
putchar (c);
buf2[i][j] = ' ';
cmplus (1);
}
for (i = 0; i < line; i++) {
for (j = 0; j < maxcol; j++) {
c = buf2[i][j];
if (c && c != ' ') {
cmgoto (i, j);
putchar (c);
cmplus (1);
}
}
}
cmgoto (Wcm.cm_rows - 1, 0);
if (ce)
tputs (ce, 1, cmputc);
stty (in_fd, &old);
exit (0);
}
makebuf (bp) char ***bp; {
register char **l, *s;
register int i = ScreenRows - 1;
if ((l = (char **) malloc ((unsigned) i * sizeof (char *))) == 0)
return -1;
*bp = l;
while (--i >= 0) {
if ((*l = malloc ((unsigned) ScreenCols)) == 0)
return -1;
bzero (*l++, (unsigned) ScreenCols);
}
return 0;
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 floop/floop.c
/bin/echo -n ' '; /bin/ls -ld floop/floop.c
fi
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 755 floop
/bin/echo -n ' '; /bin/ls -ld floop
fi
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP: seismo!umcp-cs!chris
CSNet: chris at umcp-cs ARPA: chris at maryland
More information about the Comp.sources.unix
mailing list