From 8c1ee49d76ea920662b31211606a60dbcbd19ea9 Mon Sep 17 00:00:00 2001 From: thor Date: Sat, 14 May 2022 13:26:37 +0000 Subject: [PATCH] term: the new switchery to later enable term_type=win32 git-svn-id: svn://scm.orgis.org/mpg123/trunk@5082 35dc7657-300d-0410-a2e5-dc2837fedb53 --- configure.ac | 14 ++++ src/Makemodule.am | 13 +++ src/common.c | 1 + src/local.c | 60 -------------- src/mpg123.c | 1 + src/out123.c | 5 -- src/term.c | 139 +++----------------------------- src/term_none.c | 31 ++++++++ src/term_posix.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 268 insertions(+), 195 deletions(-) create mode 100644 src/term_none.c create mode 100644 src/term_posix.c diff --git a/configure.ac b/configure.ac index 9220127e..5e63f437 100644 --- a/configure.ac +++ b/configure.ac @@ -1209,11 +1209,13 @@ if test "x$have_mmap" = "xno"; then AC_CHECK_FUNCS([shmget shmat shmdt shmctl],[], [buffer=disabled]) fi +term_type=none # Check if system supports termios AC_SYS_POSIX_TERMIOS if test "x$ac_cv_sys_posix_termios" = "xyes"; then AC_DEFINE_UNQUOTED([HAVE_TERMIOS], 1, [Define this if you have the POSIX termios library]) + term_type=posix fi AC_CHECK_FUNCS( random ) @@ -2659,6 +2661,12 @@ AM_CONDITIONAL([NET123_EXEC], [ test x$network_type = xexec ]) AM_CONDITIONAL([NET123_WINHTTP], [ test x$network_type = xwinhttp ]) AM_CONDITIONAL([NET123_WININET], [ test x$network_type = xwininet ]) +dnl ############## Terminal choice + +AM_CONDITIONAL( [TERM_POSIX], [test "x$term_type" = xposix] ) +AM_CONDITIONAL( [TERM_NONE], [test "x$term_type" = xnone] ) +AM_CONDITIONAL( [TERM_WIN32], [test "x$term_type" = xwin32] ) + dnl ############## FIFO enable if test x"$fifo" = xauto; then @@ -2718,6 +2726,11 @@ AC_CONFIG_FILES([ src/libsyn123/syn123.h ]) + +AM_CONDITIONAL( [TERM_POSIX], [test "x$term_type" = xposix] ) +AM_CONDITIONAL( [TERM_NONE], [test "x$term_type" = xnone] ) + + AC_OUTPUT @@ -2732,6 +2745,7 @@ echo " Compiler Optimization ... $with_optimization Gapless Support ......... $gapless Debugging ............... $debugging + Terminal control ........ $term_type Extreme debugging ....... $xdebugging Seek table size ......... $seektable FIFO support ............ $fifo diff --git a/src/Makemodule.am b/src/Makemodule.am index 68d9668a..7b302179 100644 --- a/src/Makemodule.am +++ b/src/Makemodule.am @@ -75,6 +75,7 @@ src_mpg123_SOURCES = \ src/streamdump.c \ src/term.c \ src/term.h \ + src/terms.h \ src/win32_support.h # Does that finally work to build/link the correct object file? @@ -105,6 +106,18 @@ src_mpg123_strip_SOURCES = \ src/getlopt.c \ src/getlopt.h +if TERM_POSIX +src_mpg123_SOURCES += src/term_posix.c +endif + +if TERM_WIN32 +src_mpg123_SOURCES += src/term_win32.c +endif + +if TERM_NONE +src_mpg123_SOURCES += src/term_none.c +endif + if NET123_EXEC src_mpg123_SOURCES += src/net123.h src/net123_exec.c endif diff --git a/src/common.c b/src/common.c index 164943a5..2421fd50 100644 --- a/src/common.c +++ b/src/common.c @@ -15,6 +15,7 @@ #include "out123.h" #include #include "common.h" +#include "terms.h" #include "debug.h" diff --git a/src/local.c b/src/local.c index a3424198..d012e8a5 100644 --- a/src/local.c +++ b/src/local.c @@ -112,66 +112,6 @@ static int is_utf8(const char *lang) return 0; } -int term_have_fun(int fd, int want_visuals) -{ - if(term_is_fun > -1) - return term_is_fun; - else - term_is_fun = 0; -#ifdef HAVE_TERMIOS - if(term_width(fd) > 0 && want_visuals) - { - /* Only play with non-dumb terminals. */ - char *tname = compat_getenv("TERM"); - if(tname) - { - if(strcmp(tname, "") && strcmp(tname, "dumb")) - term_is_fun = 1; - free(tname); - } - } -#endif - return term_is_fun; -} - -/* Also serves as a way to detect if we have an interactive terminal. */ -int term_width(int fd) -{ -#ifdef HAVE_TERMIOS -/* POSIX */ - struct winsize geometry; - geometry.ws_col = 0; - if(ioctl(fd, TIOCGWINSZ, &geometry) >= 0) - return (int)geometry.ws_col; -#elif defined(WIN32) - CONSOLE_SCREEN_BUFFER_INFO pinfo; - HANDLE hStdout; - DWORD handle; - - switch(fd){ - case STDIN_FILENO: - handle = STD_INPUT_HANDLE; - break; - case STDOUT_FILENO: - handle = STD_OUTPUT_HANDLE; - break; - case STDERR_FILENO: - handle = STD_ERROR_HANDLE; - break; - default: - return -1; - } - - hStdout = GetStdHandle(handle); - if(hStdout == INVALID_HANDLE_VALUE || hStdout == NULL) - return -1; - if(GetConsoleScreenBufferInfo(hStdout, &pinfo)){ - return pinfo.dwMaximumWindowSize.X; - } -#endif - return -1; -} - // Moved encoding stuff over from metaprint.c and removed references to libmpg123, // meaning no mpg123_string for you! diff --git a/src/mpg123.c b/src/mpg123.c index 3ae3c7e8..24aab7a1 100644 --- a/src/mpg123.c +++ b/src/mpg123.c @@ -36,6 +36,7 @@ #include "sysutil.h" #include "getlopt.h" #include "term.h" +#include "terms.h" #include "playlist.h" #include "metaprint.h" #include "httpget.h" diff --git a/src/out123.c b/src/out123.c index de10622f..3d4170b1 100644 --- a/src/out123.c +++ b/src/out123.c @@ -88,9 +88,6 @@ enum runmodes static int runmode = RUN_MAIN; -int stdout_is_term = FALSE; // It's an interactive terminal. -int stderr_is_term = FALSE; // It's an interactive terminal. - static FILE* input = NULL; static char *encoding_name = NULL; static int encoding = MPG123_ENC_SIGNED_16; @@ -1511,8 +1508,6 @@ int main(int sys_argc, char ** sys_argv) _wildcard(&argc,&argv); #endif - stderr_is_term = term_width(STDERR_FILENO) >= 0; - stdout_is_term = term_width(STDOUT_FILENO) >= 0; while ((result = getlopt(argc, argv, opts))) switch (result) { case GLO_UNKNOWN: diff --git a/src/term.c b/src/term.c index c03b4d7e..ab17a9a3 100644 --- a/src/term.c +++ b/src/term.c @@ -8,30 +8,21 @@ #include "mpg123app.h" -#ifdef HAVE_TERMIOS - #include #include #include "term.h" +#include "terms.h" #include "common.h" #include "playlist.h" #include "metaprint.h" #include "debug.h" static int term_enable = 0; -// This now always refers to a freshly opened terminal descriptor (e.g. /dev/tty). -// Printouts to stderr are independent of this. -static int term_fd = -1; -static struct termios old_tio; int seeking = FALSE; extern out123_handle *ao; -/* Buffered key from a signal or whatnot. - We ignore the null character... */ -static char prekey = 0; - /* Hm, next step would be some system in this, plus configurability... Two keys for everything? It's just stop/pause for now... */ struct keydef { const char key; const char key2; const char* desc; }; @@ -74,51 +65,6 @@ struct keydef term_help[] = ,{ MPG123_TREBLE_DOWN_KEY, 0, "less treble" } }; -void term_sigcont(int sig); -static void term_sigusr(int sig); - -/* This must call only functions safe inside a signal handler. */ -int term_setup(struct termios *pattern) -{ - mdebug("setup on fd %d", term_fd); - - /* One might want to use sigaction instead. */ - signal(SIGCONT, term_sigcont); - signal(SIGUSR1, term_sigusr); - signal(SIGUSR2, term_sigusr); -#ifndef __OS2__ - struct termios tio = *pattern; - tio.c_lflag &= ~(ICANON|ECHO); - tio.c_cc[VMIN] = 1; - tio.c_cc[VTIME] = 0; - return tcsetattr(term_fd,TCSANOW,&tio); -#else - return 0; -#endif -} - -void term_sigcont(int sig) -{ - term_enable = 0; - - if (term_setup(&old_tio) < 0) - { - fprintf(stderr,"Can't set terminal attributes\n"); - return; - } - - term_enable = 1; -} - -static void term_sigusr(int sig) -{ - switch(sig) - { - case SIGUSR1: prekey=*param.term_usr1; break; - case SIGUSR2: prekey=*param.term_usr2; break; - } -} - /* initialze terminal */ void term_init(void) { @@ -133,41 +79,15 @@ void term_init(void) return; term_enable = 0; - const char *term_name; -#ifdef HAVE_CTERMID - term_name = ctermid(NULL); -#else - term_name = "/dev/tty"; -#endif - if(term_name) - mdebug("accessing terminal for control via %s", term_name); - else + errno = 0; + if(term_setup() < 0) { - error("no controlling terminal"); + if(errno) + merror("failed to set up terminal: %s", strerror(errno)); + else + error("failed to set up terminal"); return; } - term_fd = open(term_name, O_RDONLY); - if(term_fd < 0) - { - merror("failed to open terminal: %s", strerror(errno)); - return; - } -// Testing if OS2 works without the attr fun, at all. -#ifndef __OS2__ - if(tcgetattr(term_fd, &old_tio) < 0) - { - merror("failed to get terminal attributes: %s", strerror(errno)); - return; - } - - if(term_setup(&old_tio) < 0) - { - close(term_fd); - error("failure setting terminal attributes"); - return; - } -#endif - term_enable = 1; } @@ -286,37 +206,6 @@ static void seekmode(mpg123_handle *mh, out123_handle *ao) } } -/* Get the next pressed key, if any. - Returns 1 when there is a key, 0 if not. */ -static int get_key(int do_delay, char *val) -{ - fd_set r; - struct timeval t; - - /* Shortcut: If some other means sent a key, use it. */ - if(prekey) - { - debug1("Got prekey: %c\n", prekey); - *val = prekey; - prekey = 0; - return 1; - } - - t.tv_sec=0; - t.tv_usec=(do_delay) ? 10*1000 : 0; - - FD_ZERO(&r); - FD_SET(term_fd,&r); - if(select(term_fd+1,&r,NULL,NULL,&t) > 0 && FD_ISSET(term_fd,&r)) - { - if(read(term_fd,val,1) <= 0) - return 0; /* Well, we couldn't read the key, so there is none. */ - else - return 1; - } - else return 0; -} - static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val) { debug1("term_handle_key: %c", val); @@ -622,7 +511,7 @@ static void term_handle_input(mpg123_handle *fr, out123_handle *ao, int do_delay { char val; /* Do we really want that while loop? This means possibly handling multiple inputs that come very rapidly in one go. */ - while(get_key(do_delay, &val)) + while(term_get_key(do_delay, &val)) { term_handle_key(fr, ao, val); } @@ -638,15 +527,5 @@ void term_exit(void) if(!term_enable) return; -#ifndef __OS2__ - debug("reset attrbutes"); - tcsetattr(term_fd,TCSAFLUSH,&old_tio); -#endif - - if(term_fd > -1) - close(term_fd); - term_fd = -1; + term_restore(); } - -#endif - diff --git a/src/term_none.c b/src/term_none.c new file mode 100644 index 00000000..ec24e08b --- /dev/null +++ b/src/term_none.c @@ -0,0 +1,31 @@ +/* + term_none: no-op terminal, nothing at all + + copyright 2008-2022 by the mpg123 project - free software under the terms of the LGPL 2.1 + see COPYING and AUTHORS files in distribution or http://mpg123.org + initially written by Thomas Orgis and Jonathan Yong +*/ + +int term_have_fun(int fd, int want_visuals) +{ + return 0; +} + +int term_width(int fd) +{ + return -1; +} + +int term_setup(void) +{ + return -1; +} + +void term_restore(void) +{ +} + +int term_get_key(int do_delay, char *val) +{ + return 0; +} diff --git a/src/term_posix.c b/src/term_posix.c new file mode 100644 index 00000000..e49132c1 --- /dev/null +++ b/src/term_posix.c @@ -0,0 +1,199 @@ +/* + term_posix: POSIX-specifc terminal functionality + + HAVE_TERMIOS is a prerequisite. + + copyright 2008-2022 by the mpg123 project - free software under the terms of the LGPL 2.1 + see COPYING and AUTHORS files in distribution or http://mpg123.org + initially written by Thomas Orgis +*/ + +#include "config.h" + +#include "compat.h" + +#ifndef HAVE_TERMIOS +#error "No TERMIOS? Here?" +#endif + +// for param struct +#include "mpg123app.h" + +#include +#include + +#include "terms.h" + +#include "debug.h" + +static int term_is_fun = -1; +// This now always refers to a ;freshly opened terminal descriptor (e.g. /dev/tty). +// Printouts to stderr are independent of this. +static int term_fd = -1; +static struct termios old_tio; + +/* Buffered key from a signal or whatnot. + We ignore the null character... */ +static char prekey = 0; + +int term_have_fun(int fd, int want_visuals) +{ + if(term_is_fun > -1) + return term_is_fun; + else + term_is_fun = 0; + if(term_width(fd) > 0 && want_visuals) + { + /* Only play with non-dumb terminals. */ + char *tname = compat_getenv("TERM"); + if(tname) + { + if(strcmp(tname, "") && strcmp(tname, "dumb")) + term_is_fun = 1; + free(tname); + } + } + return term_is_fun; +} + +/* Also serves as a way to detect if we have an interactive terminal. */ +int term_width(int fd) +{ + struct winsize geometry; + geometry.ws_col = 0; + if(ioctl(fd, TIOCGWINSZ, &geometry) >= 0) + return (int)geometry.ws_col; + return -1; +} + +static int term_setup_detail(struct termios *pattern); + +static void term_sigcont(int sig) +{ + if(term_setup_detail(&old_tio) < 0) + { + debug("Can't set terminal attributes"); + return; + } +} + +static void term_sigusr(int sig) +{ + switch(sig) + { + case SIGUSR1: prekey=*param.term_usr1; break; + case SIGUSR2: prekey=*param.term_usr2; break; + } +} + +/* This must call only functions safe inside a signal handler. */ +static int term_setup_detail(struct termios *pattern) +{ + mdebug("setup on fd %d", term_fd); + + /* One might want to use sigaction instead. */ + signal(SIGCONT, term_sigcont); + signal(SIGUSR1, term_sigusr); + signal(SIGUSR2, term_sigusr); + struct termios tio = *pattern; + tio.c_lflag &= ~(ICANON|ECHO); + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; +#ifdef __OS2__ + // Do not care for the error until OS/2 is known to work. + tcsetattr(term_fd,TCSANOW,&tio); + return 0; +#else + return tcsetattr(term_fd,TCSANOW,&tio); +#endif +} + +int term_setup(void) +{ + if(term_fd < 0) + { + const char *term_name; +#ifdef HAVE_CTERMID + term_name = ctermid(NULL); +#else + term_name = "/dev/tty"; +#endif + if(term_name) + mdebug("accessing terminal for control via %s", term_name); + else + { + error("no controlling terminal"); + return -1; + } + term_fd = open(term_name, O_RDONLY); + if(term_fd < 0) + { + merror("failed to open terminal: %s", strerror(errno)); + return -1; + } + } + + if(tcgetattr(term_fd, &old_tio) < 0) + { + // For now, this always fails on OS/2, but they might fix things. + // So just try to move on. +#ifndef __OS2__ + merror("failed to get terminal attributes: %s", strerror(errno)); + return -1; +#endif + } + + errno = 0; + if(term_setup_detail(&old_tio) < 0) + { + close(term_fd); + term_fd = -1; + if(errno) + merror("failure setting terminal attributes: %s", strerror(errno)); + else + error("failure setting terminal attributes"); + return -1; + } + return 0; +} + +/* Get the next pressed key, if any. + Returns 1 when there is a key, 0 if not. */ +int term_get_key(int do_delay, char *val) +{ + fd_set r; + struct timeval t; + + /* Shortcut: If some other means sent a key, use it. */ + if(prekey) + { + debug1("Got prekey: %c\n", prekey); + *val = prekey; + prekey = 0; + return 1; + } + + t.tv_sec=0; + t.tv_usec=(do_delay) ? 10*1000 : 0; + + FD_ZERO(&r); + FD_SET(term_fd,&r); + if(select(term_fd+1,&r,NULL,NULL,&t) > 0 && FD_ISSET(term_fd,&r)) + { + if(read(term_fd,val,1) <= 0) + return 0; /* Well, we couldn't read the key, so there is none. */ + else + return 1; + } + else return 0; +} + +void term_restore(void) +{ + debug("reset attrbutes"); + tcsetattr(term_fd,TCSAFLUSH,&old_tio); + + if(term_fd > -1) + close(term_fd); + term_fd = -1; +}