worms.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /* $NetBSD: worms.c,v 1.16 2004/09/12 04:51:32 christos Exp $ */
  2. /*
  3. * Copyright (c) 1980, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the University nor the names of its contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  22. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. */
  30. #include <sys/cdefs.h>
  31. #ifndef lint
  32. __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
  33. The Regents of the University of California. All rights reserved.\n");
  34. #endif /* not lint */
  35. #ifndef lint
  36. #if 0
  37. static char sccsid[] = "@(#)worms.c 8.1 (Berkeley) 5/31/93";
  38. #else
  39. __RCSID("$NetBSD: worms.c,v 1.16 2004/09/12 04:51:32 christos Exp $");
  40. #endif
  41. #endif /* not lint */
  42. /*
  43. *
  44. * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@
  45. * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@
  46. * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@
  47. * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
  48. * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
  49. * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@
  50. * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@
  51. * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@
  52. * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@
  53. *
  54. * Eric P. Scott
  55. * Caltech High Energy Physics
  56. * October, 1980
  57. *
  58. */
  59. #include <sys/types.h>
  60. #include <curses.h>
  61. #include <err.h>
  62. #include <signal.h>
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <unistd.h>
  66. static const struct options {
  67. int nopts;
  68. int opts[3];
  69. }
  70. normal[8] = {
  71. { 3, { 7, 0, 1 } },
  72. { 3, { 0, 1, 2 } },
  73. { 3, { 1, 2, 3 } },
  74. { 3, { 2, 3, 4 } },
  75. { 3, { 3, 4, 5 } },
  76. { 3, { 4, 5, 6 } },
  77. { 3, { 5, 6, 7 } },
  78. { 3, { 6, 7, 0 } }
  79. }, upper[8] = {
  80. { 1, { 1, 0, 0 } },
  81. { 2, { 1, 2, 0 } },
  82. { 0, { 0, 0, 0 } },
  83. { 0, { 0, 0, 0 } },
  84. { 0, { 0, 0, 0 } },
  85. { 2, { 4, 5, 0 } },
  86. { 1, { 5, 0, 0 } },
  87. { 2, { 1, 5, 0 } }
  88. },
  89. left[8] = {
  90. { 0, { 0, 0, 0 } },
  91. { 0, { 0, 0, 0 } },
  92. { 0, { 0, 0, 0 } },
  93. { 2, { 2, 3, 0 } },
  94. { 1, { 3, 0, 0 } },
  95. { 2, { 3, 7, 0 } },
  96. { 1, { 7, 0, 0 } },
  97. { 2, { 7, 0, 0 } }
  98. },
  99. right[8] = {
  100. { 1, { 7, 0, 0 } },
  101. { 2, { 3, 7, 0 } },
  102. { 1, { 3, 0, 0 } },
  103. { 2, { 3, 4, 0 } },
  104. { 0, { 0, 0, 0 } },
  105. { 0, { 0, 0, 0 } },
  106. { 0, { 0, 0, 0 } },
  107. { 2, { 6, 7, 0 } }
  108. },
  109. lower[8] = {
  110. { 0, { 0, 0, 0 } },
  111. { 2, { 0, 1, 0 } },
  112. { 1, { 1, 0, 0 } },
  113. { 2, { 1, 5, 0 } },
  114. { 1, { 5, 0, 0 } },
  115. { 2, { 5, 6, 0 } },
  116. { 0, { 0, 0, 0 } },
  117. { 0, { 0, 0, 0 } }
  118. },
  119. upleft[8] = {
  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, { 3, 0, 0 } },
  126. { 2, { 1, 3, 0 } },
  127. { 1, { 1, 0, 0 } }
  128. },
  129. upright[8] = {
  130. { 2, { 3, 5, 0 } },
  131. { 1, { 3, 0, 0 } },
  132. { 0, { 0, 0, 0 } },
  133. { 0, { 0, 0, 0 } },
  134. { 0, { 0, 0, 0 } },
  135. { 0, { 0, 0, 0 } },
  136. { 0, { 0, 0, 0 } },
  137. { 1, { 5, 0, 0 } }
  138. },
  139. lowleft[8] = {
  140. { 3, { 7, 0, 1 } },
  141. { 0, { 0, 0, 0 } },
  142. { 0, { 0, 0, 0 } },
  143. { 1, { 1, 0, 0 } },
  144. { 2, { 1, 7, 0 } },
  145. { 1, { 7, 0, 0 } },
  146. { 0, { 0, 0, 0 } },
  147. { 0, { 0, 0, 0 } }
  148. },
  149. lowright[8] = {
  150. { 0, { 0, 0, 0 } },
  151. { 1, { 7, 0, 0 } },
  152. { 2, { 5, 7, 0 } },
  153. { 1, { 5, 0, 0 } },
  154. { 0, { 0, 0, 0 } },
  155. { 0, { 0, 0, 0 } },
  156. { 0, { 0, 0, 0 } },
  157. { 0, { 0, 0, 0 } }
  158. };
  159. static const char flavor[] = {
  160. 'O', '*', '#', '$', '%', '0', '@', '~'
  161. };
  162. static const short xinc[] = {
  163. 1, 1, 1, 0, -1, -1, -1, 0
  164. }, yinc[] = {
  165. -1, 0, 1, 1, 1, 0, -1, -1
  166. };
  167. static struct worm {
  168. int orientation, head;
  169. short *xpos, *ypos;
  170. } *worm;
  171. volatile sig_atomic_t sig_caught = 0;
  172. int main(int, char **);
  173. void nomem(void) __attribute__((__noreturn__));
  174. void onsig(int);
  175. int
  176. main(argc, argv)
  177. int argc;
  178. char *argv[];
  179. {
  180. int x, y, h, n;
  181. struct worm *w;
  182. const struct options *op;
  183. short *ip;
  184. int CO, LI, last, bottom, ch, length, number, trail;
  185. short **ref;
  186. const char *field;
  187. char *mp;
  188. unsigned int delay = 0;
  189. /* Revoke setgid privileges */
  190. setregid(getgid(), getgid());
  191. mp = NULL;
  192. length = 16;
  193. number = 3;
  194. trail = ' ';
  195. field = NULL;
  196. while ((ch = getopt(argc, argv, "d:fl:n:t")) != -1)
  197. switch(ch) {
  198. case 'd':
  199. if ((delay = (unsigned int)strtoul(optarg, (char **)NULL, 10)) < 1 || delay > 1000)
  200. errx(1, "invalid delay (1-1000)");
  201. delay *= 1000; /* ms -> us */
  202. break;
  203. case 'f':
  204. field = "WORM";
  205. break;
  206. case 'l':
  207. if ((length = atoi(optarg)) < 2 || length > 1024) {
  208. errx(1, "invalid length (%d - %d).",
  209. 2, 1024);
  210. }
  211. break;
  212. case 'n':
  213. if ((number = atoi(optarg)) < 1) {
  214. errx(1, "invalid number of worms.");
  215. }
  216. break;
  217. case 't':
  218. trail = '.';
  219. break;
  220. case '?':
  221. default:
  222. (void)fprintf(stderr,
  223. "usage: worms [-ft] [-d delay] [-l length] [-n number]\n");
  224. exit(1);
  225. }
  226. if (!(worm = malloc((size_t)number *
  227. sizeof(struct worm))) || !(mp = malloc((size_t)1024)))
  228. nomem();
  229. initscr();
  230. curs_set(0);
  231. CO = COLS;
  232. LI = LINES;
  233. last = CO - 1;
  234. bottom = LI - 1;
  235. if (!(ip = malloc((size_t)(LI * CO * sizeof(short)))))
  236. nomem();
  237. if (!(ref = malloc((size_t)(LI * sizeof(short *)))))
  238. nomem();
  239. for (n = 0; n < LI; ++n) {
  240. ref[n] = ip;
  241. ip += CO;
  242. }
  243. for (ip = ref[0], n = LI * CO; --n >= 0;)
  244. *ip++ = 0;
  245. for (n = number, w = &worm[0]; --n >= 0; w++) {
  246. w->orientation = w->head = 0;
  247. if (!(ip = malloc((size_t)(length * sizeof(short)))))
  248. nomem();
  249. w->xpos = ip;
  250. for (x = length; --x >= 0;)
  251. *ip++ = -1;
  252. if (!(ip = malloc((size_t)(length * sizeof(short)))))
  253. nomem();
  254. w->ypos = ip;
  255. for (y = length; --y >= 0;)
  256. *ip++ = -1;
  257. }
  258. (void)signal(SIGHUP, onsig);
  259. (void)signal(SIGINT, onsig);
  260. (void)signal(SIGQUIT, onsig);
  261. (void)signal(SIGTSTP, onsig);
  262. (void)signal(SIGTERM, onsig);
  263. if (field) {
  264. const char *p = field;
  265. for (y = LI; --y >= 0;) {
  266. for (x = CO; --x >= 0;) {
  267. addch(*p++);
  268. if (!*p)
  269. p = field;
  270. }
  271. refresh();
  272. }
  273. }
  274. for (;;) {
  275. refresh();
  276. if (sig_caught) {
  277. endwin();
  278. exit(0);
  279. }
  280. if (delay) {
  281. if (delay % 1000000 != 0)
  282. usleep(delay % 1000000);
  283. if (delay >= 1000000)
  284. sleep(delay / 1000000);
  285. }
  286. for (n = 0, w = &worm[0]; n < number; n++, w++) {
  287. if ((x = w->xpos[h = w->head]) < 0) {
  288. mvaddch(y = w->ypos[h] = bottom,
  289. x = w->xpos[h] = 0,
  290. flavor[n % sizeof(flavor)]);
  291. ref[y][x]++;
  292. }
  293. else
  294. y = w->ypos[h];
  295. if (++h == length)
  296. h = 0;
  297. if (w->xpos[w->head = h] >= 0) {
  298. int x1, y1;
  299. x1 = w->xpos[h];
  300. y1 = w->ypos[h];
  301. if (--ref[y1][x1] == 0) {
  302. mvaddch(y1, x1, trail);
  303. }
  304. }
  305. op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation];
  306. switch (op->nopts) {
  307. case 0:
  308. refresh();
  309. abort();
  310. return(1);
  311. case 1:
  312. w->orientation = op->opts[0];
  313. break;
  314. default:
  315. w->orientation =
  316. op->opts[(int)random() % op->nopts];
  317. }
  318. mvaddch(y += yinc[w->orientation],
  319. x += xinc[w->orientation],
  320. flavor[n % sizeof(flavor)]);
  321. ref[w->ypos[h] = y][w->xpos[h] = x]++;
  322. }
  323. }
  324. }
  325. void
  326. onsig(signo)
  327. int signo __attribute__((__unused__));
  328. {
  329. sig_caught = 1;
  330. }
  331. void
  332. nomem()
  333. {
  334. errx(1, "not enough memory.");
  335. }