From 5869159abfbd8973e3cf37ea53bed7f1cae20b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Palmat=C3=A8?= Date: Sat, 13 Aug 2022 20:42:04 +0200 Subject: [PATCH 1/3] Removed hidden macro and replaced with HIDDEN --- library/include/features.h | 6 +++--- library/prng/rand48.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/include/features.h b/library/include/features.h index f798bd24..e54f295f 100755 --- a/library/include/features.h +++ b/library/include/features.h @@ -440,9 +440,9 @@ # define __USE_EXTERN_INLINES 1 #endif -#define weak __attribute__((__weak__)) -#define hidden __attribute__((__visibility__("hidden"))) -#define weak_alias(old, new) \ +#define WEAK __attribute__((__weak__)) +#define HIDDEN __attribute__((__visibility__("hidden"))) +#define WEAK_ALIAS(old, new) \ extern __typeof(old) new __attribute__((__weak__, __alias__(#old))) diff --git a/library/prng/rand48.h b/library/prng/rand48.h index ab774957..9ab8979c 100644 --- a/library/prng/rand48.h +++ b/library/prng/rand48.h @@ -1,5 +1,5 @@ #include #include -hidden uint64_t __rand48_step(unsigned short *xi, unsigned short *lc); -extern hidden unsigned short __seed48[7]; +HIDDEN uint64_t __rand48_step(unsigned short *xi, unsigned short *lc); +extern HIDDEN unsigned short __seed48[7]; From 99718a345f5708d6a63fcfc195cb91994579510b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Palmat=C3=A8?= Date: Tue, 16 Aug 2022 13:12:11 +0200 Subject: [PATCH 2/3] Fix a problem on CTRL_C not handled correctly. Try to fix ncurses library to work correctly with terminfo/termcap --- library/fcntl/open.c | 2 +- library/include/termios.h | 82 +-- library/libc_init_global.c | 39 +- library/posix/checkabort.c | 36 -- library/posix/raise.c | 55 +- library/socket/ioctl.c | 1 - library/stdio/file_init.c | 93 +-- library/stdlib/main.c | 8 +- library/termcap/termcap.c | 12 +- library/termios/cfgetispeed.c | 2 + library/termios/cfgetospeed.c | 2 + library/termios/cfmakeraw.c | 3 + library/termios/cfsetispeed.c | 2 + library/termios/cfsetospeed.c | 3 + library/termios/console_fdhookentry.c | 874 ++++++++++++-------------- library/termios/tcflow.c | 2 + library/termios/tcflush.c | 2 + library/termios/tcgetattr.c | 46 +- library/termios/tcsendbreak.c | 2 + library/termios/tcsetattr.c | 11 +- 20 files changed, 630 insertions(+), 647 deletions(-) diff --git a/library/fcntl/open.c b/library/fcntl/open.c index 7aebd6ea..1488696b 100644 --- a/library/fcntl/open.c +++ b/library/fcntl/open.c @@ -259,7 +259,7 @@ open(const char *path_name, int open_flag, ... /* mode_t mode */) { fd = __fd[fd_slot_number]; if (is_directory || FLAG_IS_SET(open_flag, O_PATH)) - __initialize_fd(fd, __fd_hook_entry, dir_lock, 0, fd_lock); + __initialize_fd(fd, __fd_hook_entry, dir_lock, 0, fd_lock); // TODO - Create a new dir hook else __initialize_fd(fd, __fd_hook_entry, handle, 0, fd_lock); diff --git a/library/include/termios.h b/library/include/termios.h index c822052f..29c82eb8 100755 --- a/library/include/termios.h +++ b/library/include/termios.h @@ -51,57 +51,57 @@ struct termios /* c_iflag */ -#define IGNBRK 0x00001 /* Ignore VINTR */ -#define BRKINT 0x00002 /* Unimpl. */ -#define IGNPAR 0x00004 /* Unimpl. */ +#define IGNBRK 0x00001 /* Ignore VINTR */ +#define BRKINT 0x00002 /* Unimpl. */ +#define IGNPAR 0x00004 /* Unimpl. */ #define IMAXBEL 0x00008 /* Unimpl. */ -#define INPCK 0x00010 /* Unimpl. */ -#define ISTRIP 0x00020 /* 7-bit data (strip high bit) */ -#define INLCR 0x00040 /* Map NL->CR */ -#define IGNCR 0x00080 /* Map CR->nothing */ -#define ICRNL 0x00100 /* Map CR->NL */ -#define IXON 0x00400 /* Unimpl. Enable XON/XOFF for output. */ -#define IXOFF 0x01000 /* Unimpl. Enable XON/XOFF for input. */ -#define IUCLC 0x04000 /* Unimpl. */ -#define IXANY 0x08000 /* Unimpl. */ -#define PARMRK 0x10000 /* Unimpl. */ -#define IUTF8 0x20000 /* Unimpl. */ +#define INPCK 0x00010 /* Unimpl. */ +#define ISTRIP 0x00020 /* 7-bit data (strip high bit) */ +#define INLCR 0x00040 /* Map NL->CR */ +#define IGNCR 0x00080 /* Map CR->nothing */ +#define ICRNL 0x00100 /* Map CR->NL */ +#define IXON 0x00400 /* Unimpl. Enable XON/XOFF for output. */ +#define IXOFF 0x01000 /* Unimpl. Enable XON/XOFF for input. */ +#define IUCLC 0x04000 /* Unimpl. */ +#define IXANY 0x08000 /* Unimpl. */ +#define PARMRK 0x10000 /* Unimpl. */ +#define IUTF8 0x20000 /* Unimpl. */ /* c_oflag */ -#define OPOST (1 << 0L) /* Enable output processing. */ -#define ONLCR (1 << 1L) /* Map NL->CR+NL */ -#define OCRNL (1 << 2L) /* Map CR->NL */ -#define ONOCR (1 << 3L) /* Map CR->nothing, but only in column 0. */ -#define ONLRET (1 << 4L) /* Map CR->nothing */ +#define OPOST (1 << 0L) /* Enable output processing. */ +#define ONLCR (1 << 1L) /* Map NL->CR+NL */ +#define OCRNL (1 << 2L) /* Map CR->NL */ +#define ONOCR (1 << 3L) /* Map CR->nothing, but only in column 0. */ +#define ONLRET (1 << 4L) /* Map CR->nothing */ /* c_cflag */ -#define CSIZE (0x07) /* Bit-width mask. */ -#define CS5 (0x01) /* 5-bits */ -#define CS6 (0x02) /* 6-bits */ -#define CS7 (0x03) /* 7-bits */ -#define CS8 (0x04) /* 8-bits */ -#define CSTOPB (1 << 3L) /* Use 2 stop bits. */ -#define CREAD (1 << 4L) /* Enable reading/receiving. */ -#define PARENB (1 << 5L) /* Enable parity generation/checking. */ -#define PARODD (1 << 6L) /* Parity is odd. */ -#define HUPCL (1 << 7L) /* Hangup on close (when the device is closed). */ -#define CLOCAL (1 << 8L) /* Ignore modem control lines (i.e. a null-modem) */ +#define CSIZE (0x07) /* Bit-width mask. */ +#define CS5 (0x01) /* 5-bits */ +#define CS6 (0x02) /* 6-bits */ +#define CS7 (0x03) /* 7-bits */ +#define CS8 (0x04) /* 8-bits */ +#define CSTOPB (1 << 3L) /* Use 2 stop bits. */ +#define CREAD (1 << 4L) /* Enable reading/receiving. */ +#define PARENB (1 << 5L) /* Enable parity generation/checking. */ +#define PARODD (1 << 6L) /* Parity is odd. */ +#define HUPCL (1 << 7L) /* Hangup on close (when the device is closed). */ +#define CLOCAL (1 << 8L) /* Ignore modem control lines (i.e. a null-modem) */ /* c_lflag */ -#define ISIG 0x0001 -#define ICANON 0x0002 -#define ECHO 0x0004 -#define ECHOE 0x0008 -#define ECHOK 0x0010 -#define ECHONL 0x0020 -#define NOFLSH 0x0040 -#define TOSTOP 0x0080 -#define IEXTEN 0x0100 -#define FLUSHO 0x0200 -#define ECHOKE 0x0400 +#define ISIG 0x0001 +#define ICANON 0x0002 +#define ECHO 0x0004 +#define ECHOE 0x0008 +#define ECHOK 0x0010 +#define ECHONL 0x0020 +#define NOFLSH 0x0040 +#define TOSTOP 0x0080 +#define IEXTEN 0x0100 +#define FLUSHO 0x0200 +#define ECHOKE 0x0400 #define ECHOCTL 0x0800 /* Speeds */ diff --git a/library/libc_init_global.c b/library/libc_init_global.c index a1da95ea..513cab2b 100755 --- a/library/libc_init_global.c +++ b/library/libc_init_global.c @@ -29,6 +29,18 @@ #include #include +static APTR +hook_function(struct Hook *hook, APTR userdata, struct Process *process) { + uint32 pid = (uint32) userdata; + (void) (hook); + + if (process->pr_ProcessID == pid) { + return process; + } + + return 0; +} + /* random table */ static uint32_t _random_init[] = { 0x00000000, 0x5851f42d, 0xc0b18ccf, 0xcbb5f646, @@ -45,9 +57,7 @@ static uint32_t _random_init[] = { extern struct Library *__ElfBase; extern struct ElfIFace *__IElf; -struct _clib2 NOCOMMON -* -__global_clib2; +struct _clib2 NOCOMMON* __global_clib2; void reent_init() { @@ -213,8 +223,27 @@ reent_init() { /* Remove timer tasks */ if (__global_clib2->tmr_real_task != NULL) { - Signal((struct Task *) __global_clib2->tmr_real_task, SIGBREAKF_CTRL_F); - WaitForChildExit(__global_clib2->tmr_real_task->pr_ProcessID); + struct Hook h = {{NULL, NULL}, (HOOKFUNC) hook_function, NULL, NULL}; + int32 pid, process; + + /* Block SIGALRM signal from raise */ + sigblock(SIGALRM); + /* Get itimer process ID */ + pid = __global_clib2->tmr_real_task->pr_ProcessID; + + Forbid(); + /* Scan for process */ + process = ProcessScan(&h, (CONST_APTR) pid, 0); + /* If we find the process send a signal to kill it */ + while (process > 0) { + /* Send a SIGBREAKF_CTRL_F signal until the timer task return to Wait state + * and can get the signal */ + Signal((struct Task *) __global_clib2->tmr_real_task, SIGBREAKF_CTRL_F); + process = ProcessScan(&h, (CONST_APTR) pid, 0); + usleep(100); + } + Permit(); + WaitForChildExit(pid); __global_clib2->tmr_real_task = NULL; } diff --git a/library/posix/checkabort.c b/library/posix/checkabort.c index 16a87b03..e04f124a 100644 --- a/library/posix/checkabort.c +++ b/library/posix/checkabort.c @@ -10,47 +10,11 @@ #include "stdio_headers.h" #endif /* _STDIO_HEADERS_H */ -static APTR -hook_function(struct Hook *hook, APTR userdata, struct Process *process) { - uint32 pid = (uint32) userdata; - (void) (hook); - - if (process->pr_ProcessID == pid) { - return process; - } - - return 0; -} - void __check_abort(void) { ENTER(); if (__check_abort_enabled && FLAG_IS_SET(SetSignal(0, __break_signal_mask), __break_signal_mask)) { - if (__global_clib2->tmr_real_task != NULL) { - struct Hook h = {{NULL, NULL}, (HOOKFUNC) hook_function, NULL, NULL}; - int32 pid, process; - - /* Block SIGALRM signal from raise */ - sigblock(SIGALRM); - /* Get itimer process ID */ - pid = __global_clib2->tmr_real_task->pr_ProcessID; - - Forbid(); - /* Scan for process */ - process = ProcessScan(&h, (CONST_APTR) pid, 0); - /* If we find the process send a signal to kill it */ - while (process > 0) { - /* Send a SIGBREAKF_CTRL_F signal until the timer task return to Wait state - * and can get the signal */ - Signal((struct Task *) __global_clib2->tmr_real_task, SIGBREAKF_CTRL_F); - process = ProcessScan(&h, (CONST_APTR) pid, 0); - usleep(100); - } - Permit(); - WaitForChildExit(pid); - __global_clib2->tmr_real_task = NULL; - } raise(SIGINT); } diff --git a/library/posix/raise.c b/library/posix/raise.c index 9c58b4eb..df9a9911 100644 --- a/library/posix/raise.c +++ b/library/posix/raise.c @@ -6,6 +6,22 @@ #include "signal_headers.h" #endif /* _SIGNAL_HEADERS_H */ +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +static APTR +hook_function(struct Hook *hook, APTR userdata, struct Process *process) { + uint32 pid = (uint32) userdata; + (void) (hook); + + if (process->pr_ProcessID == pid) { + return process; + } + + return 0; +} + /* This table holds pointers to all signal handlers configured at a time. */ signal_handler_t NOCOMMON __signal_handler_table[NSIG] = { SIG_DFL, /* SIGHUP */ @@ -82,6 +98,32 @@ raise(int sig) { SHOWMSG("this is the default handler"); if (sig == SIGINT || sig == SIGTERM) { + /* Check ig we have timer terminal running. If so let's kill it */ + if (__global_clib2->tmr_real_task != NULL) { + struct Hook h = {{NULL, NULL}, (HOOKFUNC) hook_function, NULL, NULL}; + int32 pid, process; + + /* Block SIGALRM signal from raise */ + sigblock(SIGALRM); + /* Get itimer process ID */ + pid = __global_clib2->tmr_real_task->pr_ProcessID; + + Forbid(); + /* Scan for process */ + process = ProcessScan(&h, (CONST_APTR) pid, 0); + /* If we find the process send a signal to kill it */ + while (process > 0) { + /* Send a SIGBREAKF_CTRL_F signal until the timer task return to Wait state + * and can get the signal */ + Signal((struct Task *) __global_clib2->tmr_real_task, SIGBREAKF_CTRL_F); + process = ProcessScan(&h, (CONST_APTR) pid, 0); + usleep(100); + } + Permit(); + WaitForChildExit(pid); + __global_clib2->tmr_real_task = NULL; + } + char break_string[80]; /* Turn off ^C checking for good. */ @@ -95,12 +137,7 @@ raise(int sig) { SHOWMSG("bye, bye..."); } /* If we have a SIGALRM without associated handler don't call abort but exit directly */ - else if (sig != SIGALRM) { - /* Drop straight into abort(), which might call signal() - again but is otherwise guaranteed to eventually - land us in _exit(). */ - abort(); - } else if (sig == SIGALRM) { + if (sig == SIGALRM) { __print_termination_message("Alarm Clock"); /* Block SIGALRM signal from raise again */ @@ -109,6 +146,12 @@ raise(int sig) { /* Since we got a signal we interrrupt every sleep function like nanosleep */ Signal((struct Task *) __global_clib2->self, SIGBREAKF_CTRL_E); } + else { + /* Drop straight into abort(), which might call signal() + again but is otherwise guaranteed to eventually + land us in _exit(). */ + abort(); + } } else if (handler == SIG_ERR) { __set_errno(EINVAL); diff --git a/library/socket/ioctl.c b/library/socket/ioctl.c index ca3ab840..91fce49b 100644 --- a/library/socket/ioctl.c +++ b/library/socket/ioctl.c @@ -83,7 +83,6 @@ ioctl(int sockfd, int request, ... /* char *arg */) { SHOWPOINTER(param); result = __IoctlSocket(fd->fd_Socket, request, param); - Printf("result = %ld\n", result); if (result == 0) { const int *option = (const int *) param; diff --git a/library/stdio/file_init.c b/library/stdio/file_init.c index 24c8d863..557b6bcd 100644 --- a/library/stdio/file_init.c +++ b/library/stdio/file_init.c @@ -31,45 +31,46 @@ static BPTR old_input; static BPTR output; static BPTR input; -struct WBStartup *NOCOMMON __WBenchMsg; +struct WBStartup *NOCOMMON +__WBenchMsg; /* CPU cache line size; used to align I/O buffers for best performance. */ ULONG __cache_line_size = 32; FILE_DESTRUCTOR(workbench_exit) -{ - ENTER(); + { + ENTER(); - /* Now clean up after the streams set up for Workbench startup... */ - if (restore_console_task) { - SetConsoleTask((struct MsgPort *) old_console_task); - old_console_task = NULL; + /* Now clean up after the streams set up for Workbench startup... */ + if (restore_console_task) { + SetConsoleTask((struct MsgPort *) old_console_task); + old_console_task = NULL; - restore_console_task = FALSE; - } + restore_console_task = FALSE; + } - if (restore_streams) { - SelectInput(old_input); - old_input = ZERO; + if (restore_streams) { + SelectInput(old_input); + old_input = ZERO; - SelectOutput(old_output); - old_output = ZERO; + SelectOutput(old_output); + old_output = ZERO; - restore_streams = FALSE; - } + restore_streams = FALSE; + } - if (input != ZERO) { - Close(input); - input = ZERO; - } + if (input != ZERO) { + Close(input); + input = ZERO; + } - if (output != ZERO) { - Close(output); - output = ZERO; - } + if (output != ZERO) { + Close(output); + output = ZERO; + } - LEAVE(); -} + LEAVE(); + } static int wb_file_init(void) { @@ -168,13 +169,12 @@ FILE_CONSTRUCTOR(stdio_file_init) } /* Now initialize the standard I/O streams (input, output, error). */ - for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) - { + for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) { switch (i) { case STDIN_FILENO: iob_flags = IOBF_IN_USE | IOBF_READ | IOBF_NO_NUL | IOBF_BUFFER_MODE_LINE; - fd_flags = FDF_IN_USE | FDF_READ | FDF_NO_CLOSE; + fd_flags = FDF_IN_USE | FDF_READ | FDF_NO_CLOSE | FDF_IS_INTERACTIVE; default_file = Input(); break; @@ -229,41 +229,6 @@ FILE_CONSTRUCTOR(stdio_file_init) stdio_lock); } -#if 0 - { - /* If the program was launched from Workbench, we continue by - duplicating the default output stream for use as the - standard error stream. */ - if (__WBenchMsg != NULL) { - __fd[STDERR_FILENO]->fd_File = Output(); - SET_FLAG(__fd[STDERR_FILENO]->fd_Flags, FDF_NO_CLOSE); - } - else { - BPTR ces; - - /* Figure out what the default error output stream is. */ - ces = ErrorOutput(); - - /* Is the standard error stream configured? If so, use it. - Otherwise, try to duplicate the standard output stream. */ - if (ces != ZERO) { - __fd[STDERR_FILENO]->fd_File = ces; - - SET_FLAG(__fd[STDERR_FILENO]->fd_Flags, FDF_NO_CLOSE); - } - else { - __fd[STDERR_FILENO]->fd_File = Open("CONSOLE:", MODE_NEWFILE); - } - } - - /* Figure out if the standard error stream is bound to a console. */ - if (FLAG_IS_CLEAR(__fd[STDERR_FILENO]->fd_Flags, FDF_STDIO)) { - if (IsInteractive(__fd[STDERR_FILENO]->fd_File)) - SET_FLAG(__fd[STDERR_FILENO]->fd_Flags, FDF_IS_INTERACTIVE); - } - } -#endif /* __THREAD_SAFE */ - success = TRUE; out: diff --git a/library/stdlib/main.c b/library/stdlib/main.c index 3553ce5f..fd164662 100644 --- a/library/stdlib/main.c +++ b/library/stdlib/main.c @@ -352,9 +352,11 @@ _main() } /* Set default terminal mode to "amiga" if not set */ - if (FindVar("TERM", LV_VAR) == NULL) { - const char buffer[6] = "amiga\0"; - SetVar("TERM", buffer, -1, 0); + char term_buffer[32] = {0}; + LONG term_len = GetVar("TERM",(STRPTR) term_buffer, 32, 0); + if (term_len <= 0) { + strncpy(term_buffer, "amiga-clib2", 5); + SetVar("TERM", term_buffer, 5, 0); } /* The following code will be executed if the program is to keep diff --git a/library/termcap/termcap.c b/library/termcap/termcap.c index c8a034d9..334feba0 100644 --- a/library/termcap/termcap.c +++ b/library/termcap/termcap.c @@ -19,10 +19,10 @@ Boston, MA 02111-1307, USA. */ /* Emacs config.h may rename various library functions such as malloc. */ -#include -#include -#include -#include +#ifndef _TERMIOS_HEADERS_H +#include "termios_headers.h" +#endif + #include /* BUFSIZE is the initial size allocated for the buffer @@ -230,6 +230,8 @@ tputs(const char *str, int nlines, register int (*outfun)()) { register int padcount = 0; register int speed; + __check_abort(); + if (ospeed == 0) speed = tputs_baud_rate; else if (ospeed >= sizeof(speeds)) @@ -297,6 +299,8 @@ tgetent(char *bp, const char *name) { char *tcenv = NULL; /* TERMCAP value, if it contains :tc=. */ char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */ + __check_abort(); + /* For compatibility with programs like `less' that want to put data in the termcap buffer themselves as a fallback. */ if (bp) diff --git a/library/termios/cfgetispeed.c b/library/termios/cfgetispeed.c index 02b0b1a4..0579d871 100644 --- a/library/termios/cfgetispeed.c +++ b/library/termios/cfgetispeed.c @@ -23,6 +23,8 @@ cfgetispeed(const struct termios *tios) { out: + __check_abort(); + RETURN(result); return (result); } diff --git a/library/termios/cfgetospeed.c b/library/termios/cfgetospeed.c index cef15055..ee2a40a9 100644 --- a/library/termios/cfgetospeed.c +++ b/library/termios/cfgetospeed.c @@ -23,6 +23,8 @@ cfgetospeed(const struct termios *tios) { out: + __check_abort(); + RETURN(result); return (result); } diff --git a/library/termios/cfmakeraw.c b/library/termios/cfmakeraw.c index 82e12135..eecd6ca6 100644 --- a/library/termios/cfmakeraw.c +++ b/library/termios/cfmakeraw.c @@ -29,5 +29,8 @@ cfmakeraw(struct termios *tios) { out: + __check_abort(); + + RETURN(result); return (result); } diff --git a/library/termios/cfsetispeed.c b/library/termios/cfsetispeed.c index 9350f374..40f61d34 100644 --- a/library/termios/cfsetispeed.c +++ b/library/termios/cfsetispeed.c @@ -58,6 +58,8 @@ cfsetispeed(struct termios *tios, speed_t ispeed) { out: + __check_abort(); + RETURN(result); return (result); } diff --git a/library/termios/cfsetospeed.c b/library/termios/cfsetospeed.c index 40a0d52e..5f105561 100644 --- a/library/termios/cfsetospeed.c +++ b/library/termios/cfsetospeed.c @@ -60,5 +60,8 @@ cfsetospeed(struct termios *tios, speed_t ospeed) { out: + __check_abort(); + + RETURN(result); return (result); } diff --git a/library/termios/console_fdhookentry.c b/library/termios/console_fdhookentry.c index b328b8dd..2cda3536 100644 --- a/library/termios/console_fdhookentry.c +++ b/library/termios/console_fdhookentry.c @@ -1,18 +1,14 @@ /* * $Id: termios_console_fdhookentry.c,v 1.7 2021-01-31 13:12:59 clib2devs Exp $ -*/ + * + * Hook for termios emulation on a console. This can probably be cleaned up a bit + * by removing things which will (should) never happen on a console. + */ #ifndef _TERMIOS_HEADERS_H #include "termios_headers.h" #endif /* _TERMIOS_HEADERS_H */ -/****************************************************************************/ - -/* - * Hook for termios emulation on a console. This can probably be cleaned up a bit - * by removing things which will (should) never happen on a console. - */ - #ifndef _STDIO_HEADERS_H #include "stdio_headers.h" #endif /* _STDIO_HEADERS_H */ @@ -21,540 +17,498 @@ #include "unistd_headers.h" #endif /* _UNISTD_HEADERS_H */ -/****************************************************************************/ - #ifndef _STDLIB_MEMORY_H #include "stdlib_memory.h" #endif /* _STDLIB_MEMORY_H */ -/****************************************************************************/ - #include #include -/****************************************************************************/ - /* * Emulate canonical no-echo mode with a simple line-editor in raw mode. */ static int64_t -LineEditor(BPTR file, char *buf, const int buflen, struct termios *tios) -{ - int64_t pos = 0, len = 0; - unsigned char z; - int do_edit = 1; - int shift_mode = 0; - - SetMode(file, DOSTRUE); /* Set raw mode. */ +LineEditor(BPTR file, char *buf, const int buflen, struct termios *tios) { + int64_t pos = 0, len = 0; + unsigned char z; + int do_edit = 1; + int shift_mode = 0; - while (do_edit && len < buflen) - { - if (WaitForChar(file, 5000000) != DOSFALSE) /* 5 seconds. */ - { - if (Read(file, &z, 1) == ERROR) - { - len = -1; - break; - } + SetMode(file, DOSTRUE); /* Set raw mode. */ - if (z == tios->c_cc[VQUIT]) - break; + while (do_edit && len < buflen) { + /* 5 seconds. */ + if (WaitForChar(file, 5000000) != DOSFALSE) { + if (Read(file, &z, 1) == ERROR) { + len = -1; + break; + } - switch (z) - { - case '\n': /* NL */ - case '\r': /* CR */ + if (z == tios->c_cc[VQUIT]) + break; - do_edit = 0; + switch (z) { + case '\n': /* NL */ + case '\r': /* CR */ - buf[len++] = '\n'; - continue; + do_edit = 0; - case 155: /* CSI */ + buf[len++] = '\n'; + continue; - shift_mode = 1; - continue; + case 155: /* CSI */ + shift_mode = 1; + continue; - case '\b': /* Backspace */ + case '\b': /* Backspace */ - if (pos > 0) - { - memmove(&buf[pos - 1], &buf[pos], len - pos); - pos--; - len--; - } + if (pos > 0) { + memmove(&buf[pos - 1], &buf[pos], len - pos); + pos--; + len--; + } - continue; + continue; - case 127: /* Delete */ + case 127: /* Delete */ - if (pos < len) - { - memmove(&buf[pos], &buf[pos + 1], len - pos - 1); - len--; - } + if (pos < len) { + memmove(&buf[pos], &buf[pos + 1], len - pos - 1); + len--; + } - continue; - } + continue; + } - if (shift_mode) - { - shift_mode = 0; + if (shift_mode) { + shift_mode = 0; - switch (z) - { - case 'C': /* Right arrowkey */ + switch (z) { + case 'C': /* Right arrowkey */ - if (pos < len) - pos++; + if (pos < len) + pos++; - continue; + continue; - case 'D': /* Left arrowkey */ + case 'D': /* Left arrowkey */ - if (pos > 0) - pos--; + if (pos > 0) + pos--; - continue; - } - } + continue; + } + } - if (pos != len) - memmove(&buf[pos + 1], &buf[pos], len - pos); + if (pos != len) + memmove(&buf[pos + 1], &buf[pos], len - pos); - buf[pos] = z; - pos++; - len++; - } - } + buf[pos] = z; + pos++; + len++; + } + } - if (len >= 0 && len < buflen) /* Does not hurt to null-terminate if we can. */ - buf[len] = '\0'; + if (len >= 0 && len < buflen) /* Does not hurt to null-terminate if we can. */ + buf[len] = '\0'; - SetMode(file, DOSFALSE); /* Restore mode */ + SetMode(file, DOSFALSE); /* Restore mode */ - return (len); /* Number of characters read. */ + return (len); /* Number of characters read. */ } -/****************************************************************************/ - -int64_t -__termios_console_hook(struct fd *fd, struct file_action_message *fam) -{ - const unsigned char CR = '\r', NL = '\n'; - struct FileHandle *fh; - char *buffer = NULL; - int64_t result = EOF; - int actual_out; - BOOL is_aliased; - BPTR file; - struct termios *tios; - - ENTER(); - - assert(fam != NULL && fd != NULL); - assert(__is_valid_fd(fd)); - assert(FLAG_IS_SET(fd->fd_Flags, FDF_TERMIOS)); - assert(fd->fd_Aux != NULL); - - tios = (struct termios *)fd->fd_Aux; - - /* Careful: file_action_close has to monkey with the file descriptor - table and therefore needs to obtain the stdio lock before - it locks this particular descriptor entry. */ - if (fam->fam_Action == file_action_close) - __stdio_lock(); - - __fd_lock(fd); - - file = __resolve_fd_file(fd); - if (file == ZERO) - { - SHOWMSG("file is closed"); - - fam->fam_Error = EBADF; - goto out; - } - - switch (fam->fam_Action) - { - case file_action_read: - - SHOWMSG("file_action_read"); - - if (FLAG_IS_CLEAR(tios->c_cflag, CREAD)) - { - SHOWMSG("Reading is not enabled for this console descriptor."); - fam->fam_Error = EIO; - goto out; - } - - assert(fam->fam_Data != NULL); - assert(fam->fam_Size > 0); - - D(("read %ld bytes from position %ld to 0x%08lx", fam->fam_Size, Seek(file, 0, OFFSET_CURRENT), fam->fam_Data)); - - /* Attempt to fake everything needed in non-canonical mode. */ - if (FLAG_IS_SET(tios->c_lflag, ICANON)) /* Canonical read = same as usual. Unless... */ - { - if (FLAG_IS_CLEAR(tios->c_lflag, ECHO)) /* No-echo mode needs to be emulated. */ - result = LineEditor(file, fam->fam_Data, fam->fam_Size, tios); - else - result = Read(file, fam->fam_Data, fam->fam_Size); - } - else if (fam->fam_Size > 0) - { - /* Non-canonical reads have timeouts and a minimum number of characters to read. */ - int i = 0; - - result = 0; - - if (tios->c_cc[VMIN] > 0) - { - i = Read(file, fam->fam_Data, 1); /* Reading the first character is not affected by the timeout unless VMIN==0. */ - if (i == ERROR) - { - fam->fam_Error = EIO; - goto out; - } - - result = i; - - while ((result < tios->c_cc[VMIN]) && (result < fam->fam_Size)) - { - if (tios->c_cc[VTIME] > 0) - { - if (WaitForChar(file, 100000 * tios->c_cc[VTIME]) == DOSFALSE) - break; /* No more characters available within alloted time. */ - } - - i = Read(file, &fam->fam_Data[result], 1); - if (i <= 0) - break; /* Break out of this while loop only. */ - - result += i; - } - } - else - { - if (WaitForChar(file, 100000 * tios->c_cc[VTIME])) - result = Read(file, fam->fam_Data, fam->fam_Size); - } - } - else - { - result = 0; /* Reading zero characters will always succeed. */ - } - - if (result == ERROR) - { - D(("read failed ioerr=%ld", IoErr())); - - fam->fam_Error = __translate_io_error_to_errno(IoErr()); - goto out; - } - - if (result > 0) - { - if (tios->c_iflag != 0) /* Input processing enabled. */ - { - int i, n; - int num_bytes = result; - unsigned char byte_in; - - /* XXX The input substitution could possibly be moved to the console handler with an input-map. (?) */ - for (i = n = 0; i < num_bytes; i++) - { - byte_in = fam->fam_Data[i]; - - if (FLAG_IS_SET(tios->c_iflag, ISTRIP)) /* Strip 8:th bit. Done before any other processing. */ - byte_in &= 0x7f; - - if (FLAG_IS_SET(tios->c_iflag, IGNCR) && byte_in == CR) /* Remove CR */ - { - result--; - continue; - } - - if (FLAG_IS_SET(tios->c_iflag, ICRNL) && byte_in == CR) /* Map CR->NL */ - byte_in = NL; - - if (FLAG_IS_SET(tios->c_iflag, INLCR) && byte_in == NL) /* Map NL->CR */ - byte_in = CR; - - fam->fam_Data[n++] = byte_in; - } - } - - if (FLAG_IS_SET(tios->c_lflag, ECHO) && FLAG_IS_CLEAR(tios->c_lflag, ICANON) && FLAG_IS_SET(fd->fd_Flags, FDF_WRITE)) - { - if (Write(file, fam->fam_Data, result) == ERROR) - { - /* "Silently" disable echoing. */ - SHOWMSG("Echo failed and has been disabled."); - CLEAR_FLAG(tios->c_lflag, ECHO); - } - } - } - - if (FLAG_IS_SET(fd->fd_Flags, FDF_CACHE_POSITION)) - fd->fd_Position += (ULONG)result; - - break; - - case file_action_write: - - SHOWMSG("file_action_write"); - - assert(fam->fam_Data != NULL); - assert(fam->fam_Size > 0); - - if (FLAG_IS_SET(tios->c_oflag, OPOST)) /* Output processing enabled. */ - { - unsigned char byte_out; - int i, n; - - buffer = malloc(2 * fam->fam_Size); - if (buffer == NULL) - { - fam->fam_Error = ENOMEM; - goto out; - } - - for (i = n = 0; i < fam->fam_Size; i++) - { - byte_out = fam->fam_Data[i]; - - if (FLAG_IS_SET(tios->c_oflag, ONLRET) && byte_out == CR) - continue; - - if (FLAG_IS_SET(tios->c_oflag, OCRNL) && byte_out == CR) - byte_out = NL; - - if (FLAG_IS_SET(tios->c_oflag, ONOCR) && byte_out == CR) - byte_out = NL; - - if (FLAG_IS_SET(tios->c_oflag, ONLCR) && byte_out == NL) - { - buffer[n++] = CR; - byte_out = NL; - } - - buffer[n++] = byte_out; - } - - actual_out = n; - } - else - { - buffer = fam->fam_Data; - actual_out = fam->fam_Size; - } - - /* Note. When output processing is enabled, write() can return _more_ than the data length. */ - D(("write %ld bytes to position %ld from 0x%08lx", actual_out, Seek(file, 0, OFFSET_CURRENT), buffer)); +int64_t +__termios_console_hook(struct fd *fd, struct file_action_message *fam) { + const unsigned char CR = '\r', NL = '\n'; + struct FileHandle *fh; + char *buffer = NULL; + int64_t result = EOF; + int actual_out; + BOOL is_aliased; + BPTR file; + struct termios *tios; + + ENTER(); + + assert(fam != NULL && fd != NULL); + assert(__is_valid_fd(fd)); + assert(FLAG_IS_SET(fd->fd_Flags, FDF_TERMIOS)); + assert(fd->fd_Aux != NULL); + + tios = (struct termios *) fd->fd_Aux; + + /* Careful: file_action_close has to monkey with the file descriptor + * table and therefore needs to obtain the stdio lock before + * it locks this particular descriptor entry. */ + if (fam->fam_Action == file_action_close) + __stdio_lock(); + + __fd_lock(fd); + + file = __resolve_fd_file(fd); + if (file == ZERO) { + SHOWMSG("file is closed"); + + fam->fam_Error = EBADF; + goto out; + } + + switch (fam->fam_Action) { + case file_action_read: + SHOWMSG("file_action_read"); + + if (FLAG_IS_CLEAR(tios->c_cflag, CREAD)) { + SHOWMSG("Reading is not enabled for this console descriptor."); + fam->fam_Error = EIO; + goto out; + } + assert(fam->fam_Data != NULL); + assert(fam->fam_Size > 0); + + D(("read %ld bytes from position %ld to 0x%08lx", fam->fam_Size, Seek(file, 0, OFFSET_CURRENT), fam->fam_Data)); + + /* Attempt to fake everything needed in non-canonical mode. */ + if (FLAG_IS_SET(tios->c_lflag, ICANON)) { + /* Canonical read = same as usual. Unless... */ + if (FLAG_IS_CLEAR(tios->c_lflag, ECHO)) { + /* No-echo mode needs to be emulated. */ + result = LineEditor(file, fam->fam_Data, fam->fam_Size, tios); + } + else { + result = Read(file, fam->fam_Data, fam->fam_Size); + } + } else if (fam->fam_Size > 0) { + /* Non-canonical reads have timeouts and a minimum number of characters to read. */ + int i = 0; + result = 0; + + if (tios->c_cc[VMIN] > 0) { + /* Reading the first character is not affected by the timeout unless VMIN==0. */ + i = Read(file, fam->fam_Data, 1); + if (i == ERROR) { + fam->fam_Error = EIO; + goto out; + } + + result = i; + + while ((result < tios->c_cc[VMIN]) && (result < fam->fam_Size)) { + if (tios->c_cc[VTIME] > 0) { + if (WaitForChar(file, 100000 * tios->c_cc[VTIME]) == DOSFALSE) + break; /* No more characters available within alloted time. */ + } + + i = Read(file, &fam->fam_Data[result], 1); + if (i <= 0) + break; /* Break out of this while loop only. */ + + result += i; + } + } else { + if (WaitForChar(file, 100000 * tios->c_cc[VTIME])) + result = Read(file, fam->fam_Data, fam->fam_Size); + } + } else { + result = 0; /* Reading zero characters will always succeed. */ + } + + if (result == ERROR) { + D(("read failed ioerr=%ld", IoErr())); + + fam->fam_Error = __translate_io_error_to_errno(IoErr()); + goto out; + } + + if (result > 0) { + /* Input processing enabled. */ + if (tios->c_iflag != 0) { + int64_t i, n; + int64_t num_bytes = result; + unsigned char byte_in; + + /* XXX The input substitution could possibly be moved to the console handler with an input-map. (?) */ + for (i = n = 0; i < num_bytes; i++) { + byte_in = fam->fam_Data[i]; + + if (FLAG_IS_SET(tios->c_iflag, ISTRIP)) { + /* Strip 8:th bit. Done before any other processing. */ + byte_in &= 0x7f; + } + + if (FLAG_IS_SET(tios->c_iflag, IGNCR) && byte_in == CR) { + /* Remove CR */ + result--; + continue; + } + + if (FLAG_IS_SET(tios->c_iflag, ICRNL) && byte_in == CR) /* Map CR->NL */ + byte_in = NL; + + if (FLAG_IS_SET(tios->c_iflag, INLCR) && byte_in == NL) /* Map NL->CR */ + byte_in = CR; + + if (FLAG_IS_SET(tios->c_lflag, ISIG)) { + //Printf("byte_in = %ld\n", byte_in); + switch (byte_in) { + case 3: //INTR + raise(SIGINT); + break; + case 28: //QUIT + raise(SIGQUIT); + break; + default: + // no other signals can be raised + break; + } + } + fam->fam_Data[n++] = byte_in; + } + } + + if (FLAG_IS_SET(tios->c_lflag, ECHO) && FLAG_IS_CLEAR(tios->c_lflag, ICANON) && + FLAG_IS_SET(fd->fd_Flags, FDF_WRITE)) { + if (Write(file, fam->fam_Data, result) == ERROR) { + /* "Silently" disable echoing. */ + SHOWMSG("Echo failed and has been disabled."); + CLEAR_FLAG(tios->c_lflag, ECHO); + } + } + } + + if (FLAG_IS_SET(fd->fd_Flags, FDF_CACHE_POSITION)) + fd->fd_Position += (ULONG) result; + + break; + + case file_action_write: + + SHOWMSG("file_action_write"); + + assert(fam->fam_Data != NULL); + assert(fam->fam_Size > 0); + + if (FLAG_IS_SET(tios->c_oflag, OPOST)) /* Output processing enabled. */ + { + unsigned char byte_out; + int i, n; + + buffer = malloc(2 * fam->fam_Size); + if (buffer == NULL) { + fam->fam_Error = ENOMEM; + goto out; + } + + for (i = n = 0; i < fam->fam_Size; i++) { + byte_out = fam->fam_Data[i]; + + if (FLAG_IS_SET(tios->c_oflag, ONLRET) && byte_out == CR) + continue; + + if (FLAG_IS_SET(tios->c_oflag, OCRNL) && byte_out == CR) + byte_out = NL; + + if (FLAG_IS_SET(tios->c_oflag, ONOCR) && byte_out == CR) + byte_out = NL; + + if (FLAG_IS_SET(tios->c_oflag, ONLCR) && byte_out == NL) { + buffer[n++] = CR; + byte_out = NL; + } + + buffer[n++] = byte_out; + } + + actual_out = n; + } else { + buffer = fam->fam_Data; + actual_out = fam->fam_Size; + } + + /* Note. When output processing is enabled, write() can return _more_ than the data length. */ + D(("write %ld bytes to position %ld from 0x%08lx", actual_out, Seek(file, 0, OFFSET_CURRENT), buffer)); + + if (actual_out > 0) { + result = Write(file, buffer, actual_out); + } else { + result = 0; + } + + if (buffer == fam->fam_Data) + buffer = NULL; /* Must do this to avoid freeing the user data. */ + + if (result == ERROR) { + D(("write failed ioerr=%ld", IoErr())); + + fam->fam_Error = __translate_io_error_to_errno(IoErr()); + goto out; + } + + if (FLAG_IS_SET(fd->fd_Flags, FDF_CACHE_POSITION)) + fd->fd_Position += (ULONG) result; + + break; + + case file_action_close: + + SHOWMSG("file_action_close"); + + /* The following is almost guaranteed not to fail. */ + result = OK; + + /* If this is an alias, just remove it. */ + is_aliased = __fd_is_aliased(fd); + if (is_aliased) { + __remove_fd_alias(fd); + } else if (FLAG_IS_CLEAR(fd->fd_Flags, FDF_STDIO)) { + /* Should we reset this file into line buffered mode? */ + if (FLAG_IS_SET(fd->fd_Flags, FDF_NON_BLOCKING) && FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) + SetMode(fd->fd_File, DOSFALSE); - if (actual_out > 0) - { - result = Write(file, buffer, actual_out); - } - else - { - result = 0; - } - - if (buffer == fam->fam_Data) - buffer = NULL; /* Must do this to avoid freeing the user data. */ + /* Are we allowed to close this file? */ + if (FLAG_IS_CLEAR(fd->fd_Flags, FDF_NO_CLOSE)) { + /* Call a cleanup function, such as the one which + * releases locked records. + */ + if (fd->fd_Cleanup != NULL) + (*fd->fd_Cleanup)(fd); - if (result == ERROR) - { - D(("write failed ioerr=%ld", IoErr())); + if (CANNOT Close(fd->fd_File)) + { + fam->fam_Error = __translate_io_error_to_errno(IoErr()); - fam->fam_Error = __translate_io_error_to_errno(IoErr()); - goto out; - } + result = EOF; + } - if (FLAG_IS_SET(fd->fd_Flags, FDF_CACHE_POSITION)) - fd->fd_Position += (ULONG)result; + fd->fd_File = ZERO; + } + } - break; + __fd_unlock(fd); - case file_action_close: + /* Free the lock semaphore now. */ + if (NOT is_aliased) + __delete_semaphore(fd->fd_Lock); - SHOWMSG("file_action_close"); + /* And that's the last for this file descriptor. */ + memset(fd, 0, sizeof(*fd)); + fd = NULL; - /* The following is almost guaranteed not to fail. */ - result = OK; + break; - /* If this is an alias, just remove it. */ - is_aliased = __fd_is_aliased(fd); - if (is_aliased) - { - __remove_fd_alias(fd); - } - else if (FLAG_IS_CLEAR(fd->fd_Flags, FDF_STDIO)) - { - /* Should we reset this file into line buffered mode? */ - if (FLAG_IS_SET(fd->fd_Flags, FDF_NON_BLOCKING) && FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) - SetMode(fd->fd_File, DOSFALSE); + case file_action_seek: - /* Are we allowed to close this file? */ - if (FLAG_IS_CLEAR(fd->fd_Flags, FDF_NO_CLOSE)) - { - /* Call a cleanup function, such as the one which - * releases locked records. - */ - if (fd->fd_Cleanup != NULL) - (*fd->fd_Cleanup)(fd); - - if (CANNOT Close(fd->fd_File)) - { - fam->fam_Error = __translate_io_error_to_errno(IoErr()); - - result = EOF; - } - - fd->fd_File = ZERO; - } - } - - __fd_unlock(fd); - - /* Free the lock semaphore now. */ - if (NOT is_aliased) - __delete_semaphore(fd->fd_Lock); - - /* And that's the last for this file descriptor. */ - memset(fd, 0, sizeof(*fd)); - fd = NULL; - - break; - - case file_action_seek: - - SHOWMSG("file_action_seek"); + SHOWMSG("file_action_seek"); - fam->fam_Error = EINVAL; - goto out; + fam->fam_Error = EINVAL; + goto out; - case file_action_set_blocking: + case file_action_set_blocking: - SHOWMSG("file_action_set_blocking"); + SHOWMSG("file_action_set_blocking"); - if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) - { - LONG mode; + if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) { + LONG mode; - SHOWMSG("changing the mode"); + SHOWMSG("changing the mode"); - if (fam->fam_Arg != 0) - mode = DOSFALSE; /* buffered mode */ - else - mode = DOSTRUE; /* single character mode */ + if (fam->fam_Arg != 0) + mode = DOSFALSE; /* buffered mode */ + else + mode = DOSTRUE; /* single character mode */ - if (CANNOT SetMode(file, mode)) - { - fam->fam_Error = __translate_io_error_to_errno(IoErr()); - goto out; - } + if (CANNOT SetMode(file, mode)) { + fam->fam_Error = __translate_io_error_to_errno(IoErr()); + goto out; + } - /* Update tios to reflect state change. */ - if (mode == DOSTRUE) - CLEAR_FLAG(tios->c_lflag, ICANON); - else - SET_FLAG(tios->c_lflag, ICANON); + /* Update tios to reflect state change. */ + if (mode == DOSTRUE) + CLEAR_FLAG(tios->c_lflag, ICANON); + else + SET_FLAG(tios->c_lflag, ICANON); - result = OK; - } - else - { - SHOWMSG("can't do anything here"); + result = OK; + } else { + SHOWMSG("can't do anything here"); - fam->fam_Error = EBADF; - } - break; + fam->fam_Error = EBADF; + } + break; - case file_action_examine: + case file_action_examine: - SHOWMSG("file_action_examine"); + SHOWMSG("file_action_examine"); - fh = BADDR(file); + fh = BADDR(file); - /* Special treatment for "NIL:", for which we make - some stuff up. */ - if (fh->fh_Type == NULL) - { - /* Make up some stuff for this stream. */ - memset(fam->fam_FileInfo, 0, sizeof(*fam->fam_FileInfo)); + /* Special treatment for "NIL:", for which we make some stuff up. */ + if (fh->fh_Type == NULL) { + /* Make up some stuff for this stream. */ + memset(fam->fam_FileInfo, 0, sizeof(*fam->fam_FileInfo)); - DateStamp(&fam->fam_FileInfo->Date); + DateStamp(&fam->fam_FileInfo->Date); - fam->fam_FileInfo->Type = ST_NIL; - } - else - { - fam->fam_FileInfo = ExamineObjectTags(EX_FileHandleInput, file, TAG_DONE); - if (fam->fam_FileInfo == NULL) - { - LONG error; + fam->fam_FileInfo->Type = ST_NIL; + } else { + fam->fam_FileInfo = ExamineObjectTags(EX_FileHandleInput, file, TAG_DONE); + if (fam->fam_FileInfo == NULL) { + LONG error; - /* So that didn't work. Did the file system simply fail to - respond to the request or is something more sinister - at work? */ - error = IoErr(); - if (error != ERROR_ACTION_NOT_KNOWN) - { - SHOWMSG("couldn't examine the file"); + /* So that didn't work. Did the file system simply fail to + respond to the request or is something more sinister + at work? */ + error = IoErr(); + if (error != ERROR_ACTION_NOT_KNOWN) { + SHOWMSG("couldn't examine the file"); - fam->fam_Error = __translate_io_error_to_errno(error); - goto out; - } + fam->fam_Error = __translate_io_error_to_errno(error); + goto out; + } - /* OK, let's have another look at this file. Could it be a - console stream? */ - if (NOT IsInteractive(file)) - { - SHOWMSG("whatever it is, we don't know"); + /* OK, let's have another look at this file. Could it be a + console stream? */ + if (NOT IsInteractive(file)) { + SHOWMSG("whatever it is, we don't know"); - fam->fam_Error = ENOSYS; - goto out; - } + fam->fam_Error = ENOSYS; + goto out; + } - /* Make up some stuff for this stream. */ - memset(fam->fam_FileInfo, 0, sizeof(*fam->fam_FileInfo)); + /* Make up some stuff for this stream. */ + memset(fam->fam_FileInfo, 0, sizeof(*fam->fam_FileInfo)); - DateStamp(&fam->fam_FileInfo->Date); + DateStamp(&fam->fam_FileInfo->Date); - fam->fam_FileInfo->Type = ST_CONSOLE; - } - } + fam->fam_FileInfo->Type = ST_CONSOLE; + } + } - fam->fam_FileSystem = fh->fh_Type; + fam->fam_FileSystem = fh->fh_Type; - result = OK; + result = OK; - break; + break; - default: + default: - SHOWVALUE(fam->fam_Action); + SHOWVALUE(fam->fam_Action); - fam->fam_Error = EBADF; - break; - } + fam->fam_Error = EBADF; + break; + } out: - __fd_unlock(fd); + __fd_unlock(fd); - if (fam->fam_Action == file_action_close) - __stdio_unlock(); + if (fam->fam_Action == file_action_close) + __stdio_unlock(); - if (buffer != NULL) - free(buffer); + if (buffer != NULL) + free(buffer); - SHOWVALUE(result); + SHOWVALUE(result); - RETURN(result); - return (result); + RETURN(result); + return (result); } diff --git a/library/termios/tcflow.c b/library/termios/tcflow.c index e80089e7..e1044f1a 100644 --- a/library/termios/tcflow.c +++ b/library/termios/tcflow.c @@ -35,6 +35,8 @@ tcflow(int file_descriptor, int UNUSED action) { __stdio_unlock(); + __check_abort(); + RETURN(result); return (result); } diff --git a/library/termios/tcflush.c b/library/termios/tcflush.c index 3684292b..7bccea99 100644 --- a/library/termios/tcflush.c +++ b/library/termios/tcflush.c @@ -99,6 +99,8 @@ tcflush(int file_descriptor, int queue) { __stdio_unlock(); + __check_abort(); + RETURN(result); return (result); } diff --git a/library/termios/tcgetattr.c b/library/termios/tcgetattr.c index f6fab4f9..b2de72cd 100644 --- a/library/termios/tcgetattr.c +++ b/library/termios/tcgetattr.c @@ -1,5 +1,5 @@ /* - * $Id: termios_tcgetattr.c,v 1.3 2006-01-08 12:04:27 clib2devs Exp $ + * $Id: termios_tcgetattr.c,v 1.4 2022-08-15 12:04:27 clib2devs Exp $ */ #ifndef _TERMIOS_HEADERS_H @@ -7,20 +7,20 @@ #endif /* _TERMIOS_HEADERS_H */ static const cc_t def_console_cc[NCCS] = - { - 3, /* VINTR = ETX */ - 28, /* VQUIT = FS */ - 127, /* VERASE = DEL */ - 24, /* VKILL = DC4 */ - 4, /* VEOF = EOT */ - 1, /* VMIN = Minimum number of characters in a non-canonical read. */ - 0, /* VEOL = NUL */ - 0, /* VTIME = Timout in deciseconds for a non-canonical read. */ - 17, /* VSTART = DC1 */ - 19, /* VSTOP = DC3 */ - 26, /* VSUSP = SUB */ - 23 /* VWERASE = ETB */ - }; +{ + 3, /* VINTR = ETX */ + 28, /* VQUIT = FS */ + 127, /* VERASE = DEL */ + 24, /* VKILL = DC4 */ + 4, /* VEOF = EOT */ + 1, /* VMIN = Minimum number of characters in a non-canonical read. */ + 0, /* VEOL = NUL */ + 0, /* VTIME = Timout in deciseconds for a non-canonical read. */ + 17, /* VSTART = DC1 */ + 19, /* VSTOP = DC3 */ + 26, /* VSUSP = SUB */ + 23 /* VWERASE = ETB */ +}; static struct termios * get_console_termios(struct fd *fd) { @@ -36,7 +36,6 @@ get_console_termios(struct fd *fd) { memset(tios, 0, sizeof(*tios)); - /* Set up the initial termios state. */ tios->c_iflag = 0; tios->c_oflag = 0; tios->c_cflag = CS8 | CLOCAL; @@ -44,7 +43,8 @@ get_console_termios(struct fd *fd) { if (FLAG_IS_SET(fd->fd_Flags, FDF_READ)) SET_FLAG(tios->c_cflag, CREAD); - tios->c_lflag = ISIG | ICANON | ECHO; + /* Set up the initial termios state in RAW mode */ + cfmakeraw(tios); memcpy(tios->c_cc, def_console_cc, NCCS); @@ -69,8 +69,8 @@ struct termios * __get_termios(struct fd *fd) { struct termios *tios = NULL; - if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_SOCKET)) /* Network socket. Remote terminal? */ - { + if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_SOCKET)) { + /* Network socket. Remote terminal? */ __set_errno(ENODEV); goto out; } @@ -135,5 +135,13 @@ tcgetattr(int file_descriptor, struct termios *user_tios) { __stdio_unlock(); + __check_abort(); + + /* If someone ask for tcgetattr on STDOUT or STDERR make sure that we set also + * STDIN. This hack fix ncurses library for example */ + if (file_descriptor == STDOUT_FILENO || file_descriptor == STDERR_FILENO) { + tcgetattr(STDIN_FILENO, user_tios); + } + return (result); } diff --git a/library/termios/tcsendbreak.c b/library/termios/tcsendbreak.c index c48a7e84..0ff246b7 100644 --- a/library/termios/tcsendbreak.c +++ b/library/termios/tcsendbreak.c @@ -68,6 +68,8 @@ tcsendbreak(int file_descriptor, int duration) { __stdio_unlock(); + __check_abort(); + RETURN(result); return (result); } diff --git a/library/termios/tcsetattr.c b/library/termios/tcsetattr.c index 2f1bd258..d0e06897 100644 --- a/library/termios/tcsetattr.c +++ b/library/termios/tcsetattr.c @@ -2,9 +2,9 @@ * $Id: termios_tcsetattr.c,v 1.5 2006-11-16 14:39:23 clib2devs Exp $ */ -#ifndef _TERMIOS_HEADERS_H +#ifndef _TERMIOS_HEADERS_H #include "termios_headers.h" -#endif /* _TERMIOS_HEADERS_H */ +#endif static int set_console_termios(struct fd *fd, struct termios *new_tios) { @@ -34,8 +34,7 @@ set_console_termios(struct fd *fd, struct termios *new_tios) { } /* Most of the processing (except raw/cooked mode switch) is handled in the hook. */ - memcpy(old_tios, new_tios, offsetof( - struct termios,type)); + memcpy(old_tios, new_tios, offsetof(struct termios,type)); result = OK; @@ -68,11 +67,9 @@ tcsetattr(int file_descriptor, int how, struct termios *tios) { __fd_lock(fd); - /* To use STDOUT we need to enable FDF_IS_INTERACTIVE, ICANON and ECHO */ + /* To use STDOUT we need to enable FDF_IS_INTERACTIVE */ if (FLAG_IS_SET(fd->fd_Flags, FDF_STDIO) && FLAG_IS_CLEAR(fd->fd_Flags, FDF_IS_INTERACTIVE)) { SET_FLAG(__fd[file_descriptor]->fd_Flags, FDF_IS_INTERACTIVE); - SET_FLAG(__fd[file_descriptor]->fd_Flags, ICANON); - SET_FLAG(__fd[file_descriptor]->fd_Flags, ECHO); } /* The following is in case the termios structure was manually constructed. (it should have been zero:ed in that case) */ From cb320a6bdaee9c74d0ebb85cc395c6e588f01d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Palmat=C3=A8?= Date: Wed, 17 Aug 2022 18:51:07 +0200 Subject: [PATCH 3/3] Fixed (and hacked) some termios functions to work properly with ncurses. Added scandir to dirent. Added termcap.os4 file that is used in ncurses --- libc.gmk | 1 + library/dirent/scandir.c | 58 +++++++++++++++++++++++++++ library/include/dirent.h | 9 +++-- library/termios/console_fdhookentry.c | 36 ++++++++++++++++- library/termios/tcgetattr.c | 14 +++---- specs => misc/specs | 0 misc/termcap.os4 | 58 +++++++++++++++++++++++++++ test_programs/dirent/scandir.c | 21 ++++++++++ 8 files changed, 184 insertions(+), 13 deletions(-) create mode 100644 library/dirent/scandir.c rename specs => misc/specs (100%) create mode 100644 misc/termcap.os4 create mode 100644 test_programs/dirent/scandir.c diff --git a/libc.gmk b/libc.gmk index a9362cd0..3c26c82c 100755 --- a/libc.gmk +++ b/libc.gmk @@ -100,6 +100,7 @@ C_DIRENT := \ dirent/dirfd.o \ dirent/fdopendir.o \ dirent/opendir.o \ + dirent/scandir.o \ dirent/readdir.o \ dirent/readdir_r.o \ dirent/readdir64_r.o \ diff --git a/library/dirent/scandir.c b/library/dirent/scandir.c new file mode 100644 index 00000000..d30e3278 --- /dev/null +++ b/library/dirent/scandir.c @@ -0,0 +1,58 @@ +/* + * $Id: dirent_scandir.c,v 1.0 2022-08-17 12:04:22 clib2devs Exp $ +*/ + +#ifndef _DIRENT_HEADERS_H +#include "dirent_headers.h" +#endif /* _DIRENT_HEADERS_H */ + +#ifndef _STDLIB_MEMORY_H +#include "stdlib_memory.h" +#endif /* _STDLIB_MEMORY_H */ + +int scandir(const char *path, struct dirent ***res, + int (*sel)(const struct dirent *), + int (*cmp)(const struct dirent **, const struct dirent **)) { + DIR *d = opendir(path); + struct dirent *de, **names = 0, **tmp; + size_t cnt = 0, len = 0; + int old_errno = errno; + + if (!d) { + __set_errno(EACCES); + return -1; + } + + while ((errno = 0), (de = readdir(d))) { + if (sel && !sel(de)) + continue; + if (cnt >= len) { + len = 2 * len + 1; + if (len > SIZE_MAX / sizeof *names) + break; + tmp = realloc(names, len * sizeof *names); + if (!tmp) + break; + names = tmp; + } + names[cnt] = malloc(de->d_reclen); + if (!names[cnt]) + break; + memcpy(names[cnt++], de, de->d_reclen); + } + + closedir(d); + + if (errno) { + if (names) + while (cnt-- > 0) free(names[cnt]); + free(names); + return -1; + } + __set_errno(old_errno); + + if (cmp) + qsort(names, cnt, sizeof *names, (int (*)(const void *, const void *)) cmp); + *res = names; + return cnt; +} \ No newline at end of file diff --git a/library/include/dirent.h b/library/include/dirent.h index 1738b04f..de82f3a7 100755 --- a/library/include/dirent.h +++ b/library/include/dirent.h @@ -39,12 +39,13 @@ struct dirent { }; extern DIR *opendir(const char * path_name); -extern struct dirent * readdir(DIR * directory_pointer); +extern struct dirent *readdir(DIR * directory_pointer); extern void rewinddir(DIR * directory_pointer); -extern int closedir(DIR * directory_pointer); +extern int closedir(DIR * directory_pointer); extern DIR *fdopendir(int); -extern int alphasort(const struct dirent **a, const struct dirent **b); -extern int dirfd(DIR *dirp); +extern int alphasort(const struct dirent **a, const struct dirent **b); +extern int dirfd(DIR *dirp); +extern int scandir(const char *, struct dirent ***, int (*)(const struct dirent *), int (*)(const struct dirent **, const struct dirent **)); extern int readdir_r(DIR *dir, struct dirent *buf, struct dirent **result); extern int readdir64_r(DIR *dir, struct dirent *buf, struct dirent **result); diff --git a/library/termios/console_fdhookentry.c b/library/termios/console_fdhookentry.c index 2cda3536..49bfff2a 100644 --- a/library/termios/console_fdhookentry.c +++ b/library/termios/console_fdhookentry.c @@ -33,12 +33,14 @@ LineEditor(BPTR file, char *buf, const int buflen, struct termios *tios) { unsigned char z; int do_edit = 1; int shift_mode = 0; + int esc_mode = 0; SetMode(file, DOSTRUE); /* Set raw mode. */ while (do_edit && len < buflen) { /* 5 seconds. */ - if (WaitForChar(file, 5000000) != DOSFALSE) { + if (WaitForChar(file, 5000000) != DOSFALSE) + { if (Read(file, &z, 1) == ERROR) { len = -1; break; @@ -56,6 +58,10 @@ LineEditor(BPTR file, char *buf, const int buflen, struct termios *tios) { buf[len++] = '\n'; continue; + case 27: /* ESC */ + esc_mode = 1; + continue; + case 155: /* CSI */ shift_mode = 1; continue; @@ -80,8 +86,10 @@ LineEditor(BPTR file, char *buf, const int buflen, struct termios *tios) { continue; } - if (shift_mode) { + + if (shift_mode || esc_mode) { shift_mode = 0; + esc_mode = 0; switch (z) { case 'C': /* Right arrowkey */ @@ -97,6 +105,21 @@ LineEditor(BPTR file, char *buf, const int buflen, struct termios *tios) { pos--; continue; + + case 'A': /* Up arrowkey */ + + if (pos < len) + pos++; + + continue; + + case 'B': /* Down arrowkey */ + + if (pos > 0) + pos--; + + continue; + } } @@ -175,6 +198,15 @@ __termios_console_hook(struct fd *fd, struct file_action_message *fam) { result = LineEditor(file, fam->fam_Data, fam->fam_Size, tios); } else { + /* Well.. this seems an hack to make ncurses works correctly + * I don't know if there are other problems setting STDIO always + * in RAW Mode but I suppose that we are ok since we are using + * a termios hook + */ + if (FLAG_IS_SET(fd->fd_Flags, FDF_STDIO)) { + /* Set raw mode. */ + SetMode(file, DOSTRUE); + } result = Read(file, fam->fam_Data, fam->fam_Size); } } else if (fam->fam_Size > 0) { diff --git a/library/termios/tcgetattr.c b/library/termios/tcgetattr.c index b2de72cd..c505be1b 100644 --- a/library/termios/tcgetattr.c +++ b/library/termios/tcgetattr.c @@ -43,8 +43,7 @@ get_console_termios(struct fd *fd) { if (FLAG_IS_SET(fd->fd_Flags, FDF_READ)) SET_FLAG(tios->c_cflag, CREAD); - /* Set up the initial termios state in RAW mode */ - cfmakeraw(tios); + tios->c_lflag = ISIG|ICANON|ECHO; memcpy(tios->c_cc, def_console_cc, NCCS); @@ -131,17 +130,18 @@ tcgetattr(int file_descriptor, struct termios *user_tios) { __fd_unlock(fd); + /* If someone ask for tcgetattr on STDOUT or STDERR make sure that we set also + * STDIN. This hack fix ncurses library for example */ + if (file_descriptor == STDOUT_FILENO || file_descriptor == STDERR_FILENO) { + tcgetattr(STDIN_FILENO, user_tios); + } + out: __stdio_unlock(); __check_abort(); - /* If someone ask for tcgetattr on STDOUT or STDERR make sure that we set also - * STDIN. This hack fix ncurses library for example */ - if (file_descriptor == STDOUT_FILENO || file_descriptor == STDERR_FILENO) { - tcgetattr(STDIN_FILENO, user_tios); - } return (result); } diff --git a/specs b/misc/specs similarity index 100% rename from specs rename to misc/specs diff --git a/misc/termcap.os4 b/misc/termcap.os4 new file mode 100644 index 00000000..fd1bd8a3 --- /dev/null +++ b/misc/termcap.os4 @@ -0,0 +1,58 @@ +# From: Kent Polk , 30 May 90 +# Added a few more entries, converted caret-type control sequence (^x) entries +# to '\0xx' entries since a couple of people mentioned losing '^x' sequences. +# +# :as:, :ae: Support for alternate character sets. +# :ve=\E[\040p:vi=\E[\060\040p: cursor visible/invisible. +# :xn: vt100 kludginess at column 80/NEWLINE ignore after 80 cols(Concept) +# This one appears to fix a problem I always had with a line ending +# at 'width+1' (I think) followed by a blank line in vi. The blank +# line tended to disappear and reappear depending on how the screen +# was refreshed. Note that this is probably needed only if you use +# something like a Dnet Fterm with the window sized to some peculiar +# dimension larger than 80 columns. +# :k0=\E9~: map F10 to k0 - could have F0-9 -> k0-9, but ... F10 was 'k;' + +# From: Hans Verkuil , 4 Dec 1995 +# (amiga: added empty to suppress a warning --esr) +# Additions by Steven Solie , 24 July 2006 +# Added colors by Andrea Palmate' , 17 August 2022 +amiga-clib2|Amiga ANSI ncurses:\ + :am:bs:bw:ms:xn:mi:cc:\ + :Co#16:NC#3:co#80:li#24:pa#64:\ + :AB=\2334%dm:AF=\2333%dm:AL=\233%dL:DC=\233%dP:\ + :DL=\233%dM:dl=\233M:op=\23339;49m:\ + :DC=\233%dP:DO=\233%dB:IC=\233%d@:LE=\233%dD:RI=\233%dC:\ + :SF=\233%dS:SR=\233%dT:UP=\233%dA:ac=:ae=^O:as=^N:bl=^G:\ + :bt=\233Z:cd=\233J:ce=\233K:cl=\233H\233J:\ + :cm=\233%i%d;%dH:cr=^M:dc=\233P:do=\233B:ec=\233%dP:ei=:\ + :ho=\233H:ic=\233@:im=:is=\23320l:k0=\2339~:k1=\2330~:\ + :k2=\2331~:k3=\2332~:k4=\2333~:k5=\2334~:k6=\2335~:\ + :k7=\2336~:k8=\2337~:k9=\2338~:kD=\177:kb=^H:kd=\233B:\ + :kl=\233D:kr=\233C:ku=\233A:le=\233D:mb=\2337;2m:\ + :md=\2331m:me=\2330m:mh=\2332m:mk=\2338m:mr=\2337m:\ + :nd=\233C:nw=\233B\r:r1=\Ec:se=\2330m:sf=\233S:so=\2337m:\ + :sr=\233T:ta=^I:te=\233?7h:ti=\233?7l:ue=\2330m:up=\233A:\ + :us=\2334m:vb=^G:ve=\233 p:vi=\2330 p:\ + :kI=\23340~:kP=\23341~:kN=\23342~:kh=\23344~:@7=\23345~:\ + :F1=\23320~:F2=\23321~: + +amiga-clib2-mono|Amiga ANSI ncurses:\ + :am:bs:bw:ms:xn:mi:cc:\ + :co#80:li#24:\ + :AB=\2334%dm:AF=\2333%dm:AL=\233%dL:DC=\233%dP:\ + :DL=\233%dM:dl=\233M:op=\23339;49m:\ + :DC=\233%dP:DO=\233%dB:IC=\233%d@:LE=\233%dD:RI=\233%dC:\ + :SF=\233%dS:SR=\233%dT:UP=\233%dA:ac=:ae=^O:as=^N:bl=^G:\ + :bt=\233Z:cd=\233J:ce=\233K:cl=\233H\233J:\ + :cm=\233%i%d;%dH:cr=^M:dc=\233P:do=\233B:ec=\233%dP:ei=:\ + :ho=\233H:ic=\233@:im=:is=\23320l:k0=\2339~:k1=\2330~:\ + :k2=\2331~:k3=\2332~:k4=\2333~:k5=\2334~:k6=\2335~:\ + :k7=\2336~:k8=\2337~:k9=\2338~:kD=\177:kb=^H:kd=\233B~:\ + :kl=\233D:kr=\233C:ku=\233A~:le=\233D:mb=\2337;2m:\ + :md=\2331m:me=\2330m:mh=\2332m:mk=\2338m:mr=\2337m:\ + :nd=\233C:nw=\233B\r:r1=\Ec:se=\2330m:sf=\233S:so=\2337m:\ + :sr=\233T:ta=^I:te=\233?7h:ti=\233?7l:ue=\2330m:up=\233A:\ + :us=\2334m:vb=^G:ve=\233 p:vi=\2330 p:\ + :kI=\23340~:kP=\23341~:kN=\23342~:kh=\23344~:@7=\23345~:\ + :F1=\23320~:F2=\23321~: \ No newline at end of file diff --git a/test_programs/dirent/scandir.c b/test_programs/dirent/scandir.c new file mode 100644 index 00000000..1b3dd720 --- /dev/null +++ b/test_programs/dirent/scandir.c @@ -0,0 +1,21 @@ +#include +#include +#include + +int main() { + struct dirent **namelist; + int i, n; + + n = scandir("T:", &namelist, 0, alphasort); + if (n < 0) + perror("scandir"); + else { + for (i = 0; i < n; i++) { + printf("%s\n", namelist[i]->d_name); + free(namelist[i]); + } + } + free(namelist); + + return 0; +} \ No newline at end of file