/**********************************************************************/
/*            Low-Level I/O Routines with Carrier Detect              */
/*                                                                    */
/* By: Bryan D. Hall                                   Date: 03/15/89 */
/* GEnie Address: BDHALL                                              */
/* Fnet  Address: Bryan Hall, Node 227 CO (719)543-1869 12/24/96 HST  */
/*                                        M-F 4PM-10AM, 24Hrs Weekends*/
/*                                                                    */
/* Modified for Turbo C by Wolfgang Zweygart           Date: 01/09/89 */
/**********************************************************************/

/** cd_check() ********************************************************/
/*   INPUT: None (hardware) CD Line                                   */
/* PROCESS: This is a routine to check for carrier. Exits program if  */
/*          no carrier                                                */
/*  OUTPUT: None.  Exits with status 1                                */
/**********************************************************************/

void cd_check(void)
{
long old_stack;
char *gpip;
char test;

	gpip=(char *)0xFFFFFA01L;
	old_stack = Super(0L);
	test= *gpip;    
	Super((void *) old_stack);
	if (test & 2) exit(1); /* no carrier.. get out of this! */
}


/** cd_bconin(int) ****************************************************/
/*   INPUT: Device number. 0=prn:, 1=aux:, 2=con:, or 3=MIDI.  See    */
/*          Bconin for more info.                                     */
/* PROCESS: Same as for Bconin, but also checks for a carrier.        */
/*  OUTPUT: See Bconin                                                */
/**********************************************************************/

int cd_bconin(int device)
{
switch(device) {
  case 1: while(1){ 	/* AUX: set as primary device */
            cd_check();    /* first make sure there is a carrier */
            if (Bconstat(2) != 0) 
               return((int)Bconin(2));  /* then get char from console */
            if (Bconstat(device) != 0) 
               return((int)Bconin(device));  /* then get char from device */
          }
  case 2: /* CON: set as primary device */
          return((int)Bconin(device));  /* then get char from console */
  case 3: /* MIDI: set as primary device */
          if (Bconstat(2) != 0) return((int)Bconin(2));  /* then get char from console */
          else return((int)Bconin(device));  /* then get char from device */
  default: return(0);
  }
}


/** cd_bconout(int,int) ***********************************************/
/*   INPUT: (1) Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc. see*/
/*          Bconout for more info.                                    */
/*          (2) Character to output, in low byte.                     */
/* PROCESS: Same as for Bconout, except checks for a carrier, and also*/
/*          sends the character to the keyboard if aux: is selected.  */
/*  OUTPUT: None                                                      */
/**********************************************************************/

void cd_bconout(int device, char character)
{
switch(device) {
  case 1:   /* aux: set as the primary device */
            cd_check();    /* first make sure there is a carrier */
            Bconout(device,(int)character); /* sent to device and console */
            Bconout(2,(int)character);
            break;
  case 0:   /* Any other legal device */
  case 2:
  case 3:
  case 4:
  case 5:   Bconout(device,(int)character); /* send to device only */
            break;
  }
}
     

/** cd_bconstat(int) **************************************************/
/*   INPUT: Device number 0=prn:, 1=aux:, 2=con:, or 3=MIDI.  See     */
/*          Bconstat for more info.                                   */
/* PROCESS: Same as for Bconstat, except checks for a carrier, and    */
/*          also checks the keyboard if aux: is selected.             */
/*  OUTPUT: Returns -1 if at least one character is ready, else 0     */
/**********************************************************************/

int cd_bconstat(int device)
{
switch(device) {
  case 1:   /* AUX: set as primary device */
            cd_check();    /* first make sure there is a carrier */
            if (Bconstat(2) != 0)
                 return((int)Bconstat(2));  /* then send "console is ready" */
            else return((int)Bconstat(device)); /* otherwise check AUX: */
  case 0:   /* PRN:, CON:, or MIDI: */
  case 2:
  case 3:   return(Bconstat(device));
  default:  return(0);
  }
}


/** cd_bcostat(int) ***************************************************/
/*   INPUT: Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc.  See   */
/*          Bcostat for more info.                                    */
/* PROCESS: Same as for Bcostat, except it also checks for a carrier. */
/*  OUTPUT: Returns -1 if device is ready, else 0.                    */
/**********************************************************************/

int cd_bcostat(int device)
{
switch(device) {
  case 1:   /* AUX: set as primary device */
            cd_check();    /* first make sure there is a carrier */
            return((int)Bcostat(device));
  case 0:   /* Any other legal device */
  case 2:
  case 3:
  case 4:
  case 5:   return((int)Bcostat(device));
  default:  return(0);
  }
}


/** cd_getchar(int) ***************************************************/
/*   INPUT: Device number 0=prn:, 1=aux:, 2=con:, or 3=MIDI.  See     */
/*          Bcostat for more info                                     */
/* PROCESS: Waits for a character from the specified device.  Then it */
/*          checks to see if the chatacter is printable.  If so, it   */
/*          is displayed and returned.  However, if the character is  */
/*          a <CTRL-S>, the routine remembers this, and the next time */
/*          called, will not echo the character, but will return it   */
/*          and cancel the pause.                                     */
/*          NOTE: If the device is not con:, it will also get the     */
/*                from the keyboard.                                  */
/*  OUTPUT: Returns the character, as an int.                         */
/**********************************************************************/

int cd_getchar(int device)
{
int temp;
static int paused;

 while (cd_bconstat(device) == 0);   /* wait for a character */
 temp = cd_bconin(device);     /* get character */
 if ((isprint(temp) || (temp==10) || (temp==13) || (temp==8)) && !paused )
      {
      cd_bconout(device,temp);    /* echo out to device */
      }
 else {
      if (temp == 19)  /* CTRL-S */
           paused = 1;  /* set flag */
      else
           paused = 0; /* not paused */
      }
 return( temp );     /* return ASCII code */
}


/** cd_hgetchar(int) **************************************************/
/*   INPUT: Device number 0=prn:, 1=aux:, 2=con:, or 3=MIDI.  See     */
/*          Bcostat for more info.                                    */
/* PROCESS: Waits for a character from the specified device.  Does NOT*/
/*          echo character to device or screen.                       */
/*  OUTPUT: Returns the character as an int.                          */
/**********************************************************************/

int cd_hgetchar(int device) /* hidden get character (no echo) */
{
 while (cd_bconstat(device) == 0) ;  /* wait for a character */
 return( cd_bconin(device) );     /* return ASCII code */
}


/** cd_putchar(char,int) **********************************************/
/*   INPUT: (1) Character to output.                                  */
/*          (2) Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc. See*/
/*          Bcostat for more info.                                    */
/* PROCESS: Sends out a character to the specified device.  If the    */
/*          character is a LineFeed, then it also sends a <CR>.       */
/*          NOTE: If the device is not con:, it will also send the    */
/*                char. to the screen.                                */
/*  OUTPUT: None                                                      */
/**********************************************************************/

void cd_putchar(char outchar, int device)
{
 static int pause = 0;

 cd_bconout(device, outchar);   /* send out character */
 if (outchar == 10)    /* LF */
      cd_bconout(device, 13);   /* send out CR */

 do
  {
	 if(cd_bconstat(device)==-1)
	  {
	   if(cd_bconin(device)==19) pause=-1; else pause=0;
	  }
  }
 while(pause==-1);
}


/** cd_gets(char,int,int) *********************************************/
/*   INPUT: (1) "String" pointer.                                     */
/*          (2) Maximum number of chars to get.                       */
/*          (3) Device number 0=prn:, 1=aux:, 2=con:, or 3=MIDI.  See */
/*          Bcostat for more info.                                    */
/* PROCESS: Works somewhat like gets(), except that you can set the   */
/*          maximum number of characters to be typed in, plus allows  */
/*          for non-redirectable input.  It also sends out a <BELL>   */
/*          character when a user tries to backspace past the         */
/*          beginning of the line, and also after the last acceptable */
/*          character space has been filled.  This allows the user to */
/*          then backspace for corrections.                           */
/*          NOTE: If the device is not con:, it will also get the     */
/*                "string" from the keyboard.                         */
/*  OUTPUT: None.                                                     */
/**********************************************************************/

void cd_gets(char *s, int n, int device)
{
register int c;
int at_now=0;
 while(1)
  {
  while (cd_bconstat(device) == 0) ;   /* wait for a character */
  c = cd_bconin(device);     /* get character */
  if (c == 8) /* BS */
   {
   if (at_now > 0)
        {
        n+=1;
        at_now-=1;
        cd_bconout(device,c);    /* echo out to device */
        }
   else {
        cd_bconout(device,7); /* echo bell out to device */
        }                    
   }
  else {
       if ((isprint(c) || (c == 10) || (c == 13) || (c == 8)))
        {
        s[at_now++] = c;
        if (!(n-2)) cd_bconout(device,7); /* echo bell out to device */
        if ((--n <= 0) || (c == 13) || (s[at_now-1] == '\n'))
             {
             s[at_now-1] = '\0';
             return;
             }
        cd_bconout(device,c);    /* echo out to device */
        }
       }
  }
}


/** cd_puts(char,int) *************************************************/
/*   INPUT: (1) Pointer to "string" to output.                        */
/*          (2) Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc. See*/
/*          Bcostat for more info.                                    */
/* PROCESS: Works just like puts() (except for re-direction           */
/*          protection), plus adds the pause features found in the    */
/*          cd_putchar routine.                                       */
/*          NOTE: If the device is not con:, it will also send the    */
/*                "string" to the screen.                             */
/*  OUTPUT: None.                                                     */
/**********************************************************************/

void cd_puts(char *s, int device)
{
 char c;
 while ((c = *s++) !=0) cd_putchar(c, device);
}

/** cd_printf(int device, const char *format, ...) ********************/
/*   INPUT: (1) Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc. See*/
/*          Bcostat for more info.                                    */
/*          (2) Format string like printf()									 */
/*				(.) Parameters like printf()										 */
/* PROCESS: Works just like printf() (except for re-direction         */
/*          protection), plus adds the pause features found in the    */
/*          cd_putchar routine.                                       */
/*          NOTE: If the device is not con:, it will also send the    */
/*                "string" to the screen.                             */
/*  OUTPUT: None.                                                     */
/**********************************************************************/

void cd_printf(int device, const char *format, ...)
{
 va_list arg_point;
 char temp[255];

 va_start(arg_point, format);
 vsprintf(temp, format, arg_point);
 cd_puts(temp, device);
 va_end(arg_point);
}


/** cd_nputs(char,int,int) ********************************************/
/*   INPUT: (1) Pointer to "string" to be output.                     */
/*          (2) Maximum number of chars to output.                    */
/*          (3) Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc. See*/
/*          Bcostat for more info                                     */
/* PROCESS: Works just like cd_puts() but allows you to specify the   */
/*          maximum number of characters to be output.                */
/*          NOTE: If the device is not con:, it will also send the    */
/*                "string" to the screen.                             */
/*  OUTPUT: None.                                                     */
/**********************************************************************/

void cd_nputs(char *s, int n, int device)
{
 char c;
 while (((c = *s++) !=0) && (--n)) cd_putchar(c, device);
}


/** clr_scrn(int) *****************************************************/
/*   INPUT: Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc. see    */
/*          Bcostat for more info                                     */
/* PROCESS: Sends both a VT-52 clear screen & home cursor, and a <LF> */
/*          to the device, and just the VT-52 code to con:            */
/*  OUTPUT: None.                                                     */
/**********************************************************************/

void clr_scrn(int device)
{
 cd_puts("\033E \f",device); /* clear screen */
 cd_puts("\033E",2);
}


/** read_file(char,int) ***********************************************/
/*   INPUT: (1) Pointer to file path\name. Exp: "c:\txt\read.me"      */ 
/*          (2) Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc. See*/
/*          Bcostat for more info                                     */
/* PROCESS: Opens an ASCII (non-binary) file in read-only mode and    */
/*          sends it one character at a time, to the device.  If a    */
/*          <CTRL-S> is recieved (not echoed to device), it will pause*/
/*          until any other character is received.  If <CTRL-C> is    */
/*          recieved when not paused, it will close the file and      */
/*          abort.  If the file cannot be opened, a message will be   */
/*          displayed and the function will abort.                    */
/*          NOTE: If the device is not con:, it will also send the    */
/*                file to the screen.                                 */
/*  OUTPUT: None.                                                     */
/**********************************************************************/

void read_file(char filename[], int device)
{
FILE *fp;
int stat =0;
char ch;

 if ((fp = fopen(filename,"r")) != NULL)
  {
  while (((ch = fgetc(fp)) != EOF) && (stat != 1))
       {
       cd_putchar(ch,device); /* send out char */
       if (cd_bconstat(device) == -1L) /* If true, char is availible*/
        {
        ch=cd_hgetchar(device);       /* Get input */
        if (ch == 19) /* CTRL - S */
             {
             cd_hgetchar(device); /* wait for key */
             stat = 0;
             }
        else if (ch == 3) /* CTRL - C */
             stat = 1;
        }
       }
  }
 else
  {
   cd_puts("\nCannot open file: ", device);
   cd_puts(filename, device);
   return;
  }
fclose(fp);
}


/** do_pushany(int) ***************************************************/
/*   INPUT: Device number 0=prn:, 1=aux:, 2=con:, 3=MIDI, etc.  See   */
/*          Bcostat for more info.                                    */
/* PROCESS: Sends out a "Press any key message", then waits for a     */
/*          character.                                                */
/*          NOTE: If the device is not con:, it will also send the    */
/*                message to the screen.                              */
/*  OUTPUT: None.                                                     */
/**********************************************************************/

void do_pushany(int device)
{
 cd_puts("\n << Press ANY Key to Continue >>\n",device);
 cd_hgetchar(device);
}
