Classic Computer Magazine Archive COMPUTE! ISSUE 90 / NOVEMBER 1987 / PAGE 86

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:

ValueFunction
0All characters accepted
1Numbers 0–9
2Punctuation marks.,+, and -
4Upper-and lowercase letters A–Z
8Blanks (spaces) allowed
16Uppercase letter A–Z
32Characters Y and N
64Null 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