chris@umcp-cs.UUCP (Chris Torek) (07/09/85)
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@umcp-cs ARPA: chris@maryland