/*********************************************************************
*
*	TITLE:	DMOUTIL
*
*	DATE:	10-05-90
*
*	ABSTRACT: This module contains utility functions for the demo
*             program for the DOSRMX Real Time Extensions.
*
*
*   MODIFIED: 
*
***********************************************************************/

/*
 *			 INTEL CORPORATION PROPRIETARY INFORMATION
 *
 *		  This software is supplied under the terms of a 
 *		  license agreement or nondisclosure agreement with
 *		  Intel Corporation and may not be copied or disclosed
 *		  except in accordance with the terms of that agreement.
 *
 */
#ifdef DOS
#include <ctype.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rmxc.h>
#include <rmxerr.h>

#include "jobnames.h"

#ifdef DOS
#include "rwdosrte.h"
#include <graph.h>
#endif

#define TRUE            0xff
#define FALSE           0x0
#define FOUND           0x0
#define MYJOB           1
#define ROOTJOB         3
#define INFINITE        0xffff
#define NOWAITING       0x0
#define ReadOnlyShare   1
#define GetTermChars    4
#define SetTermChars    5
#define MaskEditBits    0xfdfc
#define SetNoEditMode   0x0201
#define VDUPARAMSIZE    36
#define ZeroBuffers     0
#define SizeOfName      4
#define ScreenSize      25
#define zeroaddr        0
#define onemegalias     0x100000
#define HIGHWORD        0xffff0000
#define LOWWORD         0x0000ffff

/* get object literals */

#define MAXNOOBJS       20
#define fifoobjmbx      0
#define fifodatmbx      0x20
#define fifo            0
#define zerounits       0
#define maxtenunits     10
#define objmailboxtype  1
#define datmailboxtype  2
#define descriptortype  3
#define semaphoretype   4
#define segmenttype     6

/* rmx types returned by rqgettype */

#define rmxjobtype      1
#define rmxtasktype     2
#define rmxmbxtype      3
#define rmxsemtype      4
#define rmxregtype      5
#define rmxsegtype      6
#define rmxexttype      7

/* VDU control string literals to index control structure */

#define AFES 0
#define AFER 1
#define AFEK 2
#define AFEL 3
#define AFMB 4
#define AFML 5
#define AFMR 6
#define AFMU 7
#define AFMD 8
#define AFMH 9
#define ControlMax 10

typedef struct rmxstring {
	BYTE  numb_char;
	char string[128];
} RMXSTRING;

typedef struct pointer {
	TOKEN segment;
	WORD  offset;
} POINTER;

/* list of object names created */

RMXSTRING list_of_names[MAXNOOBJS];

#ifdef RMX
/* VDU parameters and control sequences */

RMXSTRING control[ControlMax];

TERMATTRIBSTRUCT vdu_param;

TOKEN vdu_connection;
TOKEN vdu_read_mbx;

static char * ControlName[ControlMax] = {"AFES","AFER","AFEK","AFEL","AFMB",
										"AFML","AFMR","AFMU","AFMD","AFMH"};

#endif

TOKEN root_job; /* used to catalogue my job in for the other prog to find */
TOKEN my_job; /* Used to catalogue objects against */

static char * create_error[7] = {	" ", /* object type 0 invalid */
									"Exception creating object mailbox",
									"Exception creating data mailbox",
									"Exception creating a descriptor",
									" ", /* object type 5 invalid */
									"Exception creating a segment"};

static BYTE rq_global_strg[] = {8,"RQGLOBAL"};
static BYTE rcrt_strg[] = {5,"R?CRT"};
static BYTE termcapfile[] = {15,":CONFIG:TERMCAP"};
static BYTE CI[] = {4,":CI:"};
static char name[] = "NAME";
static char error_exists_wrong_type[] = "ERROR - object is the incorrect type\n";
static char obj_list_full[] = "ERROR - no more space available in object list\n";
static char error_invalid_type[] = "ERROR - invalid object type, not supported\n";
static char error_invalid_objdir[] = "ERROR - invalid job token for object dir\n";
static char nul_message[] = {0};
static char LF = 0x0a;
static char CR = 0x0d;
static char VT = 0x0b;

int debug_char2;

#ifdef RMX
/*
** RQEREADSEGMENT - copies pvam mode data to real mode space
*/
void rqereadsegment(TOKEN pvam_seg, DWORD pvam_offset,
					DWORD realmode_ptr, WORD size, WORD far * except_ptr)
{
TOKEN realmodeseg;
void * dest_ptr;
void * source_ptr;
union {
void near * offset;
DWORD realaddr;
} buildoffset;

	realmodeseg = rqecreatedescriptor(zeroaddr,
									  onemegalias,
									  except_ptr);

	if (*except_ptr == EOK)
	{
        buildoffset.realaddr = (((realmode_ptr & HIGHWORD) >> 12) +
                            	(realmode_ptr & LOWWORD));
		dest_ptr = buildptr(realmodeseg,buildoffset.offset);

        buildoffset.realaddr = pvam_offset;

		source_ptr = buildptr(pvam_seg,buildoffset.offset);

		memcpy(dest_ptr,source_ptr,size);

        rqedeletedescriptor(realmodeseg,except_ptr);
	}
}


/*
** RQEWRITESEGMENT - copies real mode data to pvam mode segment
*/
void rqewritesegment(DWORD realmode_ptr, TOKEN pvam_seg,
					DWORD pvam_offset, WORD size, WORD far * except_ptr)
{
TOKEN realmodeseg;
void * dest_ptr;
void * source_ptr;
union {
void near * offset;
DWORD realaddr;
} buildoffset;

	realmodeseg = rqecreatedescriptor(zeroaddr,
									  onemegalias,
									  except_ptr);

	if (*except_ptr == EOK)
	{
        buildoffset.realaddr = (((realmode_ptr & HIGHWORD) >> 12) +
                            	(realmode_ptr & LOWWORD));
		source_ptr = buildptr(realmodeseg,buildoffset.offset);

        buildoffset.realaddr = pvam_offset;

		dest_ptr = buildptr(pvam_seg,buildoffset.offset);

		memcpy(dest_ptr,source_ptr,size);

        rqedeletedescriptor(realmodeseg,except_ptr);
	}
}
#endif

/*
** CHECKSEG - checks the memory pointed to for a valid RMXSTRING
*/
BYTE checkseg(TOKEN seg_tkn, DWORD segsize)
{
RMXSTRING name;
BYTE count;
WORD except;

#ifdef DOS

	rqereadsegment(seg_tkn,(DWORD)0,&name,(WORD)(segsize < 129 ? segsize : 129),&except);
#else
	memcpy(&name,buildptr(seg_tkn,0),(segsize < 129 ? segsize : 129));
	except = EOK;
#endif

	if ((except == EOK) &&
		( name.numb_char <= 128) &&
		( name.numb_char <= (segsize - 2)) &&
		(name.string[name.numb_char] == 0))
	{
		for ( count = 0; (count < name.numb_char) &&
						 ((isprint(name.string[count]) != 0) ||
						  (name.string[count] == '?')); count++) ;

		if (count == name.numb_char) return TRUE;

	}

	return FALSE;

}

/*
** ADD_TO_LIST - adds the rmx name to a list used to remove delete the objects
** created by this job when it terminates.
*/
void add_to_list(RMXSTRING far * namptr, WORD far * exptr)
{
WORD index;

	for ( index = 0; ((index < MAXNOOBJS) &&
					 (list_of_names[index].numb_char != 0)); index++) ;

	if ( index < MAXNOOBJS )
	{
		memcpy(list_of_names[index].string,namptr->string,namptr->numb_char);
		list_of_names[index].numb_char = namptr->numb_char;
		*exptr = EOK;
	}
	else *exptr = ESPACE;
}

/*
** REMOVE_FROM_LIST - removes an rmx name from the list of names
*/
void remove_from_list(RMXSTRING far * namptr)
{
WORD index;
WORD rindex;

	index = 0;

	while ( (index < MAXNOOBJS) &&
			((list_of_names[index].numb_char != namptr->numb_char) ||
			 (memcmp(list_of_names[index].string,
					 namptr->string,
					 namptr->numb_char) != 0))) index++;

	if (index < MAXNOOBJS)
	{
		/*
		** found a match, need to remove from list by copying last entry
		** over the matched entry and deleting the last entry
		*/

		for (rindex = 0;
			((rindex < MAXNOOBJS) && (list_of_names[rindex].numb_char != 0));
			rindex++ ) ;

		rindex--; /* point to last entry */

		memcpy( list_of_names[index].string,
				list_of_names[rindex].string,
				list_of_names[rindex].numb_char );

		list_of_names[index].numb_char = list_of_names[rindex].numb_char;
		list_of_names[rindex].numb_char = 0;
	}
}

/******************************************************************
*
*    TITLE: REMOVE_MY_NAME
*
*    CALLING SEQUENCE: remove_my_name();
*
*    INTERFACE VARIABLES: NONE
*
*    PARAMETERS:
*
*    GLOBAL VARIABLES: 
*
*
*    ABSTRACT: This function uncatalogues the program name from the
*              root job.
*
******************************************************************/
void remove_my_name()
{
WORD except;

#ifdef DOS
	rquncatalogobject(root_job,myjobname,&except);
#else
	rquncatalogobject(root_job,(char *)myjobname,&except);
#endif
}

/*
** READ_CAT_NAME - reads a ten character name from the keyboard
*/

BYTE read_cat_name(char far * msg_ptr,char name[])
{
BYTE name_complete;
BYTE i;

	name_complete = FALSE;

	while (name_complete == FALSE)
	{
		printf("%s",msg_ptr);

		i = 0;

		while(((i < 10) && (name[i] = getchar()) !='\n')) i++;
		if (i < 10)
		{
			name[i] = 0; /* null terminate the string */

			for(i = 0; ((isprint(name[i]) != 0) || (name[i] != 0)); i++)
				 name[i] = toupper(name[i]);

			if (name[i] == 0) name_complete = TRUE;
			else
			{
				printf("\nERROR - Only Alphanumeric characters\n");
				printf("Press ENTER to continue :-");
				while((name[i] = getchar()) !='\n') ;
			}
		}
		else
		{
			while((name[i] = getchar()) !='\n') ;
			printf("\nERROR - name too long, only 10 characters max\n");
			printf("Press ENTER to continue :-");
			while((name[i] = getchar()) !='\n') ;
		}
	}
	return i;
}

/*
** DELETE_OBJECT - deletes object passed to it
*/

void delete_object(WORD objecttype, TOKEN object, WORD far * exptr)
{
	switch(objecttype)
	{
	case objmailboxtype:
	case datmailboxtype:	rqdeletemailbox(object,exptr);
							break;

	case semaphoretype:		rqdeletesemaphore(object,exptr);
							break;

	case descriptortype:	rqedeletedescriptor(object,exptr);
							break;

	case segmenttype:		rqdeletesegment(object,exptr);
							break;

	default:				error_message(error_invalid_type);
							*exptr = ETYPE;
							break;

	}
}

/*
** DELETE_RMX_OBJECT - deletes object passed to it
*/

void delete_RMX_object(WORD rmxtype, TOKEN object, WORD far * exptr)
{
	switch(rmxtype)
	{
	case rmxmbxtype:	rqdeletemailbox(object,exptr);
						break;

	case rmxsemtype:	rqdeletesemaphore(object,exptr);
						break;

	case rmxsegtype:	rqdeletesegment(object,exptr);
						break;


	default:			error_message(error_invalid_type);
						*exptr = ETYPE;
						break;

	}
}

/*
** FIND_NAMED_OBJECT - looks for the object token in the two possible
** job object directories.
*/
TOKEN find_named_object(RMXSTRING far * namptr,TOKEN far * job_tkn_ptr,WORD far * exptr)
{
TOKEN job_tkn;
int count;
TOKEN temp_tkn;

	/* see if the object exist in the other jobs directory first */
#ifdef DOS
	job_tkn = rqlookupobject(root_job,otherjobname, 0, exptr);
#else
	job_tkn = rqlookupobject(root_job,(char *)otherjobname, 0, exptr);
#endif
	if (*exptr == EOK) count = 2; /* two loops */

	else
	{
		count = 1; /* only one loop, no other job only our job */
		job_tkn = my_job;		
	}

	while (count > 0)
	{
		temp_tkn = rqlookupobject(job_tkn, (BYTE far * )namptr,(WORD)0, exptr);

		if (*exptr == EOK)
		{
			*job_tkn_ptr = job_tkn;
			return temp_tkn;
		}
		else
		{
			job_tkn = my_job;
			count--;
		}
	}
	return 0;
}

/******************************************************************
*
*    TITLE: REMOVE_ALL_OBJECTS
*
*    CALLING SEQUENCE: remove_all_objects();
*
*    INTERFACE VARIABLES: NONE
*
*    PARAMETERS:
*
*    GLOBAL VARIABLES: 
*
*
*    ABSTRACT: This function deletes all objects created by this
*              program.
*
******************************************************************/
void remove_all_objects()
{
WORD index;
TOKEN del_tkn;
WORD rmx_type;
WORD except;

	for (index = 0;
		((index < MAXNOOBJS) && (list_of_names[index].numb_char != 0));
		index++)
	{
		del_tkn = rqlookupobject(my_job,(BYTE far * )&list_of_names[index],
								NOWAITING,&except);
		if (except == EOK)
		{ /* object exists, uncatalog it and delete it */

			rquncatalogobject(my_job,(BYTE far * )&list_of_names[index],&except);

			rmx_type = rqgettype(del_tkn,&except);
			if (except == EOK)
				delete_rmx_object(rmx_type,del_tkn,&except);
		}
	}

}

/*
** REMOVE_OBJECT - deletes a named object that is catalogued in one on
** the job object directories.
*/
void remove_object(RMXSTRING far * namptr)
{
TOKEN obj_tkn;
TOKEN job_tkn;
WORD rmx_type;
WORD except;

	remove_from_list(namptr);

	obj_tkn = find_named_object(namptr,&job_tkn,&except);

	if (except == EOK) /* name found */
	{
		rquncatalogobject(job_tkn,(BYTE far * )namptr,&except); /* remove from obj dir */
		rmx_type = rqgettype(obj_tkn,&except); /* find type */
		delete_rmx_object(rmx_type,obj_tkn,&except);
	}
}

/*
** CREATE_OBJECT - creates a requested object
*/
TOKEN create_object(void far * p, WORD far * exptr)
{
TOKEN temp_tkn;
struct {
WORD objecttype;
TOKEN objdir;
RMXSTRING name;
} far * param_p;
struct {
WORD objecttype;
TOKEN objdir;
RMXSTRING name;
DWORD absaddr;
DWORD segsize;
} far * descrip_p;
struct {
WORD objecttype;
TOKEN objdir;
RMXSTRING name;
DWORD segsize;
} far * segment_p;
WORD except;

	param_p = p; /* setup parameter pointers */
	descrip_p = p;
	segment_p = p;

	add_to_list(&param_p->name,exptr);

	if (*exptr == EOK)
	{

		switch(param_p->objecttype)
		{
		case objmailboxtype:	temp_tkn = rqcreatemailbox(fifoobjmbx,exptr);
								break;

		case datmailboxtype:	temp_tkn = rqcreatemailbox(fifodatmbx,exptr);
								break;

		case semaphoretype:		temp_tkn = rqcreatesemaphore(zerounits,
															maxtenunits,
															fifo,
															exptr);
								break;

		case descriptortype:	temp_tkn = rqecreatedescriptor(descrip_p->absaddr,
															  descrip_p->segsize,
															  exptr);
								break;

		case segmenttype:		temp_tkn = rqcreatesegment(segment_p->segsize,
														   exptr);
								break;

		default:				error_message(error_invalid_type);
								remove_from_list(&param_p->name);
								*exptr = ETYPE;
								break;

		}

		/* catalogue the object */

		if (*exptr == EOK) rqcatalogobject ( param_p->objdir,
											 temp_tkn,
											 (BYTE far * )&param_p->name,
											 exptr);
		else
		{
			printf("%04XH %s",*exptr,create_error[param_p->objecttype]);
			error_message(nul_message); /* wait for CR, no message */
		}

		if (*exptr == EOK) return temp_tkn;
		else
		{
			delete_object(param_p->objecttype,temp_tkn,&except);
			remove_from_list(&param_p->name);
			error_message(error_invalid_objdir);
			return 0;
		}
	}
	else return 0;
}

/*
** CHECK_TYPE - checks that the two types are equal
*/

WORD check_type(WORD type, WORD req_type)
{
	if (((req_type == objmailboxtype) ||
		 (req_type == datmailboxtype)) &&
		 (type == rmxmbxtype)) return EOK;

	else if (((req_type == descriptortype) ||
				(req_type == segmenttype)) &&
				(type == rmxsegtype)) return EOK;


	else if (((req_type == semaphoretype)) &&
				(type == rmxsemtype)) return EOK;

	else return ETYPE;
}

/*
** GET_RMX_OBJECT - creates the desired object and returns the token
*/
TOKEN get_rmx_object(void far * p, WORD far * exptr)
{
int count;
TOKEN temp_tkn;
WORD type;
struct {
WORD objecttype;
TOKEN objdir;
RMXSTRING name;
} far * param_p;

	param_p = p; /* setup parameter pointers */

	temp_tkn = find_named_object(&param_p->name,&param_p->objdir,exptr);

	if (*exptr == EOK)
	{
		type = rqgettype(temp_tkn,exptr);
		if (*exptr == EOK)
		{
			if (check_type(type,param_p->objecttype) == EOK)
													return temp_tkn;
			else
			{
				error_message(error_exists_wrong_type);
				*exptr = ETYPE; /* name exists but type wrong */
				return 0;
			}
		}
		else return 0;
	}
	return 0;
}

#ifdef RMX
/******************************************************************
*
*    TITLE: GETCHE
*
*    CALLING SEQUENCE: getche();
*
*    INTERFACE VARIABLES: NONE
*
*    PARAMETERS:
*
*    GLOBAL VARIABLES: 
*
*
*    ABSTRACT: This function emulates the getche function of microsoft
*              C for the RMX version of the program.
*
******************************************************************/
int getche()
{
int character;
DWORD actual;
WORD except;

	character = 0;

	rqaread(vdu_connection,&character,1,vdu_read_mbx,&except);

	if (except == EOK)
	{
		actual = rqwaitio(vdu_connection,vdu_read_mbx,INFINITE,&except);
		if ((except == EOK) && (actual == 1))
		{

			debug_char2 = character;
			return character;
		}
		else return 0;
	}
	else return 0;

}
#endif

/*
** displays the memory on the screen
*/
void display_memory(TOKEN pvam_seg, DWORD pvam_offset,DWORD segsize)
{
BYTE i;
BYTE j;
BYTE mp[160];
unsigned count;
DWORD mem_offset;
DWORD mem_count;
DWORD display_count;
DWORD offset_addr;
WORD except;
WORD objtype;
char again;

	printf("\n\n");

	again = 'Y';

	mem_count = 0;

	mem_offset = pvam_offset;

	while (again != 'q' && again != 'Q' && mem_count != segsize)
	{
		display_count = (segsize-mem_count)<=160?(segsize-mem_count):160;

		objtype = rqgettype(pvam_seg,&except); /* check if stil there */
		if (except == EOK)
		{
#ifdef DOS
			rqereadsegment(pvam_seg,mem_offset,mp,display_count,&except);
			if (except !=EOK)
			{
				printf("\n\nException %04XH from rqereadsegment in display_memory\n\n",except);
			}
#else
			memcpy(&mp[0],buildptr(pvam_seg,(void near * )mem_offset),display_count);
#endif

			for (count = 0; ((count < 10) && (mem_count != segsize)); count ++)
			{
				offset_addr = (mem_offset + (count*16));
#ifdef DOS
				printf("%04X:%08XH ",pvam_seg,offset_addr);
#else
				printf("%04X:%08XH ",((WORD)pvam_seg),offset_addr);
#endif
				for (i=0; ((i < 16) && (mem_count != segsize)); i++)
				{
					printf("%02X ",mp[i+(count * 16)]);
					mem_count++;
				}
				j = i;
				for (i; i < 16; i++) printf("   ");
				for (i=0; ((i < 16) && (i < j)); i++)
				{
					if ((mp[i+(count * 16)] > 0x1f) && (mp[i+(count * 16)] < 0x7f))
						printf("%c",mp[i+(count * 16)]);
					else
						printf(".");
				}
				printf("\n");
			}
			mem_offset += display_count;
			printf("Enter Q or q to quit, any other key to continue :- ");
			again = getche();

			printf("\n");
		}
		else
		{
			printf("\n\nERROR The segment no longer exists\n");
			error_message(nul_message);
			again = 'Q';
		}
	}
}

#ifdef RMX
/*
** Sets up the vdu control data structure from the  data passed to it
*/
void setup_control_struc(char far * vdu_data)
{
int index;
WORD count;
DWORD control_sequence;
BYTE far * ptr;

	for (index = 0; index < ControlMax; index++)
	{
		count = 0; /* find the control sequence in the buffer */
		while (	(strncmp(ControlName[index],
						&vdu_data[count],
						(strlen(ControlName[index]))) != FOUND) &&
				(strncmp("//",&vdu_data[count],2) != FOUND)) count++;

		if (strncmp("//",&vdu_data[count],2) != FOUND)
		{
		/* Found the control sequence extract it and save */

			count += strlen(ControlName[index]); /* point to after control name */
			ptr = (BYTE far *)&vdu_data[count];

			count = 0;
			while ((isalnum(ptr[count]) == 0) && (ptr[count] != ';')) count++;

			if (ptr[count] == ';') control[index].numb_char = 0; /* Not present */

			else if (isalnum(ptr[count]) != 0)
			{
				ptr = &ptr[count];
				count = 0;
				control_sequence = 0;
				for (count = 0; ptr[count] != ';'; count++)
				{
					if (isalpha(ptr[count]) != 0)
						control_sequence = (control_sequence * 0x10) +
											(ptr[count] - 0x37);
					else
						control_sequence = (control_sequence * 0x10) +
											(ptr[count] - 0x30);
				}
				count = (count/2) + (count%2); /* number of characters */
				control[index].numb_char = count;
				while (count > 0)
				{
					control[index].string[count - 1] = (control_sequence >>
									((control[index].numb_char - count)*8)) &
									 0x000000ff;
					count--;
				}
			}
			else
			{ /* ASCII control string to copy to control string */

				ptr = &ptr[count];
				count = 0;
				while (ptr[count] != ';')
				{
					control[index].string[count] = ptr[count];
				}
			}
		}
		else control[index].numb_char = 0; /* Not present */
	}
}
#endif

/******************************************************************
*
*    TITLE: INITIALISATION
*
*    CALLING SEQUENCE: initialisation();
*
*    INTERFACE VARIABLES: NONE
*
*    PARAMETERS:
*
*    GLOBAL VARIABLES: 
*
*
*    ABSTRACT: This function provides the initialisation of the
*              program.
*
******************************************************************/
void initialisation()
{
TOKEN hi_job;
TOKEN rq_global;
TOKEN terminal_type;
TOKEN termcap;
TOKEN buffer_seg;
char far * charptr;
RMXSTRING far * ptr;
DWORD bytes_read;
#ifdef RMX
char far * term_ptr;
SFILESTATUSSTRUCT term_info;
TERMATTRIBSTRUCT vdu_output_param;
BOOLEAN VduFound;
#endif
WORD  count;
WORD  oldexcept;
WORD  except;

/* Set up the video control data structure */

	root_job = rqgettasktokens(ROOTJOB, &except);

	if (except != EOK) exit(except);

	my_job = rqgettasktokens(MYJOB, &except);

#ifdef RMX
	if (except == EOK)
	{
		hi_job = rqlookupobject(my_job,
								(BYTE far * )rq_global_strg,
								INFINITE,
								&except);
	}
	else exit(except);

	/* setup vdu connection */

	vdu_connection = rqsattachfile(&CI,
									&except);

	if (except != EOK) exit(except);

	rqsopen(vdu_connection, ReadOnlyShare, ZeroBuffers, &except);

	if (except != EOK) exit(except);

	rqsspecial(vdu_connection, GetTermChars, &vdu_output_param, 0, &except);

	if (except != EOK) exit(except);

	vdu_read_mbx = rqcreatemailbox(fifoobjmbx,&except);

	if (except != EOK) exit(except);

	memcpy(&vdu_param, &vdu_output_param, VDUPARAMSIZE); /* save */

	vdu_output_param.connectionflags = (vdu_output_param.connectionflags &
										MaskEditBits) | SetNoEditMode;

	rqsspecial(vdu_connection, SetTermChars, &vdu_output_param, 0, &except);

	if (except != EOK) exit(except);

	/* Find the HI job, this is where RQGLOBAL points to itself */

	if (except == EOK)
	{
		rq_global = rqlookupobject(hi_job,
									&rq_global_strg,
									INFINITE,
									&except);
	}
	else exit(except);

	if (except == EOK)
	{
		while (rq_global != hi_job)
		{
			hi_job = rq_global;
			rq_global = rqlookupobject(hi_job,
										&rq_global_strg,
										INFINITE,
										&except);

			if (except != EOK) exit(except);
		}
	}
	else exit(except);

	/* Found the HI JOB, now lookup the terminal token R?CRT */

	terminal_type = rqlookupobject(hi_job,
									&rcrt_strg,
									INFINITE,
									&except);

	if (except != EOK) exit(except);

 /* found R?CRT token, extract the terminal type. */

	ptr = buildptr(terminal_type,0);

	termcap = rqsattachfile(&termcapfile,&except);
	if (except != EOK) exit(except);

	rqsgetfilestatus(&termcapfile,&term_info,&except);
	if (except != EOK) exit(except);

	rqsopen(termcap,ReadOnlyShare,ZeroBuffers,&except);
	if (except != EOK)
	{
		oldexcept = except;
		rqsdeleteconnection(termcap,&except);
		exit(oldexcept);
	}
	buffer_seg = rqcreatesegment((term_info.filesize + 1),&except);
	if (except != EOK) exit(except);

	charptr = buildptr(buffer_seg,0);

	bytes_read = rqsreadmove(termcap,charptr,term_info.filesize,&except);
	if ((except != EOK) || (bytes_read != term_info.filesize))
	{ /* ERROR reading file */
		if (except != EOK) oldexcept = except;
		else oldexcept = ESPACE; /* not all read */

		rqsclose(termcap,&except);
		rqsdeleteconnection(termcap,&except);
		exit(oldexcept);
	}
	/* finished with the file, close it */

	rqsclose(termcap,&except);
	rqsdeleteconnection(termcap,&except);

	ptr->string[ptr->numb_char] = 0; /* null the end of the string */
	charptr[term_info.filesize] = 0; /* null the end of the string */

	/* make sure all chars are upper case */

	for(count = 0;charptr[count] != 0; count++)
				 charptr[count] = toupper(charptr[count]);
	for(count = 0;ptr->string[count] != 0; count++)
				 ptr->string[count] = toupper(ptr->string[count]);

	term_ptr = charptr;
	VduFound = FALSE;

	while (VduFound == FALSE)
	{
		term_ptr = strstr(term_ptr,&name[0]);

		if (term_ptr == NULL) exit(ESUPPORT); /* if end of file exit */

		term_ptr = &term_ptr[SizeOfName]; /* point to end of 'NAME' */

		count = 0;

		/* Find the start of the VDU name */
		while (isalnum(term_ptr[count]) == 0) count++;

		term_ptr = &term_ptr[count];  /* point to VDU name */

		if (strncmp(ptr->string,term_ptr,ptr->numb_char) == FOUND)
														 VduFound = TRUE;
	}
	/* found the terminal type, now initialise the structure */

	count = 0;
	while (term_ptr[count] != ';') /* find start of control sequences */
							 count++;

	setup_control_struc(&term_ptr[count]); /* setup the data structure */

#endif

	for ( count = 0; count < MAXNOOBJS; count++) /* clear list of object names */
					list_of_names[count].numb_char = 0;

#ifdef DOS
	rqcatalogobject(root_job,my_job,myjobname,&except);
#else
	rqcatalogobject(root_job,my_job,(char *)myjobname,&except);
#endif

	if (except != EOK) exit(except);

}

/******************************************************************
*
*    TITLE: CLEAR_SCREEN
*
*    CALLING SEQUENCE: clear_screen();
*
*    INTERFACE VARIABLES: NONE
*
*    PARAMETERS:
*
*    GLOBAL VARIABLES: 
*
*
*    ABSTRACT: This function clears the screen.
*
******************************************************************/
void clear_screen()
{
BYTE count;

	/* Clear the screen */

#ifdef RMX
	if (control[AFES].numb_char > 0)
	{
		for (count = 0; count < control[AFES].numb_char; count++)
			putchar(control[AFES].string[count]);
	}
	else
	{
		putchar(CR);
		for (count = 0; count < ScreenSize; count++)
			putchar(LF);
	}

	/* Cursor home */

	if (control[AFMB].numb_char > 0)
	{
		for (count = 0; count < control[AFMB].numb_char; count++)
			putchar(control[AFMB].string[count]);
	}
	else
	{
		for (count = 0; count < ScreenSize; count++)
			putchar(VT);
	}
#else

	_clearscreen(_GCLEARSCREEN);

#endif

}

