Newer
Older
Microsoft / screendoor / VKEYIN.C
@tundra tundra on 24 May 2012 15 KB Initial revision
/*  VKEYIN.C - Main Keyboard And Video Handler For Programs Using
			   The VSTRUCT Video Control Structure
				Last Modified: 06/13/87
				Copyright (C) 1986, 1986  T.A. Daneliuk
*/


#include		<stdio.h>
#include		<system.h>
#include		<t&r.h>
#include		<vstruct.h>


/* Error Messages */

static	char	msg_rreqd[]={"Entry Required In This Field!"};
static	char	msg_mfill[]={"This Field Must Be Filled!"};
static	char	msg_rval[]={"User Validation Error Occurred!"};


/* Global Variables Needed By VKEYIN */

int		errbeep_on=TRUE;			/* If TRUE, Will Beep On Error */
unsigned errfreq=600;				/* Frequency In Hz Of Error Beep */
unsigned errtime=7;					/* Beep Duration - 18/second */
int		clear_attr=clrnorm;			/* Color To Use For Clearing Edit Fill Characters */
int		errmsg_attr=clrerr;			/* Color To Use For Displaying Error Messages */
int		errmsg_row=24;				/* Beginning Row For Error Messages */
int		errmsg_col=0;				/* Beginning Column For Error Messages */
int		errmsg_on=TRUE;				/* If TRUE Error Messages Will Be Displayed */
int		errmsg_len=79;				/* Maximum Error Message Length */
int		errmsg_cattr=clrnorm;		/* Attribute To Use When Clearing Error Message */
char	clear_fill=' ';				/* Character To Use When Clearing Edit Fill Characters */
char	errmsg_fill=' ';			/* Character To Use When Clearing Error Message */
char	*errmsg_rreqd=msg_rreqd;	/* Pointer To rreqd Validation Error Message */
char	*errmsg_mfill=msg_mfill;	/* Pointer To mustfill Validation Error Message */
char	*errmsg_rval=msg_rval;	/* Pointer To rvalid Validation Error Message */
char	vkeyin_version[]={"2.1.1.pcMsoft "};

/*****************************************************************************/

/* This Function Determines Whether The Current Field Can Receive A User Response.
	User Response Is Allowed If:
					1) rallow is TRUE in the structure for the field, and
					2) rarray is not NULL for the field, and
					3) rlen is > 0 for the field

	If Any Of These Conditions Is Not Met, The Field Is Assumed Not To Receive
	User Response.

	If The Field Can Receive A Response, TRUE Is Returned, Else FALSE Is Returned.
*/

static	int	res_allowed(fldptr)

struct	VSTRUCT	*fldptr;

{
if (!(fldptr->rallow) || ((fldptr->rarray)==NULL) || ((fldptr->rlen)<=0))
	return(FALSE);
else
	return(TRUE);
}

/*****************************************************************************/

/* This Function Displays The Current Field With Editing Fill Chars */

static	void	showfld(vptr,offset)

struct	VSTRUCT	*vptr;
int		offset;

{
	scr_cursoff();
	fill_lin(vptr->rvert,vptr->rhoriz,vptr->rfill,vptr->rlen,vptr->iattrib);	/* Do a line of fill chars */
	dsplylin(vptr->rvert,vptr->rhoriz,vptr->rarray,vptr->iattrib);					/* Overlay with existing data */
	v_rowcol(vptr->rvert,(vptr->rhoriz)+offset);												/* Put cursor where it was */
	scr_curson();
}

/*****************************************************************************/

/* This Function Cleans Editing Garbage Currently On Screen And
   Redisplays The Current Contents Of The Response Array

   This Function Also Performs Whole Field, Required Entry, And
   Must Fill Validations.  FALSE Is Returned If No Error Is 
   Detected.  If Error Is Detected, TRUE Is Returned, And Error
   Message Is Displayed Per The Global Error Variables.	
*/


static	int		endfld(xptr,fld)

struct	VSTRUCT	*xptr;
int		fld;

{

struct	VSTRUCT	*vptr;
static	int	error=FALSE;		/* Error Flag */

vptr=xptr+fld;

	fill_lin(vptr->rvert,vptr->rhoriz,clear_fill,vptr->rlen,clear_attr);	/* This clears the fld we just ended */
	dsplylin(vptr->rvert,vptr->rhoriz,vptr->rarray,vptr->rattrib);			/* This (re-)displays the contents of the current field */

	if (error && errmsg_on)	/* Currently processing and displaying errors */
		dsplylin(errmsg_row,errmsg_col,mkstr(errmsg_fill,errmsg_len),errmsg_cattr);		/* Clear last error message */

	error=FALSE;		/* Assume the error has been corrected */

	if ((vptr->rreqd) && (strlen(vptr->rarray)==0))		/* No entry found in a rreqd field */
		{
		error=TRUE;
		if (errmsg_on)
			dsplylin(errmsg_row,errmsg_col,*errmsg_rreqd,errmsg_attr);
		}

	else if ((vptr->mustfill) && (strlen(vptr->rarray)!=(vptr->rlen)))		/* Field not full in mustfill field */
		{
		error=TRUE;
		if (errmsg_on)
			dsplylin(errmsg_row,errmsg_col,*errmsg_mfill,errmsg_attr);
		}

	else if ((vptr->rvalid) != NULL)		/* See if user validation routine enabled */
		{
		if ((*(vptr->rvalid)) (xptr,fld))	/* Call it - Validation error if TRUE returned */
			{
			error=TRUE;
			if (errmsg_on)
				dsplylin(errmsg_row,errmsg_col,*errmsg_rval,errmsg_attr);
			}
		}

	if (error && errbeep_on)
		sound(errfreq,errtime);

	return(error);			/* Return error condition */

}

/*****************************************************************************/

/* This Function Deletes The Character At Current Offset Within RARRAY,
   Moves Characters To The Right Of This Location Over, And Appends A
   \0 To The End Of The Array
*/

static	void	delchar(vptr,offset)

struct	VSTRUCT	*vptr;
int		offset;

{
	scr_cursoff();
	strcpy((vptr->rarray)+offset,(vptr->rarray)+offset+1);
	v_rowcol(vptr->rvert,vptr->rhoriz);
	scr_aputs(vptr->rarray,vptr->iattrib);
	scr_aputs(mkstr(vptr->rfill,1),vptr->iattrib);
	scr_curson();
}


/*****************************************************************************/

/* This Function Makes Room For A Character To Be Inserted At Current
   Offset Position.
*/

static	void	inschar(vptr,offset)

struct	VSTRUCT	*vptr;
int		offset;

{
	int		length=strlen(vptr->rarray);

	scr_cursoff();

	*((vptr->rarray)+length+1)='\0';

	while(length > offset)
		{
			*((vptr->rarray)+length)=*((vptr->rarray)+length-1);
			length--;
		}
	v_rowcol(vptr->rvert,(vptr->rhoriz)+offset+1);
	scr_aputs(((vptr->rarray)+offset+1),vptr->iattrib);

	scr_curson();
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/

/* vkeyin() Function Entry:

		vptr -		Pointer To An Array Of Structures Per VSTRUCT.H
		fld -		Field Number At Which Processing Is To Begin
		singlefld -	If TRUE, Forces vkeyin To Process Only One Field And Then Return

*/
	

void	vkeyin(vptr,fld,singlefld)

struct	VSTRUCT	*vptr;			/* Pointer To Control Structure */
unsigned int		fld;		/* Starting Field Number */
int		singlefld;				/* If TRUE, Process Only One Field, Then Return */

{

int		c,cntrl,insert,offset,flderror,last,modified,resallowed,dummy,firstfld;
int	lasthelp;

modified=insert=FALSE;
resallowed=FALSE;		/* Will be set to TRUE if any field allows a response */
last=offset=0;
lasthelp=0xffff;	/* 0xffff Flags The Fact That This Is 1st Time Through */

	firstfld=fld;		/* Save in case we're only processing one field */

	while (((vptr+last)->lastfld) != TRUE)	/* Calculate last field number */
				last++;

	fld=(fld>last ? 0:fld);  /* Force 1st field into range */

	for (dummy=0;dummy<=last;++dummy)		/* See if response allowed in any field */
		{
			if (res_allowed(vptr+dummy))
				resallowed=TRUE;
		}

	if (resallowed)		/* Point to 1st field >= entry field which allows entry */
		{
			while (!res_allowed(vptr+fld))
				fld=(fld<last ? ++fld:0);  /* No entry allowed, get next fld */
		}

	v_rowcol((vptr+fld)->rvert,(vptr+fld)->rhoriz);	/* Position cursor */

	if (singlefld && (firstfld != fld))			/* Make sure we're in field we started in */
		resallowed=FALSE;	

/*
	Main loop executes only if:
	1) The user doen't terminate with an FN3 key.
	2) A response is allowed somewhere on the current screen.
	3) In the case of single field processing, loop executes until current field is terminated.
*/

	while (resallowed)

		{
			flderror=FALSE;							/* TRUE means we got a fld validation error */

			c=ci();									/* Get a character */
			cntrl=FALSE;

			if (c==0)								/* Prefix To Extended ASCII */
				{
				cntrl=TRUE;
				c=ci();								/* Get next character */
				}

			if (c==ENTER || c==CLR_FLD || c==TAB || c==BKSPC)		/* Cursor control key */
				cntrl=TRUE;


			if (cntrl==TRUE)							/* Must be cursor control */

				{

					if (c==DARROW)
						c=TAB;							/* TAB and Dn-Arrow Same Thing */
					if (c==UARROW)
						c=TABBK;						/* BackTAB and Up-Arrow Same Thing */

					switch(c)							/* Cursor control handling */

					{

						case FN3:					/* User wants to quit */
							if (flderror=endfld(vptr,fld))		/* Got an Error! Can't quit. */
								;					/* So do nothing and keep looping */
							else					/* No error, we're done */
								resallowed=FALSE;	/* Turn main loop off */
							break;

						case HELP:
							if ((vptr+fld)->hlp)		/* FALSE==NULL means no help screen */
								lasthelp=show_help(vptr,fld,lasthelp);	/* Display The Help Screen */
						break;

						case TAB:						/* Tab */
							if (!(flderror=endfld(vptr,fld)))		/* No Error Occured */
								fld=((fld<last) ? ++fld:0);	/* Point to next field */
							offset=0;
							modified=insert=FALSE;
							break;

						case TABBK:						/* Reverse TAB */
							if (!(flderror=endfld(vptr,fld)))		/* No Error Occured */
								{
								fld=((fld==0) ? last:--fld); /* Previous field */
								while (!res_allowed(vptr+fld))
									fld=(fld==0 ? last:--fld);  /* No entry allowed, get next fld */
								}
							offset=0;					/* Beginning of fld - Use offset as usual */
							modified=insert=FALSE;
							break;

						case ENTER:						/* Enter */
							if (!(flderror=endfld(vptr,fld)))		/* No Error Occured */
								{
								fld=(((vptr+fld)->autoskp) ? ++fld:fld);	/* Increment if autoskip set */
								fld=(fld>last ? 0:fld);						/* Make sure fld in range */
								}
							offset=0;									/* Beginning of fld */
							modified=insert=FALSE;
							break;

						case PGUP:						/* Pg Up */
							if (!(flderror=endfld(vptr,fld)))		/* No error occured */
								fld=0; 					/* Pt to first fld */
							offset=0;					/* Beginning of fld */
							modified=insert=FALSE;
							break;

						case PGDN:						/* Pg Dn */
							if (!(flderror=endfld(vptr,fld)))		/* No error occured */
								{
								fld=last; 					/* Pt to last fld */
								while (!res_allowed(vptr+fld))
									fld=(fld==0 ? last:--fld);  /* No entry allowed, get next fld */
								}
							offset=0;					/* Beginning of fld */
							modified=insert=FALSE;
							break;

						case INS:						/* INSert mode toggle */
							insert=((insert==FALSE) ? TRUE:FALSE);
							break;	

						case DEL:						/* DELete character */
							if (!modified)					/* 1st time through */
								{
									showfld(vptr+fld,offset);
									modified=TRUE;									/* Indicate that field was modified */
								}
							delchar(vptr+fld,offset);
							break;

						case CLR_FLD:
							for (offset=0;offset <= ((vptr+fld)->rlen);offset++)
								*(((vptr+fld)->rarray)+offset)='\0';
							offset=0;
							showfld(vptr+fld,offset);
							modified=TRUE;
							break;

						case BKSPC:						/* Backspace */
							if (!modified)				/* 1st time through */
								{
									showfld(vptr+fld,offset);
									modified=TRUE;									/* Indicate that field was modified */
								}
							offset=(offset==0 ? ((vptr+fld)->rlen)-1:--offset);
							offset=(offset>strlen((vptr+fld)->rarray) ? strlen((vptr+fld)->rarray):offset);		/* Cursor past end of valid data */
							delchar(vptr+fld,offset);
							break;

						case RARROW:					/* Right Arrow */
							offset=(offset>=(((vptr+fld)->rlen)-1) ? 0:++offset);	/* Position no greater than field length */
							offset=(offset>strlen((vptr+fld)->rarray) ? 0:offset);	/* Position only 1 past end of existing data */
							break;

						case LARROW:					/* Left Arrow */
							offset=(offset==0 ? ((vptr+fld)->rlen)-1:--offset);
							offset=(offset>strlen((vptr+fld)->rarray) ? strlen((vptr+fld)->rarray):offset);		/* Cursor past end of valid data */
							break;

						case HOME:						/* Home Key */
							offset=0;					/* Go to start of fld */
							break;

						case END:						/* End Key */
							offset=strlen((vptr+fld)->rarray);	/* Go to end of fld */
							if (offset==((vptr+fld)->rlen))		/* Never wrap back to beginning */
								--offset;
							break;

					}
				if ((!flderror) && singlefld && (c==TAB || c==TABBK || c==ENTER || c==PGUP || c==PGDN))
					resallowed=FALSE;				/* Single Field Processing */
				}

			/* Not A Cursor Motion Control Character - Must Be Printable Or Out-Of-Range */

			else if ((offset < ((vptr+fld)->rlen)) && isprint(c) && ((c!=SPACE) || (c==SPACE && ((vptr+fld)->rspace))))	/* Legitimate characters from 0x20 to 0x7E */
				{

				/* Individual Character Validations - If Validation Fails, c Is Set To 0 */

					switch((vptr+fld)->rcval)
						{
							case 0:					/* No Validation */
								break;
							case 1:					/* Force Upper Case */
								c=toupper(c);
								break;
							case 2:					/* Force Lower Case */
								c=tolower(c);
								break;
							case 3:					/* Alpha Only */
								if (!isalpha(c))
									c=0;
								break;
							case 4:					/* Alpha Only - UC */
								c=toupper(c);
								if (!isalpha(c))
									c=0;
								break;
							case 5:					/* Alpha Only - LC */
								c=tolower(c);
								if (!isalpha(c))
									c=0;
								break;
							case 6:					/* AlphaNumeric Only */
								if (!isalnum(c))
									c=0;
								break;
							case 7:					/* AlphaNumeric Only - UC */
								c=toupper(c);
								if (!isalnum(c))
									c=0;
								break;
							case 8:					/* AlphaNumeric Only - LC */
								c=tolower(c);
								if (!isalnum(c))
									c=0;
								break;
							case 9:					/* Binary Digits Only */
								if (c<'0' || c>'1')
									c=0;
								break;
							case 10:				/* Octal Digits Only */
								if (c<'0' || c>'7')
									c=0;
								break;
							case 11:				/* Decimal Digits Only */
								if (!isdigit(c))
									c=0;
								break;
							case 12:				/* Hexadecimal Digits Only - UC */
								c=toupper(c);
								if (!isdigit(c) && (c<'A' || c>'F'))
									c=0;
								break;
							case 13:				/* 'Y' or 'N' Only - UC */
								c=toupper(c);
								if ((c!='Y') && (c!='N'))
									c=0;
								break;
							case 14:				/* Floating Point Format */
								if (!isdigit(c) && c!='.' && c!='+' && c!='-')
									c=0;
								break;
							case 15:				/* Unsigned Floating Point Format */
								if (!isdigit(c) && c!='.')
									c=0;
								break;
							case 16:				/* Exponential Floating Point Format */
								c=toupper(c);
								if (!isdigit(c) && c!='E' && c!='.' && c!='+' && c!='-')
									c=0;
								break;
						}

					if (c != 0)		/* Process Character Only If Validation Was OK */
						{

						if (!modified)					/* 1st time through */
							{
								showfld(vptr+fld,offset);
								modified=TRUE;									/* Indicate that field was modified */
							}
						scr_aputs(mkstr(c,1),(vptr+fld)->iattrib);		/* Display the character */
						if (insert)										/* Insert mode set */
							inschar((vptr+fld),offset);
						*(((vptr+fld)->rarray)+offset)=c;			/* And stuff into proper array location */
						++offset;		/* Increment position and don't wrap */
						}
					}
/*
	Housekeeping done each time we go through the main while loop
*/

			while (!res_allowed(vptr+fld))
				fld=(fld<last ? ++fld:0);  /* No entry allowed, get next fld */
			v_rowcol((vptr+fld)->rvert,((vptr+fld)->rhoriz)+offset);	/* Position cursor */
			if (strlen((vptr+fld)->rarray)>=(vptr+fld)->rlen)
				insert=FALSE;		/* Field Full - Can't Insert */
			cursorblk(insert);		/* Show current insert status */

		}
}