
/*
 *   RTERM.C
 *
 *   Terminal emulator for iRMX                                    Version  1.0
 *
 * HISTORY:
 *
 *     - Version X.01 to X.10:
 *
 *		Prototype software, many features added
 *		and many bug fixes.				Nam Ly 02/29/90
 *
 *     - Version 1.0:
 *		First version checked into the source data base, many features
 *		added and many bug fixes.			Nam Ly 09/15/90
 *
 */

#include <stdio.h>
#include <dos.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include "rterm.h"
/*
 * -- External declaration
 */
extern int kb_char(void);
extern void set_dos_flag(void);

extern unsigned pascal RQLookupObject(unsigned, unsigned char far *, unsigned, unsigned far *);
extern void pascal RQSendMessage(unsigned, unsigned, unsigned, unsigned far *);
extern unsigned pascal RQGetTaskTokens(unsigned char, unsigned far *);

#define VERSION "V1.0"
char version[] = "program_version_number=V1.0program_name=RTERM";

static char cpyrt[] = {0x43,0x6F,0x70,0x79,0x72,0x69,0x67,0x68,0x74,};
static char name[] = " 1989 Intel Corporation";

#define EOK				0
#define rootjob			3
#define callingtask		0

static unsigned	roottoken;
static unsigned	vm86j;
static unsigned	Kb_Mux;
static unsigned	except;
static unsigned	response;
static unsigned	segment;
static unsigned	rootjobtoken;

unsigned char vm86[12] ={10,'R','?','V','M','8','6','_','J','O','B',0};

unsigned char kb_mb[14] ={12,'R','?','K','B','_'
							,'M','A','I','L','B','O','X',0};

   union REGS ireg;
/*
 * Standard way of doing things
 */
static void set_cursor(unsigned char, unsigned char);
static unsigned int get_key(void);
static void set_page(unsigned int);
static void get_mode(void);
static void set_mode(unsigned char);
static unsigned char get_cols(void);
static void str_copy(int *, int *, unsigned int);
static void update_screen(void);
static void restore(void);
static void set_screen_attrib(void);
static void set_forg_col(void);
static void set_back_col(void);
static void send_data(unsigned int);
static unsigned int restore_r_screen(void);
static unsigned int save_r_screen(void);

OUT_BUFFER far *out_buf= MK_FP (0x0040, 0xE0);
IN_BUFFER  far *in_buf = MK_FP (0x0040, 0xE2);

/*
 * -----------------------   Main Program  ------------------------------------
 */
main()
{
   printf("\niRMX Terminal emulator, ");
   printf(VERSION);
   printf("\n%s%s\n",cpyrt,name);
 
  /*
   * The following copyright message is printed ONLY because of the
   * licensing agreement associated with the Microsoft C compiler.
   * It must be removed if this utility is ever generated with a 
   * different compiler.
   */
   printf("%s (c) Microsoft Corp 1984, 1985, 1986, 1987.",cpyrt);
   printf(" All rights reserved.\n\n");

  /*
   * initialize save buffer ptr
   */
   save_buff = (int far *)save_buffer;
  /*
   * Set up the screen attribute
   */
   forground  = (WHITE | HI_INTENS);
   background = BLUE;

   r_term.row    = CRTROWS;         /* Set number of rows    */

   get_mode();
   r_term.column = get_cols();      /* Get columns           */
   r_term.crtlen = r_term.row * r_term.column;

   r_term.console_state = 0;        /*     ????              */
   r_term.output_state  = 0;        /*     ????              */
   r_term.routine_index = 0;        /*     default           */

   r_term.displayw = ((background << 4) + forground) << 8;  /* Set colors */
   /*
    * Find base address of display memory
    */
   FP_SEG(video_p) = (r_term.mode == 7) ?  0xb000 :  0xb800;
   FP_OFF(video_p) = 0;
   /*
    * save stuff on the DOS screen
    */
   movedata (FP_SEG(video_p), FP_OFF(video_p),       /* source seg. off. */
             FP_SEG(save_buff), FP_OFF(save_buff),   /* destin seg. off. */
             4000);                                  /* count            */

   if ( !restore_r_screen() )
   {
      /*
       * blank the screen
       */
       temp_ptr =(int far *) video_p;
       for(tmp=0; tmp < r_term.crtlen; tmp++)
       {
         (*temp_ptr++) = r_term.displayw;
       }
       /*
        * put the cursor to top of screen
        */
       r_term.row = 0;
       r_term.column = 0;
       set_cursor(r_term.row, r_term.column);
    }
    Stop_output = FALSE;

   /*
    * initialize input/output buffer @ iRMX comm. area
    */
   if( in_buf->count > 29 )
      in_buf->count   = 0;

   Num_chars          = 0;
   out_buf->flag_byte = 0;
   out_buf->data_byte = 0;

	roottoken = RQGetTaskTokens(rootjob,&except);
	if (except != EOK)
	{
		printf("RQGetTaskTokens fail, error: %X\n", except);
		exit(0);
	}
	vm86j = RQLookupObject(roottoken,&vm86[0],0,&except);
	if (except != EOK)
	{
		printf("RQLookupObject fail, error: %X\n", except);
		exit(0);
	}

	Kb_Mux = RQLookupObject(vm86j,&kb_mb[0],0,&except);
	if (except != EOK)
	{
		printf("RQLookupObject fail, error: %X\n", except);
		exit(0);
	}

	response	= 0;
	segment		= Kb_Mux;


   for (;;)   /*  forever loop */
   {
      if( kb_char() )                 /* keyboard data is available */
      {
        if(Stop_output)               /* output is stopped          */
        {
          Stop_output = FALSE;        /* then enable screen output  */
          temp = get_key();           /* and flush the kb buffer    */
        }
        else
        {
          switch (temp = get_key())
          {
            case 0x0E08:              /* Backspace key       */
                 temp = 0x7f;
                 send_data(temp);
                 break;
            case 0x1011:              /* Control-Q           */
                 Stop_output = FALSE;
                 break;
            case 0x1117:              /* Control-W           */
                 temp = 0x17;
                 send_data(temp);
                 break;
            case 0x1312:              /* Control-R           */
                 temp = 0x12;
                 send_data(temp);
                 break;
            case 0x1910:              /* Control-P           */
                 temp = 0x10;
                 send_data(temp);
                 break;
            case 0x1F13:              /* Control-S           */
                 Stop_output = TRUE;
                 break;
            case 0x2C1A:              /* Control-Z           */
                 temp = 0x1A;
                 send_data(temp);
                 break;
            case 0x2D18:              /* Control-X           */
                 temp = 0x18;
                 send_data(temp);
                 break;
            case 0x8200:              /* ALT (minus)         */
                 set_back_col();
                 break;
            case 0x8300:              /* ALT (plus)          */
                 set_forg_col();
                 break;

            case 0x2d00:              /* ALT-X  exit program */
                 save_r_screen();
                 restore();           /* restore the screen  */
                 exit(0);
            case 0x2300:              /* ALT-H key           */
                 break;
            case 0x2E03:              /* Control-C key       */
                 break;

            case 0x4700:              /* Home key            */
                 temp = 0x1d;
                 send_data(temp);
                 break;

            case 0x4900:              /* Page-up key         */
                 break;
            case 0x4F00:              /* End key             */
                 break;
            case 0x5100:              /* Page down           */
                 break;

            case 0x4800:              /* Up arrow            */
                 temp = 0x1e;
                 send_data(temp);
                 break;
            case 0x4B00:              /* Left arrow          */
                 temp = 0x1f;
                 send_data(temp);
                 break;
            case 0x4D00:              /* Right arrow         */
                 temp = 0x19;
                 send_data(temp);
                 break;
            case 0x5000:              /* Down arrow          */
                 temp = 0x1c;
                 send_data(temp);
                 break;

            case 0x7500:              /* Ctrl-End            */
                 *bflag_ptr = 0x1234; /* skip the mem. test  */
                 outp(0x64, 0xFC);    /* do warm reset       */
                 break;

            case 0x7700:              /* Ctrl-Home           */
                 temp = 0xEE;         /* Break to SDM mon    */
                 send_data(temp);
                 break;

            case 0x7200:              /* Ctrl-SysRq          */
            case 0x7600:              /* Ctrl-Pgdn           */
                 temp = 0xEF;         /* reload DOS frm. RMX */
                 send_data(temp);
                 break;

            default:
                       /* send characters to the comm area for iRMX */
                 send_data(temp);
                 break;
          }
        }
      }

     /*
      * check the comm. area and process characters from iRMX driver
      * and display them.
      */
      if (((in_buf->count) > 0) && (Num_chars == 0))
      {
        /*
         * copy data from iRMX to local buffer
         */
        for(tmp=0; tmp < in_buf->count; tmp++)
           Temp_str[tmp] = in_buf->data_byte[tmp];

        Num_chars = in_buf->count;   /* save count for update_screen */
        in_buf->count = 0;           /* tell RMX we read the data    */
       }

       update_screen();             /*    write data to screen       */

   }        /* end forever!!!??? */

   restore();                       /*    restore the DOS screen     */
   exit(0);

} /* --------------------- end of main code section ------------------------ */

/*
 *  -----------------------  Local procedures -------------------------------
 *
 * Title : update_screen
 *         Process characters from the input data segment and update screen
 */

void update_screen()
{

if ( ( Stop_output ) || ( Num_chars == 0) )
  return;

for (index = 0; index <= Num_chars - 1; index++)
{
	/*
	 *  Get one character from buffer
	 */
	X_char =  Temp_str[index];

	switch (r_term.routine_index)
	{
	case 0 :
		/* routine$index = 0 - ordinary character */ 
		{
		if (X_char < DISPLAYABLECHAR &&
					 (r_term.console_state & LITERALMODE) == 0)
			switch (X_char)
			{
			case 0 :
				{
				/* CASE 0 -	 */
				}
				break;
			case 1 :			/* CASE 1 - erase rest of screen */
				{
					temp_w = r_term.displayw + BLANKCHARACTER;
					t_count = (CRTCOLS * (CRTROWS - r_term.row - 1) + CRTCOLS - r_term.column);
					des_ptr =(int far *) video_p+(r_term.row * CRTCOLS + r_term.column);
					for(tmp=0; tmp < t_count; ++tmp)
					{
						(*des_ptr++) = temp_w;
					}
				}
				break;
			case 2 :			/* CASE 2 - erase line */
				{
					temp_w = r_term.displayw + BLANKCHARACTER;
					t_count = CRTCOLS;
					des_ptr =(int far *) video_p+(r_term.row * CRTCOLS);
					for(tmp=0; tmp < t_count; ++tmp)
					{
						(*des_ptr++) = temp_w;
					}
				}
				break;
			case 3 :			/* CASE 3 - erase rest of line */
				{
					temp_w = r_term.displayw + BLANKCHARACTER;
					t_count = CRTCOLS - r_term.column;
					des_ptr =(int far *) video_p+(r_term.row * CRTCOLS + r_term.column);
					for(tmp=0; tmp < t_count; ++tmp)
					{
						(*des_ptr++) = temp_w;
					}
				}
				break;
			case 4 :			/* CASE 4 - cursor absolute */
				{
				r_term.routine_index = 1;
				}
				break;
			case 5 :			/* CASE 5 - line delete */
				{
					t_count = (LASTROW - r_term.row) * CRTCOLS * 2;
					src_ptr =(int far *) video_p+((r_term.row + 1) * CRTCOLS);
					des_ptr =(int far *) video_p+(r_term.row * CRTCOLS);

					movedata (FP_SEG(src_ptr), FP_OFF(src_ptr), /* source seg. off. */
							FP_SEG(des_ptr), FP_OFF(des_ptr),   /* destin seg. off. */
							t_count);                           /* count            */

					temp_w = r_term.displayw + BLANKCHARACTER;
					t_count = CRTCOLS;
					des_ptr =(int far *) video_p+(LASTROW * CRTCOLS);
					for(tmp=0; tmp < t_count; ++tmp)
					{
						(*des_ptr++) = temp_w;
					}
				}
				break;
			case 6 :			/* CASE 6 - line insert */
				{
					t_count = (LASTROW - r_term.row) * CRTCOLS;
					src_ptr =(int far *) video_p+(r_term.row * CRTCOLS) + t_count;
					des_ptr =(int far *) video_p+((r_term.row + 1) * CRTCOLS) + t_count;
					for(tmp=0; tmp < t_count; ++tmp)
					{
						(*des_ptr--) = (*src_ptr--);
					}

					temp_w = r_term.displayw + BLANKCHARACTER;
					t_count = CRTCOLS;
					des_ptr =(int far *) video_p+(r_term.row * CRTCOLS);
					for(tmp=0; tmp < t_count; ++tmp)
					{
						(*des_ptr++) = temp_w;
					}
				}
				break;
			case 7 :			/* CASE 7 - bell */
				{
				}
				break;
			case 8 :			/* CASE 8 - backspace */
				{
					if (r_term.column == 0)
					{
						if (r_term.row > 0)
						{
							--r_term.row;
							r_term.column = LASTCOL;
						}
					}
					else
						--r_term.column;
				}
				break;
			case 9 :			/* CASE 9 - tab */
				{
				/* CASE 9 - tab */
				}
				break;
			case 10 :			/* CASE 0A - linefeed */
				{
					if (r_term.row >= LASTROW)
					{
						t_count = CRTCOLS * LASTROW * 2;
						src_ptr =(int far *) video_p + CRTCOLS;
						des_ptr =(int far *) video_p;

						movedata (FP_SEG(src_ptr), FP_OFF(src_ptr), /* source seg. off. */
								FP_SEG(des_ptr), FP_OFF(des_ptr),   /* destin seg. off. */
								t_count);                           /* count            */

						temp_w = r_term.displayw + BLANKCHARACTER;
						t_count = CRTCOLS;
						des_ptr =(int far *) video_p+(CRTCOLS * LASTROW);
						for(tmp=0; tmp < t_count; ++tmp)
						{
							(*des_ptr++) = temp_w;
						}
					}
					else
						++r_term.row;
				}
				break;
			case 11 :			/* CASE 0B - set color */
				{
					r_term.routine_index = 3;
				}
				break;
			case 12 :			/* CASE 0C - erase screen */
				{
					temp_w = r_term.displayw + BLANKCHARACTER;
					des_ptr =(int far *) video_p;
					for(tmp=0; tmp < r_term.crtlen; ++tmp)
					{
						(*des_ptr++) = temp_w;
					}

					r_term.row = 0;
					r_term.column = 0;
				}
				break;
			case 13 :			/* CASE 0D - CR */
				{
				r_term.column = 0;
				}
				break;
			case 14 :			/* CASE 0E - literal */
				{
				r_term.console_state = r_term.console_state | LITERALMODE;
				}
				break;
			case 15 :			/* CASE 0F - set raw mode */
				{
				r_term.console_state = r_term.console_state | RAWMODE;
				}
				break;
			case 16 :			/* CASE 10 - set cooked mode */
				{
				r_term.console_state = r_term.console_state & ~RAWMODE;
				}
				break;
			case 17 :			/* CASE 11 - X-ON	*/
				{
				/* CASE 11 - X-ON	*/
				}
				break;
			case 18 :			/* CASE 12		 */
				{
				/* CASE 12		 */
				}
				break;
			case 19 :			/* CASE 13 - X-OFF */
				{
				/* CASE 13 - X-OFF */
				}
				break;
			case 20 :			/* CASE 14		 */
				{
				/* CASE 14 */
				}
				break;
			case 21 :			/* CASE 15		 */
				{
				/* CASE 15 */
				}
				break;
			case 22 :			/* CASE 16		 */
				{
				/* CASE 16 */
				}
				break;
			case 23 :			/* CASE 17		 */
				{
				/* CASE 17 */
				}
				break;
			case 24 :			/* CASE 18		 */
				{
				/* CASE 18 */
				}
				break;
			case 25 :			/* CASE 19 - cursor right */
				{
					if (r_term.column >= LASTCOL)
					{
						if (r_term.row < LASTROW)
						{
							++r_term.row;
							r_term.column = 0;
						}
					}
					else
					{
						++r_term.column;
					}
				}
				break;
			case 26 :			/* CASE 1A  */
				{
				/* CASE 1A */
				}
				break;
			case 27 :			/* CASE 1B */
				{
				/* CASE 1B */
				}
				break;
			case 28 :			/* CASE 1C - cursor down */
				{
				if (r_term.row != LASTROW) ++r_term.row;
				}
				break;
			case 29 :			/* CASE 1D - cursor home */
				{
					r_term.row    = 0;
					r_term.column = 0;
				}
				break;
			case 30 :			/* CASE 1E - cursor up */
				{
					if (r_term.row != 0) --r_term.row;
				}
				break;
			case 31 :			/* CASE 1F - cursor left */
				{
					if (r_term.column == 0)
					{
						if (r_term.row > 0)
						{
							--r_term.row;
							r_term.column = LASTCOL;
						}
					}
					else
						--r_term.column;
				}
				break;
			}	/* CASE char */

		else	/* process normal character */
		{
			r_term.console_state = r_term.console_state & ~LITERALMODE;

			/* write the characrer to display ram at current cursor pos. */

			(*video_p)[r_term.row * CRTCOLS + r_term.column] = r_term.displayw + X_char;

			/* update cursor position */

			++r_term.column;

			if (r_term.column > LASTCOL)
			{
				r_term.column = 0;
				if (r_term.row >= LASTROW)
				{
					/* scroll the display up one line */
					t_count = CRTCOLS * LASTROW * 2;
					src_ptr =(int far *) video_p + CRTCOLS;
					des_ptr =(int far *) video_p;

					movedata (FP_SEG(src_ptr), FP_OFF(src_ptr), /* source seg. off. */
							FP_SEG(des_ptr), FP_OFF(des_ptr),   /* destin seg. off. */
							t_count);                           /* count            */

					/* erase the last line on the screen */
					temp_w = r_term.displayw + BLANKCHARACTER;
					t_count = CRTCOLS;
					des_ptr =(int far *) video_p+(CRTCOLS * LASTROW);
					for(tmp=0; tmp < t_count; ++tmp)
					{
						(*des_ptr++) = temp_w;
					}
				}
				else
					++r_term.row;
			}
		}
	}	/* of case 0	=> routine$index = 0 */
	break;

	case 1 :
		/* routine$index = 1 - second byte of absolute cursor position */
		{
			r_term.routine_index = 2;
			temp = X_char - 0x20;
			if (temp < CRTROWS)
				r_term.row = temp;
			else
				r_term.row = 0;
		}
		break;

	case 2 :
		/* routine$index = 2 - third byte of absolute cursor position */
		{
			r_term.routine_index = 0;
			temp = X_char - 0x20;
			if (temp <= CRTCOLS)
				r_term.column = temp;
			else
				r_term.column = 0;
		}
		/* routine$index = 3 - second byte of set foreground color */
		break;
	case 3 :
		{
			r_term.routine_index = 0;
			r_term.displayw = X_char * 256;
		}
		break;
	}	/* CASE routine$index */
}	/* of DO index */

End_of_output:

Num_chars = 0;

set_cursor(r_term.row, r_term.column);

}	/* End update_screen */


/*
 *  Title:    get_mode
 *            Determine the display mode.
 *
 *   Return: r_term.mode
 *           r_term.page
 *           r_term.column
 */

void get_mode(void)
{
   ireg.h.ah = 0x0f;
   int86(0x10, &ireg, &ireg);

   r_term.mode = (ireg.h.al);
   r_term.page = (ireg.h.bh);
   r_term.column = (ireg.h.ah);
}

/*
 *  Title:   set_mode
 *           Set the display mode for the video device.
 */

void set_mode(unsigned char mode)
{
   ireg.h.ah = 0x00;                      /* Function 0 */
   ireg.h.al = mode;

   int86(0x10, &ireg, &ireg);
}

/*
 *  Title:    get_cols()
 *            Determine the number of columns being used by the video display
 *            via interrupt 0x10, function 0x0f.
 *  Return:   number of columns (40 or 80).
 */

unsigned char get_cols(void)
{
   ireg.h.ah = 0x0f;

   int86(0x10, &ireg, &ireg);            /* mode is returned in ireg.h.al  */

   if (ireg.h.al < 2)
      return 40;                         /* 40-column mode                 */
   if (ireg.h.al > 3 && ireg.h.al != 7)
      return 0;                          /* Return 0 for any graphics mode */
   else
      return 80;                         /* 80-column mode                 */
}


/*
 *  Title:  set_page
 *          Set the currently-active video page.
 */

#define MAXPAGE   8

void set_page(unsigned int page)
{
   ireg.h.ah = 0x05;                      /* Function */
   ireg.h.al = (page % MAXPAGE);

   int86(0x10, &ireg, &ireg);
}


/*
 *  Title:  read_cursor()
 *          Read the current row and column position of the cursor.
 *  Input:  int *row and int *col
 */

void read_cursor(int *row, int *col)
{
   ireg.h.ah = 0x03;                   /* Function     */
   ireg.h.bh = r_term.page;             /* Current page */
   int86(0x10, &ireg, &ireg);

   *row = (int) ireg.h.dh;
   *col = (int) ireg.h.dl;
}

/*
 * Title:	set_cursor
 */

void set_cursor(unsigned char row, unsigned char col)
{
   ireg.h.ah = 0x02;                   /* Function */
   ireg.h.bh = r_term.page;            /* Current page */
   ireg.h.dh = row;
   ireg.h.dl = col;

   int86(0x10, &ireg, &ireg);

}

/*
 *  Title:  send_data
 *          Copy a byte of data to iRMX buffer
 */
void send_data(unsigned int data_byte)
{
	if (!(out_buf->flag_byte))
	{
		out_buf->data_byte = (unsigned char) (data_byte & 0x00ff);
		out_buf->flag_byte = TRUE;
		RQSendMessage(Kb_Mux, segment, response, &except);
		if (except != EOK)
		{
			printf("RQSendMessage fail, error: %X\n", except);
			exit(0);
		}

	}
}


/*
 * Title:  get_key
 */

unsigned int get_key()
{
    ireg.h.ah = 0;                  /* Get next key from keyboard   */

    int86(0x16, &ireg, &ireg);
    return(ireg.x.ax);
}

/*
 * Title restore
 *        Restore the screen
 */

void restore()
{
 movedata (FP_SEG(save_buff), FP_OFF(save_buff),   /* source seg. off. */
           FP_SEG(video_p), FP_OFF(video_p),       /* destin seg. off. */
          4000);                                   /* count            */

r_term.row = 25;
r_term.column = 0;
set_cursor(r_term.row, r_term.column);

}

/*
 * Title:    str_copy()
 */

void str_copy(int *source, int *target, unsigned int count)
{

   while (count !=0)
   {
      *target++ = *source++;
      --count;
   }
}

/*
 *  Change forground color
 */
void set_forg_col()
{
	if( ((++forground) && 0x1f) > 0x0f )
		forground = 0;
	if (forground == background)
	{
		if( ((++forground) && 0x1f) > 0x0f )
			forground = 0;
	}
	r_term.displayw = ((((background << 4) + forground) << 8) & 0x7f00 );
	set_screen_attrib();
}

/*
 *  Change background color
 */
void set_back_col()
{
	if( ((++background) && 0x0f) > 0x07 )
		background = 0;
	if (forground == background)
	{
		if( ((++background) && 0x0f) > 0x07 )
			background = 0;
	}
	r_term.displayw = ((((background << 4) + forground) << 8) & 0x7f00 );
	set_screen_attrib();
}

/*
 * Title:  set_screen_attrib
 *         Set attribute for the whole screen
 */

void set_screen_attrib()
{
	unsigned char far *tmp_ptr;
	unsigned int temp_b;
	unsigned char x;
	unsigned int y;

	temp_b = (r_term.displayw >> 8);
	x = (char) temp_b;
	x &= NO_BLINK;
	tmp_ptr =(char far *) video_p +1;

	for(y=1; y <= 2000; ++y)
	{
		(*tmp_ptr) = (char) x;
		tmp_ptr += 2;
	}
}
/*
 *  Title:  save_r_screen
 *          Save iRMX screen in file RMX$$$.SCR
 */
unsigned int save_r_screen()
{
    int *buff_ptr, *last_b_ptr;
    int far *screen_ptr;
    int fd_out, bytes;

    if ((fd_out = open("\\RMX$$$.SCR",
                       O_WRONLY|O_CREAT|O_BINARY,
                               S_IREAD|S_IWRITE)) < 0)
    {
      return(FALSE);  /* error open file */
    }
    /* Copy the screen into a near buffer. */

    last_b_ptr = &Temp_Buff[SCREENLENGTH];
    buff_ptr = Temp_Buff;

    screen_ptr = (int far *) video_p;
    for (; buff_ptr < last_b_ptr; ++buff_ptr, ++screen_ptr)
        *buff_ptr = *screen_ptr;

    /* Write it to file. */

    bytes = write(fd_out, Temp_Buff, SCREENLENGTH * 2);
    if (bytes != SCREENLENGTH * 2)
    {
     close(fd_out) ;
     return(FALSE);  /* error writing file */
    }
    /*
     * Save screen cursor location to file
     */
    Temp_Buff[0] = ( (r_term.row << 8) + r_term.column );
    bytes = write(fd_out, Temp_Buff, 2);
    /*
     * Save screen attribute
     */
	Temp_Buff[0] = r_term.displayw;
    bytes = write(fd_out, Temp_Buff, 2);

    close(fd_out) ;
    return(TRUE);
}

/*
 *  Title:  restore_r_screen
 *          Restore iRMX screen from file RMX$$$.SCR
 */
unsigned int restore_r_screen()
{
    int *buff_ptr, *last_b_ptr;
    int far *screen_ptr;
    int fd_in, bytes, Temp_W;

    if ((fd_in = open("\\RMX$$$.SCR", O_RDONLY | O_BINARY)) < 0)
    {
      return(FALSE);  /* error open file */
    }

    /* Read the file into buffer. */

    bytes = read(fd_in, Temp_Buff, SCREENLENGTH * 2);

    if (bytes <= 0)
    {
      close(fd_in) ;
      return(FALSE);  /* error reading file */
    }

    /* Copy the buffer to screen memory. */

    last_b_ptr = &Temp_Buff[bytes / 2];
    buff_ptr = Temp_Buff;

    screen_ptr = (int far *) video_p;
    for (; buff_ptr < last_b_ptr; ++buff_ptr, ++screen_ptr)
        *screen_ptr = *buff_ptr;

    /*
     * read the screen cursor location from file
     */
    bytes = read(fd_in, Temp_Buff, 2);

    Temp_W = Temp_Buff[0];
    r_term.row = (unsigned char) (Temp_W >> 8);
    Temp_W = Temp_Buff[0];
    r_term.column = (unsigned char) (Temp_W);
    /*
     * read screen attribute
     */
    bytes = read(fd_in, Temp_Buff, 2);
    r_term.displayw = Temp_Buff[0];

    close(fd_in) ;
    set_cursor(r_term.row, r_term.column);
    return(TRUE);
}
