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.5 (Berkeley) 06/27/88"; 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 static char *TE; 151 static 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[40]; 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 onsig(); 180 short **ref; 181 char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR, *tcp, 182 *field, tcb[100], *mp, *malloc(), *getenv(), *tgetstr(), 183 *tgoto(); 184 long random(); 185 #ifdef USG 186 struct termio sg; 187 #else 188 struct sgttyb sg; 189 #endif 190 191 length = 16; 192 number = 3; 193 trail = ' '; 194 field = NULL; 195 while ((ch = getopt(argc, argv, "fl:n:t")) != EOF) 196 switch((char)ch) { 197 case 'f': 198 field = "WORM"; 199 break; 200 case 'l': 201 if ((length = atoi(optarg)) < 2 || length > 1024) { 202 fprintf(stderr, "%s: invalid length; range %d - %d.\n", *argv, 2, 1024); 203 exit(1); 204 } 205 break; 206 case 'n': 207 if ((number = atoi(optarg)) < 1 || number > 40) { 208 fprintf(stderr, "%s: invalid number of worms; range %d - %d.\n", *argv, 1, 40); 209 exit(1); 210 } 211 break; 212 case 't': 213 trail = '.'; 214 break; 215 case '?': 216 default: 217 fprintf(stderr, "usage: %s [-ft] [-length #] [-number #]\n", *argv); 218 exit(1); 219 } 220 221 if (!(term = getenv("TERM"))) { 222 fprintf(stderr, "%s: TERM: parameter not set\n", *argv); 223 exit(1); 224 } 225 if (!(mp = malloc((u_int)1024))) { 226 fprintf(stderr, "%s: out of space.\n", *argv); 227 exit(1); 228 } 229 if (tgetent(mp, term) <= 0) { 230 fprintf(stderr, "%s: %s: unknown terminal type\n", *argv, term); 231 exit(1); 232 } 233 tcp = tcb; 234 if (!(CM = tgetstr("cm", &tcp))) { 235 fprintf(stderr, "%s: terminal not capable of cursor motion\n", *argv); 236 exit(1); 237 } 238 AL = tgetstr("al", &tcp); 239 BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp); 240 if ((CO = tgetnum("co")) <= 0) 241 CO = 80; 242 last = CO - 1; 243 EI = tgetstr("ei", &tcp); 244 HO = tgetstr("ho", &tcp); 245 IC = tgetstr("ic", &tcp); 246 IM = tgetstr("im", &tcp); 247 IN = tgetflag("in"); 248 IP = tgetstr("ip", &tcp); 249 if ((LI = tgetnum("li")) <= 0) 250 LI = 24; 251 bottom = LI - 1; 252 SR = tgetstr("sr", &tcp); 253 TE = tgetstr("te", &tcp); 254 UP = tgetstr("up", &tcp); 255 #ifdef USG 256 ioctl(1, TCGETA, &sg); 257 ospeed = sg.c_cflag&CBAUD; 258 #else 259 gtty(1, &sg); 260 ospeed = sg.sg_ospeed; 261 #endif 262 Wrap = tgetflag("am"); 263 if (!(ip = (short *)malloc((u_int)(LI * CO * sizeof(short))))) { 264 fprintf(stderr, "%s: out of memory\n", *argv); 265 exit(1); 266 } 267 if (!(ref = (short **)malloc((u_int)(LI * sizeof(short *))))) { 268 fprintf(stderr, "%s: out of memory\n", *argv); 269 exit(1); 270 } 271 for (n = 0; n < LI; ++n) { 272 ref[n] = ip; 273 ip += CO; 274 } 275 for (ip = ref[0], n = LI * CO; --n >= 0;) 276 *ip++ = 0; 277 if (Wrap) 278 ref[bottom][last] = 1; 279 for (n = number, w = &worm[0]; --n >= 0; w++) { 280 w->orientation = w->head = 0; 281 if (!(ip = (short *)malloc((u_int)(length * sizeof(short))))) { 282 fprintf(stderr, "%s: out of memory\n", *argv); 283 exit(1); 284 } 285 w->xpos = ip; 286 for (x = length; --x >= 0;) 287 *ip++ = -1; 288 if (!(ip = (short *)malloc((u_int)(length * sizeof(short))))) { 289 fprintf(stderr, "%s: out of memory\n", *argv); 290 exit(1); 291 } 292 w->ypos = ip; 293 for (y = length; --y >= 0;) 294 *ip++ = -1; 295 } 296 297 (void)signal(SIGHUP, onsig); 298 (void)signal(SIGINT, onsig); 299 (void)signal(SIGQUIT, onsig); 300 (void)signal(SIGSTOP, onsig); 301 (void)signal(SIGTSTP, onsig); 302 (void)signal(SIGTERM, onsig); 303 304 tputs(tgetstr("ti", &tcp), 1, fputchar); 305 tputs(tgetstr("cl", &tcp), 1, fputchar); 306 if (field) { 307 register char *p = field; 308 309 for (y = bottom; --y >= 0;) { 310 for (x = CO; --x >= 0;) { 311 fputchar(*p++); 312 if (!*p) 313 p = field; 314 } 315 if (!Wrap) 316 fputchar('\n'); 317 (void)fflush(stdout); 318 } 319 if (Wrap) { 320 if (IM && !IN) { 321 for (x = last; --x > 0;) { 322 fputchar(*p++); 323 if (!*p) 324 p = field; 325 } 326 y = *p++; 327 if (!*p) 328 p = field; 329 fputchar(*p); 330 if (BC) 331 tputs(BC, 1, fputchar); 332 else 333 cursor(last - 1, bottom); 334 tputs(IM, 1, fputchar); 335 if (IC) 336 tputs(IC, 1, fputchar); 337 fputchar(y); 338 if (IP) 339 tputs(IP, 1, fputchar); 340 tputs(EI, 1, fputchar); 341 } 342 else if (SR || AL) { 343 if (HO) 344 tputs(HO, 1, fputchar); 345 else 346 cursor(0, 0); 347 if (SR) 348 tputs(SR, 1, fputchar); 349 else 350 tputs(AL, LI, fputchar); 351 for (x = CO; --x >= 0;) { 352 fputchar(*p++); 353 if (!*p) 354 p = field; 355 } 356 } 357 else for (x = last; --x >= 0;) { 358 fputchar(*p++); 359 if (!*p) 360 p = field; 361 } 362 } 363 else for (x = CO; --x >= 0;) { 364 fputchar(*p++); 365 if (!*p) 366 p = field; 367 } 368 } 369 for (;;) { 370 (void)fflush(stdout); 371 for (n = 0, w = &worm[0]; n < number; n++, w++) { 372 if ((x = w->xpos[h = w->head]) < 0) { 373 cursor(x = w->xpos[h] = 0, 374 y = w->ypos[h] = bottom); 375 fputchar(flavor[n % 6]); 376 ref[y][x]++; 377 } 378 else 379 y = w->ypos[h]; 380 if (++h == length) 381 h = 0; 382 if (w->xpos[w->head = h] >= 0) { 383 register int x1, y1; 384 385 x1 = w->xpos[h]; 386 y1 = w->ypos[h]; 387 if (--ref[y1][x1] == 0) { 388 cursor(x1, y1); 389 if (trail) 390 fputchar(trail); 391 } 392 } 393 op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation]; 394 switch (op->nopts) { 395 case 0: 396 (void)fflush(stdout); 397 abort(); 398 return; 399 case 1: 400 w->orientation = op->opts[0]; 401 break; 402 default: 403 w->orientation = op->opts[(int)random() % op->nopts]; 404 } 405 cursor(x += xinc[w->orientation], y += yinc[w->orientation]); 406 if (!Wrap || x != last || y != bottom) 407 fputchar(flavor[n % 6]); 408 ref[w->ypos[h] = y][w->xpos[h] = x]++; 409 } 410 } 411 } 412 413 static 414 onsig() 415 { 416 tputs(TE, 1, fputchar); 417 exit(0); 418 } 419 420 static 421 fputchar(c) 422 char c; 423 { 424 putchar(c); 425 } 426