In memory of The Tigercub ==================== Jim Peterson is no longer with us. He was a keen supporter of the TI99/4A, writing a long series of monthly articles for users newsletters, reprinted throughout the world. In his memory here are two of his columns. Please do not write to try to buy the software! The article is presented in its original 28 column format- it was printed in 3 columns on two sheets of A4 paper. ------------------------- TIPS FROM THE TIGERCUB #56 Tigercub Software *** **lli***ood Ave. Columbus OH 432** I am still offering over 120 original and unique entertainment, educational and utility programs at just $1.00 each, or on collection disks at $5.00 per disk. The contents of the first 52 issues of this news- letter are available as ready-to-run programs on 5 Tips Disks at $10 each. And my three Nuts & Bolts Disk, $15 each, each contain over 100 subprograms for you to merge into your own pro- grams to do all kinds of wonderful things. My catalog is available for $1, deductable from your first order (specify TIGERCUB catalog). *************************** TI-PD LIBRARY I have selected public domain programs, by cate- gory, to fill over 200 disks, as full as possible if I had enough programs of the category, with all the Basic-only programs con- verted to XBasic, with an E/A loader provided for assembly programs if poss- ible, instructions added and any obvious bugs cor- rected, and with an auto- loader by full program name on each disk. These are available as a copying ser- vice for just $1.50 post- paid in U.S. and Canada. No fairware will be offered without the author's per- mission. Send SASE for list or $1, refundable, for 9-page catalog listing all titles and authors. Be sure to specify TI-PD catalog. *************************** In Tips #55, I showed you some quick and easy ways to create new character sets. Since folks nowadays don't like to key in long pro- grams, let's continue with "tinygram" programming, and at the same time show you how to manipulate strings, and teach you the value of using MERGE format. First, let's make a screen to display our new charac- ters. Some of them will have to be double-spaced horizontally or vertically, so - 100 CALL CLEAR :: X=1 :: FOR CH=48 TO 159 :: PRINT CHR$( CH)&" ";:: X=X+2 :: IF X<29 THEN 110 ELSE PRINT "":"":"" ;:: X=1 110 NEXT CH Save it- SAVE DSK1.100,MERGE Now, you might like to move the common punctuation marks into the same character sets as the characters, so that you will not have to reiden- tify so many sets, also so you can color them easier. 120 DATA 32,33,34,44,46 130 FOR J=1 TO 5 :: READ CH :: CALL CHARPAT(CH,CH$):: CA LL CHAR(J+90,CH$):: CALL CHA R(J+122,CH$) 140 NEXT J :: CALL CHARPAT(6 3,CH$):: CALL CHAR(64,CH$):: :: CALL CHAR(96,CH$) If you want to program in Basic, or use BXB with char- acters all the way up to ASCII 159, add CALL CHAR(J+1 54,CH$) to the end of line 130 and CALL CHAR(128,CH$) to the end of line 140. Save by SAVE DSK1.120,MERGE If you are using that trans- literation, you must remem- ber that with upper case characters the ? is @, space is [, ! is \, " is ], comma is , period is _. With the lower case they are FCTN keys C, F, A, G, W and V and for the 3rd set (ASCII 129 to 154) they are CTRL comma, period,;,=,* and (. You can transfer upper case to lower by - CALL CHARPAT(CH,CH$) and then CALL CHAR(CH+32,CH$) or the opposite by CH-32 and if you have BXB merged in you can create a 3rd set by CH+64. The following are all in- compatible with each other, so give them all line number 150 and save them in merge format as 150A, 150B, etc. The numerals and the upper case letters all have the topmost pixel row blank to provide spacing between lines of text. We can make taller letters by deleting the top row and doubling the 7th row - 150 FOR CH=48 TO 126 :: CALL CHARPAT(CH,CH$):: CALL CHAR (CH,SEG$(CH$,3,12)&SEG$(CH$, 13,4)):: NEXT CH 151 REM Or, you can double the 3rd row - 150 FOR CH=48 TO 95 :: CALL CHARPAT(CH,CH$):: CALL CHAR( CH,SEG$(CH$,3,4)&SEG$(CH$,5, 12)):: NEXT CH 151 REM The lower case letters are really small upper case with the upper 3 rows blank. All their vertical bars are in the 4th, 6th and 8th rows, so let's drop the first 3 rows and quadruple the 7th. 150 FOR CH=97 TO 127 :: CALL CHARPAT(CH,CH$):: CALL CHAR (CH,SEG$(CH$,7,6)&RPT$(SEG$( CH$,13,2),4)&SEG$(CH$,15,2)) :: NEXT CH 151 REM Or, for topheavy letters, quadruple the 5th row - 150 FOR CH=97 TO 127 :: CALL CHARPAT(CH,CH$):: CALL CHAR (CH,SEG$(CH$,7,2)&RPT$(SEG$( CH$,9,2),4)&SEG$(CH$,11,6)): : NEXT CH 151 REM Or, if you want line spacing - 150 FOR CH=97 TO 122 :: CALL CHARPAT(CH,CH$):: CH$=SEG$( CH$,5,8)&RPT$(SEG$(CH$,13,2) ,3)&SEG$(CH$,15,2):: CALL CH AR(CH,CH$):: NEXT CH 151 REM Or, for something silly - 150 FOR CH=48 TO 90 :: CALL CHARPAT(CH,CH$):: CALL CHAR( CH,SEG$(CH$,3,2)&RPT$(SEG$(C H$,5,2),4)&SEG$(CH$,9,4)&SEG $(CH$,15,2)):: NEXT CH 151 REM For some good blocky char- acters - 150 FOR CH=48 TO 90 :: CALL CHARPAT(CH,CH$):: CALL CHAR( CH,RPT$(SEG$(CH$,3,2),2)&SEG $(CH$,5,8)&RPT$(SEG$(CH$,15, 2),2)):: NEXT CH 151 REM Or, if you would prefer them shorter for single-line spacing - 150 FOR CH=48 TO 90 :: CALL CHARPAT(CH,CH$):: CALL CHAR( CH,"00"&RPT$(SEG$(CH$,3,2),2 )&SEG$(CH$,7,6)&RPT$(SEG$(CH $,15,2),2)):: NEXT CH 151 REM If you would like numerals the same size as lower case, 150 FOR CH=48 TO 57 :: CALL CHARPAT(CH,CH$):: CALL CHAR( CH,"0000"&SEG$(CH$,1,6)&SEG$ (CH$,9,4)&SEG$(CH$,15,2)):: NEXT CH 151 REM You can even shrink the lower case to only 4 rows high, although some letters are not very legible - 150 FOR CH=97 TO 122 :: CALL CHARPAT(CH,CH$):: CALL CHAR (CH,SEG$(CH$,1,6)&SEG$(CH$,5 ,4)&SEG$(CH$,11,6)):: NEXT C H 151 REM Something modernistic - 150 A$="00" :: FOR CH=48 TO 90 :: CALL CHARPAT(CH,CH$):: CALL CHAR(CH,SEG$(CH$,1,4)& A$&SEG$(CH$,7,6)&A$&SEG$(CH$ ,15,2)):: NEXT CH 151 REM Or perhaps even better - 150 A$="00" :: FOR CH=48 TO 90 :: CALL CHARPAT(CH,CH$):: CH$=SEG$(CH$,3,10)&RPT$(SEG $(CH$,13,2),2)&SEG$(CH$,15,2 ) 151 CALL CHAR(CH,SEG$(CH$,1, 4)&A$&SEG$(CH$,7,2)&A$&SEG$( CH$,11,2)&A$&SEG$(CH$,15,2)) :: NEXT CH I call this one "Spooky". 150 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: CH$=SEG$( CH$,3,14)&SEG$(CH$,1,2):: X$ =SEG$(CH$,1,1)&"0" 151 FOR J=3 TO 15 STEP 2 :: X$=X$&SEG$(CH$,J,1)&SEG$(CH$ ,J-1,1):: NEXT J :: CALL CHA R(CH,X$):: X$="" :: NEXT CH And "Spooky" backward - 150 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=1 T O 15 STEP 2 :: CH2$=CH2$&SEG $(CH$,J,1)&SEG$(CH$,J+3,1):: NEXT J :: CALL CHAR(CH,CH2$ ):: CH2$="" :: NEXT CH 151 REM Now, clear the memory with NEW, then - MERGE DSK1.100 MERGE DSK1.120 Add a line 500 GOTO 500 And start MERGEing in your series of "150" routines and running them to see what you have created. Then, save these next routines in MERGE format as 160A, 160B, etc. All normal characters have the leftmost column of pixels and the two right- most columns blank, for spacing between letters. We can widen the character into the left column - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=1 T O 15 STEP 2 161 CH2$=CH2$&SEG$("014589CD ",POS("01234567",SEG$(CH$,J, 1),1),1)&SEG$(CH$,J+1,1):: N EXT J :: CALL CHAR(CH,CH2$): : CH2$="" :: NEXT CH 162 REM 163 REM Or widen it both left and right - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=1 T O 15 STEP 2 161 CH2$=CH2$&SEG$("014589CD ",POS("01234567",SEG$(CH$,J, 1),1),1)&SEG$("028A",POS("04 8C",SEG$(CH$,J+1,1),1),1) 162 NEXT J :: CALL CHAR(CH,C H2$):: CH2$="" :: NEXT CH 163 REM Or even a full 8 columns wide by just changing the "028A" in line 161 to "0129" For darker characters, we can shade them into the 7th column - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=2 T O 16 STEP 2 :: IF SEG$(CH$,J -1,1)="1" THEN CH2$=CH2$&"18 " :: GOTO 163 161 IF CH=67 OR CH=71 OR CH= 99 OR CH=103 THEN 162 :: IF SEG$(CH$,J-1,1)="4" AND SEG$ (CH$,J,1)="0" THEN CH2$=CH2$ &"60" :: GOTO 163 162 CH2$=CH2$&SEG$(CH$,J-1,1 )&SEG$("0367CBEF",POS("02468 ACE",SEG$(CH$,J,1),1),1) 163 NEXT J :: CALL CHAR(CH,C H2$):: CH2$="" :: NEXT CH Or shade them both left and right - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=1 T O 15 STEP 2 :: A$=SEG$(CH$,J ,1):: P=POS("0123456789ABCDE F",A$,1) 161 A$=SEG$("0367CDEF89ABCDE F",P,1):: B$=SEG$(CH$,J+1,1) :: P=POS("02468ACE",B$,1):: B$=SEG$("0367CBEF",P,1):: CH 2$=CH2$&A$&B$ 162 NEXT J :: CALL CHAR(CH,C H2$):: CH2$="" :: NEXT CH 163 CALL CHAR(74,"000C0C0C0C 0C4C38"):: CALL CHAR(106,"00 00000C0C0C4C38") Or shaded into both of the rightmost columns - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=2 T O 16 STEP 2 :: CH2$=CH2$&SEG $(CH$,J-1,1)&SEG$("0377EBFF" ,POS("02468ACE",SEG$(CH$,J,1 ),1),1):: NEXT J :: CALL CHA R(CH,CH2$):: CH2$="" :: NEXT CH 161 REM 162 REM 163 REM Or into all 8 columns - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=1 T O 15 STEP 2 :: P=POS("012345 6789ABCDEF",SEG$(CH$,J,1),1) 161 A$=SEG$("0367CDEF89ABCDE F",P,1):: P=POS("02468ACE",S EG$(CH$,J+1,1),1):: B$=SEG$( "0367EBFF",P,1):: CH2$=CH2$& A$&B$ 162 NEXT J :: CALL CHAR(CH,C H2$):: CH2$="" :: NEXT CH 163 REM More neatly, shaded inward at right - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$) 161 FOR J=1 TO 15 STEP 2 :: CH2$=CH2$&SEG$(CH$,J,1)&SEG$ ("0C8C",POS("048C",SEG$(CH$, J+1,1),1),1):: NEXT J 162 CALL CHAR(CH,CH2$):: CH2 $="" :: NEXT CH 163 REM Or inward at right, out- ward at left - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=1 T O 15 STEP 2 161 CH2$=CH2$&SEG$("0367CBEF ",POS("01234567",SEG$(CH$,J, 1),1),1)&SEG$("0C8C",POS("04 8C",SEG$(CH$,J+1,1),1),1):: NEXT J 162 CALL CHAR(CH,CH2$):: CH2 $="" :: NEXT CH 163 REM Here's a weirdo - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=9 T O 15 STEP 2 161 CH2$=CH2$&SEG$("014589CD ",POS("01234567",SEG$(CH$,J, 1),1),1)&SEG$("028A",POS("04 8C",SEG$(CH$,J+1,1),1),1) 162 NEXT J :: CALL CHAR(CH,S EG$(CH$,1,8)&CH2$):: CH2$="" :: NEXT CH 163 REM Try changing that to FOR J =1 TO 7 and CALL CHAR(CH,CH2 $&SEG$(CH$,9,8)) And one more - 160 FOR CH=48 TO 122 :: CALL CHARPAT(CH,CH$):: FOR J=1 T O 7 STEP 2 161 A$=SEG$("02468ACE",POS(" 01234567",SEG$(CH$,J,1),1),1 ):: B$=SEG$("0808",POS("048C ",SEG$(CH$,J+1,1),1),1):: CH 2$=CH2$&A$&B$ :: NEXT J 162 CALL CHAR(CH,CH2$&SEG$(C H$,9,8)):: CH2$="" :: NEXT C H 163 REM Now, clear the memory, MERGE in 100 and 120, put in a holding line 500 GOTO 500 and start MERGEing in all of the different combinations of the 150 and 160 lines and see how many different char- acter sets you can make! Memory full, Jim Peterson TIPS FROM THE TIGERCUB #57 Tigercub Software *** ****in**ood Ave. Columbus OH 43*** I am still offering over 120 original and unique entertainment, educational and utility programs at just $1.00 each, or on collection disks at $5.00 per disk. The contents of the first 52 issues of this news- letter are available as ready-to-run programs on 5 Tips Disks at $10 each. And my three Nuts & Bolts Disk, $15 each, each contain over 100 subprograms for you to merge into your own pro- grams to do all kinds of wonderful things. My catalog is available for $1, deductable from your first order (specify TIGERCUB catalog). *************************** TI-PD LIBRARY I have selected public domain programs, by cate- gory, to fill over 200 disks, as full as possible if I had enough programs of the category, with all the Basic-only programs con- verted to XBasic, with an E/A loader provided for assembly programs if poss- ible, instructions added and any obvious bugs cor- rected, and with an auto- loader by full program name on each disk. These are available as a copying ser- vice for just $1.50 post- paid in U.S. and Canada. No fairware will be offered without the author's per- mission. Send SASE for list or $1, refundable for 9-page catalog listing all titles and authors. Be sure to specify TI-PD catalog. *************************** I like little programs that load quickly and do just what I want to do at the moment. And one of the things I wanted to do quickly was to find phone numbers. So, I used FUNLWEB to create a little file - SMITH,JOHN (999) 111-2222 BUSH, GEO. (000) 123-1234 GHADDAFI, O. (666)66-6666 and all my other frequent- ly called numbers. I SAVEd it as DSK1.PHONELIST and wrote this little routine to use it. 100 CALL CLEAR 110 OPEN #1:"DSK1.PHONELIST" ,INPUT 120 DISPLAY AT(12,1):"LAST N AME?" :: ACCEPT AT(14,1):N$ 130 LINPUT #1:M$ :: IF POS(M $,N$,1)<>0 THEN DISPLAY AT(1 6,1):M$ :: RESTORE #1 :: GOT O 120 140 IF EOF(1)<>1 THEN 130 150 DISPLAY AT(16,1):"NAME N OT FOUND" :: RESTORE #1 :: G OTO 120 Now actually, that was all I needed,(even though it did take several seconds to find a name at the end of the file), and it was easy enough to load the file into FUNLWEB when it needed updating. But, programmers are never satisfied, so I decided to write a self-contained program - 100 CALL CLEAR 200 DATA "ALDA, ALAN 888-999 9" 201 !@P- 300 DATA "BUSH, GEORGE 111-1 111" 400 DATA "PRESLEY, ELVIS 000 -0000" 499 !@P+ 500 DISPLAY AT(12,1):"LAST N AME?" :: ACCEPT AT(14,1):N$ 600 READ M$ :: IF POS(M$,N$, 1)<>0 THEN DISPLAY AT(16,1): M$ :: RESTORE 200 :: GOTO 50 0 700 ON ERROR 800 :: GOTO 600 800 DISPLAY AT(16,1):"NAME N OT FOUND" :: RESTORE 200 :: GOTO 500 That funny thing in line 201 turns off the prescan and speeds up initializa- tion. This routine is no faster than the last, but can be updated by editing the program itself. It is limited to about 500 records due to the least-known and greatest weakness of the TI, that string storage is limited to console memory. But, computer users are paranoid about speed, so I decided to put my data into a pre-loaded array with self incrementing subscript num- bers, and find the data by a binary search. 100 !QUICKFINDER by Jim Pete rson 200 DIM D$(50):: GOTO 300 :: D$(),X :: !@P- 300 X=X+1 :: D$(X)="ALDA, AL AN (999) 666-1234" 400 X=X+1 :: D$(X)="BUSH, GE ORGE (111) 111-1111" 500 X=X+1 :: D$(X)="GHADDAFI , OMAR (999) 456-1234567" 600 X=X+1 :: D$(X)="KHOMEINI , AYATOLLAH (666) 666-6666" 700 !@P+ 800 INPUT "NAME? ":M$ 900 IF M$>D$(X)THEN PRINT "N OT FOUND":"CLOSEST IS":D$(X) :: GOTO 800 1000 IF M$M$ THEN H=S :: S= INT(H/2):: GOTO 1600 1500 S=S+INT((H-S)/2) 1600 IF S=S2 THEN 1800 ELSE S2=S :: GOTO 1200 1700 PRINT D$(S):: GOTO 800 1800 PRINT "NOT FOUND":"CLOS EST ARE" 1900 IF D$(S2)>M$ THEN PRINT D$(S2-1):D$(S2+1):: GOTO 80 0 2000 PRINT D$(S2+1):D$(S2+2) :: GOTO 800 Note that in this case the records must be in alphabetical sequence. New records can be inserted in intermediate line numbers, in alphabetic sequence, always preceded by X=X+1 :: D$(X)= . Obsolete records can be deleted, and records can be corrected in place if the correction does not change the alphabetic sequence. This idea did not work out as well as I hoped. The maximum number of records is less than 300, for the reason mentioned above, and this leaves so little free memory that even a binary search is slow. However, for a smaller file this is perhaps the best method. For a large file, the best method is certainly a fixed sequential disk file, accessed by a binary search routine. But, that requires other routines to delete, add or change records, and had best be the subject of another Tips. There is apparently a mistaken belief that sprites cannot be used together with my BXB routine. Not so - you can use all 28 of them! However, you cannot change their color with CALL COLOR(#,N). The only other limitations of BXB that I can think of, are that a single CALL COLOR cannot be used for multiple character sets and a single CALL CHAR can only reidentify one character. CALL CHARPAT cannot return the hex code of an ASCII above 143 because those ASCII's were not supposed to be available in Extended Basic. I have used BXB on hundreds of Basic-only programs and have had only two rare problems. If the program contains multiple line feed colons ::::::, the computer may rearrange them into pairs of double colons :: :: and lock up. Or, if the colons are before the text, as in PRINT :"something" you may get a puzzling error message. Also on rare occasions you might get an error message indicating the subprogram was called from a line containing a CALL CHAR, if the programmer had inadvertently put more than 16 characters in the hex code. Basic just ignores any extra characters, and XBasic uses them to reidentify the following ASCII, but BXB crashes. From the T*I*M*E*S news- letter from England, here is an extremely useful bit of assembly which should be assembled as ALPHA/O and placed on the disk of every joystick program, or imbedded in it with ALSAVE. DEF ALPHA * save old R12 ALPHA MOV R12,@>FFFC * 9900 CRU base=0 CLR R12 * signal alphalock key line SBZ 21 * check alphalock other side TB 7 * jump if state=on JNE STATE * state=off SETO @>FFFE * as off skip next line JMP JUMPA * state=on STATE CLR @>FFFE * stop sending to alpha key JUMPA SBO 21 * restore R12 MOV @>FFFC,R12 * standard XB return now * clear error for basic SB @>837C,@>837C * return to calling program B @>0070 END ALPHA Now, put this in the first lines of the joystick program - 1 ! by M. Gikow, Andover MA August 1988 2 ! used with ALPHA/O, will detect whether Alpha Lock is up (A= 255) or down (A=0) 3 CALL CLEAR :: CALL INIT :: CALL LOAD("DSK1.ALPHA/O") 4 CALL LINK("ALPHA"):: CALL PEEK(-1,A):: IF A=0 THEN DIS PLAY AT(12,1):"RELEASE ALPHA LOCK" :: GOTO 4 ELSE CALL CL EAR I published this one in the C.O.N.N.I. newsletter. Barry Traver picked it up and put it in the TI Forum in Computer Shopper, but their typesetter garbled it, so here is how it was supposed to be - According to the TI-Writer Reference Guide, page 77, when you select the PrintF command, then type C and space once and then the device name, any control characters with ASCII less than 32 are removed before the file is printed. With Funlweb, at least, this is not quite true. A carriage return character, ASCII 13, or a line feed character, ASCII 10, at the end of a line is actually not deleted but is changed to the space bar character, ASCII 32. This can be proved by running this little routine - 100 OPEN #1:"DSK1.(filename) ",INPUT 110 LINPUT #1:M$ :: PRINT M$ :LEN(M$):: IF LEN(M$)>0 THEN PRINT ASC(SEG$(M$,LEN(M$),1 )) 120 CALL KEY(0,K,S):: IF S=0 THEN 120 ELSE 110 Therefore, when a file is Filled/Adjusted and the line feed characters are stripped with the C option, the lines are one character longer than they appear to be. An apparently blank line also contains ASCII 32. Since these characters are blank, they normally do no harm. However, they can create problems when records are read into programs for multiple column printing or concatenation of strings. In these cases, this routine can be used to strip out any ASCII below 33 at the ends of records. 100 DATA INPUT,OUTPUT 110 FOR J=1 TO 2 :: READ J$ :: DISPLAY AT(12,1)ERASE ALL :J$&" FILENAME?":"DSK" :: AC CEPT AT(13,4):F$(J):: OPEN # J:"DSK"&F$(J),UPDATE :: NEXT J 120 LINPUT #1:M$ 130 IF ASC(SEG$(M$,LEN(M$),1 ))<33 THEN M$=SEG$(M$,1,LEN( M$)-1):: IF LEN(M$)>0 THEN 1 30 140 PRINT #2:M$ :: IF EOF(1) <>1 THEN 120 :: CLOSE #1 :: CLOSE #2 Attention all newsletter editors! If you are going to print my Tips (or anything else that contains program listings!) through the Formatter, PLEASE first replace and transliterate the ampersand, asterisk, period, carat and "@" sign! Print this one through the Formatter and see why - 100 A=A*264 :: @=1 110 PRINT "1 . . . 2 . . . 3 . . .4 . . . 5 . . . 6 . . . 7 . . . 8 . . . 9 . . . 0" 120 M$=M$&A$&B$&C$ :: K=K^3 Here's how you do it. Load the above in the Editor, position the cursor at the beginning of the 1st line, hit FCTN 9, type RS and Enter, then /&/}/ and Enter. At the prompt, type A. Now get the cursor back to the beginning, repeat the above with /*/|/, and then /./\/ and /^/~/ and /@/{/ and the file should now look like this - 100 A=A|264 :: {=1 110 PRINT "1 \ \ \ 2 \ \ \ 3 \ \ \ 4 \ \ \ 5 \ \ \ 6 \ \ \ 7 \ \ \ 8 \ \ \ 9 \ \ \ 0" 120 M$=M$}A$}B$}C$ :: K=K~3 Now use FCTN 8 to open 5 lines at the top and add this transliteration - .TL 92:46 .TL 123:64 .TL 124:42 .TL 125:38 .TL 126:94 Save the result, go to the Formatter and print it. If my multi-column Printall program (Tips from the Tigercub #45) won't run on your Epson-compatible printer, try changing line 250 to - 250 ACCEPT AT(12,3)VALIDATE( "123")SIZE(1):P :: IF P=2 TH EN PRINT #1:CHR$(27);CHR$(77 )ELSE IF P=3 THEN PRINT #1:C HR$(15) You might also need to change the 136 in line 280 to 132. If your printer offers the elite condensed option, you might want to add - :" (4) ELITE CONDENSED" to line 240, change the VALIDATE string in 250 to "1234", add ELSE IF P=4 THEN PRINT #1:CHR$(27);CHR$(77);C HR$(15) to the revised line 250 and add +(P=4)*160 to the first statement in line 280. Memory almost full, Jim Peterson