133200Sbostic /* 233200Sbostic * Copyright (c) 1980 Regents of the University of California. 333200Sbostic * All rights reserved. 433200Sbostic * 542608Sbostic * %sccs.include.redist.c% 633200Sbostic */ 733200Sbostic 821202Sdist #ifndef lint 921202Sdist char copyright[] = 1021202Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1121202Sdist All rights reserved.\n"; 1233200Sbostic #endif /* not lint */ 138873Smckusick 1421202Sdist #ifndef lint 15*46770Sbostic static char sccsid[] = "@(#)worms.c 5.9 (Berkeley) 02/28/91"; 1633200Sbostic #endif /* not lint */ 1721202Sdist 188873Smckusick /* 1933200Sbostic * 2033200Sbostic * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ 2133200Sbostic * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ 2233200Sbostic * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ 2333200Sbostic * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 2433200Sbostic * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 2533200Sbostic * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ 2633200Sbostic * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ 2733200Sbostic * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ 2833200Sbostic * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ 2933200Sbostic * 3033200Sbostic * Eric P. Scott 3133200Sbostic * Caltech High Energy Physics 3233200Sbostic * October, 1980 3333200Sbostic * 3433200Sbostic */ 3533200Sbostic #include <sys/types.h> 368873Smckusick #include <stdio.h> 3723869Smckusick #ifdef USG 3823869Smckusick #include <termio.h> 3923869Smckusick #else 408873Smckusick #include <sgtty.h> 4123869Smckusick #endif 4223869Smckusick #include <signal.h> 4333200Sbostic 4433200Sbostic static struct options { 4533200Sbostic int nopts; 4633200Sbostic int opts[3]; 4733200Sbostic } 4833200Sbostic normal[8] = { 4933200Sbostic { 3, { 7, 0, 1 } }, 5033200Sbostic { 3, { 0, 1, 2 } }, 5133200Sbostic { 3, { 1, 2, 3 } }, 5233200Sbostic { 3, { 2, 3, 4 } }, 5333200Sbostic { 3, { 3, 4, 5 } }, 5433200Sbostic { 3, { 4, 5, 6 } }, 5533200Sbostic { 3, { 5, 6, 7 } }, 5633200Sbostic { 3, { 6, 7, 0 } } 5733200Sbostic }, upper[8] = { 5833200Sbostic { 1, { 1, 0, 0 } }, 5933200Sbostic { 2, { 1, 2, 0 } }, 6033200Sbostic { 0, { 0, 0, 0 } }, 6133200Sbostic { 0, { 0, 0, 0 } }, 6233200Sbostic { 0, { 0, 0, 0 } }, 6333200Sbostic { 2, { 4, 5, 0 } }, 6433200Sbostic { 1, { 5, 0, 0 } }, 6533200Sbostic { 2, { 1, 5, 0 } } 6633200Sbostic }, 6733200Sbostic left[8] = { 6833200Sbostic { 0, { 0, 0, 0 } }, 6933200Sbostic { 0, { 0, 0, 0 } }, 7033200Sbostic { 0, { 0, 0, 0 } }, 7133200Sbostic { 2, { 2, 3, 0 } }, 7233200Sbostic { 1, { 3, 0, 0 } }, 7333200Sbostic { 2, { 3, 7, 0 } }, 7433200Sbostic { 1, { 7, 0, 0 } }, 7533200Sbostic { 2, { 7, 0, 0 } } 7633200Sbostic }, 7733200Sbostic right[8] = { 7833200Sbostic { 1, { 7, 0, 0 } }, 7933200Sbostic { 2, { 3, 7, 0 } }, 8033200Sbostic { 1, { 3, 0, 0 } }, 8133200Sbostic { 2, { 3, 4, 0 } }, 8233200Sbostic { 0, { 0, 0, 0 } }, 8333200Sbostic { 0, { 0, 0, 0 } }, 8433200Sbostic { 0, { 0, 0, 0 } }, 8533200Sbostic { 2, { 6, 7, 0 } } 8633200Sbostic }, 8733200Sbostic lower[8] = { 8833200Sbostic { 0, { 0, 0, 0 } }, 8933200Sbostic { 2, { 0, 1, 0 } }, 9033200Sbostic { 1, { 1, 0, 0 } }, 9133200Sbostic { 2, { 1, 5, 0 } }, 9233200Sbostic { 1, { 5, 0, 0 } }, 9333200Sbostic { 2, { 5, 6, 0 } }, 9433200Sbostic { 0, { 0, 0, 0 } }, 9533200Sbostic { 0, { 0, 0, 0 } } 9633200Sbostic }, 9733200Sbostic upleft[8] = { 9833200Sbostic { 0, { 0, 0, 0 } }, 9933200Sbostic { 0, { 0, 0, 0 } }, 10033200Sbostic { 0, { 0, 0, 0 } }, 10133200Sbostic { 0, { 0, 0, 0 } }, 10233200Sbostic { 0, { 0, 0, 0 } }, 10333200Sbostic { 1, { 3, 0, 0 } }, 10433200Sbostic { 2, { 1, 3, 0 } }, 10533200Sbostic { 1, { 1, 0, 0 } } 10633200Sbostic }, 10733200Sbostic upright[8] = { 10833200Sbostic { 2, { 3, 5, 0 } }, 10933200Sbostic { 1, { 3, 0, 0 } }, 11033200Sbostic { 0, { 0, 0, 0 } }, 11133200Sbostic { 0, { 0, 0, 0 } }, 11233200Sbostic { 0, { 0, 0, 0 } }, 11333200Sbostic { 0, { 0, 0, 0 } }, 11433200Sbostic { 0, { 0, 0, 0 } }, 11533200Sbostic { 1, { 5, 0, 0 } } 11633200Sbostic }, 11733200Sbostic lowleft[8] = { 11833200Sbostic { 3, { 7, 0, 1 } }, 11933200Sbostic { 0, { 0, 0, 0 } }, 12033200Sbostic { 0, { 0, 0, 0 } }, 12133200Sbostic { 1, { 1, 0, 0 } }, 12233200Sbostic { 2, { 1, 7, 0 } }, 12333200Sbostic { 1, { 7, 0, 0 } }, 12433200Sbostic { 0, { 0, 0, 0 } }, 12533200Sbostic { 0, { 0, 0, 0 } } 12633200Sbostic }, 12733200Sbostic lowright[8] = { 12833200Sbostic { 0, { 0, 0, 0 } }, 12933200Sbostic { 1, { 7, 0, 0 } }, 13033200Sbostic { 2, { 5, 7, 0 } }, 13133200Sbostic { 1, { 5, 0, 0 } }, 13233200Sbostic { 0, { 0, 0, 0 } }, 13333200Sbostic { 0, { 0, 0, 0 } }, 13433200Sbostic { 0, { 0, 0, 0 } }, 13533200Sbostic { 0, { 0, 0, 0 } } 1368873Smckusick }; 13733200Sbostic 13833200Sbostic #define cursor(c, r) tputs(tgoto(CM, c, r), 1, fputchar) 13933200Sbostic 14038561Sbostic char *tcp; 14138561Sbostic int fputchar(); 14233200Sbostic 14333200Sbostic static char flavor[] = { 14438560Sbostic 'O', '*', '#', '$', '%', '0', '@', '~' 1458873Smckusick }; 14633200Sbostic static short xinc[] = { 14733200Sbostic 1, 1, 1, 0, -1, -1, -1, 0 14833200Sbostic }, yinc[] = { 14933200Sbostic -1, 0, 1, 1, 1, 0, -1, -1 15033200Sbostic }; 15133200Sbostic static struct worm { 15233200Sbostic int orientation, head; 15333200Sbostic short *xpos, *ypos; 15438560Sbostic } *worm; 15533200Sbostic 15633200Sbostic main(argc, argv) 15733200Sbostic int argc; 15833200Sbostic char **argv; 1598873Smckusick { 16033200Sbostic extern int optind; 16133200Sbostic extern short ospeed; 16233200Sbostic extern char *optarg, *UP; 16333200Sbostic register int x, y, h, n; 16433200Sbostic register struct worm *w; 16533200Sbostic register struct options *op; 16633200Sbostic register short *ip; 16733200Sbostic register char *term; 16838560Sbostic int CO, IN, LI, last, bottom, ch, length, number, trail, Wrap; 169*46770Sbostic void onsig(); 17033200Sbostic short **ref; 17138561Sbostic char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR; 17238560Sbostic char *field, tcb[100], *mp, *malloc(), *getenv(), *tgetstr(), *tgoto(); 17333200Sbostic long random(); 17423869Smckusick #ifdef USG 17533200Sbostic struct termio sg; 17623869Smckusick #else 17733200Sbostic struct sgttyb sg; 17823869Smckusick #endif 17933200Sbostic 18033200Sbostic length = 16; 18133200Sbostic number = 3; 18233200Sbostic trail = ' '; 18333200Sbostic field = NULL; 18433200Sbostic while ((ch = getopt(argc, argv, "fl:n:t")) != EOF) 18538560Sbostic switch(ch) { 18633200Sbostic case 'f': 18733200Sbostic field = "WORM"; 18833200Sbostic break; 18933200Sbostic case 'l': 19033200Sbostic if ((length = atoi(optarg)) < 2 || length > 1024) { 19138560Sbostic (void)fprintf(stderr, 19238560Sbostic "worms: invalid length (%d - %d).\n", 19338560Sbostic 2, 1024); 19433200Sbostic exit(1); 19533200Sbostic } 19633200Sbostic break; 19733200Sbostic case 'n': 19838560Sbostic if ((number = atoi(optarg)) < 1) { 19938560Sbostic (void)fprintf(stderr, 20038560Sbostic "worms: invalid number of worms.\n"); 20133200Sbostic exit(1); 20233200Sbostic } 20333200Sbostic break; 20433200Sbostic case 't': 20533200Sbostic trail = '.'; 20633200Sbostic break; 20733200Sbostic case '?': 20833200Sbostic default: 20938560Sbostic (void)fprintf(stderr, 21038560Sbostic "usage: worms [-ft] [-length #] [-number #]\n"); 21133200Sbostic exit(1); 21233200Sbostic } 21333200Sbostic 21433200Sbostic if (!(term = getenv("TERM"))) { 21538560Sbostic (void)fprintf(stderr, "worms: no TERM environment variable.\n"); 2168873Smckusick exit(1); 21733200Sbostic } 21838560Sbostic if (!(worm = (struct worm *)malloc((u_int)number * 21938560Sbostic sizeof(struct worm))) || !(mp = malloc((u_int)1024))) 22038560Sbostic nomem(); 22133200Sbostic if (tgetent(mp, term) <= 0) { 22238560Sbostic (void)fprintf(stderr, "worms: %s: unknown terminal type.\n", 22338560Sbostic term); 22433200Sbostic exit(1); 22533200Sbostic } 22633200Sbostic tcp = tcb; 22733200Sbostic if (!(CM = tgetstr("cm", &tcp))) { 22838560Sbostic (void)fprintf(stderr, 22938560Sbostic "worms: terminal incapable of cursor motion.\n"); 23033200Sbostic exit(1); 23133200Sbostic } 23233200Sbostic AL = tgetstr("al", &tcp); 23333200Sbostic BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp); 23433200Sbostic if ((CO = tgetnum("co")) <= 0) 23533200Sbostic CO = 80; 23633200Sbostic last = CO - 1; 23733200Sbostic EI = tgetstr("ei", &tcp); 23833200Sbostic HO = tgetstr("ho", &tcp); 23933200Sbostic IC = tgetstr("ic", &tcp); 24033200Sbostic IM = tgetstr("im", &tcp); 24133200Sbostic IN = tgetflag("in"); 24233200Sbostic IP = tgetstr("ip", &tcp); 24333200Sbostic if ((LI = tgetnum("li")) <= 0) 24433200Sbostic LI = 24; 24533200Sbostic bottom = LI - 1; 24633200Sbostic SR = tgetstr("sr", &tcp); 24733200Sbostic UP = tgetstr("up", &tcp); 24823869Smckusick #ifdef USG 24933200Sbostic ioctl(1, TCGETA, &sg); 25033200Sbostic ospeed = sg.c_cflag&CBAUD; 25123869Smckusick #else 25233200Sbostic gtty(1, &sg); 25333200Sbostic ospeed = sg.sg_ospeed; 25423869Smckusick #endif 25533200Sbostic Wrap = tgetflag("am"); 25638560Sbostic if (!(ip = (short *)malloc((u_int)(LI * CO * sizeof(short))))) 25738560Sbostic nomem(); 25838560Sbostic if (!(ref = (short **)malloc((u_int)(LI * sizeof(short *))))) 25938560Sbostic nomem(); 26033200Sbostic for (n = 0; n < LI; ++n) { 26133200Sbostic ref[n] = ip; 26233200Sbostic ip += CO; 26333200Sbostic } 26433200Sbostic for (ip = ref[0], n = LI * CO; --n >= 0;) 26533200Sbostic *ip++ = 0; 26633200Sbostic if (Wrap) 26733200Sbostic ref[bottom][last] = 1; 26833200Sbostic for (n = number, w = &worm[0]; --n >= 0; w++) { 26933200Sbostic w->orientation = w->head = 0; 27038560Sbostic if (!(ip = (short *)malloc((u_int)(length * sizeof(short))))) 27138560Sbostic nomem(); 27233200Sbostic w->xpos = ip; 27333200Sbostic for (x = length; --x >= 0;) 27433200Sbostic *ip++ = -1; 27538560Sbostic if (!(ip = (short *)malloc((u_int)(length * sizeof(short))))) 27638560Sbostic nomem(); 27733200Sbostic w->ypos = ip; 27833200Sbostic for (y = length; --y >= 0;) 27933200Sbostic *ip++ = -1; 2808873Smckusick } 28133200Sbostic 28233200Sbostic (void)signal(SIGHUP, onsig); 28333200Sbostic (void)signal(SIGINT, onsig); 28433200Sbostic (void)signal(SIGQUIT, onsig); 28533200Sbostic (void)signal(SIGSTOP, onsig); 28633200Sbostic (void)signal(SIGTSTP, onsig); 28733200Sbostic (void)signal(SIGTERM, onsig); 28833200Sbostic 28933200Sbostic tputs(tgetstr("ti", &tcp), 1, fputchar); 29033200Sbostic tputs(tgetstr("cl", &tcp), 1, fputchar); 29133200Sbostic if (field) { 29233200Sbostic register char *p = field; 29333200Sbostic 29433200Sbostic for (y = bottom; --y >= 0;) { 29533200Sbostic for (x = CO; --x >= 0;) { 29633200Sbostic fputchar(*p++); 29733200Sbostic if (!*p) 29833200Sbostic p = field; 29933200Sbostic } 30033200Sbostic if (!Wrap) 30133200Sbostic fputchar('\n'); 30233200Sbostic (void)fflush(stdout); 30333200Sbostic } 30433200Sbostic if (Wrap) { 30533200Sbostic if (IM && !IN) { 30633200Sbostic for (x = last; --x > 0;) { 30733200Sbostic fputchar(*p++); 30833200Sbostic if (!*p) 30933200Sbostic p = field; 31033200Sbostic } 31133200Sbostic y = *p++; 31233200Sbostic if (!*p) 31333200Sbostic p = field; 31433200Sbostic fputchar(*p); 31533200Sbostic if (BC) 31633200Sbostic tputs(BC, 1, fputchar); 31733200Sbostic else 31833200Sbostic cursor(last - 1, bottom); 31933200Sbostic tputs(IM, 1, fputchar); 32033200Sbostic if (IC) 32133200Sbostic tputs(IC, 1, fputchar); 32233200Sbostic fputchar(y); 32333200Sbostic if (IP) 32433200Sbostic tputs(IP, 1, fputchar); 32533200Sbostic tputs(EI, 1, fputchar); 32633200Sbostic } 32733200Sbostic else if (SR || AL) { 32833200Sbostic if (HO) 32933200Sbostic tputs(HO, 1, fputchar); 33033200Sbostic else 33133200Sbostic cursor(0, 0); 33233200Sbostic if (SR) 33333200Sbostic tputs(SR, 1, fputchar); 33433200Sbostic else 33533200Sbostic tputs(AL, LI, fputchar); 33633200Sbostic for (x = CO; --x >= 0;) { 33733200Sbostic fputchar(*p++); 33833200Sbostic if (!*p) 33933200Sbostic p = field; 34033200Sbostic } 34133200Sbostic } 34233200Sbostic else for (x = last; --x >= 0;) { 34333200Sbostic fputchar(*p++); 34433200Sbostic if (!*p) 34533200Sbostic p = field; 34633200Sbostic } 34733200Sbostic } 34833200Sbostic else for (x = CO; --x >= 0;) { 34933200Sbostic fputchar(*p++); 35033200Sbostic if (!*p) 35133200Sbostic p = field; 35233200Sbostic } 3538873Smckusick } 35433200Sbostic for (;;) { 35533200Sbostic (void)fflush(stdout); 35633200Sbostic for (n = 0, w = &worm[0]; n < number; n++, w++) { 35733200Sbostic if ((x = w->xpos[h = w->head]) < 0) { 35833200Sbostic cursor(x = w->xpos[h] = 0, 35933200Sbostic y = w->ypos[h] = bottom); 36038561Sbostic fputchar(flavor[n % sizeof(flavor)]); 36133200Sbostic ref[y][x]++; 36233200Sbostic } 36333200Sbostic else 36433200Sbostic y = w->ypos[h]; 36533200Sbostic if (++h == length) 36633200Sbostic h = 0; 36733200Sbostic if (w->xpos[w->head = h] >= 0) { 36833200Sbostic register int x1, y1; 36933200Sbostic 37033200Sbostic x1 = w->xpos[h]; 37133200Sbostic y1 = w->ypos[h]; 37233200Sbostic if (--ref[y1][x1] == 0) { 37333200Sbostic cursor(x1, y1); 37433200Sbostic if (trail) 37533200Sbostic fputchar(trail); 37633200Sbostic } 37733200Sbostic } 37833200Sbostic op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation]; 37933200Sbostic switch (op->nopts) { 38033200Sbostic case 0: 38133200Sbostic (void)fflush(stdout); 38233200Sbostic abort(); 38333200Sbostic return; 38433200Sbostic case 1: 38533200Sbostic w->orientation = op->opts[0]; 38633200Sbostic break; 38733200Sbostic default: 38838560Sbostic w->orientation = 38938560Sbostic op->opts[(int)random() % op->nopts]; 39033200Sbostic } 39138560Sbostic cursor(x += xinc[w->orientation], 39238560Sbostic y += yinc[w->orientation]); 39333200Sbostic if (!Wrap || x != last || y != bottom) 39438561Sbostic fputchar(flavor[n % sizeof(flavor)]); 39533200Sbostic ref[w->ypos[h] = y][w->xpos[h] = x]++; 3968873Smckusick } 3978873Smckusick } 3988873Smckusick } 39933200Sbostic 400*46770Sbostic void 40133200Sbostic onsig() 40223869Smckusick { 40338561Sbostic tputs(tgetstr("cl", &tcp), 1, fputchar); 40438561Sbostic tputs(tgetstr("te", &tcp), 1, fputchar); 40533200Sbostic exit(0); 40623869Smckusick } 40733200Sbostic 4088873Smckusick fputchar(c) 40933200Sbostic char c; 4108873Smckusick { 41133200Sbostic putchar(c); 4128873Smckusick } 41338560Sbostic 41438560Sbostic nomem() 41538560Sbostic { 41638560Sbostic (void)fprintf(stderr, "worms: not enough memory.\n"); 41738560Sbostic exit(1); 41838560Sbostic } 419