1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)worms.c 5.9 (Berkeley) 02/28/91"; 16 #endif /* not lint */ 17 18 /* 19 * 20 * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ 21 * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ 22 * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ 23 * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 24 * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 25 * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ 26 * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ 27 * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ 28 * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ 29 * 30 * Eric P. Scott 31 * Caltech High Energy Physics 32 * October, 1980 33 * 34 */ 35 #include <sys/types.h> 36 #include <stdio.h> 37 #ifdef USG 38 #include <termio.h> 39 #else 40 #include <sgtty.h> 41 #endif 42 #include <signal.h> 43 44 static struct options { 45 int nopts; 46 int opts[3]; 47 } 48 normal[8] = { 49 { 3, { 7, 0, 1 } }, 50 { 3, { 0, 1, 2 } }, 51 { 3, { 1, 2, 3 } }, 52 { 3, { 2, 3, 4 } }, 53 { 3, { 3, 4, 5 } }, 54 { 3, { 4, 5, 6 } }, 55 { 3, { 5, 6, 7 } }, 56 { 3, { 6, 7, 0 } } 57 }, upper[8] = { 58 { 1, { 1, 0, 0 } }, 59 { 2, { 1, 2, 0 } }, 60 { 0, { 0, 0, 0 } }, 61 { 0, { 0, 0, 0 } }, 62 { 0, { 0, 0, 0 } }, 63 { 2, { 4, 5, 0 } }, 64 { 1, { 5, 0, 0 } }, 65 { 2, { 1, 5, 0 } } 66 }, 67 left[8] = { 68 { 0, { 0, 0, 0 } }, 69 { 0, { 0, 0, 0 } }, 70 { 0, { 0, 0, 0 } }, 71 { 2, { 2, 3, 0 } }, 72 { 1, { 3, 0, 0 } }, 73 { 2, { 3, 7, 0 } }, 74 { 1, { 7, 0, 0 } }, 75 { 2, { 7, 0, 0 } } 76 }, 77 right[8] = { 78 { 1, { 7, 0, 0 } }, 79 { 2, { 3, 7, 0 } }, 80 { 1, { 3, 0, 0 } }, 81 { 2, { 3, 4, 0 } }, 82 { 0, { 0, 0, 0 } }, 83 { 0, { 0, 0, 0 } }, 84 { 0, { 0, 0, 0 } }, 85 { 2, { 6, 7, 0 } } 86 }, 87 lower[8] = { 88 { 0, { 0, 0, 0 } }, 89 { 2, { 0, 1, 0 } }, 90 { 1, { 1, 0, 0 } }, 91 { 2, { 1, 5, 0 } }, 92 { 1, { 5, 0, 0 } }, 93 { 2, { 5, 6, 0 } }, 94 { 0, { 0, 0, 0 } }, 95 { 0, { 0, 0, 0 } } 96 }, 97 upleft[8] = { 98 { 0, { 0, 0, 0 } }, 99 { 0, { 0, 0, 0 } }, 100 { 0, { 0, 0, 0 } }, 101 { 0, { 0, 0, 0 } }, 102 { 0, { 0, 0, 0 } }, 103 { 1, { 3, 0, 0 } }, 104 { 2, { 1, 3, 0 } }, 105 { 1, { 1, 0, 0 } } 106 }, 107 upright[8] = { 108 { 2, { 3, 5, 0 } }, 109 { 1, { 3, 0, 0 } }, 110 { 0, { 0, 0, 0 } }, 111 { 0, { 0, 0, 0 } }, 112 { 0, { 0, 0, 0 } }, 113 { 0, { 0, 0, 0 } }, 114 { 0, { 0, 0, 0 } }, 115 { 1, { 5, 0, 0 } } 116 }, 117 lowleft[8] = { 118 { 3, { 7, 0, 1 } }, 119 { 0, { 0, 0, 0 } }, 120 { 0, { 0, 0, 0 } }, 121 { 1, { 1, 0, 0 } }, 122 { 2, { 1, 7, 0 } }, 123 { 1, { 7, 0, 0 } }, 124 { 0, { 0, 0, 0 } }, 125 { 0, { 0, 0, 0 } } 126 }, 127 lowright[8] = { 128 { 0, { 0, 0, 0 } }, 129 { 1, { 7, 0, 0 } }, 130 { 2, { 5, 7, 0 } }, 131 { 1, { 5, 0, 0 } }, 132 { 0, { 0, 0, 0 } }, 133 { 0, { 0, 0, 0 } }, 134 { 0, { 0, 0, 0 } }, 135 { 0, { 0, 0, 0 } } 136 }; 137 138 #define cursor(c, r) tputs(tgoto(CM, c, r), 1, fputchar) 139 140 char *tcp; 141 int fputchar(); 142 143 static char flavor[] = { 144 'O', '*', '#', '$', '%', '0', '@', '~' 145 }; 146 static short xinc[] = { 147 1, 1, 1, 0, -1, -1, -1, 0 148 }, yinc[] = { 149 -1, 0, 1, 1, 1, 0, -1, -1 150 }; 151 static struct worm { 152 int orientation, head; 153 short *xpos, *ypos; 154 } *worm; 155 156 main(argc, argv) 157 int argc; 158 char **argv; 159 { 160 extern int optind; 161 extern short ospeed; 162 extern char *optarg, *UP; 163 register int x, y, h, n; 164 register struct worm *w; 165 register struct options *op; 166 register short *ip; 167 register char *term; 168 int CO, IN, LI, last, bottom, ch, length, number, trail, Wrap; 169 void onsig(); 170 short **ref; 171 char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR; 172 char *field, tcb[100], *mp, *malloc(), *getenv(), *tgetstr(), *tgoto(); 173 long random(); 174 #ifdef USG 175 struct termio sg; 176 #else 177 struct sgttyb sg; 178 #endif 179 180 length = 16; 181 number = 3; 182 trail = ' '; 183 field = NULL; 184 while ((ch = getopt(argc, argv, "fl:n:t")) != EOF) 185 switch(ch) { 186 case 'f': 187 field = "WORM"; 188 break; 189 case 'l': 190 if ((length = atoi(optarg)) < 2 || length > 1024) { 191 (void)fprintf(stderr, 192 "worms: invalid length (%d - %d).\n", 193 2, 1024); 194 exit(1); 195 } 196 break; 197 case 'n': 198 if ((number = atoi(optarg)) < 1) { 199 (void)fprintf(stderr, 200 "worms: invalid number of worms.\n"); 201 exit(1); 202 } 203 break; 204 case 't': 205 trail = '.'; 206 break; 207 case '?': 208 default: 209 (void)fprintf(stderr, 210 "usage: worms [-ft] [-length #] [-number #]\n"); 211 exit(1); 212 } 213 214 if (!(term = getenv("TERM"))) { 215 (void)fprintf(stderr, "worms: no TERM environment variable.\n"); 216 exit(1); 217 } 218 if (!(worm = (struct worm *)malloc((u_int)number * 219 sizeof(struct worm))) || !(mp = malloc((u_int)1024))) 220 nomem(); 221 if (tgetent(mp, term) <= 0) { 222 (void)fprintf(stderr, "worms: %s: unknown terminal type.\n", 223 term); 224 exit(1); 225 } 226 tcp = tcb; 227 if (!(CM = tgetstr("cm", &tcp))) { 228 (void)fprintf(stderr, 229 "worms: terminal incapable of cursor motion.\n"); 230 exit(1); 231 } 232 AL = tgetstr("al", &tcp); 233 BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp); 234 if ((CO = tgetnum("co")) <= 0) 235 CO = 80; 236 last = CO - 1; 237 EI = tgetstr("ei", &tcp); 238 HO = tgetstr("ho", &tcp); 239 IC = tgetstr("ic", &tcp); 240 IM = tgetstr("im", &tcp); 241 IN = tgetflag("in"); 242 IP = tgetstr("ip", &tcp); 243 if ((LI = tgetnum("li")) <= 0) 244 LI = 24; 245 bottom = LI - 1; 246 SR = tgetstr("sr", &tcp); 247 UP = tgetstr("up", &tcp); 248 #ifdef USG 249 ioctl(1, TCGETA, &sg); 250 ospeed = sg.c_cflag&CBAUD; 251 #else 252 gtty(1, &sg); 253 ospeed = sg.sg_ospeed; 254 #endif 255 Wrap = tgetflag("am"); 256 if (!(ip = (short *)malloc((u_int)(LI * CO * sizeof(short))))) 257 nomem(); 258 if (!(ref = (short **)malloc((u_int)(LI * sizeof(short *))))) 259 nomem(); 260 for (n = 0; n < LI; ++n) { 261 ref[n] = ip; 262 ip += CO; 263 } 264 for (ip = ref[0], n = LI * CO; --n >= 0;) 265 *ip++ = 0; 266 if (Wrap) 267 ref[bottom][last] = 1; 268 for (n = number, w = &worm[0]; --n >= 0; w++) { 269 w->orientation = w->head = 0; 270 if (!(ip = (short *)malloc((u_int)(length * sizeof(short))))) 271 nomem(); 272 w->xpos = ip; 273 for (x = length; --x >= 0;) 274 *ip++ = -1; 275 if (!(ip = (short *)malloc((u_int)(length * sizeof(short))))) 276 nomem(); 277 w->ypos = ip; 278 for (y = length; --y >= 0;) 279 *ip++ = -1; 280 } 281 282 (void)signal(SIGHUP, onsig); 283 (void)signal(SIGINT, onsig); 284 (void)signal(SIGQUIT, onsig); 285 (void)signal(SIGSTOP, onsig); 286 (void)signal(SIGTSTP, onsig); 287 (void)signal(SIGTERM, onsig); 288 289 tputs(tgetstr("ti", &tcp), 1, fputchar); 290 tputs(tgetstr("cl", &tcp), 1, fputchar); 291 if (field) { 292 register char *p = field; 293 294 for (y = bottom; --y >= 0;) { 295 for (x = CO; --x >= 0;) { 296 fputchar(*p++); 297 if (!*p) 298 p = field; 299 } 300 if (!Wrap) 301 fputchar('\n'); 302 (void)fflush(stdout); 303 } 304 if (Wrap) { 305 if (IM && !IN) { 306 for (x = last; --x > 0;) { 307 fputchar(*p++); 308 if (!*p) 309 p = field; 310 } 311 y = *p++; 312 if (!*p) 313 p = field; 314 fputchar(*p); 315 if (BC) 316 tputs(BC, 1, fputchar); 317 else 318 cursor(last - 1, bottom); 319 tputs(IM, 1, fputchar); 320 if (IC) 321 tputs(IC, 1, fputchar); 322 fputchar(y); 323 if (IP) 324 tputs(IP, 1, fputchar); 325 tputs(EI, 1, fputchar); 326 } 327 else if (SR || AL) { 328 if (HO) 329 tputs(HO, 1, fputchar); 330 else 331 cursor(0, 0); 332 if (SR) 333 tputs(SR, 1, fputchar); 334 else 335 tputs(AL, LI, fputchar); 336 for (x = CO; --x >= 0;) { 337 fputchar(*p++); 338 if (!*p) 339 p = field; 340 } 341 } 342 else for (x = last; --x >= 0;) { 343 fputchar(*p++); 344 if (!*p) 345 p = field; 346 } 347 } 348 else for (x = CO; --x >= 0;) { 349 fputchar(*p++); 350 if (!*p) 351 p = field; 352 } 353 } 354 for (;;) { 355 (void)fflush(stdout); 356 for (n = 0, w = &worm[0]; n < number; n++, w++) { 357 if ((x = w->xpos[h = w->head]) < 0) { 358 cursor(x = w->xpos[h] = 0, 359 y = w->ypos[h] = bottom); 360 fputchar(flavor[n % sizeof(flavor)]); 361 ref[y][x]++; 362 } 363 else 364 y = w->ypos[h]; 365 if (++h == length) 366 h = 0; 367 if (w->xpos[w->head = h] >= 0) { 368 register int x1, y1; 369 370 x1 = w->xpos[h]; 371 y1 = w->ypos[h]; 372 if (--ref[y1][x1] == 0) { 373 cursor(x1, y1); 374 if (trail) 375 fputchar(trail); 376 } 377 } 378 op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation]; 379 switch (op->nopts) { 380 case 0: 381 (void)fflush(stdout); 382 abort(); 383 return; 384 case 1: 385 w->orientation = op->opts[0]; 386 break; 387 default: 388 w->orientation = 389 op->opts[(int)random() % op->nopts]; 390 } 391 cursor(x += xinc[w->orientation], 392 y += yinc[w->orientation]); 393 if (!Wrap || x != last || y != bottom) 394 fputchar(flavor[n % sizeof(flavor)]); 395 ref[w->ypos[h] = y][w->xpos[h] = x]++; 396 } 397 } 398 } 399 400 void 401 onsig() 402 { 403 tputs(tgetstr("cl", &tcp), 1, fputchar); 404 tputs(tgetstr("te", &tcp), 1, fputchar); 405 exit(0); 406 } 407 408 fputchar(c) 409 char c; 410 { 411 putchar(c); 412 } 413 414 nomem() 415 { 416 (void)fprintf(stderr, "worms: not enough memory.\n"); 417 exit(1); 418 } 419