133200Sbostic /* 233200Sbostic * Copyright (c) 1980 Regents of the University of California. 333200Sbostic * All rights reserved. 433200Sbostic * 533200Sbostic * Redistribution and use in source and binary forms are permitted 634808Sbostic * provided that the above copyright notice and this paragraph are 734808Sbostic * duplicated in all such forms and that any documentation, 834808Sbostic * advertising materials, and other materials related to such 934808Sbostic * distribution and use acknowledge that the software was developed 1034808Sbostic * by the University of California, Berkeley. The name of the 1134808Sbostic * University may not be used to endorse or promote products derived 1234808Sbostic * from this software without specific prior written permission. 1334808Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434808Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534808Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633200Sbostic */ 1733200Sbostic 1821202Sdist #ifndef lint 1921202Sdist char copyright[] = 2021202Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 2121202Sdist All rights reserved.\n"; 2233200Sbostic #endif /* not lint */ 238873Smckusick 2421202Sdist #ifndef lint 25*38561Sbostic static char sccsid[] = "@(#)worms.c 5.7 (Berkeley) 08/02/89"; 2633200Sbostic #endif /* not lint */ 2721202Sdist 288873Smckusick /* 2933200Sbostic * 3033200Sbostic * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ 3133200Sbostic * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ 3233200Sbostic * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ 3333200Sbostic * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 3433200Sbostic * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 3533200Sbostic * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ 3633200Sbostic * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ 3733200Sbostic * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ 3833200Sbostic * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ 3933200Sbostic * 4033200Sbostic * Eric P. Scott 4133200Sbostic * Caltech High Energy Physics 4233200Sbostic * October, 1980 4333200Sbostic * 4433200Sbostic */ 4533200Sbostic #include <sys/types.h> 468873Smckusick #include <stdio.h> 4723869Smckusick #ifdef USG 4823869Smckusick #include <termio.h> 4923869Smckusick #else 508873Smckusick #include <sgtty.h> 5123869Smckusick #endif 5223869Smckusick #include <signal.h> 5333200Sbostic 5433200Sbostic static struct options { 5533200Sbostic int nopts; 5633200Sbostic int opts[3]; 5733200Sbostic } 5833200Sbostic normal[8] = { 5933200Sbostic { 3, { 7, 0, 1 } }, 6033200Sbostic { 3, { 0, 1, 2 } }, 6133200Sbostic { 3, { 1, 2, 3 } }, 6233200Sbostic { 3, { 2, 3, 4 } }, 6333200Sbostic { 3, { 3, 4, 5 } }, 6433200Sbostic { 3, { 4, 5, 6 } }, 6533200Sbostic { 3, { 5, 6, 7 } }, 6633200Sbostic { 3, { 6, 7, 0 } } 6733200Sbostic }, upper[8] = { 6833200Sbostic { 1, { 1, 0, 0 } }, 6933200Sbostic { 2, { 1, 2, 0 } }, 7033200Sbostic { 0, { 0, 0, 0 } }, 7133200Sbostic { 0, { 0, 0, 0 } }, 7233200Sbostic { 0, { 0, 0, 0 } }, 7333200Sbostic { 2, { 4, 5, 0 } }, 7433200Sbostic { 1, { 5, 0, 0 } }, 7533200Sbostic { 2, { 1, 5, 0 } } 7633200Sbostic }, 7733200Sbostic left[8] = { 7833200Sbostic { 0, { 0, 0, 0 } }, 7933200Sbostic { 0, { 0, 0, 0 } }, 8033200Sbostic { 0, { 0, 0, 0 } }, 8133200Sbostic { 2, { 2, 3, 0 } }, 8233200Sbostic { 1, { 3, 0, 0 } }, 8333200Sbostic { 2, { 3, 7, 0 } }, 8433200Sbostic { 1, { 7, 0, 0 } }, 8533200Sbostic { 2, { 7, 0, 0 } } 8633200Sbostic }, 8733200Sbostic right[8] = { 8833200Sbostic { 1, { 7, 0, 0 } }, 8933200Sbostic { 2, { 3, 7, 0 } }, 9033200Sbostic { 1, { 3, 0, 0 } }, 9133200Sbostic { 2, { 3, 4, 0 } }, 9233200Sbostic { 0, { 0, 0, 0 } }, 9333200Sbostic { 0, { 0, 0, 0 } }, 9433200Sbostic { 0, { 0, 0, 0 } }, 9533200Sbostic { 2, { 6, 7, 0 } } 9633200Sbostic }, 9733200Sbostic lower[8] = { 9833200Sbostic { 0, { 0, 0, 0 } }, 9933200Sbostic { 2, { 0, 1, 0 } }, 10033200Sbostic { 1, { 1, 0, 0 } }, 10133200Sbostic { 2, { 1, 5, 0 } }, 10233200Sbostic { 1, { 5, 0, 0 } }, 10333200Sbostic { 2, { 5, 6, 0 } }, 10433200Sbostic { 0, { 0, 0, 0 } }, 10533200Sbostic { 0, { 0, 0, 0 } } 10633200Sbostic }, 10733200Sbostic upleft[8] = { 10833200Sbostic { 0, { 0, 0, 0 } }, 10933200Sbostic { 0, { 0, 0, 0 } }, 11033200Sbostic { 0, { 0, 0, 0 } }, 11133200Sbostic { 0, { 0, 0, 0 } }, 11233200Sbostic { 0, { 0, 0, 0 } }, 11333200Sbostic { 1, { 3, 0, 0 } }, 11433200Sbostic { 2, { 1, 3, 0 } }, 11533200Sbostic { 1, { 1, 0, 0 } } 11633200Sbostic }, 11733200Sbostic upright[8] = { 11833200Sbostic { 2, { 3, 5, 0 } }, 11933200Sbostic { 1, { 3, 0, 0 } }, 12033200Sbostic { 0, { 0, 0, 0 } }, 12133200Sbostic { 0, { 0, 0, 0 } }, 12233200Sbostic { 0, { 0, 0, 0 } }, 12333200Sbostic { 0, { 0, 0, 0 } }, 12433200Sbostic { 0, { 0, 0, 0 } }, 12533200Sbostic { 1, { 5, 0, 0 } } 12633200Sbostic }, 12733200Sbostic lowleft[8] = { 12833200Sbostic { 3, { 7, 0, 1 } }, 12933200Sbostic { 0, { 0, 0, 0 } }, 13033200Sbostic { 0, { 0, 0, 0 } }, 13133200Sbostic { 1, { 1, 0, 0 } }, 13233200Sbostic { 2, { 1, 7, 0 } }, 13333200Sbostic { 1, { 7, 0, 0 } }, 13433200Sbostic { 0, { 0, 0, 0 } }, 13533200Sbostic { 0, { 0, 0, 0 } } 13633200Sbostic }, 13733200Sbostic lowright[8] = { 13833200Sbostic { 0, { 0, 0, 0 } }, 13933200Sbostic { 1, { 7, 0, 0 } }, 14033200Sbostic { 2, { 5, 7, 0 } }, 14133200Sbostic { 1, { 5, 0, 0 } }, 14233200Sbostic { 0, { 0, 0, 0 } }, 14333200Sbostic { 0, { 0, 0, 0 } }, 14433200Sbostic { 0, { 0, 0, 0 } }, 14533200Sbostic { 0, { 0, 0, 0 } } 1468873Smckusick }; 14733200Sbostic 14833200Sbostic #define cursor(c, r) tputs(tgoto(CM, c, r), 1, fputchar) 14933200Sbostic 150*38561Sbostic char *tcp; 151*38561Sbostic int fputchar(); 15233200Sbostic 15333200Sbostic static char flavor[] = { 15438560Sbostic 'O', '*', '#', '$', '%', '0', '@', '~' 1558873Smckusick }; 15633200Sbostic static short xinc[] = { 15733200Sbostic 1, 1, 1, 0, -1, -1, -1, 0 15833200Sbostic }, yinc[] = { 15933200Sbostic -1, 0, 1, 1, 1, 0, -1, -1 16033200Sbostic }; 16133200Sbostic static struct worm { 16233200Sbostic int orientation, head; 16333200Sbostic short *xpos, *ypos; 16438560Sbostic } *worm; 16533200Sbostic 16633200Sbostic main(argc, argv) 16733200Sbostic int argc; 16833200Sbostic char **argv; 1698873Smckusick { 17033200Sbostic extern int optind; 17133200Sbostic extern short ospeed; 17233200Sbostic extern char *optarg, *UP; 17333200Sbostic register int x, y, h, n; 17433200Sbostic register struct worm *w; 17533200Sbostic register struct options *op; 17633200Sbostic register short *ip; 17733200Sbostic register char *term; 17838560Sbostic int CO, IN, LI, last, bottom, ch, length, number, trail, Wrap; 17938560Sbostic int onsig(); 18033200Sbostic short **ref; 181*38561Sbostic char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR; 18238560Sbostic char *field, tcb[100], *mp, *malloc(), *getenv(), *tgetstr(), *tgoto(); 18333200Sbostic long random(); 18423869Smckusick #ifdef USG 18533200Sbostic struct termio sg; 18623869Smckusick #else 18733200Sbostic struct sgttyb sg; 18823869Smckusick #endif 18933200Sbostic 19033200Sbostic length = 16; 19133200Sbostic number = 3; 19233200Sbostic trail = ' '; 19333200Sbostic field = NULL; 19433200Sbostic while ((ch = getopt(argc, argv, "fl:n:t")) != EOF) 19538560Sbostic switch(ch) { 19633200Sbostic case 'f': 19733200Sbostic field = "WORM"; 19833200Sbostic break; 19933200Sbostic case 'l': 20033200Sbostic if ((length = atoi(optarg)) < 2 || length > 1024) { 20138560Sbostic (void)fprintf(stderr, 20238560Sbostic "worms: invalid length (%d - %d).\n", 20338560Sbostic 2, 1024); 20433200Sbostic exit(1); 20533200Sbostic } 20633200Sbostic break; 20733200Sbostic case 'n': 20838560Sbostic if ((number = atoi(optarg)) < 1) { 20938560Sbostic (void)fprintf(stderr, 21038560Sbostic "worms: invalid number of worms.\n"); 21133200Sbostic exit(1); 21233200Sbostic } 21333200Sbostic break; 21433200Sbostic case 't': 21533200Sbostic trail = '.'; 21633200Sbostic break; 21733200Sbostic case '?': 21833200Sbostic default: 21938560Sbostic (void)fprintf(stderr, 22038560Sbostic "usage: worms [-ft] [-length #] [-number #]\n"); 22133200Sbostic exit(1); 22233200Sbostic } 22333200Sbostic 22433200Sbostic if (!(term = getenv("TERM"))) { 22538560Sbostic (void)fprintf(stderr, "worms: no TERM environment variable.\n"); 2268873Smckusick exit(1); 22733200Sbostic } 22838560Sbostic if (!(worm = (struct worm *)malloc((u_int)number * 22938560Sbostic sizeof(struct worm))) || !(mp = malloc((u_int)1024))) 23038560Sbostic nomem(); 23133200Sbostic if (tgetent(mp, term) <= 0) { 23238560Sbostic (void)fprintf(stderr, "worms: %s: unknown terminal type.\n", 23338560Sbostic term); 23433200Sbostic exit(1); 23533200Sbostic } 23633200Sbostic tcp = tcb; 23733200Sbostic if (!(CM = tgetstr("cm", &tcp))) { 23838560Sbostic (void)fprintf(stderr, 23938560Sbostic "worms: terminal incapable of cursor motion.\n"); 24033200Sbostic exit(1); 24133200Sbostic } 24233200Sbostic AL = tgetstr("al", &tcp); 24333200Sbostic BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp); 24433200Sbostic if ((CO = tgetnum("co")) <= 0) 24533200Sbostic CO = 80; 24633200Sbostic last = CO - 1; 24733200Sbostic EI = tgetstr("ei", &tcp); 24833200Sbostic HO = tgetstr("ho", &tcp); 24933200Sbostic IC = tgetstr("ic", &tcp); 25033200Sbostic IM = tgetstr("im", &tcp); 25133200Sbostic IN = tgetflag("in"); 25233200Sbostic IP = tgetstr("ip", &tcp); 25333200Sbostic if ((LI = tgetnum("li")) <= 0) 25433200Sbostic LI = 24; 25533200Sbostic bottom = LI - 1; 25633200Sbostic SR = tgetstr("sr", &tcp); 25733200Sbostic UP = tgetstr("up", &tcp); 25823869Smckusick #ifdef USG 25933200Sbostic ioctl(1, TCGETA, &sg); 26033200Sbostic ospeed = sg.c_cflag&CBAUD; 26123869Smckusick #else 26233200Sbostic gtty(1, &sg); 26333200Sbostic ospeed = sg.sg_ospeed; 26423869Smckusick #endif 26533200Sbostic Wrap = tgetflag("am"); 26638560Sbostic if (!(ip = (short *)malloc((u_int)(LI * CO * sizeof(short))))) 26738560Sbostic nomem(); 26838560Sbostic if (!(ref = (short **)malloc((u_int)(LI * sizeof(short *))))) 26938560Sbostic nomem(); 27033200Sbostic for (n = 0; n < LI; ++n) { 27133200Sbostic ref[n] = ip; 27233200Sbostic ip += CO; 27333200Sbostic } 27433200Sbostic for (ip = ref[0], n = LI * CO; --n >= 0;) 27533200Sbostic *ip++ = 0; 27633200Sbostic if (Wrap) 27733200Sbostic ref[bottom][last] = 1; 27833200Sbostic for (n = number, w = &worm[0]; --n >= 0; w++) { 27933200Sbostic w->orientation = w->head = 0; 28038560Sbostic if (!(ip = (short *)malloc((u_int)(length * sizeof(short))))) 28138560Sbostic nomem(); 28233200Sbostic w->xpos = ip; 28333200Sbostic for (x = length; --x >= 0;) 28433200Sbostic *ip++ = -1; 28538560Sbostic if (!(ip = (short *)malloc((u_int)(length * sizeof(short))))) 28638560Sbostic nomem(); 28733200Sbostic w->ypos = ip; 28833200Sbostic for (y = length; --y >= 0;) 28933200Sbostic *ip++ = -1; 2908873Smckusick } 29133200Sbostic 29233200Sbostic (void)signal(SIGHUP, onsig); 29333200Sbostic (void)signal(SIGINT, onsig); 29433200Sbostic (void)signal(SIGQUIT, onsig); 29533200Sbostic (void)signal(SIGSTOP, onsig); 29633200Sbostic (void)signal(SIGTSTP, onsig); 29733200Sbostic (void)signal(SIGTERM, onsig); 29833200Sbostic 29933200Sbostic tputs(tgetstr("ti", &tcp), 1, fputchar); 30033200Sbostic tputs(tgetstr("cl", &tcp), 1, fputchar); 30133200Sbostic if (field) { 30233200Sbostic register char *p = field; 30333200Sbostic 30433200Sbostic for (y = bottom; --y >= 0;) { 30533200Sbostic for (x = CO; --x >= 0;) { 30633200Sbostic fputchar(*p++); 30733200Sbostic if (!*p) 30833200Sbostic p = field; 30933200Sbostic } 31033200Sbostic if (!Wrap) 31133200Sbostic fputchar('\n'); 31233200Sbostic (void)fflush(stdout); 31333200Sbostic } 31433200Sbostic if (Wrap) { 31533200Sbostic if (IM && !IN) { 31633200Sbostic for (x = last; --x > 0;) { 31733200Sbostic fputchar(*p++); 31833200Sbostic if (!*p) 31933200Sbostic p = field; 32033200Sbostic } 32133200Sbostic y = *p++; 32233200Sbostic if (!*p) 32333200Sbostic p = field; 32433200Sbostic fputchar(*p); 32533200Sbostic if (BC) 32633200Sbostic tputs(BC, 1, fputchar); 32733200Sbostic else 32833200Sbostic cursor(last - 1, bottom); 32933200Sbostic tputs(IM, 1, fputchar); 33033200Sbostic if (IC) 33133200Sbostic tputs(IC, 1, fputchar); 33233200Sbostic fputchar(y); 33333200Sbostic if (IP) 33433200Sbostic tputs(IP, 1, fputchar); 33533200Sbostic tputs(EI, 1, fputchar); 33633200Sbostic } 33733200Sbostic else if (SR || AL) { 33833200Sbostic if (HO) 33933200Sbostic tputs(HO, 1, fputchar); 34033200Sbostic else 34133200Sbostic cursor(0, 0); 34233200Sbostic if (SR) 34333200Sbostic tputs(SR, 1, fputchar); 34433200Sbostic else 34533200Sbostic tputs(AL, LI, fputchar); 34633200Sbostic for (x = CO; --x >= 0;) { 34733200Sbostic fputchar(*p++); 34833200Sbostic if (!*p) 34933200Sbostic p = field; 35033200Sbostic } 35133200Sbostic } 35233200Sbostic else for (x = last; --x >= 0;) { 35333200Sbostic fputchar(*p++); 35433200Sbostic if (!*p) 35533200Sbostic p = field; 35633200Sbostic } 35733200Sbostic } 35833200Sbostic else for (x = CO; --x >= 0;) { 35933200Sbostic fputchar(*p++); 36033200Sbostic if (!*p) 36133200Sbostic p = field; 36233200Sbostic } 3638873Smckusick } 36433200Sbostic for (;;) { 36533200Sbostic (void)fflush(stdout); 36633200Sbostic for (n = 0, w = &worm[0]; n < number; n++, w++) { 36733200Sbostic if ((x = w->xpos[h = w->head]) < 0) { 36833200Sbostic cursor(x = w->xpos[h] = 0, 36933200Sbostic y = w->ypos[h] = bottom); 370*38561Sbostic fputchar(flavor[n % sizeof(flavor)]); 37133200Sbostic ref[y][x]++; 37233200Sbostic } 37333200Sbostic else 37433200Sbostic y = w->ypos[h]; 37533200Sbostic if (++h == length) 37633200Sbostic h = 0; 37733200Sbostic if (w->xpos[w->head = h] >= 0) { 37833200Sbostic register int x1, y1; 37933200Sbostic 38033200Sbostic x1 = w->xpos[h]; 38133200Sbostic y1 = w->ypos[h]; 38233200Sbostic if (--ref[y1][x1] == 0) { 38333200Sbostic cursor(x1, y1); 38433200Sbostic if (trail) 38533200Sbostic fputchar(trail); 38633200Sbostic } 38733200Sbostic } 38833200Sbostic op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation]; 38933200Sbostic switch (op->nopts) { 39033200Sbostic case 0: 39133200Sbostic (void)fflush(stdout); 39233200Sbostic abort(); 39333200Sbostic return; 39433200Sbostic case 1: 39533200Sbostic w->orientation = op->opts[0]; 39633200Sbostic break; 39733200Sbostic default: 39838560Sbostic w->orientation = 39938560Sbostic op->opts[(int)random() % op->nopts]; 40033200Sbostic } 40138560Sbostic cursor(x += xinc[w->orientation], 40238560Sbostic y += yinc[w->orientation]); 40333200Sbostic if (!Wrap || x != last || y != bottom) 404*38561Sbostic fputchar(flavor[n % sizeof(flavor)]); 40533200Sbostic ref[w->ypos[h] = y][w->xpos[h] = x]++; 4068873Smckusick } 4078873Smckusick } 4088873Smckusick } 40933200Sbostic 41033200Sbostic onsig() 41123869Smckusick { 412*38561Sbostic tputs(tgetstr("cl", &tcp), 1, fputchar); 413*38561Sbostic tputs(tgetstr("te", &tcp), 1, fputchar); 41433200Sbostic exit(0); 41523869Smckusick } 41633200Sbostic 4178873Smckusick fputchar(c) 41833200Sbostic char c; 4198873Smckusick { 42033200Sbostic putchar(c); 4218873Smckusick } 42238560Sbostic 42338560Sbostic nomem() 42438560Sbostic { 42538560Sbostic (void)fprintf(stderr, "worms: not enough memory.\n"); 42638560Sbostic exit(1); 42738560Sbostic } 428