83b77cbb1b
git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/trunk@427 6ac86273-5f31-0410-b378-82cca8765d1b
613 lines
14 KiB
C
613 lines
14 KiB
C
/****************************************************************/
|
|
/* */
|
|
/* chario.c */
|
|
/* DOS-C */
|
|
/* */
|
|
/* Character device functions and device driver interface */
|
|
/* */
|
|
/* Copyright (c) 1994 */
|
|
/* Pasquale J. Villani */
|
|
/* All Rights Reserved */
|
|
/* */
|
|
/* This file is part of DOS-C. */
|
|
/* */
|
|
/* DOS-C is free software; you can redistribute it and/or */
|
|
/* modify it under the terms of the GNU General Public License */
|
|
/* as published by the Free Software Foundation; either version */
|
|
/* 2, or (at your option) any later version. */
|
|
/* */
|
|
/* DOS-C is distributed in the hope that it will be useful, but */
|
|
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
|
|
/* the GNU General Public License for more details. */
|
|
/* */
|
|
/* You should have received a copy of the GNU General Public */
|
|
/* License along with DOS-C; see the file COPYING. If not, */
|
|
/* write to the Free Software Foundation, 675 Mass Ave, */
|
|
/* Cambridge, MA 02139, USA. */
|
|
/* */
|
|
/****************************************************************/
|
|
|
|
#include "portab.h"
|
|
|
|
#ifdef VERSION_STRINGS
|
|
static BYTE *charioRcsId =
|
|
"$Id$";
|
|
#endif
|
|
|
|
#include "globals.h"
|
|
|
|
STATIC int CharRequest(struct dhdr FAR *dev)
|
|
{
|
|
CharReqHdr.r_unit = 0;
|
|
CharReqHdr.r_status = 0;
|
|
CharReqHdr.r_length = sizeof(request);
|
|
execrh(&CharReqHdr, dev);
|
|
if (CharReqHdr.r_status & S_ERROR)
|
|
{
|
|
charloop:
|
|
switch (char_error(&CharReqHdr, dev))
|
|
{
|
|
case ABORT:
|
|
case FAIL:
|
|
return DE_INVLDACC;
|
|
case CONTINUE:
|
|
CharReqHdr.r_count = 0;
|
|
return 0;
|
|
case RETRY:
|
|
return 1;
|
|
default:
|
|
goto charloop;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
long BinaryCharIO(struct dhdr FAR * dev, size_t n, void FAR * bp, unsigned command)
|
|
{
|
|
int err = SUCCESS;
|
|
do
|
|
{
|
|
CharReqHdr.r_command = command;
|
|
CharReqHdr.r_count = n;
|
|
CharReqHdr.r_trans = bp;
|
|
} while ((err = CharRequest(dev)) == 1);
|
|
return err == SUCCESS ? CharReqHdr.r_count : err;
|
|
}
|
|
|
|
/* STATE FUNCTIONS */
|
|
|
|
STATIC struct dhdr FAR *idx_to_dev(int sft_idx)
|
|
{
|
|
sft FAR *s = idx_to_sft(sft_idx);
|
|
if (FP_OFF(s) == (size_t)-1 || (s->sft_mode & SFT_MWRITE) ||
|
|
!(s->sft_flags & SFT_FDEVICE))
|
|
return syscon;
|
|
else
|
|
return s->sft_dev;
|
|
}
|
|
|
|
/* if sft_idx is invalid, then we just monitor syscon */
|
|
STATIC BOOL Busy(int sft_idx)
|
|
{
|
|
sft FAR *s = idx_to_sft(sft_idx);
|
|
|
|
if (s->sft_flags & SFT_FDEVICE)
|
|
{
|
|
struct dhdr FAR *dev = idx_to_dev(sft_idx);
|
|
do {
|
|
CharReqHdr.r_command = C_ISTAT;
|
|
} while(CharRequest(dev) == 1);
|
|
if (CharReqHdr.r_status & S_BUSY)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
else
|
|
return s->sft_posit >= s->sft_size;
|
|
}
|
|
|
|
BOOL StdinBusy(void)
|
|
{
|
|
return Busy(get_sft_idx(STDIN));
|
|
}
|
|
|
|
STATIC void Do_DosIdle_loop(int sft_idx)
|
|
{
|
|
/* the idle loop is only safe if we're using the character stack */
|
|
if (user_r->AH < 0xd)
|
|
while (Busy(sft_idx))
|
|
DosIdle_int();
|
|
}
|
|
|
|
/* get character from the console - this is how DOS gets
|
|
CTL_C/CTL_S/CTL_P when outputting */
|
|
STATIC int ndread(int sft_idx)
|
|
{
|
|
struct dhdr FAR *dev = idx_to_dev(sft_idx);
|
|
do {
|
|
CharReqHdr.r_command = C_NDREAD;
|
|
} while(CharRequest(dev) == 1);
|
|
if (CharReqHdr.r_status & S_BUSY)
|
|
return -1;
|
|
return CharReqHdr.r_ndbyte;
|
|
}
|
|
|
|
STATIC int con_get_char(int sft_idx)
|
|
{
|
|
unsigned char c;
|
|
BinaryCharIO(idx_to_dev(sft_idx), 1, &c, C_INPUT);
|
|
if (c == CTL_C)
|
|
handle_break(sft_idx);
|
|
return c;
|
|
}
|
|
|
|
STATIC void con_hold(int sft_idx)
|
|
{
|
|
int c;
|
|
if (control_break())
|
|
handle_break(-1);
|
|
c = ndread(sft_idx);
|
|
if (c == CTL_S)
|
|
{
|
|
con_get_char(sft_idx);
|
|
Do_DosIdle_loop(sft_idx);
|
|
/* just wait */
|
|
c = con_get_char(sft_idx);
|
|
}
|
|
if (c == CTL_C)
|
|
{
|
|
con_get_char(sft_idx);
|
|
handle_break(sft_idx);
|
|
}
|
|
}
|
|
|
|
BOOL con_break(void)
|
|
{
|
|
if (ndread(-1) == CTL_C)
|
|
{
|
|
con_get_char(-1);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/* OUTPUT FUNCTIONS */
|
|
|
|
#ifdef __WATCOMC__
|
|
void int29(char c);
|
|
#pragma aux int29 = "int 29h" parm[al] modify exact [bx]
|
|
#endif
|
|
|
|
/* writes a character in raw mode; use int29 if possible
|
|
for speed */
|
|
STATIC int raw_put_char(int sft_idx, int c)
|
|
{
|
|
struct dhdr FAR *dev = idx_to_dev(sft_idx);
|
|
unsigned char ch = (unsigned char)c;
|
|
|
|
if (PrinterEcho)
|
|
DosWrite(STDPRN, 1, &ch);
|
|
|
|
if (dev->dh_attr & ATTR_FASTCON)
|
|
{
|
|
#if defined(__TURBOC__)
|
|
_AL = ch;
|
|
__int__(0x29);
|
|
#elif defined(__WATCOMC__)
|
|
int29(ch);
|
|
#elif defined(I86)
|
|
asm
|
|
{
|
|
mov al, byte ptr ch;
|
|
int 0x29;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
c = (int)BinaryCharIO(dev, 1, &ch, C_OUTPUT);
|
|
if (c < 0)
|
|
return c;
|
|
else
|
|
return ch;
|
|
}
|
|
|
|
/* writes a character in cooked mode; maybe with printer echo;
|
|
handles TAB expansion */
|
|
STATIC int cooked_put_char(int sft_idx, int c)
|
|
{
|
|
int err = 0;
|
|
|
|
/* Test for hold char */
|
|
con_hold(sft_idx);
|
|
|
|
switch (c)
|
|
{
|
|
case CR:
|
|
scr_pos = 0;
|
|
break;
|
|
case LF:
|
|
case BELL:
|
|
break;
|
|
case BS:
|
|
if (scr_pos > 0)
|
|
scr_pos--;
|
|
break;
|
|
case HT:
|
|
do
|
|
err = raw_put_char(sft_idx, ' ');
|
|
while (err >= 0 && ((++scr_pos) & 7));
|
|
break;
|
|
default:
|
|
scr_pos++;
|
|
}
|
|
if (c != HT)
|
|
err = raw_put_char(sft_idx, c);
|
|
return err;
|
|
}
|
|
|
|
long cooked_write(int sft_idx, size_t n, char FAR *bp)
|
|
{
|
|
size_t xfer;
|
|
int err = SUCCESS;
|
|
|
|
for (xfer = 0; err >= SUCCESS && xfer < n && *bp != CTL_Z; bp++, xfer++)
|
|
err = cooked_put_char(sft_idx, *bp);
|
|
return err < SUCCESS ? err : xfer;
|
|
}
|
|
|
|
/* writes character for disk file or device */
|
|
void write_char(int c, int sft_idx)
|
|
{
|
|
unsigned char ch = (unsigned char)c;
|
|
DosRWSft(sft_idx, 1, &ch, XFR_FORCE_WRITE);
|
|
}
|
|
|
|
void write_char_stdin(int c)
|
|
{
|
|
write_char(c, get_sft_idx(STDIN));
|
|
}
|
|
|
|
#define iscntrl(c) ((unsigned char)(c) < ' ')
|
|
|
|
/* this is for handling things like ^C, mostly used in echoed input */
|
|
STATIC int echo_char(int c, int sft_idx)
|
|
{
|
|
if (iscntrl(c) && c != HT && c != LF && c != CR)
|
|
{
|
|
write_char('^', sft_idx);
|
|
write_char(c + '@', sft_idx);
|
|
}
|
|
else
|
|
write_char(c, sft_idx);
|
|
return c;
|
|
}
|
|
|
|
int echo_char_stdin(int c)
|
|
{
|
|
return echo_char(get_sft_idx(STDIN), c);
|
|
}
|
|
|
|
STATIC void destr_bs(int sft_idx)
|
|
{
|
|
write_char(BS, sft_idx);
|
|
write_char(' ', sft_idx);
|
|
write_char(BS, sft_idx);
|
|
}
|
|
|
|
/* READ FUNCTIONS */
|
|
|
|
STATIC int raw_get_char(int sft_idx, BOOL check_break)
|
|
{
|
|
unsigned char c;
|
|
int err;
|
|
|
|
Do_DosIdle_loop(sft_idx);
|
|
if (check_break)
|
|
con_hold(sft_idx);
|
|
|
|
err = (int)BinaryCharIO(idx_to_dev(sft_idx), 1, &c, C_INPUT);
|
|
return err < 0 ? err : c;
|
|
}
|
|
|
|
long cooked_read(int sft_idx, size_t n, char FAR *bp)
|
|
{
|
|
unsigned xfer = 0;
|
|
int c;
|
|
while(n--)
|
|
{
|
|
c = raw_get_char(sft_idx, TRUE);
|
|
if (c < 0)
|
|
return c;
|
|
*bp++ = c;
|
|
xfer++;
|
|
if (bp[-1] == CTL_Z)
|
|
break;
|
|
}
|
|
return xfer;
|
|
}
|
|
|
|
unsigned char read_char(int sft_idx, BOOL check_break)
|
|
{
|
|
unsigned char c;
|
|
sft FAR *s = idx_to_sft(sft_idx);
|
|
|
|
if ((FP_OFF(s) == (size_t) -1) || (s->sft_flags & SFT_FDEVICE))
|
|
return raw_get_char(sft_idx, check_break);
|
|
|
|
DosRWSft(sft_idx, 1, &c, XFR_READ);
|
|
return c;
|
|
}
|
|
|
|
STATIC unsigned char read_char_check_break(int sft_idx)
|
|
{
|
|
return read_char(sft_idx, TRUE);
|
|
}
|
|
|
|
unsigned char read_char_stdin(BOOL check_break)
|
|
{
|
|
return read_char(get_sft_idx(STDIN), check_break);
|
|
}
|
|
|
|
void KbdFlush(int sft_idx)
|
|
{
|
|
struct dhdr FAR *dev = idx_to_dev(sft_idx);
|
|
|
|
do {
|
|
CharReqHdr.r_unit = 0;
|
|
CharReqHdr.r_status = 0;
|
|
CharReqHdr.r_command = C_IFLUSH;
|
|
CharReqHdr.r_length = sizeof(request);
|
|
} while (CharRequest(dev) == 1);
|
|
}
|
|
|
|
/* reads a line (buffered, called by int21/ah=0ah, 3fh) */
|
|
void read_line(int sft_in, int sft_out, keyboard FAR * kp)
|
|
{
|
|
unsigned c;
|
|
unsigned cu_pos = scr_pos;
|
|
unsigned count = 0, stored_pos = 0;
|
|
unsigned size = kp->kb_size, stored_size = kp->kb_count;
|
|
BOOL insert = FALSE;
|
|
|
|
if (size == 0)
|
|
return;
|
|
|
|
/* the stored line is invalid unless it ends with a CR */
|
|
if (kp->kb_buf[stored_size] != CR)
|
|
stored_size = 0;
|
|
|
|
do
|
|
{
|
|
unsigned new_pos = stored_size;
|
|
|
|
c = read_char_check_break(sft_in);
|
|
if (c == 0)
|
|
c = (unsigned)read_char_check_break(sft_in) << 8;
|
|
switch (c)
|
|
{
|
|
case CTL_F:
|
|
continue;
|
|
|
|
case RIGHT:
|
|
case F1:
|
|
if (stored_pos < stored_size && count < size - 1)
|
|
local_buffer[count++] = echo_char(kp->kb_buf[stored_pos++], sft_out);
|
|
break;
|
|
|
|
case F2:
|
|
case F4:
|
|
/* insert/delete up to character c */
|
|
{
|
|
unsigned char c2 = read_char_check_break(sft_in);
|
|
new_pos = stored_pos;
|
|
if (c2 == 0)
|
|
{
|
|
read_char_check_break(sft_in);
|
|
}
|
|
else
|
|
{
|
|
char FAR *sp = fmemchr(&kp->kb_buf[stored_pos],
|
|
c2, stored_size - stored_pos);
|
|
if (sp != NULL)
|
|
new_pos = (FP_OFF(sp) - FP_OFF(&kp->kb_buf[stored_pos])) + 1;
|
|
}
|
|
}
|
|
/* fall through */
|
|
case F3:
|
|
if (c != F4) /* not delete */
|
|
{
|
|
while (stored_pos < new_pos && count < size - 1)
|
|
local_buffer[count++] = echo_char(kp->kb_buf[stored_pos++], sft_out);
|
|
}
|
|
stored_pos = new_pos;
|
|
break;
|
|
|
|
case F5:
|
|
fmemcpy(kp->kb_buf, local_buffer, count);
|
|
stored_size = count;
|
|
write_char('@', sft_out);
|
|
goto start_new_line;
|
|
|
|
case INS:
|
|
insert = !insert;
|
|
break;
|
|
|
|
case DEL:
|
|
stored_pos++;
|
|
break;
|
|
|
|
case LEFT:
|
|
case CTL_BS:
|
|
case BS:
|
|
if (count > 0)
|
|
{
|
|
unsigned new_pos;
|
|
char c2 = local_buffer[--count];
|
|
if (c2 == HT)
|
|
{
|
|
unsigned i;
|
|
new_pos = cu_pos;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (local_buffer[i] == HT)
|
|
new_pos = (new_pos + 8) & ~7;
|
|
else if (iscntrl(local_buffer[i]))
|
|
new_pos += 2;
|
|
else
|
|
new_pos++;
|
|
}
|
|
do
|
|
destr_bs(sft_out);
|
|
while (scr_pos > new_pos);
|
|
}
|
|
else
|
|
{
|
|
if (iscntrl(c2))
|
|
destr_bs(sft_out);
|
|
destr_bs(sft_out);
|
|
}
|
|
}
|
|
if (stored_pos > 0)
|
|
stored_pos--;
|
|
break;
|
|
|
|
case ESC:
|
|
write_char('\\', sft_out);
|
|
start_new_line:
|
|
write_char(CR, sft_out);
|
|
write_char(LF, sft_out);
|
|
for (count = 0; count < cu_pos; count++)
|
|
write_char(' ', sft_out);
|
|
count = 0;
|
|
stored_pos = 0;
|
|
insert = FALSE;
|
|
break;
|
|
|
|
case F6:
|
|
c = CTL_Z;
|
|
/* fall through */
|
|
|
|
default:
|
|
if (count < size - 1 || c == CR)
|
|
local_buffer[count++] = echo_char(c, sft_out);
|
|
else
|
|
write_char(BELL, sft_out);
|
|
if (stored_pos < stored_size && !insert)
|
|
stored_pos++;
|
|
break;
|
|
}
|
|
} while (c != CR);
|
|
fmemcpy(kp->kb_buf, local_buffer, count);
|
|
/* if local_buffer overflows into the CON default buffer we
|
|
must invalidate it */
|
|
if (count > LINEBUFSIZECON)
|
|
kb_buf.kb_size = 0;
|
|
/* kb_count does not include the final CR */
|
|
kp->kb_count = count - 1;
|
|
}
|
|
|
|
/* called by handle func READ (int21/ah=3f) */
|
|
size_t read_line_handle(int sft_idx, size_t n, char FAR * bp)
|
|
{
|
|
char *bufend = &kb_buf.kb_buf[kb_buf.kb_count + 2];
|
|
|
|
if (inputptr == NULL)
|
|
{
|
|
/* can we reuse kb_buf or was it overwritten? */
|
|
if (kb_buf.kb_size != LINEBUFSIZECON)
|
|
{
|
|
kb_buf.kb_count = 0;
|
|
kb_buf.kb_size = LINEBUFSIZECON;
|
|
}
|
|
read_line(sft_idx, sft_idx, &kb_buf);
|
|
bufend = &kb_buf.kb_buf[kb_buf.kb_count + 2];
|
|
bufend[-1] = echo_char(LF, sft_idx);
|
|
inputptr = kb_buf.kb_buf;
|
|
if (*inputptr == CTL_Z)
|
|
{
|
|
inputptr = NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (inputptr > bufend - n)
|
|
n = bufend - inputptr;
|
|
|
|
fmemcpy(bp, inputptr, n);
|
|
inputptr += n;
|
|
if (inputptr == bufend)
|
|
inputptr = NULL;
|
|
return n;
|
|
}
|
|
|
|
/*
|
|
* Log: chario.c,v - for newer logs do "cvs log chario.c"
|
|
*
|
|
* Revision 1.7 2000/03/09 06:07:10 kernel
|
|
* 2017f updates by James Tabor
|
|
*
|
|
* Revision 1.6 1999/09/23 04:40:45 jprice
|
|
* *** empty log message ***
|
|
*
|
|
* Revision 1.4 1999/08/25 03:18:07 jprice
|
|
* ror4 patches to allow TC 2.01 compile.
|
|
*
|
|
* Revision 1.3 1999/04/16 12:21:21 jprice
|
|
* Steffen c-break handler changes
|
|
*
|
|
* Revision 1.2 1999/04/04 18:51:42 jprice
|
|
* no message
|
|
*
|
|
* Revision 1.1.1.1 1999/03/29 15:41:45 jprice
|
|
* New version without IPL.SYS
|
|
*
|
|
* Revision 1.5 1999/02/09 02:54:23 jprice
|
|
* Added Pat's 1937 kernel patches
|
|
*
|
|
* Revision 1.4 1999/02/04 03:18:37 jprice
|
|
* Formating. Added comments.
|
|
*
|
|
* Revision 1.3 1999/02/01 01:43:28 jprice
|
|
* Fixed findfirst function to find volume label with Windows long filenames
|
|
*
|
|
* Revision 1.2 1999/01/22 04:15:28 jprice
|
|
* Formating
|
|
*
|
|
* Revision 1.1.1.1 1999/01/20 05:51:00 jprice
|
|
* Imported sources
|
|
*
|
|
*
|
|
* Rev 1.9 06 Dec 1998 8:43:36 patv
|
|
* changes in character I/O because of new I/O subsystem.
|
|
*
|
|
* Rev 1.8 11 Jan 1998 2:06:08 patv
|
|
* Added functionality to ioctl.
|
|
*
|
|
* Rev 1.7 08 Jan 1998 21:36:40 patv
|
|
* Changed automatic requestic packets to static to save stack space.
|
|
*
|
|
* Rev 1.6 04 Jan 1998 23:14:38 patv
|
|
* Changed Log for strip utility
|
|
*
|
|
* Rev 1.5 30 Dec 1997 4:00:20 patv
|
|
* Modified to support SDA
|
|
*
|
|
* Rev 1.4 16 Jan 1997 12:46:36 patv
|
|
* pre-Release 0.92 feature additions
|
|
*
|
|
* Rev 1.3 29 May 1996 21:15:12 patv
|
|
* bug fixes for v0.91a
|
|
*
|
|
* Rev 1.2 01 Sep 1995 17:48:42 patv
|
|
* First GPL release.
|
|
*
|
|
* Rev 1.1 30 Jul 1995 20:50:26 patv
|
|
* Eliminated version strings in ipl
|
|
*
|
|
* Rev 1.0 02 Jul 1995 8:05:44 patv
|
|
* Initial revision.
|
|
*
|
|
*/
|