/* 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 */ } }