
/*
 *  HANDLER.H
 */

/*  useful with GCC macro-based inlines */
#define __CONSTLIBBASEDECL__ const

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <exec/interrupts.h>
#include <exec/memory.h>
#include <exec/alerts.h>
#include <exec/execbase.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <devices/timer.h>
#include <libraries/fifo.h>

extern struct ExecBase   * SysBase;
extern struct DosLibrary * DOSBase;

#include <proto/fifo.h>
#if defined(_DCC) /*  at least the very old DICE 2.06 */
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#else /*  proto/ will include inline/ if optimization is on in GCC */
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/alib.h>
#endif

#ifdef DEBUG
#include <stdio.h>		/*  vsprintf() */
#include <stdarg.h>		/*  for xprintf() */
#endif
#include <stdlib.h>
#include <string.h>

#if defined(__GNUC__)
#define inline __inline__
#else
#define  inline
#endif

#if defined(__GNUC__)
/*  We can make GCC generate very nice code with a little help! */
#if 0
#include <inline/strsup.h>	/*  inline strlen() etc. */
#else
extern inline int strlen(const char *string)
{
    const char *s=string;
    while(*s++) ;		/*  tstb a0@+; bne 0b */
    return ~(string-s);
}

/*  Do not use this inline for strcpy(foo, "...") which is optimized away */
extern inline char *strcpy(char *d, const char *s)
{
    char *d2 = d;
    /*
     *  GCC would generate "0: moveb a@+,d0; move d0,a@+, jne 0b" instead
     */
    __asm__ volatile ("0: moveb %0@+,%1@+; jne 0b"
	: "=a" (s), "=a" (d) : "0" (s), "1" (d) : "cc", "memory");
    return d2;
}

/*
 *  GCC-1.x, 2.3.3, 2.5.8, 2.6.3, 2.7.0 use dbra
 *  in such while((short|long)(--n) != -1) loops
 *  Other loops forms may not lead to the same optimization with all GCCs
 *  short count generates single dbra, long count dbra in the inner loop
 */
extern inline char *strscpy(char *d, const char *s, short n)
{
    char *d2 = d;
    if (n) {
	--n;
	/*  0: moveb a0@+,d0; (grr) moveb d0,a0@+; beq 1f; dbra d0,0b; 1: */
	while ((*d++=*s++) && ((short)(--n) != -1)) ;
    }
    return d2;
}
/*  short is enough for fifo-handler */
#define strncpy strscpy

/*
 *  defines, not inline functions, work even without optimization
 *  and work even better than inline function with optimization on
 */
#define memscpy(d,s,scount)  \
({  void *__memscpy_d = (d); \
    void *__memscpy_s = (s); \
    short __memscpy_scount = (scount); \
    void *__memscpy_res = __memscpy_d; \
    if (!(__memscpy_scount==0)) { \
	--__memscpy_scount; \
	do { *(char*)__memscpy_d++ = *(char*)__memscpy_s++; } \
	while ((short)(--__memscpy_scount)!=-1); \
    } \
    __memscpy_res; \
})
/*
 *  The following redefine is safe because: 1st count is small,
 *  2nd this memscpy() can still copy overlapping memory to
 *  lower addresses and this is exactly what fifo-handler needs
 */
#define memmove(d,s,count)  memscpy(d,s,count)

/*  BUG: wrong sign for chars > 127 */
#define streql(s1,s2)  \
({  char *__streql_s1 = (s1), *__streql_s2 = (s2); \
    char __streql_c1, __streql_c2; \
    while (!(__streql_c1=*__streql_s1++ \
	     -(__streql_c2=*__streql_s2++)) \
	   && __streql_c2) ; \
    __streql_c1; \
})
/*  the sign bug is not important, only 0 counts in fifo-handler */
#define strcmp(s1,s2)  streql(s1,s2)
#endif /*  0        */
#endif /*  __GNUC__ */

#ifndef memmove
#define memmove(to,from,count)  bcopy(from,to,count)
#endif

#define Prototype extern

#define DOS_TRUE    -1
#define DOS_FALSE   0

#define CB_SIZE     1024	/*  lines buffer */
#define FIFO_SIZE   2048

#define BTOC(bptr)  ((void *)((unsigned long)(bptr) << 2))
#define CTOB(cptr)  ((BPTR)(((unsigned long)cptr) >> 2))

#define SIGS	(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)

typedef struct DosPacket    DosPacket;
typedef struct FileHandle   FileHandle;
typedef struct DeviceNode   DeviceNode;
typedef struct Process	    Process;
typedef struct MinNode	    Node;
typedef struct MinList	    List;
typedef struct Node	    MaxNode;
typedef struct List	    MaxList;
typedef struct MsgPort	    MsgPort;
typedef struct Message	    Message;
typedef struct Interrupt    Interrupt;
typedef struct DosList	    DosList;
typedef struct RootNode     RootNode;
typedef struct DosInfo	    DosInfo;

typedef struct SharRead {
    void	*sr_FifoR;
    long	sr_Refs;
} SharRead;

typedef struct FHan {
    MaxNode	ff_Node;    /*	fifo node, ln_name holds fifo name */
    short	ff_Flags;
    short	ff_Refs;    /*	open refs   */
    SharRead	*ff_SRead;  /*	fifo handle for reading */
    void	*ff_FifoW;  /*	fifo handle for writing */
    long	ff_FHBufSiz;/*	FifoW half buffer size	*/
    Message	ff_RdMsg;
    Message	ff_WrMsg;
    MsgPort	*ff_Port;   /*	unique port for messages    */
    List	ff_RdWait;
    List	ff_WrWait;
    char	*ff_CookBuf;/*	cooked buffer handling	    */
    short	ff_CookIdx;
    short	ff_LRet;
    MsgPort	*ff_SigPort;/*	message port instead of task to signal */
} FHan;

#define ff_FifoR    ff_SRead->sr_FifoR

#define FHF_COOKED	0x0001
#define FHF_RPEND	0x0002
#define FHF_WAVAIL	0x0004
#define FHF_READ	0x0008
#define FHF_WRITE	0x0010
#define FHF_CLOSEEOF	0x0020
#define FHF_MASTER	0x0040
#define FHF_TEE 	0x0080
#define FHF_SHELL	0x0100
#define FHF_COOKBFUL	0x0200	    /*	cooked buffer is full	*/
#define FHF_COOKECHOBLK 0x0400	    /*	blocked echoing chars!	*/
#define FHF_REOF	0x0800	    /*	REMOTE EOF		*/
#define FHF_WIHOLD	0x1000	    /*	write hold due to input */
#define FHF_COOKCRLF	0x2000	    /*	need to write CRLF	*/
#define FHF_RREQUIRED	0x4000
#define FHF_STARTCOOK	0x8000	    /*	start cooked processing */

typedef struct WaitTreq {
    struct timerequest	wt_timereq;
    DosPacket		*wt_packet;
} WaitTreq;

/* Were Protoize used
#include "fifohan-protos.h"
*/

