/* Part of DoorLib v1.12

   Name   : DoorLib112
   Version: 1.12
   Date   : Saturday, 1st June 1996

   Purpose: DoorLib's 'core' functions.

   Creator: Richard Murray
*/

#include <stdio.h>
#include <stdlib.h>

#include "ctype.h"
#include "kernel.h"
#include "stdarg.h"
#include "strings.h"
#include "time.h"

#include "doorlib.h"

extern void poll_the_wimp(void);


int doors_scanconnect(int bs_doornumber)
/* Will continually scan all bs_ports until a connection established */
{
   int bs_port=0;
   int bs_reply;
   int bs_done=FALSE;
   _kernel_swi_regs bs_rin, bs_rout;

   while (bs_doornumber!=0 && !bs_done)
   {
      bs_port=0;
      do
      {
         bs_rin.r[0]=bs_port;
         _kernel_swi(ARCbbsDoors_ReadStatus,&bs_rin,&bs_rout);
         bs_reply=bs_rout.r[0];

         if (bs_reply == bs_doornumber)
         {
            bs_doornumber=0;
            bs_rin.r[0] = bs_port;
            bs_rin.r[1] = 255;
            _kernel_swi(ARCbbsDoors_WriteStatus,&bs_rin,&bs_rout);
            bs_done=TRUE;
         }
      }
      while (++bs_port<36 && !bs_done);
      bs_port--;
      poll_the_wimp();
   } /* Here we are connected */
   doors_connectedokay=TRUE;
   return bs_port;
}


int doors_scanconnecttimed(int bs_doornumber, int bs_timeout)
/* Will continually scan all bs_ports until a connection established or timeout passed */
{
   int bs_port=0;
   int bs_reply=0;
   int bs_done=FALSE;
   int bs_timed=TRUE;
   int bs_tick=0;
   int bs_tock=0;
   _kernel_swi_regs bs_rin, bs_rout;

   if (bs_doornumber < 0) return -1;    /* Trap silly door numbers */
   if (bs_doornumber > 254) return -1;  /* Trap silly door numbers */

   if (bs_timeout==0) bs_timed=FALSE;

   if (bs_timed==TRUE)
   {
      bs_timeout = bs_timeout * 100; /* Convert to cS */

      _kernel_swi(0x42,&bs_rin,&bs_rout);
      bs_tick = bs_rout.r[0];
      bs_tick = bs_tick + bs_timeout;
   }

   while (bs_doornumber!=0 && !bs_done)
   {
      bs_port=0;
      do
      {
         bs_rin.r[0]=bs_port;
         _kernel_swi(ARCbbsDoors_ReadStatus,&bs_rin,&bs_rout);
         bs_reply=bs_rout.r[0];

         if (bs_reply == bs_doornumber)
         {
            bs_doornumber=0;
            bs_rin.r[0] = bs_port;
            bs_rin.r[1] = 255;
            _kernel_swi(ARCbbsDoors_WriteStatus,&bs_rin,&bs_rout);
            bs_done=TRUE;
         }
      }
      while (++bs_port<36 && !bs_done);
      bs_port--;
      poll_the_wimp();
      if (bs_timed==TRUE)
      {
         _kernel_swi(0x42,&bs_rin,&bs_rout);
         bs_tock = bs_rout.r[0];
         if (bs_tick < bs_tock)
         return -1; /* TIMEOUT */
      }
   } /* Here we are connected */
   doors_connectedokay=TRUE;
   return bs_port;
}


int doors_getbyte(int bs_port)
/* Gets the next byte from port and returns it, or -1 if no byte */
{
   _kernel_swi_regs bs_rin, bs_rout;
   int bs_reply=-1;

   bs_rin.r[0] = bs_port;
   _kernel_swi(ARCbbsDoors_InputRead,&bs_rin,&bs_rout);
   bs_reply = bs_rout.r[0];
   return bs_reply;
}


int doors_getbytef(int bs_port, int bs_timeout)
/* Gets the next byte from port and returns it (in time limit?), or -1 timed out */
{
   int bs_timed=TRUE;
   int bs_tick;
   int bs_tock;
   _kernel_swi_regs bs_rin, bs_rout;
   int bs_reply=-1;

   if (bs_timeout==0) bs_timed=FALSE;

   if (bs_timed==TRUE)
   {
      bs_timeout = bs_timeout * 100; /* Convert to cS */

      _kernel_swi(0x42,&bs_rin,&bs_rout);
      bs_tick = bs_rout.r[0];
      bs_tick = bs_tick + bs_timeout;
   }

   do
   {
      poll_the_wimp();

      bs_rin.r[0] = bs_port;
      _kernel_swi(ARCbbsDoors_InputRead,&bs_rin,&bs_rout);
      bs_reply = bs_rout.r[0];

      if (bs_timed==TRUE)
      {
         _kernel_swi(0x42,&bs_rin,&bs_rout);
         bs_tock = bs_rout.r[0];
         if (bs_tick < bs_tock)
         return -1; /* TIMEOUT */
      }

   } while (bs_reply<0);

   return bs_reply;
}


int doors_byteswaiting(int bs_port)
/* This returns the number of bytes WAITING in the input buffer */
{
   int bs_reply=0;
   _kernel_swi_regs bs_rin, bs_rout;

   bs_rin.r[0] = bs_port;
   _kernel_swi(ARCbbsDoors_InputStatus,&bs_rin,&bs_rout);
   bs_reply = bs_rout.r[0];
   return bs_reply;
}


int doors_bytesfree(int bs_port)
/* This returns the number of bytes FREE in the output buffer */
{
   int bs_reply=0;
   _kernel_swi_regs bs_rin, bs_rout;

   bs_rin.r[0] = bs_port;
   _kernel_swi(ARCbbsDoors_OutputStatus,&bs_rin,&bs_rout);
   bs_reply = bs_rout.r[0];
   return bs_reply;
}


int doors_checkactive(int bs_port)
/* Similar to getstatus, but patched to recognise calling before connection established.
   Replies TRUE if okay and FALSE if user gone. */
{
   int bs_reply=0;
   _kernel_swi_regs bs_rin, bs_rout;

   if (doors_connectedokay==FALSE) return TRUE;
   bs_rin.r[0] = bs_port;
   _kernel_swi(ARCbbsDoors_ReadStatus,&bs_rin,&bs_rout);
   bs_reply = bs_rout.r[0];
   if (bs_reply!=255) return FALSE;
   return TRUE;
}


void doors_tx(int bs_port, char *bs_string)
/* Transmit something to the port. Uses an sprintf() to make life easier. You'll need to
   use an external sprintf() to add variables and such - but this method *also* allows
   you to do things like ' doors_tx(port,"Hello\r\n"); ' directly. :-)  */
{
   int bs_posn=0;
   int bs_reply=0;
   char bs_txbuffer[255];
   _kernel_swi_regs bs_rin, bs_rout;

   sprintf(bs_txbuffer,bs_string);
   while (bs_txbuffer[bs_posn]!=0)
   {
      do
      {
         bs_rin.r[0] = bs_port;
         _kernel_swi(ARCbbsDoors_OutputStatus,&bs_rin,&bs_rout);
         bs_reply = bs_rout.r[0];
         if (bs_reply==0) poll_the_wimp();
      }
      while (bs_reply==0);
      bs_rin.r[0] = bs_port;
      bs_rin.r[1] = (int)bs_txbuffer[bs_posn];
      _kernel_swi(ARCbbsDoors_OutputWrite,&bs_rin,&bs_rout);
      bs_posn++;
   }
}


void doors_txf(int bs_port, char *bs_string, ...)
/* Transmit something to the port. Accepts 'printf()' style input :-) */
{
   int  bs_posn=0;
   int  bs_reply=0;
   int  bs_l;
   char *bs_b;
   char *bs_s;
   va_list bs_m;
   _kernel_swi_regs bs_rin, bs_rout;

   if ((bs_b = (char *)malloc(1024)) == NULL) /* Allocate a block of memory */
      return;

   va_start(bs_m, bs_string); /* Begin format conversions */
   bs_l = vsprintf(bs_b, bs_string, bs_m);
   bs_s = bs_b;

   while (bs_s[bs_posn]!=0)   /* And then output to port as normal */
   {
      do
      {
         bs_rin.r[0] = bs_port;
         _kernel_swi(ARCbbsDoors_OutputStatus,&bs_rin,&bs_rout);
         bs_reply = bs_rout.r[0];
         if (bs_reply==0) poll_the_wimp();
      }
      while (bs_reply==0);
      bs_rin.r[0] = bs_port;
      bs_rin.r[1] = (int)bs_s[bs_posn];
      _kernel_swi(ARCbbsDoors_OutputWrite,&bs_rin,&bs_rout);
      bs_posn++;
   }
   va_end(bs_m); /* Finish up */
   free(bs_b);
}


void doors_txesc(int bs_port, char *bs_string)
/* Transmit something to the port. Uses an sprintf() to make life easier. You'll need to
   use an external sprintf() to add variables and such - but this method *also* allows
   you to do things like ' doors_tx(port,"Hello\r\n"); ' directly. :-) Difference between
   this and doors_tx() is that all '~' are replaced by escapes. */
{
   int bs_posn=0;
   int bs_reply=0;
   int bs_byte=0;
   char bs_txbuffer[255];
   _kernel_swi_regs bs_rin, bs_rout;

   sprintf(bs_txbuffer,bs_string);
   while (bs_txbuffer[bs_posn]!=0)
   {
      do
      {
         bs_rin.r[0] = bs_port;
         _kernel_swi(ARCbbsDoors_OutputStatus,&bs_rin,&bs_rout);
         bs_reply = bs_rout.r[0];
         if (bs_reply==0) poll_the_wimp();
      }
      while (bs_reply==0);
      bs_rin.r[0] = bs_port;
      bs_byte = (int)bs_txbuffer[bs_posn];
      if (bs_byte=='~') bs_byte=0x1b; /* Replace '~' with escape */
      bs_rin.r[1] = bs_byte;
      _kernel_swi(ARCbbsDoors_OutputWrite,&bs_rin,&bs_rout);
      bs_posn++;
   }
}


void doors_close(int bs_port)
/* Close door connection */
{
   _kernel_swi_regs bs_rin, bs_rout;
   bs_rin.r[0] = bs_port;
   bs_rin.r[1] = 0;
   _kernel_swi(ARCbbsDoors_WriteStatus,&bs_rin,&bs_rout);
}


void doors_doorlib_identify(int bs_port)
/* 'Hidden' function to report DoorLib version. */
{
   doors_txf(bs_port, "%c[0;1;32m\n", 27);
   doors_txf(bs_port, "BUDGIESOFT DOORLIB 1.12 JUNE 1ST 1996\n\n");
   doors_txf(bs_port, "%c[37m", 27);
   doors_txf(bs_port, "This door was written with the assistance of the\n");
   doors_txf(bs_port, "BudgieSoft ArcBBS doors library.\n\n");
   doors_txf(bs_port, "DoorLib Copyright (C) 1996 Richard Murray\n\n");
   doors_txf(bs_port, "DoorLib is available for C and APCS assembler\n");
   doors_txf(bs_port, "programmers from a good BBS near you!\n\n\n");
   return;
}


void doors_includeX0(void)
{
   printf("BUDGIESOFT DOORLIB :: DOORLIB112");
}
