1 /****************************************************************************
2 * Copyright (c) 1998-2016,2017 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
30 @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@
31 @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@
32 @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@
33 @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
34 @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
35 @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@
36 @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@
37 @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@
38 @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@
41 Caltech High Energy Physics
44 Hacks to turn this into a test frame for cursor movement:
45 Eric S. Raymond <esr@snark.thyrsus.com>
48 July 1995 (esr): worms is now in living color! :-)
50 This program makes a good torture-test for the ncurses cursor-optimization
51 code. You can use -T to set the worm move interval over which movement
52 traces will be dumped. The program stops and waits for one character of
53 input at the beginning and end of the interval.
55 $Id: worm.c,v 1.75 2017/09/08 20:00:50 tom Exp $
58 #include <test.priv.h>
60 #ifndef NCURSES_VERSION
71 #define MAX_LENGTH 1024
73 static chtype flavor[] =
75 'O', '*', '#', '$', '%', '0', '@',
77 static const int xinc[] =
79 1, 1, 1, 0, -1, -1, -1, 0
82 -1, 0, 1, 1, 1, 0, -1, -1
96 static unsigned long sequence = 0;
97 static bool quitting = FALSE;
99 static WORM worm[MAX_WORMS];
101 static int last_x, last_y;
103 static const char *field;
104 static int length = 16, number = 3;
105 static chtype trail = ' ';
107 static unsigned pending;
109 static int generation, trace_start, trace_end;
112 static const struct options {
201 failed(const char *s)
205 ExitProgram(EXIT_FAILURE);
212 USING_WINDOW(stdscr, wrefresh);
217 onsig(int sig GCC_UNUSED)
220 ExitProgram(EXIT_FAILURE);
226 long r = (rand() & 077777);
227 return ((double) r / 32768.);
231 draw_worm(WINDOW *win, void *data)
233 WORM *w = (WORM *) data;
234 const struct options *op;
235 unsigned mask = (unsigned) (~(1 << (w - worm)));
236 chtype attrs = w->attrs | ((mask & pending) ? A_REVERSE : 0);
244 if ((x = w->xpos[h = w->head]) < 0) {
245 wmove(win, y = w->ypos[h] = last_y, x = w->xpos[h] = 0);
260 if (w->xpos[w->head = h] >= 0) {
266 && --refs[y1][x1] == 0) {
288 : normal))))[w->orientation];
295 w->orientation = op->opts[0];
298 w->orientation = op->opts[(int) (ranf() * (double) op->nopts)];
303 x += xinc[w->orientation];
304 y += yinc[w->orientation];
321 quit_worm(int bitnum)
323 pending = (pending | (unsigned) (1 << bitnum));
324 napms(10); /* let the other thread(s) have a chance */
325 pending = (pending & (unsigned) ~(1 << bitnum));
330 start_worm(void *arg)
332 unsigned long compare = 0;
333 Trace(("start_worm"));
334 while (!quit_worm((int) (((struct worm *) arg) - worm))) {
335 while (compare < sequence) {
338 use_window(stdscr, draw_worm, arg);
340 draw_worm(stdscr, arg);
344 Trace(("...start_worm (done)"));
357 static bool first = TRUE;
360 for (n = 0, w = &worm[0]; n < number; n++, w++) {
361 (void) pthread_create(&(w->thread), NULL, start_worm, w);
365 for (n = 0, w = &worm[0]; n < number; n++, w++) {
368 USING_WINDOW2(stdscr, draw_worm, w)
383 ch = USING_WINDOW(stdscr, wgetch);
389 update_refs(WINDOW *win)
394 if (last_x != COLS - 1) {
395 for (y = 0; y <= last_y; y++) {
396 refs[y] = typeRealloc(int, (size_t) COLS, refs[y]);
398 failed("update_refs");
399 for (x = last_x + 1; x < COLS; x++)
404 if (last_y != LINES - 1) {
405 for (y = LINES; y <= last_y; y++)
407 refs = typeRealloc(int *, (size_t) LINES, refs);
408 for (y = last_y + 1; y < LINES; y++) {
409 refs[y] = typeMalloc(int, (size_t) COLS);
411 failed("update_refs");
412 for (x = 0; x < COLS; x++)
424 static const char *msg[] =
426 "Usage: worm [options]"
429 #if HAVE_USE_DEFAULT_COLORS
430 ," -d invoke use_default_colors"
432 ," -f fill screen with copies of \"WORM\" at start"
433 ," -l <n> set length of worms"
434 ," -n <n> set number of worms"
435 ," -t leave trail of \".\""
437 ," -T <start>,<end> set trace interval"
438 ," -N suppress cursor-movement optimization"
443 for (n = 0; n < SIZEOF(msg); n++)
444 fprintf(stderr, "%s\n", msg[n]);
446 ExitProgram(EXIT_FAILURE);
450 main(int argc, char *argv[])
459 #if HAVE_USE_DEFAULT_COLORS
463 setlocale(LC_ALL, "");
465 while ((ch = getopt(argc, argv, "dfl:n:tT:N")) != -1) {
467 #if HAVE_USE_DEFAULT_COLORS
476 if ((length = atoi(optarg)) < 2 || length > MAX_LENGTH) {
477 fprintf(stderr, "%s: Invalid length\n", *argv);
482 if ((number = atoi(optarg)) < 1 || number > MAX_WORMS) {
483 fprintf(stderr, "%s: Invalid number of worms\n", *argv);
492 if (sscanf(optarg, "%d,%d", &trace_start, &trace_end) != 2)
496 _nc_optimize_enable ^= OPTIMIZE_ALL; /* declared by ncurses */
507 signal(SIGINT, onsig);
520 int bg = COLOR_BLACK;
522 #if HAVE_USE_DEFAULT_COLORS
523 if (opt_d && (use_default_colors() == OK))
527 #define SET_COLOR(num, fg) \
528 init_pair(num+1, (short) fg, (short) bg); \
529 flavor[num] |= (chtype) COLOR_PAIR(num+1) | A_BOLD
531 SET_COLOR(0, COLOR_GREEN);
532 SET_COLOR(1, COLOR_RED);
533 SET_COLOR(2, COLOR_CYAN);
534 SET_COLOR(3, COLOR_WHITE);
535 SET_COLOR(4, COLOR_MAGENTA);
536 SET_COLOR(5, COLOR_BLUE);
537 SET_COLOR(6, COLOR_YELLOW);
542 refs = typeMalloc(int *, (size_t) max_refs);
543 for (y = 0; y < max_refs; y++) {
544 refs[y] = typeMalloc(int, (size_t) COLS);
545 for (x = 0; x < COLS; x++) {
551 /* if addressing the lower right corner doesn't work in your curses */
552 refs[last_y][last_x] = 1;
553 #endif /* BADCORNER */
555 for (n = number, w = &worm[0]; --n >= 0; w++) {
556 w->attrs = flavor[(unsigned) n % SIZEOF(flavor)];
560 if (!(ip = typeMalloc(int, (size_t) (length + 1)))) {
561 fprintf(stderr, "%s: out of memory\n", *argv);
562 ExitProgram(EXIT_FAILURE);
565 for (x = length; --x >= 0;)
567 if (!(ip = typeMalloc(int, (size_t) (length + 1)))) {
568 fprintf(stderr, "%s: out of memory\n", *argv);
569 ExitProgram(EXIT_FAILURE);
572 for (y = length; --y >= 0;)
578 for (y = last_y; --y >= 0;) {
579 for (x = COLS; --x >= 0;) {
580 addch((chtype) (*p++));
586 USING_WINDOW(stdscr, wrefresh);
587 nodelay(stdscr, TRUE);
591 if ((ch = get_input()) > 0) {
593 if (trace_start || trace_end) {
594 if (generation == trace_start) {
597 } else if (generation == trace_end) {
607 if (ch == KEY_RESIZE) {
608 USING_WINDOW(stdscr, update_refs);
613 * Make it simple to put this into single-step mode, or resume
614 * normal operation -T.Dickey
620 } else if (ch == 's') {
621 nodelay(stdscr, FALSE);
622 } else if (ch == ' ') {
623 nodelay(stdscr, TRUE);
627 done = draw_all_worms();
629 USING_WINDOW(stdscr, wrefresh);
635 for (y = 0; y < max_refs; y++) {
639 for (n = number, w = &worm[0]; --n >= 0; w++) {
646 * Do this just in case one of the threads did not really exit.
648 Trace(("join all threads"));
649 for (n = 0; n < number; n++) {
650 pthread_join(worm[n].thread, NULL);
653 ExitProgram(EXIT_SUCCESS);