/*
 * lineread.c
 *
 * Author: Tomi Ollila <too@cs.hut.fi>
 *
 * This module is FREEWARE. Standard "NO WARRANTY" disclaimer applies.
 *
 * Created: Thu Jul 12 16:40:03 EET 1990 too
 * Last modified: Tue Jul 13 18:05:49 1993 too
 *
 * $Id: lineread.c,v 1.3 1993/07/13 15:15:53 too Exp $
 *
 * HISTORY
 * $Log: lineread.c,v $
 * Revision 1.3  1993/07/13  15:15:53  too
 * Made lineread.c compile without <sys/cdefs.h> file
 *
 * Revision 1.1  1993/06/16  16:43:52  too
 * Initial revision
 *
 *
 */

#include "lineread.h"

#ifdef AMIGA
extern struct Library * SocketBase;
#define READ(a, b, c) recv(a, b, c, 0)
#if __SASC
#include <proto/socket.h>
#elif __GNUC__
#include <inline/socket.h>
#endif
#else /* not AMIGA */
#define READ(a, b, c) read(a, b, c)
#endif /* AMIGA */

#ifndef NULL
#define NULL 0
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef __CONCAT
#if defined (__STDC__) || defined (__cplusplus)
#define __CONCAT(x,y) x ## y
#else
#define __CONCAT(x,y) x/**/y
#endif
#endif /* __CONCAT not defined */  
  
#define RLP(field) __CONCAT(rl->rl_Private.rlp_,field)


#if defined (__STDC__) || defined (__cplusplus)

int lineRead(struct LineRead * rl)

#else

int lineRead(rl)
     struct LineRead * rl;

#endif
{
  int i;
  
  if (RLP(Bufpointer) == RLP(Howlong))

    if (RLP(Selected)) {

      if (RLP(Line_completed))
	RLP(Startp) = RLP(Bufpointer) = 0;

      if ((i = READ(rl->rl_Fd,
		    RLP(Buffer) + RLP(Bufpointer),
		    RLP(Buffersize) - RLP(Bufpointer))) <= 0) {
	/*
	 * here if end-of-file or on error. set Howlong == Bufpointer
	 * so if non-blocking I/O is in use next call will go to READ()
	 */
	RLP(Howlong) = RLP(Bufpointer);
	rl->rl_Line = NULL;			
	return i;
      }
      else
	RLP(Howlong) = RLP(Bufpointer) + i;
    }
    else /* Inform user that next call may block (unless select()ed) */ 
      {
	RLP(Selected) = TRUE;
	return 0;
      }
  else /* Bufpointer has not reached Howlong yet. */
    {
      RLP(Buffer)[RLP(Bufpointer)] = RLP(Saved);
      RLP(Startp) = RLP(Bufpointer);
    }

  /*
   * Scan read string for next newline.
   */
  while (RLP(Bufpointer) < RLP(Howlong))
    if (RLP(Buffer)[RLP(Bufpointer)++] == '\n')
      goto Skip;

  /*
   * Here if Bufpointer == Howlong.
   */
  if (rl->rl_Lftype != RL_LFNOTREQ) {
    RLP(Selected) = TRUE;

    if (RLP(Bufpointer) == RLP(Buffersize)) {
      /*
       * Here if Bufpointer reaches end-of-buffer.
       */
      if (RLP(Startp) == 0) { /* (buffer too short for whole string) */
	RLP(Line_completed) = TRUE;
	rl->rl_Line = RLP(Buffer);
	RLP(Buffer)[RLP(Bufpointer)] = '\0';
	return -1;
      }
      /*
       * Copy partial string to start-of-buffer and make control ready for
       * filling rest of buffer when next call to lineRead() is made
       * (perhaps after select()).
       */
      for (i = 0; i < RLP(Buffersize) - RLP(Startp); i++)
	RLP(Buffer)[i] = RLP(Buffer)[RLP(Startp) + i];
      RLP(Howlong)-= RLP(Startp);
      RLP(Bufpointer) = RLP(Howlong);
      RLP(Startp) = 0;
    }
    
    RLP(Line_completed) = FALSE;
    return 0;
  }

 Skip:
  RLP(Line_completed) = TRUE;
  if (rl->rl_Lftype == RL_LFREQNUL)
    RLP(Buffer)[RLP(Bufpointer) - 1] = '\0';
  RLP(Saved) = RLP(Buffer)[RLP(Bufpointer)];
  RLP(Buffer)[RLP(Bufpointer)] = '\0';
  RLP(Selected) = FALSE;
  rl->rl_Line = RLP(Buffer) + RLP(Startp);

  return (RLP(Bufpointer) - RLP(Startp));
}

#undef READ	  

#if defined (__STDC__) || defined (__cplusplus)
	  
void initLineRead(struct LineRead * rl, int fd, int lftype, int buffersize)
	  
#else

int initLineRead(rl, fd, lftype, buffersize)
      struct LineRead * rl;
      int fd;
      int lftype;
      int buffersize;
  
#endif
{	  
  rl->rl_Fd     = fd;
  rl->rl_Lftype = lftype;

  RLP(Bufpointer) = RLP(Howlong) = 0;
  RLP(Selected) = RLP(Line_completed) = TRUE;

  RLP(Buffersize) = buffersize;
}
