#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>


#define bufsize 16384
#define linesize 1024
char outbufque[bufsize];
char *outbufwptr=outbufque,*outbufrptr=outbufque,*outbufnrptr=outbufque;
struct FileHandle *outfilehandle=NULL;
struct StandardPacket *dospacket=NULL;
struct MsgPort *dosport=NULL;
struct FileHandle *outputfilehandle=NULL;


void addchartobuf(char c);
void addstrtobuf(char *s, int l);
void cleanoutbuf(void);
int initoutbuf(void);
void writeoutbufout(void);
void outbufprintf(char *template, ...);





void cleanoutbuf()
 {
  if (dospacket && dospacket->sp_Msg.mn_Node.ln_Succ!=NULL)
   {
    AbortPkt(dosport,&dospacket->sp_Pkt);
    while (GetMsg(dosport)==NULL)
     WaitPort(dosport);
    while (GetMsg(dosport));
   }
  if (dospacket) FreeDosObject(DOS_STDPKT,(char *)dospacket+sizeof(dospacket->sp_Msg));
  if (dosport) DeleteMsgPort(dosport);
 }


int initoutbuf()
 {
  BPTR so;
  if (outputfilehandle) return -1;
  if ((so=Output())==NULL) return -2;
  outputfilehandle=(struct FileHandle *)(((int)so)<<2);
  if ((dospacket=(struct StandardPacket *)AllocDosObject(DOS_STDPKT,NULL))==NULL) return -3;
  dospacket=(char *)dospacket-sizeof(dospacket->sp_Msg);
  dospacket->sp_Msg.mn_Node.ln_Succ=NULL;
  dospacket->sp_Msg.mn_Node.ln_Name=(char *)&dospacket->sp_Pkt;
  dospacket->sp_Pkt.dp_Link=&dospacket->sp_Msg;
  atexit(cleanoutbuf);
  if ((dosport=CreateMsgPort())==NULL) return -4;
  return 0;
 }


void addchartobuf(char c)
 {
  if (outbufrptr-1==outbufwptr || (outbufrptr==outbufque && outbufwptr==outbufque+bufsize-1))  return;
  *outbufwptr++=c;
  if (outbufwptr>=outbufque+bufsize) outbufwptr=outbufque;
 }


void addstrtobuf(char *s, int sl)
 {
  int l,r;
  if (sl==0) return;
  r=outbufrptr-outbufwptr-1;
  if (r==0) return;
  else if (r<0) r=bufsize-r-2;
  if (r>sl) l=sl; else l=r;
  if ((outbufwptr-outbufque+l)<bufsize)
   {
    memcpy(outbufwptr,s,l);
    outbufwptr+=l;
   }
  else
   {
    r=outbufque+bufsize-outbufwptr;
    if (r)
     {
      memcpy(outbufwptr,s,r);
      l=l-r;
     }
    outbufwptr=outbufque;
    if (l)
     {
      outbufwptr=outbufque;
      memcpy(outbufwptr,s+r,l);
      outbufwptr+=l;
     }
   }
 }    


void writeoutbufout()
 {
  if (dospacket->sp_Msg.mn_Node.ln_Succ==NULL || GetMsg(dosport)==&(dospacket->sp_Msg))
   {
    if (dospacket->sp_Msg.mn_Node.ln_Succ!=NULL)
     {
      dospacket->sp_Msg.mn_Node.ln_Succ=NULL;
      outbufrptr=outbufnrptr;
     }
    if (outbufrptr==outbufwptr) return;
    if (outbufwptr<outbufrptr)
     {
      outbufnrptr=outbufque;
      dospacket->sp_Pkt.dp_Arg3=outbufque+bufsize-outbufrptr;
     }
    else
     {
      outbufnrptr=outbufwptr;
      dospacket->sp_Pkt.dp_Arg3=outbufwptr-outbufrptr;
     }
    dospacket->sp_Pkt.dp_Action=ACTION_WRITE;
    dospacket->sp_Pkt.dp_Arg1=outputfilehandle->fh_Arg1;
    dospacket->sp_Pkt.dp_Arg2=(int)outbufrptr;
    SendPkt(&(dospacket->sp_Pkt),outputfilehandle->fh_Type,dosport);
   }
  return;
 }
  
void outbufprintf(char *template, ...)
 {
   char linebuf[linesize];
   va_list args;
   if (dospacket==NULL) return;
   va_start(args,template);
   vsprintf( linebuf, template, args );
   addstrtobuf(linebuf,strlen(linebuf));
   writeoutbufout();
   va_end(args);
 }


