worms.c revision 1.5
1120492Sfjoe/* $NetBSD: worms.c,v 1.8 1995/04/22 08:09:22 cgd Exp $ */ 2194638Sdelphij 3120492Sfjoe/* 4120492Sfjoe * Copyright (c) 1980, 1993 5120492Sfjoe * The Regents of the University of California. All rights reserved. 6120492Sfjoe * 7120492Sfjoe * Redistribution and use in source and binary forms, with or without 8120492Sfjoe * modification, are permitted provided that the following conditions 9120492Sfjoe * are met: 10120492Sfjoe * 1. Redistributions of source code must retain the above copyright 11120492Sfjoe * notice, this list of conditions and the following disclaimer. 12120492Sfjoe * 2. Redistributions in binary form must reproduce the above copyright 13120492Sfjoe * notice, this list of conditions and the following disclaimer in the 14120492Sfjoe * documentation and/or other materials provided with the distribution. 15120492Sfjoe * 3. All advertising materials mentioning features or use of this software 16120492Sfjoe * must display the following acknowledgement: 17120492Sfjoe * This product includes software developed by the University of 18120492Sfjoe * California, Berkeley and its contributors. 19120492Sfjoe * 4. Neither the name of the University nor the names of its contributors 20120492Sfjoe * may be used to endorse or promote products derived from this software 21120492Sfjoe * without specific prior written permission. 22120492Sfjoe * 23120492Sfjoe * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24120492Sfjoe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25120492Sfjoe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26120492Sfjoe * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27120492Sfjoe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28120492Sfjoe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29120492Sfjoe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30120492Sfjoe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31120492Sfjoe * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32120492Sfjoe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33120492Sfjoe * SUCH DAMAGE. 34120492Sfjoe */ 35120492Sfjoe 36120492Sfjoe#ifndef lint 37120492Sfjoestatic char copyright[] = 38120492Sfjoe"@(#) Copyright (c) 1980, 1993\n\ 39120492Sfjoe The Regents of the University of California. All rights reserved.\n"; 40120492Sfjoe#endif /* not lint */ 41120492Sfjoe 42120492Sfjoe#ifndef lint 43120492Sfjoe#if 0 44120492Sfjoestatic char sccsid[] = "@(#)worms.c 8.1 (Berkeley) 5/31/93"; 45120492Sfjoe#else 46194638Sdelphijstatic char rcsid[] = "$NetBSD: worms.c,v 1.8 1995/04/22 08:09:22 cgd Exp $"; 47194638Sdelphij#endif 48194638Sdelphij#endif /* not lint */ 49120492Sfjoe 50120492Sfjoe/* 51120492Sfjoe * 52120492Sfjoe * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ 53120492Sfjoe * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ 54120492Sfjoe * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ 55194638Sdelphij * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 56194638Sdelphij * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 57120492Sfjoe * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ 58120492Sfjoe * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ 59120492Sfjoe * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ 60120492Sfjoe * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ 61120492Sfjoe * 62120492Sfjoe * Eric P. Scott 63120492Sfjoe * Caltech High Energy Physics 64120492Sfjoe * October, 1980 65146573Simura * 66120492Sfjoe */ 67120492Sfjoe#include <sys/types.h> 68120492Sfjoe#include <sys/ioctl.h> 69146573Simura 70146573Simura#include <signal.h> 71120492Sfjoe#include <stdio.h> 72120492Sfjoe#include <stdlib.h> 73146573Simura#include <termios.h> 74146573Simura#include <unistd.h> 75120492Sfjoe 76120492Sfjoestatic struct options { 77120492Sfjoe int nopts; 78120492Sfjoe int opts[3]; 79120492Sfjoe} 80194638Sdelphij normal[8] = { 81194638Sdelphij { 3, { 7, 0, 1 } }, 82194638Sdelphij { 3, { 0, 1, 2 } }, 83194638Sdelphij { 3, { 1, 2, 3 } }, 84194638Sdelphij { 3, { 2, 3, 4 } }, 85194638Sdelphij { 3, { 3, 4, 5 } }, 86194638Sdelphij { 3, { 4, 5, 6 } }, 87194638Sdelphij { 3, { 5, 6, 7 } }, 88194638Sdelphij { 3, { 6, 7, 0 } } 89194638Sdelphij}, upper[8] = { 90120492Sfjoe { 1, { 1, 0, 0 } }, 91120492Sfjoe { 2, { 1, 2, 0 } }, 92120492Sfjoe { 0, { 0, 0, 0 } }, 93120492Sfjoe { 0, { 0, 0, 0 } }, 94120492Sfjoe { 0, { 0, 0, 0 } }, 95120492Sfjoe { 2, { 4, 5, 0 } }, 96120492Sfjoe { 1, { 5, 0, 0 } }, 97120492Sfjoe { 2, { 1, 5, 0 } } 98120492Sfjoe}, 99120492Sfjoe left[8] = { 100120492Sfjoe { 0, { 0, 0, 0 } }, 101194638Sdelphij { 0, { 0, 0, 0 } }, 102194638Sdelphij { 0, { 0, 0, 0 } }, 103194638Sdelphij { 2, { 2, 3, 0 } }, 104194638Sdelphij { 1, { 3, 0, 0 } }, 105120492Sfjoe { 2, { 3, 7, 0 } }, 106120492Sfjoe { 1, { 7, 0, 0 } }, 107120492Sfjoe { 2, { 7, 0, 0 } } 108120492Sfjoe}, 109120492Sfjoe right[8] = { 110120492Sfjoe { 1, { 7, 0, 0 } }, 111120492Sfjoe { 2, { 3, 7, 0 } }, 112120492Sfjoe { 1, { 3, 0, 0 } }, 113120492Sfjoe { 2, { 3, 4, 0 } }, 114120492Sfjoe { 0, { 0, 0, 0 } }, 115120492Sfjoe { 0, { 0, 0, 0 } }, 116120492Sfjoe { 0, { 0, 0, 0 } }, 117120492Sfjoe { 2, { 6, 7, 0 } } 118123293Sfjoe}, 119120492Sfjoe lower[8] = { 120120492Sfjoe { 0, { 0, 0, 0 } }, 121120492Sfjoe { 2, { 0, 1, 0 } }, 122194638Sdelphij { 1, { 1, 0, 0 } }, 123120492Sfjoe { 2, { 1, 5, 0 } }, 124120492Sfjoe { 1, { 5, 0, 0 } }, 125120492Sfjoe { 2, { 5, 6, 0 } }, 126120492Sfjoe { 0, { 0, 0, 0 } }, 127120492Sfjoe { 0, { 0, 0, 0 } } 128120492Sfjoe}, 129120492Sfjoe upleft[8] = { 130120492Sfjoe { 0, { 0, 0, 0 } }, 131120492Sfjoe { 0, { 0, 0, 0 } }, 132120492Sfjoe { 0, { 0, 0, 0 } }, 133120492Sfjoe { 0, { 0, 0, 0 } }, 134194638Sdelphij { 0, { 0, 0, 0 } }, 135120492Sfjoe { 1, { 3, 0, 0 } }, 136120492Sfjoe { 2, { 1, 3, 0 } }, 137120492Sfjoe { 1, { 1, 0, 0 } } 138194638Sdelphij}, 139120492Sfjoe upright[8] = { 140120492Sfjoe { 2, { 3, 5, 0 } }, 141120492Sfjoe { 1, { 3, 0, 0 } }, 142120492Sfjoe { 0, { 0, 0, 0 } }, 143194638Sdelphij { 0, { 0, 0, 0 } }, 144120492Sfjoe { 0, { 0, 0, 0 } }, 145120492Sfjoe { 0, { 0, 0, 0 } }, 146120492Sfjoe { 0, { 0, 0, 0 } }, 147194638Sdelphij { 1, { 5, 0, 0 } } 148194638Sdelphij}, 149194638Sdelphij lowleft[8] = { 150194638Sdelphij { 3, { 7, 0, 1 } }, 151194638Sdelphij { 0, { 0, 0, 0 } }, 152194638Sdelphij { 0, { 0, 0, 0 } }, 153194638Sdelphij { 1, { 1, 0, 0 } }, 154194638Sdelphij { 2, { 1, 7, 0 } }, 155194638Sdelphij { 1, { 7, 0, 0 } }, 156194638Sdelphij { 0, { 0, 0, 0 } }, 157194638Sdelphij { 0, { 0, 0, 0 } } 158194638Sdelphij}, 159194638Sdelphij lowright[8] = { 160120492Sfjoe { 0, { 0, 0, 0 } }, 161120492Sfjoe { 1, { 7, 0, 0 } }, 162120492Sfjoe { 2, { 5, 7, 0 } }, 163120492Sfjoe { 1, { 5, 0, 0 } }, 164120492Sfjoe { 0, { 0, 0, 0 } }, 165120492Sfjoe { 0, { 0, 0, 0 } }, 166120492Sfjoe { 0, { 0, 0, 0 } }, 167120492Sfjoe { 0, { 0, 0, 0 } } 168120492Sfjoe}; 169120492Sfjoe 170120492Sfjoe#define cursor(c, r) tputs(tgoto(CM, c, r), 1, fputchar) 171120492Sfjoe 172194638Sdelphijchar *tcp; 173194638Sdelphijstatic char flavor[] = { 174194638Sdelphij 'O', '*', '#', '$', '%', '0', '@', '~' 175194638Sdelphij}; 176194638Sdelphijstatic short xinc[] = { 177194638Sdelphij 1, 1, 1, 0, -1, -1, -1, 0 178194638Sdelphij}, yinc[] = { 179194638Sdelphij -1, 0, 1, 1, 1, 0, -1, -1 180194638Sdelphij}; 181194638Sdelphijstatic struct worm { 182194638Sdelphij int orientation, head; 183194638Sdelphij short *xpos, *ypos; 184194638Sdelphij} *worm; 185194638Sdelphij 186120492Sfjoevoid fputchar __P((int)); 187194638Sdelphijvoid onsig __P((int)); 188194638Sdelphijchar *tgetstr __P((char *, char **)); 189194638Sdelphijchar *tgoto __P((char *, int, int)); 190194638Sdelphijint tputs __P((char *, int, void (*)(int))); 191120492Sfjoe 192120492Sfjoeint 193194638Sdelphijmain(argc, argv) 194194638Sdelphij int argc; 195194638Sdelphij char *argv[]; 196194638Sdelphij{ 197194638Sdelphij extern int optind; 198194638Sdelphij extern char *optarg, *UP; 199123293Sfjoe register int x, y, h, n; 200123293Sfjoe register struct worm *w; 201120492Sfjoe register struct options *op; 202120492Sfjoe register short *ip; 203120492Sfjoe register char *term; 204120492Sfjoe int CO, IN, LI, last, bottom, ch, length, number, trail, Wrap; 205120492Sfjoe short **ref; 206120492Sfjoe char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR; 207120492Sfjoe char *field, tcb[100], *mp; 208120492Sfjoe long random(); 209120492Sfjoe struct termios ti; 210120492Sfjoe#ifdef TIOCGWINSZ 211120492Sfjoe struct winsize ws; 212120492Sfjoe#endif 213120492Sfjoe 214120492Sfjoe /* revoke */ 215120492Sfjoe setegid(getgid()); 216120492Sfjoe setgid(getgid()); 217120492Sfjoe 218120492Sfjoe length = 16; 219120492Sfjoe number = 3; 220120492Sfjoe trail = ' '; 221120492Sfjoe field = NULL; 222120492Sfjoe while ((ch = getopt(argc, argv, "fl:n:t")) != -1) 223120492Sfjoe switch(ch) { 224120492Sfjoe case 'f': 225120492Sfjoe field = "WORM"; 226120492Sfjoe break; 227120492Sfjoe case 'l': 228120492Sfjoe if ((length = atoi(optarg)) < 2 || length > 1024) { 229120492Sfjoe (void)fprintf(stderr, 230120492Sfjoe "worms: invalid length (%d - %d).\n", 231194638Sdelphij 2, 1024); 232194638Sdelphij exit(1); 233194638Sdelphij } 234194638Sdelphij break; 235194638Sdelphij case 'n': 236194638Sdelphij if ((number = atoi(optarg)) < 1) { 237194638Sdelphij (void)fprintf(stderr, 238194638Sdelphij "worms: invalid number of worms.\n"); 239194638Sdelphij exit(1); 240194638Sdelphij } 241194638Sdelphij break; 242194638Sdelphij case 't': 243194638Sdelphij trail = '.'; 244120492Sfjoe break; 245120492Sfjoe case '?': 246120492Sfjoe default: 247120492Sfjoe (void)fprintf(stderr, 248194638Sdelphij "usage: worms [-ft] [-l length] [-n number]\n"); 249194638Sdelphij exit(1); 250194638Sdelphij } 251194638Sdelphij 252194638Sdelphij if (!(term = getenv("TERM"))) { 253194638Sdelphij (void)fprintf(stderr, "worms: no TERM environment variable.\n"); 254194638Sdelphij exit(1); 255194638Sdelphij } 256194638Sdelphij if (!(worm = malloc((size_t)number * 257194638Sdelphij sizeof(struct worm))) || !(mp = malloc((size_t)1024))) 258194638Sdelphij nomem(); 259194638Sdelphij if (tgetent(mp, term) <= 0) { 260194638Sdelphij (void)fprintf(stderr, "worms: %s: unknown terminal type.\n", 261194638Sdelphij term); 262194638Sdelphij exit(1); 263120492Sfjoe } 264120492Sfjoe tcp = tcb; 265120492Sfjoe if (!(CM = tgetstr("cm", &tcp))) { 266120492Sfjoe (void)fprintf(stderr, 267120492Sfjoe "worms: terminal incapable of cursor motion.\n"); 268120492Sfjoe exit(1); 269120492Sfjoe } 270120492Sfjoe AL = tgetstr("al", &tcp); 271123293Sfjoe BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp); 272120492Sfjoe EI = tgetstr("ei", &tcp); 273120492Sfjoe HO = tgetstr("ho", &tcp); 274120492Sfjoe IC = tgetstr("ic", &tcp); 275120492Sfjoe IM = tgetstr("im", &tcp); 276120492Sfjoe IN = tgetflag("in"); 277120492Sfjoe IP = tgetstr("ip", &tcp); 278120492Sfjoe SR = tgetstr("sr", &tcp); 279120492Sfjoe UP = tgetstr("up", &tcp); 280120492Sfjoe#ifdef TIOCGWINSZ 281120492Sfjoe if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) != -1 && 282120492Sfjoe ws.ws_col && ws.ws_row) { 283120492Sfjoe CO = ws.ws_col; 284120492Sfjoe LI = ws.ws_row; 285120492Sfjoe } else 286120492Sfjoe#endif 287120492Sfjoe { 288120492Sfjoe if ((CO = tgetnum("co")) <= 0) 289120492Sfjoe CO = 80; 290120492Sfjoe if ((LI = tgetnum("li")) <= 0) 291120492Sfjoe LI = 24; 292120492Sfjoe } 293120492Sfjoe last = CO - 1; 294120492Sfjoe bottom = LI - 1; 295120492Sfjoe tcgetattr(fileno(stdout), &ti); 296120492Sfjoe Wrap = tgetflag("am"); 297120492Sfjoe if (!(ip = malloc((size_t)(LI * CO * sizeof(short))))) 298120492Sfjoe nomem(); 299120492Sfjoe if (!(ref = malloc((size_t)(LI * sizeof(short *))))) 300194638Sdelphij nomem(); 301319286Sdelphij for (n = 0; n < LI; ++n) { 302194638Sdelphij ref[n] = ip; 303194638Sdelphij ip += CO; 304319286Sdelphij } 305194638Sdelphij for (ip = ref[0], n = LI * CO; --n >= 0;) 306194638Sdelphij *ip++ = 0; 307194638Sdelphij if (Wrap) 308194638Sdelphij ref[bottom][last] = 1; 309194638Sdelphij for (n = number, w = &worm[0]; --n >= 0; w++) { 310194638Sdelphij w->orientation = w->head = 0; 311194638Sdelphij if (!(ip = malloc((size_t)(length * sizeof(short))))) 312194638Sdelphij nomem(); 313194638Sdelphij w->xpos = ip; 314194638Sdelphij for (x = length; --x >= 0;) 315194638Sdelphij *ip++ = -1; 316194638Sdelphij if (!(ip = malloc((size_t)(length * sizeof(short))))) 317194638Sdelphij nomem(); 318194638Sdelphij w->ypos = ip; 319194638Sdelphij for (y = length; --y >= 0;) 320194638Sdelphij *ip++ = -1; 321194638Sdelphij } 322194638Sdelphij 323194638Sdelphij (void)signal(SIGHUP, onsig); 324194638Sdelphij (void)signal(SIGINT, onsig); 325194638Sdelphij (void)signal(SIGQUIT, onsig); 326319286Sdelphij (void)signal(SIGSTOP, onsig); 327194638Sdelphij (void)signal(SIGTSTP, onsig); 328194638Sdelphij (void)signal(SIGTERM, onsig); 329319286Sdelphij 330194638Sdelphij tputs(tgetstr("ti", &tcp), 1, fputchar); 331194638Sdelphij tputs(tgetstr("cl", &tcp), 1, fputchar); 332194638Sdelphij if (field) { 333194638Sdelphij register char *p = field; 334194638Sdelphij 335194638Sdelphij for (y = bottom; --y >= 0;) { 336194638Sdelphij for (x = CO; --x >= 0;) { 337194638Sdelphij fputchar(*p++); 338194638Sdelphij if (!*p) 339194638Sdelphij p = field; 340194638Sdelphij } 341194638Sdelphij if (!Wrap) 342194638Sdelphij fputchar('\n'); 343194638Sdelphij (void)fflush(stdout); 344194638Sdelphij } 345194638Sdelphij if (Wrap) { 346194638Sdelphij if (IM && !IN) { 347194638Sdelphij for (x = last; --x > 0;) { 348194638Sdelphij fputchar(*p++); 349120492Sfjoe if (!*p) 350120492Sfjoe p = field; 351120492Sfjoe } 352120492Sfjoe y = *p++; 353120492Sfjoe if (!*p) 354120492Sfjoe p = field; 355120492Sfjoe fputchar(*p); 356120492Sfjoe if (BC) 357120492Sfjoe tputs(BC, 1, fputchar); 358194638Sdelphij else 359194638Sdelphij cursor(last - 1, bottom); 360120492Sfjoe tputs(IM, 1, fputchar); 361120492Sfjoe if (IC) 362120492Sfjoe tputs(IC, 1, fputchar); 363120492Sfjoe fputchar(y); 364 if (IP) 365 tputs(IP, 1, fputchar); 366 tputs(EI, 1, fputchar); 367 } 368 else if (SR || AL) { 369 if (HO) 370 tputs(HO, 1, fputchar); 371 else 372 cursor(0, 0); 373 if (SR) 374 tputs(SR, 1, fputchar); 375 else 376 tputs(AL, LI, fputchar); 377 for (x = CO; --x >= 0;) { 378 fputchar(*p++); 379 if (!*p) 380 p = field; 381 } 382 } 383 else for (x = last; --x >= 0;) { 384 fputchar(*p++); 385 if (!*p) 386 p = field; 387 } 388 } 389 else for (x = CO; --x >= 0;) { 390 fputchar(*p++); 391 if (!*p) 392 p = field; 393 } 394 } 395 for (;;) { 396 (void)fflush(stdout); 397 for (n = 0, w = &worm[0]; n < number; n++, w++) { 398 if ((x = w->xpos[h = w->head]) < 0) { 399 cursor(x = w->xpos[h] = 0, 400 y = w->ypos[h] = bottom); 401 fputchar(flavor[n % sizeof(flavor)]); 402 ref[y][x]++; 403 } 404 else 405 y = w->ypos[h]; 406 if (++h == length) 407 h = 0; 408 if (w->xpos[w->head = h] >= 0) { 409 register int x1, y1; 410 411 x1 = w->xpos[h]; 412 y1 = w->ypos[h]; 413 if (--ref[y1][x1] == 0) { 414 cursor(x1, y1); 415 if (trail) 416 fputchar(trail); 417 } 418 } 419 op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation]; 420 switch (op->nopts) { 421 case 0: 422 (void)fflush(stdout); 423 abort(); 424 return; 425 case 1: 426 w->orientation = op->opts[0]; 427 break; 428 default: 429 w->orientation = 430 op->opts[(int)random() % op->nopts]; 431 } 432 cursor(x += xinc[w->orientation], 433 y += yinc[w->orientation]); 434 if (!Wrap || x != last || y != bottom) 435 fputchar(flavor[n % sizeof(flavor)]); 436 ref[w->ypos[h] = y][w->xpos[h] = x]++; 437 } 438 } 439} 440 441void 442onsig(signo) 443 int signo; 444{ 445 tputs(tgetstr("cl", &tcp), 1, fputchar); 446 tputs(tgetstr("te", &tcp), 1, fputchar); 447 exit(0); 448} 449 450void 451fputchar(c) 452 int c; 453{ 454 (void)putchar(c); 455} 456 457nomem() 458{ 459 (void)fprintf(stderr, "worms: not enough memory.\n"); 460 exit(1); 461} 462