/*
 *  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.
 */

int __read(struct file *f, char *buf, int len)
{
  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 (f->f_fh->fh_Port && 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)
            {
              SendPacket1(f, __srwport, ACTION_WAIT_CHAR, 0);
              __wait_sync_packet(&f->f_sp);
              if (! LastResult(f))
              {
                if (!res)
                {
                  res = -1;
                  err = EAGAIN;
                }
                break;
              }
	      SendPacket3(f, __srwport, ACTION_READ, f->f_fh->fh_Arg1, (long)buf, 1);
	      __wait_sync_packet(&f->f_sp);
	      if (LastResult(f) != 1) 
		{
		  err = __ioerr_to_errno(LastError(f));
		  /* if there really was no character to read, we should
		   * have escaped already at the 'if WaitForChar' line */
		  res = -1;
		  break;
		}
	      buf++;
	      res++;
	    }
	}	  
      else
	{
	  SendPacket3(f, __srwport, ACTION_READ, f->f_fh->fh_Arg1, (long)buf, len);
	  __wait_sync_packet(&f->f_sp);
	  res = LastResult(f);
	  if (res == -1)
	    err = __ioerr_to_errno(LastError(f));
	}
   }

  LastResult(f) = 0;
  __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;
}
