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.76 2017/11/18 22:41:08 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];
102 static int last_x, last_y;
104 static const char *field;
105 static int length = 16, number = 3;
106 static chtype trail = ' ';
108 static unsigned pending;
110 static int generation, trace_start, trace_end;
113 static const struct options {
202 failed(const char *s)
206 ExitProgram(EXIT_FAILURE);
213 USING_WINDOW(stdscr, wrefresh);
218 onsig(int sig GCC_UNUSED)
221 ExitProgram(EXIT_FAILURE);
227 long r = (rand() & 077777);
228 return ((double) r / 32768.);
232 draw_worm(WINDOW *win, void *data)
234 WORM *w = (WORM *) data;
235 const struct options *op;
236 unsigned mask = (unsigned) (~(1 << (w - worm)));
237 chtype attrs = w->attrs | ((mask & pending) ? A_REVERSE : 0);
245 if ((x = w->xpos[h = w->head]) < 0) {
246 wmove(win, y = w->ypos[h] = last_y, x = w->xpos[h] = 0);
261 if (w->xpos[w->head = h] >= 0) {
267 && --refs[y1][x1] == 0) {
289 : normal))))[w->orientation];
294 Trace(("done - draw_worm"));
297 w->orientation = op->opts[0];
300 w->orientation = op->opts[(int) (ranf() * (double) op->nopts)];
305 x += xinc[w->orientation];
306 y += yinc[w->orientation];
323 quit_worm(int bitnum)
325 pending = (pending | (unsigned) (1 << bitnum));
326 napms(10); /* let the other thread(s) have a chance */
327 pending = (pending & (unsigned) ~(1 << bitnum));
332 start_worm(void *arg)
334 unsigned long compare = 0;
335 Trace(("start_worm"));
336 while (!quit_worm((int) (((struct worm *) arg) - worm))) {
337 while (compare < sequence) {
340 use_window(stdscr, draw_worm, arg);
342 draw_worm(stdscr, arg);
346 Trace(("...start_worm (done)"));
359 static bool first = TRUE;
362 for (n = 0, w = &worm[0]; n < number; n++, w++) {
363 (void) pthread_create(&(w->thread), NULL, start_worm, w);
367 for (n = 0, w = &worm[0]; n < number; n++, w++) {
370 USING_WINDOW2(stdscr, draw_worm, w)
385 ch = USING_WINDOW(stdscr, wgetch);
391 update_refs(WINDOW *win)
396 if (last_x != COLS - 1) {
397 for (y = 0; y <= last_y; y++) {
398 refs[y] = typeRealloc(int, (size_t) COLS, refs[y]);
400 failed("update_refs");
401 for (x = last_x + 1; x < COLS; x++)
406 if (last_y != LINES - 1) {
407 for (y = LINES; y <= last_y; y++)
410 refs = typeRealloc(int *, (size_t) LINES, refs);
411 for (y = last_y + 1; y < LINES; y++) {
412 refs[y] = typeMalloc(int, (size_t) COLS);
414 failed("update_refs");
415 for (x = 0; x < COLS; x++)
427 static const char *msg[] =
429 "Usage: worm [options]"
432 #if HAVE_USE_DEFAULT_COLORS
433 ," -d invoke use_default_colors"
435 ," -f fill screen with copies of \"WORM\" at start"
436 ," -l <n> set length of worms"
437 ," -n <n> set number of worms"
438 ," -t leave trail of \".\""
440 ," -T <start>,<end> set trace interval"
441 ," -N suppress cursor-movement optimization"
446 for (n = 0; n < SIZEOF(msg); n++)
447 fprintf(stderr, "%s\n", msg[n]);
449 ExitProgram(EXIT_FAILURE);
453 main(int argc, char *argv[])
461 #if HAVE_USE_DEFAULT_COLORS
465 setlocale(LC_ALL, "");
467 while ((ch = getopt(argc, argv, "dfl:n:tT:N")) != -1) {
469 #if HAVE_USE_DEFAULT_COLORS
478 if ((length = atoi(optarg)) < 2 || length > MAX_LENGTH) {
479 fprintf(stderr, "%s: Invalid length\n", *argv);
484 if ((number = atoi(optarg)) < 1 || number > MAX_WORMS) {
485 fprintf(stderr, "%s: Invalid number of worms\n", *argv);
494 if (sscanf(optarg, "%d,%d", &trace_start, &trace_end) != 2)
498 _nc_optimize_enable ^= OPTIMIZE_ALL; /* declared by ncurses */
509 signal(SIGINT, onsig);
522 int bg = COLOR_BLACK;
524 #if HAVE_USE_DEFAULT_COLORS
525 if (opt_d && (use_default_colors() == OK))
529 #define SET_COLOR(num, fg) \
530 init_pair(num+1, (short) fg, (short) bg); \
531 flavor[num] |= (chtype) COLOR_PAIR(num+1) | A_BOLD
533 SET_COLOR(0, COLOR_GREEN);
534 SET_COLOR(1, COLOR_RED);
535 SET_COLOR(2, COLOR_CYAN);
536 SET_COLOR(3, COLOR_WHITE);
537 SET_COLOR(4, COLOR_MAGENTA);
538 SET_COLOR(5, COLOR_BLUE);
539 SET_COLOR(6, COLOR_YELLOW);
544 refs = typeMalloc(int *, (size_t) max_refs);
545 for (y = 0; y < max_refs; y++) {
546 refs[y] = typeMalloc(int, (size_t) COLS);
547 for (x = 0; x < COLS; x++) {
553 /* if addressing the lower right corner doesn't work in your curses */
554 refs[last_y][last_x] = 1;
555 #endif /* BADCORNER */
557 for (n = number, w = &worm[0]; --n >= 0; w++) {
558 w->attrs = flavor[(unsigned) n % SIZEOF(flavor)];
562 if (!(ip = typeMalloc(int, (size_t) (length + 1)))) {
563 fprintf(stderr, "%s: out of memory\n", *argv);
564 ExitProgram(EXIT_FAILURE);
567 for (x = length; --x >= 0;)
569 if (!(ip = typeMalloc(int, (size_t) (length + 1)))) {
570 fprintf(stderr, "%s: out of memory\n", *argv);
571 ExitProgram(EXIT_FAILURE);
574 for (y = length; --y >= 0;)
580 for (y = last_y; --y >= 0;) {
581 for (x = COLS; --x >= 0;) {
582 addch((chtype) (*p++));
588 USING_WINDOW(stdscr, wrefresh);
589 nodelay(stdscr, TRUE);
593 if ((ch = get_input()) > 0) {
595 if (trace_start || trace_end) {
596 if (generation == trace_start) {
599 } else if (generation == trace_end) {
609 if (ch == KEY_RESIZE) {
610 USING_WINDOW(stdscr, update_refs);
615 * Make it simple to put this into single-step mode, or resume
616 * normal operation -T.Dickey
621 Trace(("done - quitting"));
623 } else if (ch == 's') {
624 nodelay(stdscr, FALSE);
625 } else if (ch == ' ') {
626 nodelay(stdscr, TRUE);
630 done = draw_all_worms();
632 USING_WINDOW(stdscr, wrefresh);
638 for (y = 0; y < max_refs; y++) {
642 for (n = number, w = &worm[0]; --n >= 0; w++) {
649 * Do this just in case one of the threads did not really exit.
651 Trace(("join all threads"));
652 for (n = 0; n < number; n++) {
653 pthread_join(worm[n].thread, NULL);
656 ExitProgram(EXIT_SUCCESS);