From f94ba5ebe1fff52c660a58a31c40c309c1e72ce0 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Wed, 14 Apr 2004 09:20:08 +0000 Subject: [PATCH] Improve ^C handling: - ^C didn't work for int21/ah=3f. Corrected -- Do_DosIdle_loop still needs to wait even if it doesn't call the idle int - ^C needs to be echoed to STDOUT for low character functions (ah<0xd) but to the device that is read from for handle functions. So we need to pass either the STDOUT sft or that device on to the ^C echoer. - The ^C echo really should print ^C\r\n. - misc cleanups in break.c. git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/trunk@883 6ac86273-5f31-0410-b378-82cca8765d1b --- kernel/break.c | 67 +++++++++++++++++++-------------------- kernel/chario.c | 80 ++++++++++++++++++++++------------------------- kernel/inthndlr.c | 7 +++-- kernel/proto.h | 11 +++---- 4 files changed, 79 insertions(+), 86 deletions(-) diff --git a/kernel/break.c b/kernel/break.c index d3d24c5..7e28788 100644 --- a/kernel/break.c +++ b/kernel/break.c @@ -31,49 +31,48 @@ #include "globals.h" #include "proto.h" -extern void ASMCFUNC spawn_int23(void); - #ifdef VERSION_STRINGS static BYTE *RcsId = "$Id$"; #endif -#define CB_FLG *(UBYTE FAR*)MK_FP(0x40, 0x71) +#define CB_FLG *(UBYTE FAR*)MK_FP(0x0, 0x471) #define CB_MSK 0x80 -/* Check for ^Break. - - * Two sources are available: - * 1) flag at 40:71 bit 7 - * 2) STDIN stream via con_break() - */ -int check_handle_break(void) -{ - if (CB_FLG & CB_MSK) { - CB_FLG &= ~CB_MSK; /* reset the ^Break flag */ - handle_break(&syscon); - } - /* con_break will call handle_break() for CTL_C */ - return con_break(); -} - -/* - * Handles a ^Break state - * +/* Check for ^Break/^C. + * Three sources are available: + * 1) flag at 40:71 bit 7 + * 2) CON stream (if STDIN is redirected somewhere else) + * 3) input stream (most likely STDIN) * Actions: - * 1) clear the ^Break flag - * 2) clear the STDIN stream - * 3) decrease the InDOS flag as the kernel drops back to user space - * 4) invoke INT-23 and never come back + * 1) echo ^C + * 2) clear the STDIN stream + * 3) decrease the InDOS flag as the kernel drops back to user space + * 4) invoke INT-23 and never come back */ -void handle_break(struct dhdr FAR **pdev) +unsigned char check_handle_break(struct dhdr FAR **pdev, int sft_out) { - echo_char(CTL_C, get_sft_idx(STDOUT)); - con_flush(pdev); - if (!ErrorMode) /* within int21_handler, InDOS is not incremented */ - if (InDOS) - --InDOS; /* fail-safe */ + unsigned char c = CTL_C; + if (CB_FLG & CB_MSK) + CB_FLG &= ~CB_MSK; /* reset the ^Break flag */ + else + c = (unsigned char)ndread(&syscon); + if (c == CTL_C) + { + sft_out = -1; + pdev = &syscon; + } + else if (*pdev != syscon) + c = (unsigned char)ndread(pdev); + if (c == CTL_C) + { + con_flush(pdev); + echo_ctl_c(pdev, sft_out); + if (!ErrorMode) /* within int21_handler, InDOS is not incremented */ + if (InDOS) + --InDOS; /* fail-safe */ - spawn_int23(); /* invoke user INT-23 and never come back */ + spawn_int23(); /* invoke user INT-23 and never come back */ + } + return c; } - diff --git a/kernel/chario.c b/kernel/chario.c index 7471555..755310e 100644 --- a/kernel/chario.c +++ b/kernel/chario.c @@ -128,15 +128,15 @@ int StdinBusy(void) STATIC void Do_DosIdle_loop(struct dhdr FAR **pdev) { - /* the idle loop is only safe if we're using the character stack */ - if (user_r->AH < 0xd) - while (Busy(pdev) && Busy(&syscon)) + /* the idle int is only safe if we're using the character stack */ + while (Busy(pdev) && (*pdev == syscon || Busy(&syscon))) + if (user_r->AH < 0xd) DosIdle_int(); } /* get character from the console - this is how DOS gets CTL_C/CTL_S/CTL_P when outputting */ -STATIC int ndread(struct dhdr FAR **pdev) +int ndread(struct dhdr FAR **pdev) { CharCmd(pdev, C_NDREAD); if (CharReqHdr.r_status & S_BUSY) @@ -144,35 +144,19 @@ STATIC int ndread(struct dhdr FAR **pdev) return CharReqHdr.r_ndbyte; } -STATIC void con_skip_char(struct dhdr FAR **pdev) +STATIC void con_hold(struct dhdr FAR **pdev, int sft_out) { - if (CharIO(pdev, 0, C_INPUT) == CTL_C) - handle_break(pdev); -} - -STATIC void con_hold(struct dhdr FAR **pdev) -{ - int c = check_handle_break(); - if (*pdev != syscon) - c = ndread(pdev); - if (c == CTL_S || c == CTL_C) + unsigned char c = check_handle_break(pdev, sft_out); + if (c == CTL_S) { - con_skip_char(pdev); + CharIO(pdev, 0, C_INPUT); Do_DosIdle_loop(pdev); - /* just wait */ - check_handle_break(); - con_skip_char(pdev); + /* just wait and then skip a character */ + check_handle_break(pdev, sft_out); + CharIO(pdev, 0, C_INPUT); } } -int con_break(void) -{ - int c = ndread(&syscon); - if (c == CTL_C) - con_skip_char(&syscon); - return c; -} - /* OUTPUT FUNCTIONS */ #ifdef __WATCOMC__ @@ -231,7 +215,7 @@ STATIC int cooked_write_char(struct dhdr FAR **pdev, otherwise check every 32 characters */ if (*fast_counter <= 0x80) /* Test for hold char and ctl_c */ - con_hold(pdev); + con_hold(pdev, -1); *fast_counter += 1; *fast_counter &= 0x9f; @@ -306,7 +290,7 @@ void write_char_stdout(int c) #define iscntrl(c) ((unsigned char)(c) < ' ') /* this is for handling things like ^C, mostly used in echoed input */ -int echo_char(int c, int sft_idx) +STATIC int echo_char(int c, int sft_idx) { int out = c; if (iscntrl(c) && c != HT && c != LF && c != CR) @@ -318,6 +302,16 @@ int echo_char(int c, int sft_idx) return c; } +void echo_ctl_c(struct dhdr FAR **pdev, int sft_idx) +{ + char *buf = "^C\r\n"; + + if (sft_idx == -1) + cooked_write(pdev, 4, buf); + else + DosRWSft(sft_idx, 4, buf, XFR_FORCE_WRITE); +} + STATIC void destr_bs(int sft_idx) { write_char(BS, sft_idx); @@ -327,12 +321,12 @@ STATIC void destr_bs(int sft_idx) /* READ FUNCTIONS */ -STATIC int raw_get_char(struct dhdr FAR **pdev, BOOL check_break) +STATIC int raw_get_char(struct dhdr FAR **pdev, int sft_out, BOOL check_break) { Do_DosIdle_loop(pdev); if (check_break) { - con_hold(pdev); + con_hold(pdev, sft_out); Do_DosIdle_loop(pdev); } return CharIO(pdev, 0, C_INPUT); @@ -344,7 +338,7 @@ long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp) int c; while(n--) { - c = raw_get_char(pdev, TRUE); + c = raw_get_char(pdev, -1, TRUE); if (c < 0) return c; if (c == 256) @@ -357,26 +351,26 @@ long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp) return xfer; } -unsigned char read_char(int sft_idx, BOOL check_break) +unsigned char read_char(int sft_in, int sft_out, BOOL check_break) { unsigned char c; - struct dhdr FAR *dev = sft_to_dev(idx_to_sft(sft_idx)); + struct dhdr FAR *dev = sft_to_dev(idx_to_sft(sft_in)); if (dev) - return (unsigned char)raw_get_char(&dev, check_break); + return (unsigned char)raw_get_char(&dev, sft_out, check_break); - DosRWSft(sft_idx, 1, &c, XFR_READ); + DosRWSft(sft_in, 1, &c, XFR_READ); return c; } -STATIC unsigned char read_char_check_break(int sft_idx) +STATIC unsigned char read_char_check_break(int sft_in, int sft_out) { - return read_char(sft_idx, TRUE); + return read_char(sft_in, sft_out, TRUE); } unsigned char read_char_stdin(BOOL check_break) { - return read_char(get_sft_idx(STDIN), check_break); + return read_char(get_sft_idx(STDIN), get_sft_idx(STDOUT), check_break); } /* reads a line (buffered, called by int21/ah=0ah, 3fh) */ @@ -399,9 +393,9 @@ void read_line(int sft_in, int sft_out, keyboard FAR * kp) { unsigned new_pos = stored_size; - c = read_char_check_break(sft_in); + c = read_char_check_break(sft_in, sft_out); if (c == 0) - c = (unsigned)read_char_check_break(sft_in) << 8; + c = (unsigned)read_char_check_break(sft_in, sft_out) << 8; switch (c) { case LF: @@ -426,11 +420,11 @@ void read_line(int sft_in, int sft_out, keyboard FAR * kp) case F4: /* insert/delete up to character c */ { - unsigned char c2 = read_char_check_break(sft_in); + unsigned char c2 = read_char_check_break(sft_in, sft_out); new_pos = stored_pos; if (c2 == 0) { - read_char_check_break(sft_in); + read_char_check_break(sft_in, sft_out); } else { diff --git a/kernel/inthndlr.c b/kernel/inthndlr.c index ac4181a..441d947 100644 --- a/kernel/inthndlr.c +++ b/kernel/inthndlr.c @@ -408,7 +408,7 @@ dispatch: /* Check for Ctrl-Break */ if (break_ena || (lr.AH >= 1 && lr.AH <= 5) || (lr.AH >= 8 && lr.AH <= 0x0b)) - check_handle_break(); + check_handle_break(&syscon, -1); /* The dispatch handler */ switch (lr.AH) @@ -435,8 +435,11 @@ dispatch: /* Auxiliary Input */ case 0x03: - lr.AL = read_char(get_sft_idx(STDAUX), TRUE); + { + int sft_idx = get_sft_idx(STDAUX); + lr.AL = read_char(sft_idx, sft_idx, TRUE); break; + } /* Auxiliary Output */ case 0x04: diff --git a/kernel/proto.h b/kernel/proto.h index cbd2ff1..d342109 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -49,21 +49,18 @@ UWORD dskxfer(COUNT dsk, ULONG blkno, VOID FAR * buf, UWORD numblocks, void AllocateHMASpace (size_t lowbuffer, size_t highbuffer); /* break.c */ -#ifdef __WATCOMC__ -#pragma aux handle_break aborts; -#endif -int check_handle_break(void); -void handle_break(struct dhdr FAR **pdev); +unsigned char check_handle_break(struct dhdr FAR **pdev, int sft_out); /* chario.c */ struct dhdr FAR *sft_to_dev(sft FAR *sft); long BinaryCharIO(struct dhdr FAR **pdev, size_t n, void FAR * bp, unsigned command); int echo_char(int c, int sft_idx); -int con_break(void); +void echo_ctl_c(struct dhdr FAR **pdev, int sft_idx); +int ndread(struct dhdr FAR **pdev); int StdinBusy(void); void con_flush(struct dhdr FAR **pdev); -unsigned char read_char(int sft_idx, BOOL check_break); +unsigned char read_char(int sft_in, int sft_out, BOOL check_break); unsigned char read_char_stdin(BOOL check_break); long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp); void read_line(int sft_in, int sft_out, keyboard FAR * kp);