mirror of
https://frontier.innolan.net/github/amiga-ixemul.git
synced 2026-09-13 08:31:10 +00:00
188 lines
4.9 KiB
C
188 lines
4.9 KiB
C
/*
|
|
* This file is part of ixemul.library for the Amiga.
|
|
* Copyright (C) 1991, 1992 Markus M. Wild
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* __read.c,v 1.1.1.1 1994/04/04 04:30:12 amiga Exp
|
|
*
|
|
* __read.c,v
|
|
* Revision 1.1.1.1 1994/04/04 04:30:12 amiga
|
|
* Initial CVS check in.
|
|
*
|
|
* Revision 1.1 1992/05/14 19:55:40 mwild
|
|
* Initial revision
|
|
*
|
|
*/
|
|
|
|
#define _KERNEL
|
|
#include "ixemul.h"
|
|
#include "kprintf.h"
|
|
|
|
/*
|
|
* Starting with ixemul 42.0 we switched from asynchronous to synchronous
|
|
* reads. Apparently the ADOS CON handler uses the mp_SigTask field of the
|
|
* MsgPort struct of an ACTION_READ package to find the Task which it should
|
|
* signal when the user presses Ctrl-C. However, async reads use a special
|
|
* port where the mp_SigTask field points to an Interrupt struct. The CON
|
|
* handler seems to either use that address as the new Task pointer (I hope
|
|
* not) or disable Ctrl-C signalling entirely. I never noticed this until it
|
|
* was pointed out to me, since I always use KingCON. KingCON seems to handle
|
|
* Ctrl-C differently. Just to be sure I also changed the ACTION_WAIT_CHAR
|
|
* to synchronous mode.
|
|
*
|
|
* Starting with 43.1 I no longer use async writes at all. The overhead in
|
|
* handling async writes turned out to be bigger than the gain.
|
|
*/
|
|
|
|
#ifdef USE_VMEM
|
|
#define PUBBUFSIZE 16384
|
|
extern char pub_buf[];
|
|
# ifndef MEMF_SWAP
|
|
# define MEMF_SWAP (1L<<11)
|
|
# endif
|
|
#endif
|
|
|
|
|
|
int __read(struct file *f, char *buf, int len)
|
|
{
|
|
usetup;
|
|
int err = errno, res = 0;
|
|
int omask;
|
|
char *orig_buf;
|
|
|
|
/* always return EOF */
|
|
if (HANDLER_NIL(f)) return 0;
|
|
|
|
omask = syscall (SYS_sigsetmask, ~0);
|
|
__get_file (f);
|
|
|
|
if (f->f_ttyflags & IXTTY_PKT)
|
|
{
|
|
len--;
|
|
*buf++ = 0;
|
|
}
|
|
|
|
orig_buf = buf;
|
|
|
|
if (len > 0)
|
|
{
|
|
/* if interactive and don't block */
|
|
if (IsInteractive(CTOBPTR(f->f_fh)) && (f->f_flags & FNDELAY))
|
|
{
|
|
/* shudder.. this is the most inefficient part of the whole
|
|
* library, but I don't know of another way of doing it... */
|
|
while (res < len)
|
|
{
|
|
char c;
|
|
|
|
if (!WaitForChar(CTOBPTR(f->f_fh), 0))
|
|
{
|
|
if (!res)
|
|
{
|
|
res = -1;
|
|
err = EAGAIN;
|
|
}
|
|
break;
|
|
}
|
|
if (Read(CTOBPTR(f->f_fh), &c, 1) != 1)
|
|
{
|
|
err = __ioerr_to_errno(IoErr());
|
|
/* if there really was no character to read, we should
|
|
* have escaped already at the 'if WaitForChar' line */
|
|
res = -1;
|
|
break;
|
|
}
|
|
*buf++ = c;
|
|
res++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef USE_VMEM
|
|
if (TypeOfMem(buf) & MEMF_SWAP)
|
|
{
|
|
while (len)
|
|
{
|
|
int l = len > PUBBUFSIZE ? PUBBUFSIZE : len;
|
|
int r;
|
|
|
|
r = Read(CTOBPTR(f->f_fh), pub_buf, l);
|
|
if (r == -1)
|
|
{
|
|
res = -1;
|
|
break;
|
|
}
|
|
memcpy(buf, pub_buf, r);
|
|
buf += r;
|
|
len -= r;
|
|
res += r;
|
|
if (r < l)
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
res = Read(CTOBPTR(f->f_fh), buf, len);
|
|
#else
|
|
res = Read(CTOBPTR(f->f_fh), buf, len);
|
|
#endif
|
|
if (res == -1)
|
|
err = __ioerr_to_errno(IoErr());
|
|
}
|
|
}
|
|
|
|
__release_file (f);
|
|
syscall (SYS_sigsetmask, omask);
|
|
errno = err;
|
|
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
|
|
|
|
/* If we read something from a file, and the file is opened RAW (e.g., a stdin
|
|
* stream in RAW mode), then we replace all '\r' characters with '\n' characters.
|
|
* This is a courtesy for those programs that turn off ECHO for the input of a
|
|
* password. Turning off ECHO sets the input mode to RAW, and in RAW mode the
|
|
* Enter key inserts a '\r' into the stream. However, the stdio functions expect
|
|
* a '\n' to end a line, so we patch the input buffer.
|
|
*
|
|
* Actually, the application sets the CR->NL or NL->CR translation
|
|
* through the termios interface. Amiga cooked mode already performs the
|
|
* normal CR->NL conversion, so we only do that transformation when in
|
|
* raw mode.
|
|
*/
|
|
if (res > 0 &&
|
|
((f->f_ttyflags & IXTTY_INLCR) ||
|
|
((f->f_ttyflags & IXTTY_RAW) && (f->f_ttyflags & IXTTY_ICRNL))))
|
|
{
|
|
int i;
|
|
char match, subst;
|
|
|
|
if (f->f_ttyflags & IXTTY_INLCR)
|
|
{
|
|
match = '\n';
|
|
subst = '\r';
|
|
}
|
|
else
|
|
{
|
|
match = '\r';
|
|
subst = '\n';
|
|
}
|
|
for (i = 0; i < res; i++)
|
|
if (orig_buf[i] == match)
|
|
orig_buf[i] = subst;
|
|
}
|
|
if (res > 0 && (f->f_ttyflags & IXTTY_PKT))
|
|
res++;
|
|
return res;
|
|
}
|