]> git.draconx.ca Git - dxcommon.git/commitdiff
Add some curses-related feature tests.
authorNick Bowler <nbowler@draconx.ca>
Tue, 7 Jun 2022 03:56:03 +0000 (23:56 -0400)
committerNick Bowler <nbowler@draconx.ca>
Wed, 8 Jun 2022 01:53:48 +0000 (21:53 -0400)
Add helper macros to check the existence of specific functions in the
curses library, and also a helper to check for mouse support functions.

m4/curses-compat.m4 [new file with mode: 0644]
m4/curses.m4
t/libdummy.c
tests/libs.at

diff --git a/m4/curses-compat.m4 b/m4/curses-compat.m4
new file mode 100644 (file)
index 0000000..c445a67
--- /dev/null
@@ -0,0 +1,93 @@
+dnl Copyright © 2022 Nick Bowler
+dnl
+dnl Macros for probing specific curses library behaviour.
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
+dnl DX_CHECK_CURSES_FUNC(function, [args], [prologue])
+dnl
+dnl Simple yes/no check for whether the curses library provides the specified
+dnl function.  If it does, the macro HAVE_CURSES_func macro is defined to 1,
+dnl where func is the specified function name in capital letters.  The cache
+dnl variable dx_cv_curses_have_func is set to "yes" if the function is
+dnl detected, or "no" otherwise.
+dnl
+dnl The second argument is the argument list (without its enclosing
+dnl parentheses) used to construct a syntactically valid function call.
+dnl Typically most arguments can simply be 0.
+dnl
+dnl The third argument is additional C code to be placed before the function
+dnl call within main.  This can include declarations and statements.
+AC_DEFUN([DX_CHECK_CURSES_FUNC],
+[_DX_CURSES_LINKTEST([supports $1], [$1], [$3; $1($2)])])
+
+dnl DX_CHECK_CURSES_GETMOUSE_NCURSES
+dnl
+dnl Check if the curses library provides the getmouse function with an
+dnl ncurses-compatible interface.  Some other curses libraries also have
+dnl a function named getmouse but with a totally different interface.
+dnl
+dnl If so, the macro HAVE_CURSES_GETMOUSE_NCURSES is defined to 1 and the
+dnl cache variable dx_cv_curses_have_getmouse_ncurses is set to "yes".
+dnl Otherwise the cache variable is set to "no".
+AC_DEFUN([DX_CHECK_CURSES_GETMOUSE_NCURSES],
+[_DX_CURSES_LINKTEST([has ncurses-like getmouse], [getmouse_ncurses],
+[MEVENT ev; { extern int getmouse(MEVENT *); getmouse(&ev); } getmouse(&ev)])])
+
+dnl DX_CHECK_CURSES_MOUSE_SUPPORT
+dnl
+dnl Probe a set of mouse-related curses functions to figure out what is
+dnl needed for basic mouse support.  This is implemented using the preceding
+dnl macros and sets the same outputs.
+dnl
+dnl Additionally, the HAVE_CURSES_MOUSE_SUPPORT macro is defined to 1 if:
+dnl
+dnl   - one of mouse_set or mousemask is found, and
+dnl   - one of ncurses-style getmouse or request_mouse_pos is found.
+dnl
+dnl Currently, this probes the following functions, in order:
+dnl
+dnl   - mouse_set
+dnl   - mousemask
+dnl   - mouseinterval
+dnl   - getmouse (with ncurses interface)
+dnl   - request_mouse_pos
+dnl
+dnl To save time, not all functions are probed; only the minimum required to
+dnl determine that curses does (or does not) have usable mouse support.  As a
+dnl result, libraries that support multiple interfaces such as pdcurses might
+dnl not have every supported function reflected in the configuration macros.
+AC_DEFUN([DX_CHECK_CURSES_MOUSE_SUPPORT],
+[DX_CHECK_CURSES_FUNC([mouse_set], [BUTTON1_PRESSED])
+AS_IF([test x"$dx_cv_curses_have_mouse_set" != x"yes"],
+  [DX_CHECK_CURSES_FUNC([mousemask], [BUTTON1_PRESSED,0])])
+AS_CASE([$dx_cv_curses_have_mouse_set$dx_cv_curses_have_mousemask],
+[*yes*], [DX_CHECK_CURSES_FUNC([mouseinterval], [0])
+DX_CHECK_CURSES_GETMOUSE_NCURSES
+AS_IF([test x"$dx_cv_curses_have_getmouse_ncurses" != x"yes"],
+  [DX_CHECK_CURSES_FUNC([request_mouse_pos], [],
+    [switch (BUTTON_STATUS(1)) case BUTTON_PRESSED:;])])
+AS_CASE(
+[$dx_cv_curses_have_getmouse_ncurses$dx_cv_curses_have_request_mouse_pos],
+  [*yes*], [AC_DEFINE([HAVE_CURSES_MOUSE_SUPPORT], [1],
+    [Define to 1 if curses has usable mouse support.])])])])
+
+dnl _DX_CURSES_LINKTEST(message, key, body)
+dnl
+dnl Internal macro common to the tests above.  "message" is used to construct
+dnl the configure output and config.h template description; "key" is used to
+dnl construct macro and cache variable names; "body" is the C function body
+dnl to compile.
+AC_DEFUN([_DX_CURSES_LINKTEST],
+[AC_CACHE_CHECK([whether curses $1], [AS_TR_SH([dx_cv_curses_have_$2])],
+[_dx_save_CFLAGS=$CFLAGS _dx_save_LIBS=$LIBS
+CFLAGS="$CFLAGS $CURSES_CFLAGS" LIBS="$CURSES_LIBS"
+AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <curses.h>
+], [$3;])], [AS_TR_SH([dx_cv_curses_have_$2])=yes],
+[AS_TR_SH([dx_cv_curses_have_$2])=no])
+CFLAGS=$_dx_save_CFLAGS LIBS=$_dx_save_LIBS])
+AS_IF([test x"$AS_TR_SH([dx_cv_curses_have_$2])" = x"yes"],
+  [AC_DEFINE(AS_TR_CPP([HAVE_CURSES_$2]), [1],
+    [Define to 1 if your curses library $1])])])
index f03711c57a05320852a28deab736db0cefbc75fc..57aa76e62d45769fb3749ed4b1a2ebbc2252d468 100644 (file)
@@ -5,7 +5,8 @@ dnl This is free software: you are free to do what the fuck you want to.
 dnl There is NO WARRANTY, to the extent permitted by law.
 
 AC_DEFUN([DX_LIB_CURSES],
-[DX_LIB_SETUP([curses])dnl
+[AC_BEFORE([$0], [_DX_CURSES_LINKTEST])dnl
+DX_LIB_SETUP([curses])dnl
 DX_LIB_PKGCONFIG_FLAGS([ncurses])
 AC_MSG_CHECKING([for curses])
 DX_LIB_SEARCH_LINK([curses],
index dfa2c7d90b80823ce7bbb746d886650dd700d9d9..3e40d130941eef1390dca6b66304db67d77aa852 100644 (file)
@@ -5,3 +5,12 @@ void discid_free(void) {}
 void curs_set(int x) {}
 
 void g_get_prgname(void) {}
+
+int mouse_set(unsigned long mask) { return 0; }
+int request_mouse_pos(void) { return 0; }
+unsigned getmouse(void) { return 0; }
+unsigned long mousemask(unsigned long a, unsigned long *b) { return 0; }
+
+struct MEVENT;
+int getmouse_nc_(struct MEVENT *mev) { return 0; }
+int getmouse_bogus_(void *p) { return 0; }
index 89ecf67eb2f563a8f83eb1a3c24a2479350dafbc..1d327cc1afcc335b27d852120f9326c471b31de9 100644 (file)
@@ -141,6 +141,140 @@ AT_CHECK_UNQUOTED([cat test], [0], [no
 
 AT_CLEANUP
 
+AT_SETUP([DX_CHECK_CURSES_GETMOUSE_NCURSES])
+AT_KEYWORDS([lib curses ncurses])
+
+mkdir ncurses sysv bogus
+AT_DATA([ncurses/curses.h],
+[[typedef struct MEVENT { int x; } MEVENT;
+int getmouse_nc_(MEVENT *);
+#define getmouse getmouse_nc_
+]])
+
+AT_DATA([sysv/curses.h],
+[[unsigned getmouse(void);
+]])
+
+AT_DATA([bogus/curses.h],
+[[typedef int MEVENT;
+int getmouse_bogus_(void *);
+#define getmouse getmouse_bogus_
+]])
+
+AT_DATA([test.in],
+[[@dx_cv_curses_have_getmouse_ncurses@
+]])
+
+TEST_CONFIGURE_AC([[AC_CONFIG_HEADERS([config.h])
+DX_CHECK_CURSES_GETMOUSE_NCURSES
+AC_SUBST([dx_cv_curses_have_getmouse_ncurses])
+AC_CONFIG_FILES([test])
+]])
+TEST_AUTORECONF
+
+TEST_CONFIGURE([CURSES_CFLAGS=-Incurses CURSES_LIBS="$builddir/t/libdummy.a"])
+AT_CHECK([cat test && grep HAVE_CURSES config.h], [0], [yes
+#define HAVE_CURSES_GETMOUSE_NCURSES 1
+])
+
+TEST_CONFIGURE([CURSES_CFLAGS=-Isysv CURSES_LIBS="$builddir/t/libdummy.a"])
+AT_CHECK([cat test && grep HAVE_CURSES config.h], [0], [no
+/* #undef HAVE_CURSES_GETMOUSE_NCURSES */
+])
+
+TEST_CONFIGURE([CURSES_CFLAGS=-Ibogus CURSES_LIBS="$builddir/t/libdummy.a"])
+AT_CHECK([cat test && grep HAVE_CURSES config.h], [0], [no
+/* #undef HAVE_CURSES_GETMOUSE_NCURSES */
+])
+
+AT_CLEANUP
+
+AT_SETUP([DX_CHECK_CURSES_MOUSE_SUPPORT])
+AT_KEYWORDS([lib curses ncurses])
+
+mkdir hp ncurses sysv
+
+# HP-UX 11 curses contains definitions of mouse functions in the library but
+# is missing declarations and associated macros in <curses.h>, although they
+# are present in the alternate "cur_colr" implementation.
+#
+# Regardless, neither implementation seems to have working mouse support with
+# any X terminal emulator so for now no workarounds are provided and the checks
+# are expected to return "no".
+AT_DATA([hp/curses.h],
+[[int mouse_set(unsigned long);
+int request_mouse_pos(void);
+]])
+
+# Ncurses-like mouse functions.
+AT_DATA([ncurses/curses.h],
+[[unsigned long mousemask(unsigned long, unsigned long *);
+typedef int MEVENT;
+int getmouse_nc_(MEVENT *);
+#define getmouse getmouse_nc_
+#define BUTTON1_RELEASED 1L
+#define BUTTON1_PRESSED 2L
+
+/* rename this to avoid false positives in the test */
+#define mouse_set mouse_set_bogus_
+]])
+
+# SysV-like mouse funcitons.
+AT_DATA([sysv/curses.h],
+[[int mouse_set(unsigned long);
+int request_mouse_pos(void);
+
+#define BUTTON_STATUS(x) 0
+#define BUTTON_RELEASED 0
+#define BUTTON_PRESSED 1
+
+#define BUTTON1_RELEASED 1L
+#define BUTTON1_PRESSED 2L
+]])
+
+AT_DATA([test.in],
+[[@dx_cv_curses_have_mouse_set@
+@dx_cv_curses_have_mousemask@
+@dx_cv_curses_have_getmouse_ncurses@
+@dx_cv_curses_have_request_mouse_pos@
+]])
+
+TEST_CONFIGURE_AC([[AC_CONFIG_HEADERS([config.h])
+DX_CHECK_CURSES_MOUSE_SUPPORT
+AC_SUBST([dx_cv_curses_have_mouse_set])
+AC_SUBST([dx_cv_curses_have_mousemask])
+AC_SUBST([dx_cv_curses_have_request_mouse_pos])
+AC_SUBST([dx_cv_curses_have_getmouse_ncurses])
+AC_CONFIG_FILES([test])
+]])
+TEST_AUTORECONF
+
+TEST_CONFIGURE([CURSES_CFLAGS=-Ihp CURSES_LIBS="$builddir/t/libdummy.a"])
+AT_CHECK([cat test && grep CURSES_MOUSE_SUPPORT config.h], [0], [no
+no
+
+
+/* #undef HAVE_CURSES_MOUSE_SUPPORT */
+])
+
+TEST_CONFIGURE([CURSES_CFLAGS=-Incurses CURSES_LIBS="$builddir/t/libdummy.a"])
+AT_CHECK([cat test && grep CURSES_MOUSE_SUPPORT config.h], [0], [no
+yes
+yes
+
+#define HAVE_CURSES_MOUSE_SUPPORT 1
+])
+
+TEST_CONFIGURE([CURSES_CFLAGS=-Isysv CURSES_LIBS="$builddir/t/libdummy.a"])
+AT_CHECK([cat test && grep CURSES_MOUSE_SUPPORT config.h], [0], [yes
+
+no
+yes
+#define HAVE_CURSES_MOUSE_SUPPORT 1
+])
+
+AT_CLEANUP
+
 AT_SETUP([GLib GNU inline workaround])
 
 TEST_DUMMY_PKGCONFIG([-I.], [$builddir/t/libdummy.a])