diff --git a/kernel/break.c b/kernel/break.c index 7e28788..be097c5 100644 --- a/kernel/break.c +++ b/kernel/break.c @@ -42,37 +42,52 @@ static BYTE *RcsId = /* 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) 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 + * 2) syscon stream (usually CON:) + * 3) i/o stream (if unequal to syscon, e.g. AUX) */ -unsigned char check_handle_break(struct dhdr FAR **pdev, int sft_out) + +unsigned char ctrl_break_pressed(void) +{ + return CB_FLG & CB_MSK; +} + +unsigned char check_handle_break(struct dhdr FAR **pdev) { unsigned char c = CTL_C; - if (CB_FLG & CB_MSK) - CB_FLG &= ~CB_MSK; /* reset the ^Break flag */ - else + if (!ctrl_break_pressed()) c = (unsigned char)ndread(&syscon); - if (c == CTL_C) - { - sft_out = -1; - pdev = &syscon; - } - else if (*pdev != syscon) + if (c != CTL_C && *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 */ - } + handle_break(pdev, -1); return c; } + +/* + * Handles a ^Break state + * + * Actions: + * 1) clear the ^Break flag + * 2) clear the STDIN stream + * 3) echo ^C to sft_out or pdev if sft_out==-1 + * 4) decrease the InDOS flag as the kernel drops back to user space + * 5) invoke INT-23 and never come back + */ + +void handle_break(struct dhdr FAR **pdev, int sft_out) +{ + char *buf = "^C\r\n"; + + CB_FLG &= ~CB_MSK; /* reset the ^Break flag */ + con_flush(pdev); + if (sft_out == -1) + cooked_write(pdev, 4, buf); + else + DosRWSft(sft_out, 4, buf, XFR_FORCE_WRITE); + if (!ErrorMode) /* within int21_handler, InDOS is not incremented */ + if (InDOS) + --InDOS; /* fail-safe */ + + spawn_int23(); /* invoke user INT-23 and never come back */ +} + diff --git a/kernel/chario.c b/kernel/chario.c index 755310e..89de4d3 100644 --- a/kernel/chario.c +++ b/kernel/chario.c @@ -89,7 +89,7 @@ STATIC int CharIO(struct dhdr FAR **pdev, unsigned char ch, unsigned command) /* STATE FUNCTIONS */ -void CharCmd(struct dhdr FAR **pdev, unsigned command) +STATIC void CharCmd(struct dhdr FAR **pdev, unsigned command) { while (CharRequest(pdev, command) == 1); } @@ -126,14 +126,6 @@ int StdinBusy(void) return s->sft_posit >= s->sft_size; } -STATIC void Do_DosIdle_loop(struct dhdr FAR **pdev) -{ - /* 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 */ int ndread(struct dhdr FAR **pdev) @@ -144,19 +136,6 @@ int ndread(struct dhdr FAR **pdev) return CharReqHdr.r_ndbyte; } -STATIC void con_hold(struct dhdr FAR **pdev, int sft_out) -{ - unsigned char c = check_handle_break(pdev, sft_out); - if (c == CTL_S) - { - CharIO(pdev, 0, C_INPUT); - Do_DosIdle_loop(pdev); - /* just wait and then skip a character */ - check_handle_break(pdev, sft_out); - CharIO(pdev, 0, C_INPUT); - } -} - /* OUTPUT FUNCTIONS */ #ifdef __WATCOMC__ @@ -213,9 +192,9 @@ STATIC int cooked_write_char(struct dhdr FAR **pdev, /* if not fast then < 0x80; always check otherwise check every 32 characters */ - if (*fast_counter <= 0x80) + if (*fast_counter <= 0x80 && check_handle_break(pdev) == CTL_S) /* Test for hold char and ctl_c */ - con_hold(pdev, -1); + raw_get_char(pdev, TRUE); *fast_counter += 1; *fast_counter &= 0x9f; @@ -302,16 +281,6 @@ STATIC 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); @@ -321,15 +290,13 @@ STATIC void destr_bs(int sft_idx) /* READ FUNCTIONS */ -STATIC int raw_get_char(struct dhdr FAR **pdev, int sft_out, BOOL check_break) +STATIC unsigned char read_char_sft_dev(int sft_in, int sft_out, + struct dhdr FAR **pdev, + BOOL check_break); + +STATIC int raw_get_char(struct dhdr FAR **pdev, BOOL check_break) { - Do_DosIdle_loop(pdev); - if (check_break) - { - con_hold(pdev, sft_out); - Do_DosIdle_loop(pdev); - } - return CharIO(pdev, 0, C_INPUT); + return read_char_sft_dev(-1, -1, pdev, check_break); } long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp) @@ -338,7 +305,7 @@ long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp) int c; while(n--) { - c = raw_get_char(pdev, -1, TRUE); + c = raw_get_char(pdev, TRUE); if (c < 0) return c; if (c == 256) @@ -351,18 +318,55 @@ long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp) return xfer; } -unsigned char read_char(int sft_in, int sft_out, BOOL check_break) +STATIC unsigned char read_char_sft_dev(int sft_in, int sft_out, + struct dhdr FAR **pdev, + BOOL check_break) { unsigned char c; - struct dhdr FAR *dev = sft_to_dev(idx_to_sft(sft_in)); - if (dev) - return (unsigned char)raw_get_char(&dev, sft_out, check_break); + if (pdev) + { + FOREVER + { + if (ctrl_break_pressed()) + { + c = CTL_C; + break; + } + if (!Busy(pdev)) + { + c = CharIO(pdev, 0, C_INPUT); + break; + } + if (check_break && *pdev != syscon) + check_handle_break(&syscon); + /* the idle int is only safe if we're using the character stack */ + if (user_r->AH < 0xd) + DosIdle_int(); + } + } + else + DosRWSft(sft_in, 1, &c, XFR_READ); - DosRWSft(sft_in, 1, &c, XFR_READ); + /* check for break or stop on sft_in, echo to sft_out */ + if (check_break && (c == CTL_C || c == CTL_S)) + { + if (c == CTL_S) + c = read_char_sft_dev(sft_in, sft_out, pdev, FALSE); + if (c == CTL_C) + handle_break(pdev, sft_out); + /* DOS oddity: if you press ^S somekey ^C then ^C does not break */ + c = read_char(sft_in, sft_out, FALSE); + } return c; } +unsigned char read_char(int sft_in, int sft_out, BOOL check_break) +{ + struct dhdr FAR *dev = sft_to_dev(idx_to_sft(sft_in)); + return read_char_sft_dev(sft_in, sft_out, &dev, check_break); +} + STATIC unsigned char read_char_check_break(int sft_in, int sft_out) { return read_char(sft_in, sft_out, TRUE); diff --git a/kernel/inthndlr.c b/kernel/inthndlr.c index 441d947..fa57db2 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(&syscon, -1); + check_handle_break(&syscon); /* The dispatch handler */ switch (lr.AH) diff --git a/kernel/proto.h b/kernel/proto.h index d342109..1541a21 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -49,14 +49,18 @@ UWORD dskxfer(COUNT dsk, ULONG blkno, VOID FAR * buf, UWORD numblocks, void AllocateHMASpace (size_t lowbuffer, size_t highbuffer); /* break.c */ -unsigned char check_handle_break(struct dhdr FAR **pdev, int sft_out); +unsigned char ctrl_break_pressed(void); +unsigned char check_handle_break(struct dhdr FAR **pdev); +void handle_break(struct dhdr FAR **pdev, int sft_out); +#ifdef __WATCOMC__ +#pragma aux handle_break aborts; +#endif /* 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); -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);