Data and text entry made easy; input line editor. Robert J. Beck.
Data and Text Entry Made Easy
INPUT LINE EC(D)ITOR(R)
I once wrote a program for data entry. After the umpteenth time that I typed a line like, "I ate data entry' and had to go back and retype most of the line, I began looking around for ideas.
In the November 1981 issue of Creative Computing, Jonathan Ashwell discusses the value of the INPUT statement and the problem of entering strings with quotation and other punctuation marks. His solution neatly retains the standard editing features and cursor moves of the Apple. These let you move the cursor back and forth, up and down, and simplify retyping and deleting when the arrow keys are used to move the cursor. These features are handy, but they don't help much with some of the more common typing errors.
Leaving a letter out, accidentally inserting an extra letter, or mixing up the order in which two letters are typed may lead to much retyping and cursor moving. After you have corrected an error in the middle of a string, you must move the cursor to the end of the line since pressing the RETURN key wipes out everything after the cursor.
I became quite intolerant of this kind of thing after using Neil Konzen's Program Line Editor to correct mistakes while writing programs. I decided to develop something that would mimic the features of Konzen's program and that could be used from within a program to ease the chores of data entry and text composition.
The Applesoft subroutine presented here (lines 10-460 of Listing 2) is based on substring manipulation and can be used in place of INPUT statements in any program. It offers extended ability to control the cursor and to insert and delete characters without retyping. An additional benefit is that any character--including commas, colons, and quotation marks--is accepted, so the subordinate can be used to enter and edit prose. It is, however, limited to inputs of fewer than 256 characters.
How It Works
Figure 1 is a flow chart of the program. Numbers in parentheses refer to line numbers in Listing 2. The stripped-down algorithm of the program goes something like this:
the and
I mentioned before that the program is based on substring manipulation. What this means is that first you break a string, or sequence of characters, into pieces (substrings) then, after removing old pieces and inserting new ones, you reassemble a new version of the string. Line 120, where characters are inserted one at a time, is a good example. M$ is separated at the cursor into two substrings: LEFT$ (M$, L-1) includes everything before the cursor and MID$ (M$, L) holds everything from the curso on. Z$ is inserted between them when M$ is reassembled. The cursor is then tabbed to the correct place and the changed part of the string is reprinted. By erasing and reprinting the screen, you can see immediately what you have done.
When you program in Applesoft with the INPUT statement, you have the option of printing a prompt before the cursor. You can do the same thing with this subroutine; just put your prompt or query into the variable PR$ before calling the subordinate. You should also set T equal to the line to which the prompt should VTAB. You see, I am rather lazy, and I wanted to simplify programming the cursor movement (remember the cursor isn't moved at all by a GET command), so I chose to have the inputs take place at a fixed vertical line (see line 40).
Why does this make it easier? Because I had trouble placing the cursor where I wanted it until I realized that if I always started from the same place all I had to do was keep track of where the cursor ought to be--I use the variable L--and HTAB it there whenever I needed to.
The Real Difference
Before going any further, let's look at some specific commands:
CONTROL-Cnextother movesstring.by areby
All control characters other than those used for editing are ignored. An interesting effect of using a GET is that it interprets the arrow keys as control characters. If you want to use them, you must write your own arrow functions into the program. I have set it up so they won't have the cursor beyond the string. Use the spacebar to insert blanks.
The completed string will be in the variable R$ (line 220) after a press of the RETURN key. A very important and time-saving difference between this subroutine and regular input is that it doesn't matter where the cursor is when you press RETURN. What you see is what you get.
Because the input takes place at a fixed vertical screen line, the size of a string is limited (in addition to the usual Apple limitation of 255) to 38 + 40{22-T) characters. If this length is exceeded, the string will be correctly input but the screen will behave strangely. It is also for this reason that a routine to scroll up is included (line 260). The cursor ends up one line below the string after a RETURN.
Lines 450 and 460, called as a subroutine in line 220, illustrate a way to trap input errors and notify the user. Errors are checked for whenever the RETURN key is pressed; if one is found the RETURN key doesn't do anything. When a successful RETURN is made, any previous error message is erased (line 240).
The input string, M$, is initialized at line 30. (A preliminary blank avoids out of range subscripts when dealing with the first character position.) It is a simple matter to adapt the Input Line Editor to edit already existing string variables such as records in a file or a string array. Just change line 30 to: 30 M$ = "' + R$, where R$ is the string to be edited.
Taking Advantage Of The Monitor
The POKE in line 80 resets the keyboard strobe, and the PEEK setx X to the ASCII code of the key pressed. The POKE isn't strictly necessary, but it keeps the program from picking up a keypress until it is ready to act on it. You could substitute X = ASC(Z$ ) for the PEEK, but since this will cause an error in the unlikely event that CONTROL-SHIFT-P is typed, I prefer to PEEK.
Once X corresponds to the key that was pressed, an ON GOTO can be used to decide how to act on that keypress. Don't forget that both the PEEK and the POKE can be speeded up by using variables in place of the numbers.
The Apple monitor contains a wealth of useful routines. Three of them are used here:
Further explanations can be found in the manuals.
Taking Advantage Of Input Subroutines
With the setup that we have discussed here, CONTROL-C will not stop a run as it usually does, but of course it is easy enough to choose another key (say, CONTROL-E) and have that keypress GOTO a line with an END statement. But whenever input is channeled through a subroutine, a further refinement is possible. CONTROL-E could be used to send the program flow to an ON GOTO where the value of a flag determines which line is executed next.
Setting the flag to different values throughout the program means that CONTROL-E becomes an escape whenever there is any input. Where the escape takes you depends upon where you are in the program. For instance, you could use this feature to repeat a previous step or to return to a menu.
If you are using the input subroutine from this article, you can adjust line 85 (as I did by making the fifth line number in the ON GOTO equal 1000) to activate CONTROL-E. But you can still work it in even with a regular INPUT, as Figure 2 shows.
The input subroutine in this figure returns to the main program unless CONTROL-E is typed just before hitting the RETURN key. It doesn't matter what else is typed, so long as CONTROL-E is last.
Figure 2 also shows how you might use CONTROL-E to hop around within a program. The arrows indicate where you would go in this hypothetical example, although actually it can be set up any way you want by juggling the ON GOTO statement. The test program (see next section) has a simple example of this.
Getting back to Listing 2, we see that line 1000 has a POP and a CALL before the ON GOTO. The POP replaces are RETURN in the input subroutine and that is all that is needed if the subroutine is called from the main program.
But if the calling GOSUB is nested inside other GOSUBs or is inside a FOR NEXT loop, the 6502 stack may accumulate unneeded and unwanted return addresses. By clearing the stack each time, you will avoid OUT OF MEMORY errors, and you can do CONTROL-Es all day from anywhere within a program.
Lines 600 and 610 create a short, machine language stack clearing routine (described in Listing 1). I have located it at the ever-faithful (decimal) 768, but it could be POKED into memory anywhere between 768 and 1023 without interfering with programs, since this area is reserved for the user on the Apple.
A Test Run
The complete Listing 2 is a program that will let you experiment with the various edit functions. The program asks you to enter five strings; after you have finished, they will be printed in their final form. As a demonstration of potential freedom of movement, three different things can happen in response to CONTROL-E.
During the first input, the program will stop. If you the CONTROL-E while inputting either the second or fifth string, you will be backed up and asked again for the first or fourth, respectively. During entry of the third or fourth string, CONTROL-E bumps you forward to the printout.
Programs should always be fumbleproof. Again, for the sake of demonstration, I have arbitrarily defined as unacceptable response: if you enter ABC for any of the strings you will get an error message, and you won't be able to move on to the next step until you change the entry. Naturally, this is a trivial example, but you could easily expand on the idea to flag out of range data, typographical errors, or whatever you wished.
This test program should give you an idea of the speed and usefulness of the Input Line Editor. It is an easy way to put screen editing features into a program. Fifteen control keys have been left unused, so there is room for you to design special functions of your own.
I have been using a version of this program, in conjunction with a data manager, to edit file records.
Added options, such as backspacing through the file one field at a time and jumping ahead to the next record, give it versatility. When you respond to a request for input, you are communicating with the program.
The best kind of communication between humans is open-ended and unrestricted. We should be able to treat computers the same way.
Table: Listing 1. This stack-initializing subroutine can be relocated anywhere in memory.
Table: Listing 2.
Photo: Figure 1. Abbreviated flow chart of Input Line Editor.
Photo: Figure 2. Hypothetical program with an input subroutine.