]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - test/ditto.c
ncurses 6.5 - patch 20240504
[ncurses.git] / test / ditto.c
index 06b635536dfefecd40a5811b6d35ca5702cc0632..acac8377aad7d2e76edb696017efe18605a1c768 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright 2018-2021,2022 Thomas E. Dickey                                *
+ * Copyright 2018-2022,2023 Thomas E. Dickey                                *
  * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
@@ -30,7 +30,7 @@
 /*
  * Author: Thomas E. Dickey (1998-on)
  *
- * $Id: ditto.c,v 1.55 2022/12/04 00:40:55 tom Exp $
+ * $Id: ditto.c,v 1.59 2023/09/23 17:08:43 tom Exp $
  *
  * The program illustrates how to set up multiple screens from a single
  * program.
@@ -92,6 +92,15 @@ typedef struct {
 #endif
 } DITTO;
 
+#ifdef USE_PTHREADS
+#define LockIt()                pthread_mutex_lock(&pending_mutex)
+#define UnlockIt()              pthread_mutex_unlock(&pending_mutex)
+pthread_mutex_t pending_mutex;
+#else
+#define LockIt()               /* nothing */
+#define UnlockIt()             /* nothing */
+#endif
+
 /*
  * Structure used to pass multiple parameters via the use_screen()
  * single-parameter interface.
@@ -230,6 +239,14 @@ init_screen(
     return TRUE;
 }
 
+static void
+free_screen(DITTO * target)
+{
+    free(target->parents);
+    free(target->windows);
+    free(target->peeks);
+}
+
 static void
 open_screen(DITTO * target, char **source, int length, int which1)
 {
@@ -386,91 +403,97 @@ usage(int ok)
        fprintf(stderr, "%s\n", msg[n]);
 
     ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
-/* *INDENT-OFF* */}
+}
+/* *INDENT-OFF* */
 VERSION_COMMON()
 /* *INDENT-ON* */
 
-    int
-      main(int argc, char *argv[]) {
-       int j;
-       int ch;
-       DITTO *data;
+int
+main(int argc, char *argv[])
+{
+    int j;
+    int ch;
+    DITTO *data;
 #ifndef USE_PTHREADS
-       int count;
+    int count;
 #endif
 
-       while ((ch = getopt(argc, argv, OPTS_COMMON)) != -1) {
-           switch (ch) {
-           case OPTS_VERSION:
-               show_version(argv);
-               ExitProgram(EXIT_SUCCESS);
-               default:
-               usage(ch == OPTS_USAGE);
-               /* NOTREACHED */
-           }
-       } if (optind < argc)
-             usage(FALSE);
+    while ((ch = getopt(argc, argv, OPTS_COMMON)) != -1) {
+       switch (ch) {
+       case OPTS_VERSION:
+           show_version(argv);
+           ExitProgram(EXIT_SUCCESS);
+       default:
+           usage(ch == OPTS_USAGE);
+           /* NOTREACHED */
+       }
+    }
 
-       if ((data = typeCalloc(DITTO, (size_t) argc)) == 0)
-           failed("calloc data");
+    if ((data = typeCalloc(DITTO, (size_t) argc)) == 0)
+       failed("calloc data");
 
-       assert(data != 0);
+    assert(data != 0);
 
-       for (j = 0; j < argc; j++) {
-           open_screen(&data[j], argv, argc, j);
-       }
+    for (j = 0; j < argc; j++) {
+       open_screen(&data[j], argv, argc, j);
+    }
 
 #ifdef USE_PTHREADS
-       /*
-        * For multi-threaded operation, set up a reader for each of the screens.
-        * That uses blocking I/O rather than polling for input, so no calls to
-        * napms() are needed.
-        */
-       for (j = 0; j < argc; j++) {
-           (void) pthread_create(&(data[j].thread), NULL, handle_screen,
-                                 &data[j]);
-       }
-       pthread_join(data[1].thread, NULL);
+    pthread_mutex_init(&pending_mutex, NULL);
+    /*
+     * For multi-threaded operation, set up a reader for each of the screens.
+     * That uses blocking I/O rather than polling for input, so no calls to
+     * napms() are needed.
+     */
+    for (j = 0; j < argc; j++) {
+       (void) pthread_create(&(data[j].thread), NULL, handle_screen,
+                             &data[j]);
+    }
+    pthread_join(data[1].thread, NULL);
 #else
-       /*
-        * Loop, reading characters from any of the inputs and writing to all
-        * of the screens.
-        */
-       for (count = 0;; ++count) {
-           DDATA ddata;
-           int which = (count % argc);
+    /*
+     * Loop, reading characters from any of the inputs and writing to all
+     * of the screens.
+     */
+    for (count = 0;; ++count) {
+       DDATA ddata;
+       int which = (count % argc);
 
-           napms(20);
+       napms(20);
 
-           ddata.source = which;
-           ddata.ditto = data;
+       ddata.source = which;
+       ddata.ditto = data;
 
-           ch = USING_SCREEN(data[which].screen, read_screen, &ddata);
-           if (ch == CTRL('D')) {
-               break;
-           } else if (ch != ERR) {
-               show_ditto(data, argc, &ddata);
-           }
+       ch = USING_SCREEN(data[which].screen, read_screen, &ddata);
+       if (ch == CTRL('D')) {
+           break;
+       } else if (ch != ERR) {
+           show_ditto(data, argc, &ddata);
        }
+    }
 #endif
 
+    /*
+     * Cleanup and exit
+     */
+    for (j = argc - 1; j >= 0; j--) {
+       LockIt();
+       USING_SCREEN(data[j].screen, close_screen, 0);
+       fprintf(data[j].output, "**Closed\r\n");
+
        /*
-        * Cleanup and exit
+        * Closing before a delscreen() helps ncurses determine that there
+        * is no valid output buffer, and can remove the setbuf() data.
         */
-       for (j = argc - 1; j >= 0; j--) {
-           USING_SCREEN(data[j].screen, close_screen, 0);
-           fprintf(data[j].output, "**Closed\r\n");
-
-           /*
-            * Closing before a delscreen() helps ncurses determine that there
-            * is no valid output buffer, and can remove the setbuf() data.
-            */
-           fflush(data[j].output);
-           fclose(data[j].output);
-           delscreen(data[j].screen);
-       }
-       ExitProgram(EXIT_SUCCESS);
+       fflush(data[j].output);
+       fclose(data[j].output);
+       delscreen(data[j].screen);
+       free_screen(&data[j]);
+       UnlockIt();
     }
+    free(data);
+    ExitProgram(EXIT_SUCCESS);
+}
 #else
 int
 main(void)