Classic Computer Magazine Archive COMPUTE! ISSUE 37 / JUNE 1983 / PAGE 206

Atari Formats
Sheldon Leemon

These programs are an excellent demonstration o f Atari's deferred editing capabilities. They demonstrate a number of features which support neatly formatted output in Atari BASIC.

By this time, Atari owners probably know how easy and convenient Atari's superb editing features are. You can position the cursor anywhere on the screen, insert spaces and lines, or delete spaces and lines at will. But some people may not be familiar with the use of these same functions when they are to be executed within the course of the program itself.

Deferred Edit
A number of interesting effects can be achieved if you remember that any edit function that can be used in direct mode could also be used in deferred mode, with the aid of the Escape key. When the Escape key is pressed and then an edit command entered, the command is not immediately executed. Instead, an edit character, usually an arrow or a wedge, appears on the screen. Like any other ATASCII character, it can be put into a string, or used in a PRINT statement. When used in a PRINT statement, however, the edit character will not appear on the screen. Instead, the edit function represented by the character will be executed. For example, when you press Escape and then the Control and Clear keys, a crooked arrow () appears. Whenever that symbol appears in a PRINT statement (e.g., 10 PRINT " Where did they go?"), it clears the screen.
    This feature gives us an easy means of formatting output. Program 1 shows how this approach may be applied. The example involves the creation of a table containing three columns. In the first column, there is a number from 0 to 15 (X), that number divided by 32 (X/32), and the sin of the quantity Pi times the number divided by 8 (SIN(PI*X/8)). Negative numbers are accommodated, and trailing zeros inserted to produce a uniform appearance. (This all builds on an earlier COMPUTE! article, "Formatted Output For Atari BASIC," March 1981.)

The Quick Way
Program 1 takes a direct approach to solving this problem. Because this program uses many edit characters, REMarks remind you of the sequence of keystrokes needed to produce these characters. But you should still reread Chapter 3 and Appendix F of the Atari BASIC Reference Manual to completely familiarize yourself with Atari editing.

    Line 10 uses the symbols to clear the screen and move the cursor down one line. Notice how much easier it is to skip several lines of print by using down-arrows than to keep typing in PRINT: PRINT.
    Line 20 sets up a string (TC$) that when printed will clear the tab. While not strictly necessary, this is done to show how several edit characters can be repeatedly executed by first putting them into a string, and then printing the string. Here, the tab has five default settings, so we Tab(CHR$(127)) and then Clear Tab(CHR$(158)) five times. This way, if the tab has to be changed later in the program, all we have to do to clear the tabs is print TC$ and set the new tab stops.
    Line 30 prints TC$, which clears the tab stops, and then prints the Set Tab Character (CHR$(159)) at columns 7, 13, and 22.
    Line 40 prints the headings. Note that we can use the tab characters to print all of the column headings using only one PRINT statement.
    Line 50 sets up the FOR/NEXT loop and tabs to column 7.
    Line 60 inserts a space if X is less than 10, so that the single-digit numbers line up at the right of the column.
    Line 70 prints X and then tabs to column 13.
    Line 80 rounds X/32 to three decimal places and prints the result.
    Line 90 PEEKs memory location 85, which contains the column number of the present cursor location. This tells us where the cursor is located after print X/32. If it stops at column 14, we know that X/32 is an integer, and a decimal point is printed.
    Line 100 uses the same technique to print trailing zeros until the cursor gets to column 18.
    Line 110 tabs to column 22.
    Line 120 moves the cursor left one space to accommodate a minus sign if the output is negative.
    Line 130 prints SIN(PI*X/8) rounded to seven decimal places. To enter this line more easily, 10,000,000 can be entered using scientific notation (10E6).
    Lines 140 and 150 duplicate the function of lines 90 and 100 to fill out the third column of print. Instead of typing in these duplicate lines, use the editing keys to change the line and column numbers of the existing lines 90 and 100, and reenter them.
    Line 160 moves the cursor to the next line and loops back for the next X.

Using Default Settings
In the above example, we didn't really have to go to the trouble of setting the tab. The default settings of the tab are at columns 7, 15, 23, 31, and 39. The default settings of the PRINT(,) statement are at columns 12, 22, and 32. So, using a combination of the two, we could have printed the output at columns 7, 12, and 22, by first pressing the tab, and then the PRINT(,) statement. Moreover, the width of the PRINT columns is adjustable. To change width, we need only POKE location 201 with the new width. If we put the statement POKE 201,5 at the beginning of the program, the PRINT (,) statement would then produce output at columns 7, 12, 17, 22, etc., and there would be no need for us to tab at all to produce the desired format.
    Finally, we return to memory location 85. Not only can we PEEK this location to find the cursor, but we can also POKE 85 to position the cursor horizontally. This statement gives us the equivalent of the TAB statement found in other BASICs. To move the cursor to column 7, we could have used a POKE 85,7 with the same result as a TAB command.
    The above is offered not as a subroutine of universal applicability, but as an example of the features that the Atari offers for formatting output. The approach shown here works in this particular situation because the output is fairly uniform. When only a little straightening up is needed, a more sophisticated method would be wasted. But this routine will not work with printed output as shown (the printer does not react to screen-editing commands, although it does have its own set of control characters that might be used). And if there is a greater variation in the types of output desired, a more integrated approach would be necessary.

Same Techniques, More Integration
Even in cases where a more organized approach is required, these techniques can be adapted to yield a fairly straightforward routine (Program 2). While basically an adaptation of the March 1981 article, it has the following important differences:
    1. Decimal rounding and the addition of trailing zeros are accomplished by string manipulation rather than by mathematics. String manipulation is always faster, and here the difference is noticeable.
    2. Rather than pack the strings with spaces between the variables to be printed, the POKE 201 and PRINT(,) commands are used as tabs. This allows formatting to take place on both screen and printer, limits the GOSUBs needed, and avoids having to set up the whole line before printing takes place.
    3. A routine is added to accommodate numbers that start with -9. The Atari always rounds down, so that -9.5 rounds to -10. This means that INT(N) would have one more digit than the integer part of N does, and this throws off the decimalrounding routine. The code in line 100 prevents this by adding one to all negative numbers in INT(N) except -1, which would round to 0, thus dropping the minus sign and losing a column space.
    4. Commas are added for four-digit numbers. If numbers bigger than seven digits are used, another comma could be added by repeating the routine with the numbers representing the digits substituted accordingly.
    Here's a brief explanation. The variables set up at random in line 20 are designed to give a wide range of outputs. Lines 30-60 set up the outputs for each column, with N being the variable to be formatted, ND the number of decimal places, and RC being the width of the column, rather than the right column position. This width should allow two or three spaces for print tabbing - if the column width is less than the length of the output, the computer will lock up.
    The formatting subroutine starts at line 100, by setting up one string for N, and another for INT(N). Line 110 directs numbers which do not need decimal-rounding around the routine at: line 120, which deletes extra decimal places; line 130, which adds a decimal point to whole numbers; and line 140, which provides trailing zeros. Line 150 adds a comma for numbers with more than four whole digits, and line 160 prints the output, tabbing to the appropriate spot, in order to line up the right-hand columns.
    These, then, are some of the exciting features that the Atari computers offer, and they're not only useful for print formatting. The screen editing functions, for example, might be used for simple animation. The graphics capabilities allow you to print alternating lines of regular and reverse video, for easy-to-read tables.

Program 1: Atari Formatting -A Table With Three Columns
20 DIM TC$(11):TC$="{TAB}{CLR TAB}
30 ? TC$:? "{6 SPACES}{SET TAB}
   ;6 SP.;TABSET;9 SP;T.S.
40 ? "{TAB} X{TAB} X/32{TAB}{LEFT}SI
   N(PI*X/8)":REM - [ESC][TAB];[ESC]
50 FOR X=0 TO 15:? "{TAB}";:REM -[ES
   C] [TAB]
60 IF X<10 THEN ? " ";
70 ? X;"{TAB}";:REM -[ESC] [TAB]
80 ? (INT(X/32*1000))/1000;
90 IF PEEK(85)=14 THEN ? ".";
100 IF PEEK(85)<=17 THEN ? "0";:GOTO
110 ? "{TAB}";:REM -[ESC] [TAB]
120 IF SIN(4*ATN(1)*X/8)<0 THEN ? "
    (LEFT)";:REM -[ESC] [CTRL][+]
130 ? (INT(SIN(4*ATN(1)*X/8)*1000000
140 IF PEEK(85)=23 THEN ? "."
150 IF PEEK(85)<=30 THEN ? "0";:GOTO
160 ? :NEXT X

Program 2:
Atari Formatting - Integrated Approach
10 DIM N$(80),I$(80):POKE 82,1:GRAPH
   ICS 0:POKE 752,1
20 FOR X=1 TO 20:R1=RND(0)*100:R2=(-
30 N=X:RC=4:ND=0:GOSUB 100
40 N=Z:PC=10:ND=0:GOSUB 100
50 N=Z1:RC=11:ND=2:GOSUB 100
60 N=Z2:RC=12:ND=3:GOSUB 100
70 ? :NEXT X
80 END
100 N$=STR$(N):I=INT(N):I$=STR$(I+((
    I<>-1) AND (SGN(N)=-1)))
110 IF ND=0 THEN N$=I$:GOTO 150
120 IF LEN(N$)>LEN(I$)+ND+1 THEN N$=
140 IF LEN(N$)<LEN(I$)+ND+1 THEN N$(
    LEN(N$)+1)="0":GOTO 140
150 IF ((LEN(I$)>3 AND SGN(VAL(I$)>-
    1)) OR (LEN(I$)>4)) THEN L=LEN(I
160 POKE 201,(RC-LEN(N$)):? ,N$;:RET