Masked Input For The Amiga
Steve Michel
Here's a versatile input routine for use in your Amiga Basic programs. Written as a subprogram, this input routine selectively masks out all unwanted characters. Whether you need numeric input or a simple Y/N response, "Masked Input" can do the job.
Probably the most vulnerable part of a program is its input routine. If a program is going to crash, it usually does so here. To avoid such occurrences, input routines must carefully screen illegal and unacceptable keypresses. For example, when the program is expecting a numeric response, the input routine should accept only numeric data. Editing keys must be monitored as well. You do not want someone who is using the program to accidentally clear the screen or backspace over your input prompt simply because they press the wrong key.
"Masked Input" is an Amiga Basic subprogram that provides a welcome alternative to the INPUT statement. Because it is a subprogram, Masked Input can be easily transported into your own programs. Besides being useful, Masked Input offers a good example of the use of subprograms and Amiga library routines.
Getting Started
Type in the demo program and save a copy before you run it. This program contains both the Masked Input subprogram, named INPUTSTRING, and some preliminary code that demonstrates its use.
Masked Input makes use of the Amiga library file graphics.bmap. This file is included in the Basic-Demos drawer of the Amiga Extras disk. Before you run the program, make sure that a copy of the graphics.bmap file is on the same disk as the demo program. The location of this file is important. It must be either in the current directory, or in the directory named LIBS on the disk used when you booted the system. If you do not have this library file in the correct place, BASIC will stop with a file not found error when you run the program.
When run, the demo program asks you to enter a string length and edit mask (see below for details). Next, the program calls the INPUTSTRING subprogram using your previous two entries, prompting you for your final input. After you press RETURN, the computer echoes your entry to the screen, waits for the RETURN key to be pressed, and then reruns the program.
Using The Subprogram
The proper syntax for calling INPUTSTRING is
CALL INPUTSTRING(entry$,strlen,emask)
Amiga Basic also provides an alternative call syntax that allows the subprogram to be used like a new BASIC command:
INPUTSTRING entry$,strlen,emask
INPUTSTRING requires three parameters: entry$, strlen, and emask. The string variable entry$ returns the text entered by the user. The strlen parameter specifies the maximum length of input to be allowed. The emask parameter is an edit mask that determines the type of data that can be entered. Valid values for emask range from 0 to 127. Different mask values produce the following results:
Value | Function |
0 | All characters accepted |
1 | Numbers 0–9 |
2 | Punctuation marks.,+, and - |
4 | Upper-and lowercase letters A–Z |
8 | Blanks (spaces) allowed |
16 | Uppercase letter A–Z |
32 | Characters Y and N |
64 | Null input not allowed |
An important aspect of this method of masking is that the emask values may be added together to produce a cumulative effect. A value of 85 (1 + 4 + 16 + 64), for example, allows numbers, upper and lowercase letters, and spaces, but not punctuation characters or a null input. This method of input masking puts the programmer in complete control.
INPUTSTRING uses less-than and greater-than symbols to frame the area of input. This lets the user see exactly how many characters can be entered. All responses are returned in the variable entry$. If a numeric value is required, entry$ may be converted to a number with the VAL function as illustrated in the demo program.
This subprogram is fully documented with remark statements. All comments that follow the apostrophes found at the end of lines are instructional and may be omitted. The comments following the REMs, however, should be left in place to document the different parameters that are necessary for using the subprogram.
Editing Keys
In addition to the keys allowed by the edit mask, several other keys are available for editing input. The RETURN key terminates input. The cursor keys allow you to move through entered text. The current position of the cursor is denoted by an underline character. The BACK SPACE key deletes characters at the end of the input string. Pressing the DEL key erases the entire input field.
Subprograms
As explained above, the entire input routine is contained in the subprogram named INPUTSTRING. A subprogram is a section of code that is called by the main program and interacts with the main program by passing data back and forth through variables called parameters. Parameters are listed in parentheses after the subprogram name. Other variables may also be held in common between the main program and the subprogram through the use of the SHARED statement. Except for passed parameters and shared variables, the subprogram acts as though it were in a world by itself. All other variables used within the subprogram are referred to as local variables, which means they are known only to the subprogram. Thus, the variable LOOP.CNTR in the main program and the variable LOOP.CNTR in a subprogram are treated as two different variables and do not interfere with each other.
Why use a subprogram instead of a subroutine to perform this input function? The main reason is efficiency. Once a subprogram has been written, debugged, and polished up, it can be attached to any program that requires its services. With a variety of prewritten subprograms, you no longer have to rewrite vital routines for each new program. Ideally, one could build and maintain a whole library of subprograms, each one designed for a specific application (inputting, sorting, reading a disk directory, and so on). Writing a program would then simply consist of splicing the appropriate subprogram into the main program. And because each subprogram acts independently, you do not have to worry about conflicting variable names.
It's easy to create a version of the Masked Input subprogram that you can add to your own programs. First, load the demonstration program and delete all the lines that come before the SUB INPUTSTRING statement. Next, save the subprogram text to disk as an ASCII file. Use a statement of the form
SAVE "masked input",A
When you want to add the subprogram to one of your own programs, load or type in that program, then use a command of the form
MERGE "masked input"
to add the subprogram text from disk. Then add the statements for access to the graphics library routines, as explained below. All that's left is to add CALL statements for the INPUTSTRING subprogram and your program is set up for customized customized input.
Libraries
When the Amiga is first booted with Kickstart, approximately 192K of operating system is loaded into the upper part of the computer's memory. (Kickstart is found in ROM on the Amiga 500 and Amiga 2000.) This code contains, among many other things, a whole set of instructions that manage the Amiga's graphics. This set of instructions is organized into a neat collection of routines collectively known as the graphics library, which consists of such routines as ClearScreen(), Draw(), WritePixel(), and SetSoftStyle().
Before any library routine can be used from BASIC, you must open the library with the LIBRARY command. In the case of our Masked Input routine, the command LIBRARY "graphics.library" is used. Executing this command instructs Amiga Basic to load the file graphics.bmap.
To create an underlined cursor, INPUTSTRING uses the graphics library routine named SetSoftStyle(). This routine allows you to change a font's type style. The syntax for SetSoftStyle is
CALL SetSoftStyle&(WINDOW(8), font. Style, font, mask)
where WINDOW(8) is a pointer to the RastPort for the current window, font.style is a value in the range 0–7, and font.mask is a value that specifies which type styles are valid for a particular font. Not all fonts have the capability of producing every type style.
To insure that Amiga BASIC interprets this as a function and not as an array reference, a DECLARE FUNCTION Ask SoftStyle& LIBRARY command is placed near the beginning of the demo program.
At this point, we're ready to change a character's font style to produce an underlined cursor. Legal values for the font.style parameter are
0 = normal |
1 = underlined |
2 = boldface |
4 = italics |
These values may be added together to achieve multiple font styles. For example, a value of 3 produces underlined boldface type. For Our purposes, however, we need only use a 1 for underline.
Masked Input—Demo Program
For instructions on entering this program, please refer to "COMPUTE!‘s Guide to Typing In Programs" elsewhere in this issue.
‘ copyright 1987 COMPUTE! Public ations, Inc. ‘ All Rights Reserved demo. driver: ‘ the following declaration must be made in the calling program DECLARE FUNCTION AskSoftStyle& LIBRARY LIBRARY "graphics. library" tell AmigaBAISC to read it start: CLS PRINT " copyright 1987 COMPUTE! Publications, Inc." PRINT" All Rights Reserved." : For tt = l To 3500 : NEXT tt CLS strLen = 2: emask = l ‘ set default values LOCATE 2, 2: PRINT "Enter string length "; ‘ set up prompt CALL INPUTSTRING (entry $ , strLen, emask) ‘ get input size = VAL (entry $ ): StrLen = 3 ‘ Convert to # & reset length LOCATE 4, 2 : PRINT "Enter edit mask (0 – 127) "; CALL INPUTSTRING (entry $ , strLen, emask) mask = VAL (entry $ ) ‘ convert to number CLS : PRINT : PRINT "Enter input here = > "; CALL INPUTSTRING (entry $ , size, mask) PRINT: PRINT: PRINT "User input was = > ";entry $ LOCATE 20, 10 : PRINT "PRESS ANY KEY" get.Loop: g $ = INKEY $ : IF g $ = "" THEN get .Loop GOTO start: SUB INPUTSTRING (entry $ , strLen, emask) STATIC: REM entry $ = input string returned to calling program REM strlen = maximum size of field to be input REM emask = number (0–127) that determines input field traits REM emask = see table at end of subprogram for values & traits Poss . styLe % = AskSoftStyle & (WINDOW (8)) ‘ get possible styles IF emask < 0 OR emask > 127 THEN emask = 0 input.string: g $ = INKEY $ : IF g $ <> "" THEN input.string ‘ clear out keyboard buffer yLine = CSRLIN : xcol = POS (0) ‘ get screen positions PRINT "<" : LOCATE YLine, xcoL + strLen + l : PRINT ">"; : LOCATE YLine, xcoL Pos.cntr = l : LEN. cntr = l entry $ ="" : backspace $ = CHR $ (8) next.key : IF Len. cntr = pos. cntr AND Len.cntr <> strLen + l THEN LOCATE yLine, xcol + pos. cntr: PRINT"_"; END IF get.key : g $ = INKEY $ : IF g $ = "" THEN get.key ascii = ASC (g $ ) IF ascii = 13 THEN quit.sub ‘ return IF ascii = 8 THEN back.up ‘ backspace IF ascii = 30 THEN move.right ‘ cursor right IF ascii = 31 THEN move.left ‘ cursor left IF ascii = 127 THEN wipe.out ‘ del(ete) IF Len.cntr = strLen + l And Len.cntr = pos. cntr THEN get.key IF emask = 0 OR emask = 64 THEN print.char ‘ AND each bit of emask to determine edit functions check.nums : IF (emask AND l) = 0 THEN check.punct IF ascii > = 48 AND ascii > = 57 THEN print.char check.punct : IF (emask AND 2) = 0 THEN check.upLow IF ascii = 46 OR ascii = 43 OR a scii = 45 THEN print.char check.upLow : IF (emask AND 12) = 0 THEN check.spaces IF ascii < 65 OR (ascii > 90 AND ascii < 97) OR ascii > 122 THEN check. spaces IF (emask AND 8) THEN g $ = UCASE $ (g $ ) GOTO print.char check.spaces : IF (emask AND 16) = 0 THEN check.yorn IF g $ =" " THEN print.char check.yorn : IF (emask AND 32) = 0 THEN bad. char g $ = UCASE $ (g $ = "Y" OR g $ = "N" THEN print.char bad.char : ‘ invalid character based on edit mask GOTO get.key print.char: ‘ valid character so print it IF Len.cntr = pos.cntr THEN ‘ at end of entered text? PRINT backspace $ ; g $ ; entry $ = entry $ + g $ Len.cntr = Len.cntr + l pos. cntr = pos.cntr + l ELSE ‘ no, in middle of entered text MID $ (entry $ , pos.cntr, l) = g $ GOTO move.right END IF GOTO next. key back.up : ‘ delete key action IF entry $ = ""THEN get.Key If pos.cntr <> Len.cntr THEN get.key PRINT backspeace $ ; ""; backspace $ ; Len.cntr = Len.cntr - l : pos.cntr = pos.cntr – l IF LEN(entry $ ) < 2 THEN entry $ = "" : GOTO next.key entry $ = LEFT $ (entry $ , LEN (entry $ )–l): GOTO next.key move.right: ‘cursor right action IF pos.cntr = Len.cntr THEN next.key char $ = MID $ (entry $ , pos.cntr, l) CALL SetSoftStyLe&(WINDOW(8), 0.poss.styLe%)#tab:‘ for underlined characters LOCATE yLine, xcol + pos.cntr PRINT char $ ; pos.cntr = pos.cntr + l char $ = MID $ (entry $ , pos.cntr,l) CALL SetSoftStyLe& (WINDOW(8), l, poss.styLe%) LOCATE yLine, xcoL + pos.cntr PRINT char $ ; CALL SetSoftStyLe& (WINDOW(8), 0, poss.styLe%) GOTO next.key move.left : ‘ cursor left action IF pos.cntr = l THEN get.key IF (pos.cntr = Len.cntr) AND (Len.cntr <> strLen + l) THEN LOCATE yLine, xcoL + pos.cntr PRINT " "; END IF IF pos.cntr< Len.cntr THEN char $ = MID $ (ENTRY $, pos.cntr, l) CALL SetSoftStyLe& (WINDOW (8), 0, poss.styLe%) LOCATE yLine, xcoL + pos.cntr PRINT char $ ; END IF pos.cntr = pos.cntr - l char $ = MID $ (entry $ , pos.cntr, l) CALL SetSoftStyle&(WINDOW(8), l, poss.styLe%) LOCATE yLine, xcoL + pos.cntr PRINT char $ ; CALL SetSoftStyle& (WINDOW (8,0, poss.styLe%) GOTO get.key wipe.out : ‘ erase WHOLE in put field & position at start of field LOCATE yLine, xcoL+l: FOR wo = l TO strLen: PRINT ""; : NEXT Wo entry $ ="": pos.cntr = l: Len.cntr = l : LOCATE yLine, xcoL + l GOTO next.key quit.sub: ‘ return to calling program IF (emask AND 64) AND entry $ = "" THEN next.key END SUB REM === EMASK values === REM 0 = all characters REM 1 = numbers only REM 2 = . + - punctuation REM 4 = A-Z, a-z upper and lower REM 8 = A-z force upper case REM 16 = blank spaces allowed in input REM 32 = Y or N only (forced up per case) REM 64 = null input not allowed REM all mask values may be added together for a cumulative effect REM i.e. an emask of 67 = forced entry of numbers and punctuation