]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - test/worm.c
ncurses 6.4 - patch 20240414
[ncurses.git] / test / worm.c
index 2e31638d302e203613491bf436d681a07b6b627d..7c4842e4004f3bc772080e9dd9f2607402691e60 100644 (file)
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 1998-2016,2017 Free Software Foundation, Inc.              *
+ * Copyright 2018-2020,2022 Thomas E. Dickey                                *
+ * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
@@ -52,7 +53,7 @@
   traces will be dumped.  The program stops and waits for one character of
   input at the beginning and end of the interval.
 
-  $Id: worm.c,v 1.76 2017/11/18 22:41:08 tom Exp $
+  $Id: worm.c,v 1.89 2022/12/24 20:46:49 tom Exp $
 */
 
 #include <test.priv.h>
@@ -106,6 +107,18 @@ static int length = 16, number = 3;
 static chtype trail = ' ';
 
 static unsigned pending;
+
+#ifdef USE_PTHREADS
+#define Locked(statement) { \
+       pthread_mutex_lock(&pending_mutex); \
+       statement; \
+       pthread_mutex_unlock(&pending_mutex); \
+    }
+pthread_mutex_t pending_mutex;
+#else
+#define Locked(statement) statement
+#endif
+
 #ifdef TRACE
 static int generation, trace_start, trace_end;
 #endif /* TRACE */
@@ -197,12 +210,25 @@ static const struct options {
 };
 /* *INDENT-ON* */
 
+#if HAVE_USE_WINDOW
+static int
+safe_wgetch(WINDOW *w, void *data GCC_UNUSED)
+{
+    return wgetch(w);
+}
+static int
+safe_wrefresh(WINDOW *w, void *data GCC_UNUSED)
+{
+    return wrefresh(w);
+}
+#endif
+
 #ifdef KEY_RESIZE
 static void
 failed(const char *s)
 {
     perror(s);
-    exit_curses();
+    stop_curses();
     ExitProgram(EXIT_FAILURE);
 }
 #endif
@@ -210,8 +236,8 @@ failed(const char *s)
 static void
 cleanup(void)
 {
-    USING_WINDOW(stdscr, wrefresh);
-    exit_curses();
+    USING_WINDOW1(stdscr, wrefresh, safe_wrefresh);
+    stop_curses();
 }
 
 static void
@@ -234,13 +260,18 @@ draw_worm(WINDOW *win, void *data)
     WORM *w = (WORM *) data;
     const struct options *op;
     unsigned mask = (unsigned) (~(1 << (w - worm)));
-    chtype attrs = w->attrs | ((mask & pending) ? A_REVERSE : 0);
+    chtype attrs;
 
     int x;
     int y;
     int h;
 
     bool done = FALSE;
+    bool is_pending;
+
+    Locked(is_pending = ((mask & pending) != 0));
+
+    attrs = w->attrs | (is_pending ? A_REVERSE : 0);
 
     if ((x = w->xpos[h = w->head]) < 0) {
        wmove(win, y = w->ypos[h] = last_y, x = w->xpos[h] = 0);
@@ -322,9 +353,12 @@ draw_worm(WINDOW *win, void *data)
 static bool
 quit_worm(int bitnum)
 {
-    pending = (pending | (unsigned) (1 << bitnum));
+    Locked(pending = (pending | (unsigned) (1 << bitnum)));
+
     napms(10);                 /* let the other thread(s) have a chance */
-    pending = (pending & (unsigned) ~(1 << bitnum));
+
+    Locked(pending = (pending & (unsigned) ~(1 << bitnum)));
+
     return quitting;
 }
 
@@ -334,13 +368,13 @@ start_worm(void *arg)
     unsigned long compare = 0;
     Trace(("start_worm"));
     while (!quit_worm((int) (((struct worm *) arg) - worm))) {
-       while (compare < sequence) {
+       for (;;) {
+           bool done = FALSE;
+           Locked(done = (compare >= sequence));
+           if (done)
+               break;
            ++compare;
-#if HAVE_USE_WINDOW
-           use_window(stdscr, draw_worm, arg);
-#else
-           draw_worm(stdscr, arg);
-#endif
+           USING_WINDOW2(stdscr, draw_worm, arg);
        }
     }
     Trace(("...start_worm (done)"));
@@ -365,13 +399,7 @@ draw_all_worms(void)
     }
 #else
     for (n = 0, w = &worm[0]; n < number; n++, w++) {
-       if (
-#if HAVE_USE_WINDOW
-              USING_WINDOW2(stdscr, draw_worm, w)
-#else
-              draw_worm(stdscr, w)
-#endif
-           )
+       if (USING_WINDOW2(stdscr, draw_worm, w))
            done = TRUE;
     }
 #endif
@@ -382,17 +410,18 @@ static int
 get_input(void)
 {
     int ch;
-    ch = USING_WINDOW(stdscr, wgetch);
+    ch = USING_WINDOW1(stdscr, wgetch, safe_wgetch);
     return ch;
 }
 
 #ifdef KEY_RESIZE
 static int
-update_refs(WINDOW *win)
+update_refs(WINDOW *win, void *data)
 {
     int x, y;
 
     (void) win;
+    (void) data;
     if (last_x != COLS - 1) {
        for (y = 0; y <= last_y; y++) {
            refs[y] = typeRealloc(int, (size_t) COLS, refs[y]);
@@ -422,12 +451,13 @@ update_refs(WINDOW *win)
 #endif
 
 static void
-usage(void)
+usage(int ok)
 {
     static const char *msg[] =
     {
        "Usage: worm [options]"
        ,""
+       ,USAGE_COMMON
        ,"Options:"
 #if HAVE_USE_DEFAULT_COLORS
        ," -d       invoke use_default_colors"
@@ -446,8 +476,11 @@ usage(void)
     for (n = 0; n < SIZEOF(msg); n++)
        fprintf(stderr, "%s\n", msg[n]);
 
-    ExitProgram(EXIT_FAILURE);
+    ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
 }
+/* *INDENT-OFF* */
+VERSION_COMMON()
+/* *INDENT-ON* */
 
 int
 main(int argc, char *argv[])
@@ -464,7 +497,7 @@ main(int argc, char *argv[])
 
     setlocale(LC_ALL, "");
 
-    while ((ch = getopt(argc, argv, "dfl:n:tT:N")) != -1) {
+    while ((ch = getopt(argc, argv, OPTS_COMMON "dfl:n:tT:N")) != -1) {
        switch (ch) {
 #if HAVE_USE_DEFAULT_COLORS
        case 'd':
@@ -477,13 +510,13 @@ main(int argc, char *argv[])
        case 'l':
            if ((length = atoi(optarg)) < 2 || length > MAX_LENGTH) {
                fprintf(stderr, "%s: Invalid length\n", *argv);
-               usage();
+               usage(FALSE);
            }
            break;
        case 'n':
            if ((number = atoi(optarg)) < 1 || number > MAX_WORMS) {
                fprintf(stderr, "%s: Invalid number of worms\n", *argv);
-               usage();
+               usage(FALSE);
            }
            break;
        case 't':
@@ -492,19 +525,22 @@ main(int argc, char *argv[])
 #ifdef TRACE
        case 'T':
            if (sscanf(optarg, "%d,%d", &trace_start, &trace_end) != 2)
-               usage();
+               usage(FALSE);
            break;
        case 'N':
            _nc_optimize_enable ^= OPTIMIZE_ALL;        /* declared by ncurses */
            break;
 #endif /* TRACE */
+       case OPTS_VERSION:
+           show_version(argv);
+           ExitProgram(EXIT_SUCCESS);
        default:
-           usage();
+           usage(ch == OPTS_USAGE);
            /* NOTREACHED */
        }
     }
     if (optind < argc)
-       usage();
+       usage(FALSE);
 
     signal(SIGINT, onsig);
     initscr();
@@ -585,19 +621,23 @@ main(int argc, char *argv[])
            }
        }
     }
-    USING_WINDOW(stdscr, wrefresh);
+    USING_WINDOW1(stdscr, wrefresh, safe_wrefresh);
     nodelay(stdscr, TRUE);
 
+#ifdef USE_PTHREADS
+    pthread_mutex_init(&pending_mutex, NULL);
+#endif
+
     while (!done) {
-       ++sequence;
+       Locked(++sequence);
        if ((ch = get_input()) > 0) {
 #ifdef TRACE
            if (trace_start || trace_end) {
                if (generation == trace_start) {
-                   trace(TRACE_CALLS);
+                   curses_trace(TRACE_CALLS);
                    get_input();
                } else if (generation == trace_end) {
-                   trace(0);
+                   curses_trace(0);
                    get_input();
                }
 
@@ -629,11 +669,20 @@ main(int argc, char *argv[])
 
        done = draw_all_worms();
        napms(10);
-       USING_WINDOW(stdscr, wrefresh);
+       USING_WINDOW1(stdscr, wrefresh, safe_wrefresh);
     }
 
     Trace(("Cleanup"));
     cleanup();
+#ifdef USE_PTHREADS
+    /*
+     * Do this just in case one of the threads did not really exit.
+     */
+    Trace(("join all threads"));
+    for (n = 0; n < number; n++) {
+       pthread_join(worm[n].thread, NULL);
+    }
+#endif
 #if NO_LEAKS
     for (y = 0; y < max_refs; y++) {
        free(refs[y]);
@@ -643,15 +692,6 @@ main(int argc, char *argv[])
        free(w->xpos);
        free(w->ypos);
     }
-#endif
-#ifdef USE_PTHREADS
-    /*
-     * Do this just in case one of the threads did not really exit.
-     */
-    Trace(("join all threads"));
-    for (n = 0; n < number; n++) {
-       pthread_join(worm[n].thread, NULL);
-    }
 #endif
     ExitProgram(EXIT_SUCCESS);
 }