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