Lately, there has been a lot of discussion on Delphi regarding simple yet helpful subroutines. During the discussions, Ted Jaeger mentioned he had written an "intelligent entry" subroutine for OS-9 BASIC. Essentially, you can specify what characters a user is allowed to enter, and any special characters, that may be required, such as the hyphen in a nine-digit zip code (30125-5114). This type of a routine is extremely useful for data entry applications, as it helps ensure valid data is being typed in.
I decided to take his OS-9 BASIC source and port it over to C to allow wider use of the routine. Listing #1, "entry.bas", is the commented OS-9 BASIC source for the Intelligent Entry subroutine. Listing #2 is the commented source for "testentry.bas", which is a simple program to demonstrate how to use the entry routines.
For C programmers, due to limited space, I've not included Ted's comments within the C source, but you can simply look to the OS-9 BASIC source if you have questions about the code. Listing #3, "entry.c", is the C source which can easily be compiled down to a relocateable '.r' file. If you're using the Microware C Compiler, you simply type "cc entry.c -r=<dir>" where <dir> is the directory you want the '.r' file to be placed in. After you have the relocateable file, any programs you compile in the future that use the entry routine simply have to be "linked" to 'entry.r' by the compiler. This also is fairly easy. For instance, to compile listing #4, "testentry.c", using the Microware C Compiler, you may use "cc testentry.c -l=entry.r". ( The previous assumes that entry.r is in the current data directory. If not, the entire pathlist to entry.r would need to be specified.)
As always, anyone else with helpful OS-9 subroutines, please feel free to send them in!
LISTING #1: "entry.bas" ======================= PROCEDURE entry (* Nov 5, 1993 (* Intelligent entry routine (* allows predefined characters in a string (* and restriction of user input to (* programmer specified characters (* Cursor selection and input (* positioning on screen also included (* Inspired by a similar GWBASIC program (* written by Paul Lepato and published in (* November PCM (* return string to calling routine (* adjust string length as needed PARAM result:STRING[5] (* initial value of input string (* string length should match length of "result" string PARAM fields:STRING[5] (* string of characters identified as acceptable (* to this routine (* again, adjust string length as needed PARAM allow:STRING[15] (* asc specification of cursor character PARAM cursor:INTEGER (* location on screen where input will occur PARAM row,col:INTEGER DIM char:STRING[1] DIM offset:INTEGER DIM errnum:INTEGER DIM ok:BOOLEAN DIM k:INTEGER (* check for legitimate values of row and col IF row>24 OR col>76 THEN PRINT CHR$(7); END ENDIF (* add BACKSPACE to allowable characters allow=allow+CHR$(8) offset=1 ok=FALSE ON ERROR GOTO 100 SHELL "tmode noecho" (* cursor off PRINT CHR$($05); CHR$($20) PRINT CHR$(2); CHR$(31+col); CHR$(31+row); fields PRINT CHR$(2); CHR$(31+col); CHR$(31+row); CHR$(cursor); WHILE offset<=LEN(fields) DO IF MID$(fields,offset,1)=" " THEN GET #0,char (* is it allowable character? GOSUB 10 IF ok=TRUE THEN (* go process the letter GOSUB 20 ELSE (* beep at user PRINT CHR$(7); ENDIF ELSE (* skip predefined characters result=result+MID$(fields,offset,1) PRINT CHR$(2); CHR$(31+col+offset); CHR$(31+row); CHR$(cursor); offset=offset+1 ENDIF ok=FALSE ENDWHILE END 10 (* see if allowable character was entered k=1 WHILE k<=LEN(allow) DO IF MID$(allow,k,1)=char THEN ok=TRUE ENDIF k=k+1 ENDWHILE RETURN 20 (* determine letter and take action IF char<>CHR$(8) THEN PRINT CHR$(2); CHR$(31+col+offset-1); CHR$(31+row); char; result=result+char offset=offset+1 ELSE (* erase cursor PRINT CHR$(2); CHR$(31+col+offset-1); CHR$(31+row); " "; (* find fields field WHILE offset>1 DO offset=offset-1 EXITIF MID$(fields,offset,1)=" " THEN ENDEXIT ENDWHILE PRINT CHR$(2); CHR$(31+col+offset); CHR$(31+row); MID$(fields,offset+1,1); result=LEFT$(result,offset-1) ENDIF (* display cursor IF MID$(fields,offset,1)=" " THEN PRINT CHR$(2); CHR$(31+col+offset-1); CHR$(31+row); CHR$(cursor); ENDIF RETURN 100 errnum=ERR (* user struck [ESC] key IF errnum=211 THEN END ENDIF LISTING #2: "testentry.bas" =========================== PROCEDURE testentry DIM result:STRING[5] DIM allow:STRING[15] DIM fields:STRING[5] DIM cursor:INTEGER DIM row,col:INTEGER DIM sub:STRING[5] sub="entry" (* allow user to enter only numbers allow="1234567890" (* define original fields string (* with predefined colon fields=" : " (* pick a cursor (* examples from MM1 ascii codes (* 63= question mark; 254=small block; 95=underline (* 219=large block; dollar sign=36; number sign=35 cursor=219 (* define position on screen col=50 row=10 (* initialize return string result="" RUN sub(result,fields,allow,cursor,row,col) PRINT PRINT result; " returned" SHELL "tmode echo" (* turn cursor back on PRINT CHR$($05); CHR$($21); LISTING #3: "entry.c" ===================== #include <stdio.h> #define FALSE 0 #define TRUE 1 #define STDIN 0 int entry(result, fields, allow, cursor, row, col) char *result, *fields, *allow; int cursor, row, col; { char chr[2]; int offset, errnum, ok; if (row > 24 || col > 76) { putchar(7); return(0); } offset = 1; ok = FALSE; *result = 0x00; chr[1] = 0x00; system("tmode noecho\n"); printf("\x05\x20"); printf("\x02%c%c%s", 31 + col, 31 + row, fields); printf("\x02%c%c%c", 31 + col, 31 + row, cursor); fflush(stdout); while(offset <= strlen(fields)) { if (*(fields + offset - 1) == 0x20) { if (read(STDIN, chr, 1) != 1) return(FALSE); ok = check_valid_char(chr[0], allow); if (ok) process_char(chr, fields, result, &offset, cursor, row, col); else putchar(7); } else { chr[0] = *(fields + offset - 1); strcat(result, chr); printf("\x02%c%c%c", 31 + col + offset, 31 + row, cursor); offset++; } fflush(stdout); ok = FALSE; } return(TRUE); } int check_valid_char(chr, allow) char chr, *allow; { int k; if (chr == 0x08) return(TRUE); k = 1; for (k = 1; k <= strlen(allow); k++) { if (*(allow + k - 1) == chr) return(TRUE); } return(FALSE); } process_char(chr, fields, result, offset, cursor, row, col) char *chr, *fields, *result; int *offset, cursor, row, col; { if (*chr != 0x08) { printf("\x02%c%c%c", 30 + col + *offset, 31 + row, *chr); strcat(result, chr); *offset += 1; } else { printf("\x02%c%c%c", 30 + col + *offset, 31 + row, 0x20); while(*offset > 1) { *offset -= 1; if (*(fields + *offset - 1) == 0x20) break; } printf("\x02%c%c%c", 31 + col + *offset, 31 + row, *(fields + *offset)); *(result + strlen(result) - 1) = 0x00; } if (*(fields + *offset - 1) == 0x20) printf("\x02%c%c%c", 30 + col + *offset, 31 + row, cursor); return; } LISTING #4: "testentry.c" ======================== #include <stdio.h> main() { char result[6], fields[6], allow[15]; int cursor, row, col, ok; strcpy(allow, "1234567890"); strcpy(fields, " : "); cursor = 219; col = 50; row = 10; result[0] = 0x00; ok = entry(result, fields, allow, cursor, row, col); if (ok) printf("\n%s returned.\n", result); else printf("\nError occured while reading keyboard.\n"); system("tmode echo\n"); printf("\x05\x21"); }