LBSOS KRNLI/O ERRORFILE 'SOS.KERNEL' NOT FOUNDINVALID KERNEL FILExةw,@  4  J  ȱ⩤i8#) ) 8LeARTICLE10v ' '*ARTICLE.107Dބ" 0,CREATE.TRASH 0! +DECODE.DUMP )1! (&DECODE # ++DUMP.STATUS %F! (*GET.STATUS -? ,!+%SEG.T jK Ÿ/ )PRINT.ALL KDISKNAME.DAT#l1k5III.BSB.05IC.03u' ARTICLE10 <ARTICLE11# <ARTICLE12$$*HELLO.TEXT lO*MENU.MAKER K;+REQUEST.INVm#im#iЛ#Lȱ  6L憦  Lsmm l y` @8(Je稽 ʈ! )*GOSSIPFILE  !HSCROLL.ARRAY #F HSCROLL "( {1-SCROLL.4.WAYS # 1/SCROLL.VARIABLE k A+SET.CONTROL { " +STATUS.OUT5l" (TRY.STAT 3*! *+TWO.SPD.SC2  0 .TWO.SPD.SCROLL ~ !bout. 3 Once a sanitation engineer was repulsed by a reluctant but enthusiastic young tadpole which neither of them talked to their analyst about. 4 Once a frog was impressed by a willing but enthusiastic young tadpole which neither of them talked to t 1 Once a duke was completely overwhelmed by a eager but shy young lady marine which neither of them talked to their best friends about. 2 Once a frog was captivated by a willing but wholesome young tadpole which neither of them talked to their father a:200hi>zipt=zip:b$=bnk$ 100:(hi+79+zip<=maxlenghtt=zip:b$=bnk$ 105::26);0);23);=maxlenghtindex=vi-25:hiindex=80+hi:j=124:b$,t*j-t+1,t)=a$(index+j),hiindex,t)::hi=hi+t:leftscroll$((t=1));b$;k7nvi24scrolldown$;a$(vi-25),hi,80);:vi=vi-1}cursor=27cursor=10)+4*(cursor=11)+5*(cursor=136)+6*(cursor=149)Xb$=blank24$:t=1'Zmove+1130,100,105,110,120,135,140 _:80wdhi>tindex=vi-25:hiindex=hi-t:j=124:b$,t*j-t+1,t)=a$(index+j),hiindex,t)::hi=hi-t:rightscroll$((t=1));b$;fihi+80<11)+SYNC$<:21);"5";6Ai=023:a$(i))>80a$(i),1,80);::a$(i):Fhi=1:vi=24:'Hblank24$=" " Ibnk$="" Ki=1t:bnk$=bnk$+blank24$:Mb$=bnk$:c$=bnk$Pa$:cursor=a$)[Umove=(cursor=8)+2*(cursor=21)+3*()+zip)+26)+0)+0)+2)+26)+zip-1)+24)+3)+21)+"5"+12)Y.rightscroll$(1)=SYNC$+23)+1)+26)+0)+0)+2)+26)+0)+24)+3)+21)+"5"?2scrollup$=16)+3)+26)+0)+23)+10)+21)+"5"+SYNC$,7scrolldown$=16)+3)+12)+ record=i %SYNC$=""m(leftscroll$(0)=SYNC$+23)+256-zip)+26)+80-zip)+0)+2)+26)+zip-1)+24)+3)+21)+"5"+12)a)leftscroll$(1)=SYNC$+23)+255)+26)+79)+0)+2)+26)+0)+24)+3)+21)+"5"+12)e-rightscroll$(0)=SYNC$+23+a$(500),rightscroll$(1),leftscroll$(1)'"File name to scroll through: ";a$ a$=""200 #1,a$maxlenght=0-"How many units to fast scroll by? ";zip ž#135Ei=0500:#1;a$(i):a$(i))>maxlenghtmaxlenght=a$(i)):::#lastheir grand-parents about. 5 Once a frog was impressed by a eager but wholesome young lady marine which neither of them talked to their analyst about. 6 Once a sanitation engineer was completely overwhelmed by a willing but wild young tadpole which neit|+a$(500),rightscroll$(1),leftscroll$(1)'"File name to scroll through: ";a$ a$=""200 #1,a$maxlenght=0-"How many units to fast scroll by? ";zip ž#135Ei=0500:#1;a$(i):a$(i))>maxlenghtmaxlenght=a$(i)):::#lastlesome young queen which neither of them talked to their mother about. 30 Once a sanitation engineer was bored by a eager but wild young queen which neither of them talked to their grand-parents about. neither of them talked to their grand-parents about. 28 Once a frog was completely overwhelmed by a pathetic but wholesome young lady marine which neither of them talked to their father about. 29 Once a dowager duchess was repulsed by a reluctant but whoe which neither of them talked to their mother about. 26 Once a duke was impressed by a handsome but wholesome young tadpole which neither of them talked to their mother about. 27 Once a duke was impressed by a pathetic but wholesome young tadpole which climber which neither of them talked to their best friends about. 24 Once a frog was bored by a pathetic but wild young king which neither of them talked to their grand-parents about. 25 Once a prince was repulsed by a eager but enthusiastic young tadpolr best friends about. 22 Once a dowager duchess was repulsed by a reluctant but wholesome young lady marine which neither of them talked to their best friends about. 23 Once a dowager duchess was completely overwhelmed by a eager but wild young flagpole a dowager duchess was completely overwhelmed by a willing but wild young queen which neither of them talked to their grand-parents about. 21 Once a sanitation engineer was bored by a pathetic but wild young lady marine which neither of them talked to theince a frog was bored by a handsome but reserved young king which neither of them talked to their father about. 19 Once a prince was bored by a handsome but enthusiastic young lady marine which neither of them talked to their grand-parents about. 20 Once ored by a reluctant but enthusiastic young queen which neither of them talked to their analyst about. 17 Once a dowager duchess was captivated by a pathetic but enthusiastic young flagpole climber which neither of them talked to their analyst about. 18 Oic but enthusiastic young tadpole which neither of them talked to their father about. 15 Once a prince was repulsed by a handsome but wholesome young flagpole climber which neither of them talked to their mother about. 16 Once a sanitation engineer was byoung lady marine which neither of them talked to their grand-parents about. 13 Once a frog was completely overwhelmed by a willing but shy young queen which neither of them talked to their father about. 14 Once a dowager duchess was repulsed by a pathetlagpole climber which neither of them talked to their analyst about. 11 Once a sanitation engineer was impressed by a handsome but shy young tadpole which neither of them talked to their analyst about. 12 Once a duke was captivated by a pathetic but shy neither of them talked to their grand-parents about. 9 Once a prince was repulsed by a eager but shy young flagpole climber which neither of them talked to their analyst about. 10 Once a dowager duchess was impressed by a handsome but wholesome young fher of them talked to their best friends about. 7 Once a dowager duchess was bored by a eager but enthusiastic young queen which neither of them talked to their analyst about. 8 Once a prince was repulsed by a reluctant but wild young lady marine whichrecord=im(leftscroll$(0)=23)+256-zip)+26)+80-zip)+0)+2)+26)+zip-1)+24)+3)+21)+"5"+12)+22)a)leftscroll$(1)=23)+255)+26)+79)+0)+2)+26)+0)+24)+3)+21)+"5"+12)+22)e-rightscroll$(0)=23)+zip)+26)+0:21);"5";HAi=0wnd.ht-1:a$(i))>wnd.widea$(i),1,wnd.wide);::a$(i):Fhi=1:vi=wnd.htHblank$=" )+21)+"5"+12)c.rightscroll$(1)=SYNC$+23)+1)+26)+0)+0)+2)+26)+0)+wnd.ht)+3)+21)+"5"+12)D2scrollup$=21)+"="+26)+0)+wnd.ht-1)+10)+21)+"5"+SYNC$57scrolldown$=21)+"="+12)+11)+21)+"5"+sync$<set.window$;:ip)+0)+2)+26)+zip-1)+wnd.ht)+3)+21)+"5"+12)m)leftscroll$(1)=SYNC$+23)+255)+26)+wnd.wide-1)+0)+2)+26)+0)+wnd.ht)+3)+21)+"5"+12)i-rightscroll$(0)=SYNC$+23)+zip)+26)+0)+0)+2)+26)+zip-1)+wnd.ht)+3 !record=iF$"window top,height,left,width: ";wnd.top,wnd.ht,wnd.left,wnd.wide%sync$=22)g&set.window$=16)+3)+26)+wnd.left)+wnd.top)+2)+26)+wnd.wide-1)+wnd.ht-1)+3)+12)w(leftscroll$(0)=SYNC$+23)+256-zip)+26)+wnd.wide-zi+a$(500),rightscroll$(1),leftscroll$(1)'"File name to scroll through: ";a$ a$=""200 #1,a$maxlenght=0-"How many units to fast scroll by? ";zip ž#135Ei=0500:#1;a$(i):a$(i))>maxlenghtmaxlenght=a$(i)):::#last00hi>zipt=zip:b$=bnk$ 100:(hi+79+zip<=maxlenghtt=zip:b$=bnk$ 105::26);0);23);nghtindex=vi-25:hiindex=80+hi:j=124:b$,t*j-t+1,t)=a$(index+j),hiindex,t)::hi=hi+t:leftscroll$((t=1));b$;k7nvi24scrolldown$;a$(vi-25),hi,80);:vi=vi-1}cursor=27:2=10)+4*(cursor=11)+5*(cursor=136)+6*(cursor=149)Xb$=blank24$:t=1'Zmove+1130,100,105,110,120,135,140 _:80wdhi>tindex=vi-25:hiindex=hi-t:j=124:b$,t*j-t+1,t)=a$(index+j),hiindex,t)::hi=hi-t:rightscroll$((t=1));b$;fihi+80<=maxle22)<:21);"5";6Ai=023:a$(i))>80a$(i),1,80);::a$(i):Fhi=1:vi=24:'Hblank24$=" " Ibnk$="" Ki=1t:bnk$=bnk$+blank24$:Mb$=bnk$:c$=bnk$Pa$:cursor=a$)[Umove=(cursor=8)+2*(cursor=21)+3*(cursor)+0)+2)+26)+zip-1)+24)+3)+21)+"5"+12)+22)_.rightscroll$(1)=23)+1)+26)+0)+0)+2)+26)+0)+24)+3)+21)+"5"+12)+22)?2scrollup$=16)+3)+26)+0)+23)+10)+21)+"5"+22),7scrolldown$=16)+3)+12)+11)+ "Kbnk$=blank$,1,t*wnd.ht)Lone.bnk$=blank$,1,wnd.ht)Pa$:cursor=a$)[Umove=(cursor=8)+2*(cursor=21)+3*(cursor=10)+4*(cursor=11)+5*(cursor=136)+6*(cursor=149)#Xb$=one.bnk$:t=1::set.window$;'Zmove+1130,100,105,110,120,135,140_80dhi>tindex=vi-wnd.ht-1:hiindex=hi-t:j=1wnd.ht:b$,t*j-t+1,t)=a$(index+j),hiindex,t)::hi=hi-t:rightscroll$((t=1));b$;fihi+wnd.wide<=maxlenghtindex=vi-wnd.ht-1:hiindex=wnd.wide+hi:j=1wnd.ht:b$,t*j-t+1,t)=;:i:#3:j:0 8,41,2,1,1,1,6,-1,5,-1,1,1,1,1,1,1,2,1,2433temp=626);0);0);2);26);79);2);3);12);:=vtemp:=htemp<"Press RETURN to reconstruct the captured display: ";a$buf1$=buffer$,4,240)Zj=13:=j:=1:i=140:#3;buf1$,80*(j-1)+i,1);buf1$,80*(j-1)+i+40,1)exvalue$):char<32char=char+128:char$=char) ;charbuf$=charbuf$+char$+" "!<#3"2a,x";hexvalue$,3,2);3Ai/26=i/26)#3:#3;charbuf$:charbuf$="":#3Fi$H#3:#3;charbuf$:charbuf$="":#3Kstat=18160P35dn}vtemp=:h$&'range, try again":35='statuslen(stat)<0"Invalid status code, try again":35(buffer$="")stat=18125"*status(%stat,@buffer$)device$+stat=18140-endlist=statuslen(stat)2i=1endlist"7hexvalue$=buffer$,i,1)))-9char=h statuslen(19))under$=10)+8)+8)+8):up$=11)#3,"status.out"".D1/request.inv"i=018:statuslen(i):device$=".console"#"Status code: ";stat$$stat$=""100%stat=stat$)@&stat<0stat>18"Status code out of );12);._22);:j=023:"6#.3#";c(j);::1);`90dD#1,"fill":#2,"column"a$(23),b$(23),c(23)2i=023:#1;a$(i):#2;b$(i):c(i)=10000*1):21);"5"; i=184=10*(i-1)+1:=0:2);:=10:=23:3);:12);%F22);:j=023:a$(j);::1);Pi)Zi=15:23);254);::4j=023:b$(j);::1);`90d&#1,"fill":#2,"column"a$(23),b$(23)#i=023:#1;a$(i):#2;b$(i):i21);"5"; i=184=10*(i-1)+1:=0:2);:=10:=23:3);:12);%F22);:j=023:a$(j);::1);Pi)Zi=15:23);254);::4);12);%_22);:00:0hi+wnd.wide+zip-1<=maxlenghtt=zip:b$=bnk$ 105::26);0);22);36a$(index+j),hiindex,t)::hi=hi+t:leftscroll$((t=1));b$;k=nviwnd.htscrolldown$;a$(vi-wnd.ht-1),hi,wnd.wide);:vi=vi-1}cursor=27:200hi>zipt=zip:b$=bnk$ 1 statuslen(19))under$=10)+8)+8)+8):up$=11)#3,"decode.out"".D1/request.inv"i=018:statuslen(i):device$=".console"#"Status code: ";stat$$stat$=""100%stat=stat$)@&stat<0stat>18"Status code out of /"File to fill with assorted trash: ";file$ file$=""230 #1,file$A"How many lines of this trash do you want to create: ";line$line=0:line=line$)line<15D- "duke","prince","frog","sanitation engineer","dowager duchess"J2"2a,x,4a,a,2x,a";hexvalue$,3,2),under$,char$,up$;Ai/26=i/26):Fi H::P35dn/ 8,41,2,1,1,1,6,-1,5,-1,1,1,1,1,1,1,2,1,-11,.5='statuslen(stat)<0"Invalid status code, try again":35(buffer$="""*status(%stat,@buffer$)device$-endlist=statuslen(stat)2i=1endlist"7hexvalue$=buffer$,i,1)))-9char=hexvalue$):char<32char=char+128:char$=char):< statuslen(19))under$=10)+8)+8)+8):up$=11)".D1/request.inv"i=018:statuslen(i):device$=".console"#"Status code: ";stat$$stat$=""100%stat=stat$)@&stat<0stat>18"Status code out of range, try again":3 8,41,2,1,1,1,6,-1,5,-1,1,1,1,1,1,1,2,1,2433;0);2);26);79);2);3);12);:=vtemp:=htemp<"Press RETURN to reconstruct the captured display: ";a$buf1$=buffer$,4,240)Zj=13:=j:=1:i=140:#3;buf1$,80*(j-1)+i,1);buf1$,80*(j-1)+i+40,1);:i:#3:j:0exvalue$):char<32char=char+128:char$=char) ;charbuf$=charbuf$+char$+" "!<#3"2a,x";hexvalue$,3,2);3Ai/26=i/26)#3:#3;charbuf$:charbuf$="":#3FiH#3:#3:#3Kstat=18160P35dn}vtemp=:htemp=626);0)(*+range, try again":35='statuslen(stat)<0"Invalid status code, try again":35(buffer$="")stat=18125"*status(%stat,@buffer$)device$+stat=18140-endlist=statuslen(stat)2i=1endlist"7hexvalue$=buffer$,i,1)))-9char=h "captivated","impressed","repulsed","bored","completely overwhelmed":7 "handsome","pathetic","eager","reluctant","willing" 9< "wholesome","reserved","wild","enthusiastic","shy" BA "king","queen","tadpole","flagpole climber","lady marine" @F /1689:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyan apology for being absent from these pages last month. Sometimes the press of earthbound duties prevents the treading of etherial pathways. Ah, well, here's hoping that this issue will keep you busy enough to make up for the gap in our cycle of explora T H E T H I R D B A S I C by Taylor Pohlman EXPLORING BUSINESS BASIC - PART 10 First things first. I must offer 80 0D 80 01 01 0E 67 F3 03 g s 00 01 0B 67 F3 g s 80 80 2E 63 6F 6E 73 6F 6C 65 . c o n s o l e 28 00 01 0B 67 F3 01 01 0E 67 F3 03 00 80 0D 00 80 80 80 80 80 82 0D 00 17 00 ( g s g s 4F 00 17 0F 00 82 0D 00 17 00 4F 00 17 0F 00 O O ,2,1,1,1,6,-1,5,-1,1,1,1,1,1,1,2,1,2433char=char+128:char$=char):<"2a,x,4a,a,2x,a";hexvalue$,3,2),under$,char$,up$;Ai/26=i/26):Fi H::P35dn}vtemp=:htemp=626);0);0);2);26);79);2);3);12);:=vtemp:=htemp0 8,41245='statuslen(stat)<0"Invalid status code, try again":35(buffer$="")stat=18125"*status(%stat,@buffer$)device$+stat=18140-endlist=statuslen(stat)2i=1endlist"7hexvalue$=buffer$,i,1)))-9char=hexvalue$):char<32 statuslen(19))under$=10)+8)+8)+8):up$=11)".D1/request.inv"i=018:statuslen(i):device$=".console"#"Status code: ";stat$$stat$=""100%stat=stat$)@&stat<0stat>18"Status code out of range, try again":3as ";b$(1)*5+1));!#1;" by a ";c$(1)*5+1)); #1;" but ";d$(1)*5+1));"#1;" young ";e$(1)*5+1));K#1;" which neither of them talked to their ";f$(1)*5+1));" about."i"mother","father","grand-parents","analyst","best friends"Pi=15:a$(i):Zi=15:b$(i):di=15:c$(i):ni=15:d$(i):xi=15:e$(i):i=15:f$(i):i=1line#1;"3#,x";i;"#1;"Once a ";a$(1)*5+1)); #1;" wtion. On the subject of exploration, congratulations are due to John Jeppson for the excellent couple of articles on Basic and the Apple ///. The April issue which covered a character set editor was a fine one. If you haven't seen it, check for a backdevices, the keyboard (normally a read-only device) and the screen (normally a write-only device). To communicate with these devices, especially to change their operating characteristics, SOS allows you to give and receive information from the "driver", ainating discussions to follow. The discussion of the .CONSOLE driver starts on page 27 of the manual, and our first task is to get familar with the capabilities it provides. Some further CONSOLEation The console on the Apple /// really consists of two en announced that this issue will deal with the .CONSOLE driver (that wonderful driver that you communicate with via keyboard and screen), your next logical step is to get out your "Standard Device Drivers" manual, and prepare to follow along with the fascS views files as one of two fundamental types, "character" and "block". The control and status functions we will use this time are generally applicable to character files, and are documented in the respective manuals for the devices. Since its already beions "filread" and "filwrite" which correspond to the SOS F_READ and F_WRITE calls. This month we will concentrate on "control" and "status" functions of the "request.inv" module, which correspond to the SOS D_CONTROL and D_STATUS calls. Remember that SOis concluded, we'll see how to do these things and more using Basic and the power of SOS! We have previously done some work with the Basic invokable module called "request.inv", found on the Business Basic product disk. That article covered the two functnd was perplexed as to how to do it without having to rewrite the screen each time. After seeing how well Visicalc did its vertical and horizontal scrolling, he was even more convinced that assembly language was the only way to go. Before this article modules, the question of what he wanted to do happened to come up. As expected, he wanted to do special handling of input for some menu screens and most interestingly, he also wanted to handle the listing of records longer than 80 columns to the screen, aS" The inspiration for this month's article came from a friend who was complaining that it was hard to write in assembly language on the Apple /// and use that code in a Basic program. After letting him know about the technical note on writing Invokable to write programs which can run on as many computers as possible, but the truth is that some modification is always required, so why not make the best of the environment you have (especially if that environment can save you some work). Basic with "hot SO. Since every computer and every implementation of Basic is different, it pays to check out the computer on which the program will be running, and see what features and capablities it can lend to the task. Sure, some will insist that it is most importantal, there is no substitute for taking a little time to think about the best way to implement a program, before beginning to write it. Along with choosing the best method to implement a particular task, a good programmer always looks at the tools at hand techniques which substituted a little thinking about how to access records by key values for the brute force of having the computer scan hundreds of records looking for the one we wanted. The result was a method which was both fast and flexible. In gener issue copy, it was really that excellent. On With It This month's article could really be entitled "Down and Dirty in the SOS mines" or perhaps more accurately "The .CONSOLE driver is your friend". Last article, you will perhaps recall, we looked at software routine which is responsible for managing the physical screen and keyboard hardware. Information about the driver is obtained by using the "status" commands, and changes are made through the "control" commands. Let's start with "status". The following program uses the "request.inv" invokable module to allow calls to determine the status of the console: 10 DIM statuslen(18) 15 DATA 8,41,2,1,1,1,6,-1,5,-1,1,1,1,1,1,1,2,1,-1 20 INVOKE"/basic/request.inv" 25 FOR i=0 TO 18:READ statusl some! 28 00 01 0B 67 F3 01 01 0E 67 F3 03 00 80 0D 00 80 80 80 80 80 82 0D 00 17 00 ( g s g s 4F 00 17 0F 00 82 0D 00 17 00 4F 00 17 0F 00 O O Note that on your screen, the speciaAll others can be deduced by their HEX equivalents above. As you fool around with other status calls, the order in which these status indications fall will become apparent. In the meantime, here's everything you wanted to know about the console, and thenng accessed, to wit: 2E 63 6F 6E 73 6F 6C 65 More interesting, and twice as mysterious is status 1, which returns the total state of the console driver. For reasons of compatibility with printers, only the printable ASCII characters are listed below. 0 INVOKE 110 END Lets look at some sample output for a few typical "status" calls: First, something simple. According to the manual, status 0 should do nothing. The request module does a little better than that, returning the name of the device beineed to be printed than can fit on a single line and line 72 cleans up after the last line of HEX values is printed. All that remains is to return to request the next status code, and to provide a place to go to terminate the program. 80 GOTO 35 10ch character. The "line$" string accumulates the ASCII character values (after changing "real" control characters to printable control characters in line 57) so they can be printed out below the HEX values. Line 65 handles the case where more characters IF i/26=INT(i/26) THEN PRINT:PRINT line$:line$="" 70 NEXT i 72 PRINT:PRINT line$:PRINT Note that "endlist" is the number of valid bytes of status information, so the routine from line 50 to 70 scans "buffer$" and prints out the HEX value of ealen(stat) 47 line$="" 50 FOR i=1 TO endlist 55 hexvalue$=HEX$(ASC(MID$(buffer$,i,1))) 57 char=TEN(hexvalue$):IF char<32 THEN char=char+128 58 char$=CHR$(char) 59 line$=char$+" " 60 PRINT USING"2a,x";MID$(hexvalue$,3,2); 65 o pass the address (location) of the buffer$ variable, so that "status" can return the requested information in the string. Now that buffer$ contains the mystery information, we can print it out in meaningful form with the following: 45 endlist=statustus(%stat,@buffer$)device$ Lines 35 through 42 check the status request for validity, and then use the PERFORM statement to make the SOS call. Remember that "status" returns its result in the string variable "buffer$" and the "@" symbol instructs Basic tat$ 36 IF stat$="" THEN 100 37 stat=CONV(stat$) 38 IF stat<0 OR stat>18 THEN PRINT"Status code out of range, try again":GOTO 35 39 IF statuslen(stat)<0 THEN PRINT"Invalid status code, try again":GOTO 35 40 buffer$="" 42 PERFORM stae anomilies in the list, but have faith, it will all be explained later. Note also that the INVOKE statement needs to be changed to refer to the proper pathname for "request.inv" on your system. Meanwhile, on with the code: 35 INPUT"Status code: ";stdifferent call. Note that some calls are reserved, and therefore invalid, and are indicated by a -1 in the data list. Those of you who are comparing the data statement with the descriptions of the status calls in the Device Drivers manual will notice somen(i):NEXT 30 device$=".console" These first lines do some initialization. Since the status call will always return the buffer string fully padded to 255 characters in lenght, the "statuslen" array is set to the number of valid bytes returned by each l character symbols will actually print out. Now for something simpler, and more useful. Status code 2 is advertised as indicating the status of the "line termination character." Of course, you know the line termination character as the RETURN key or perhaps you have noticed that RETURN and CTRL-M are the same character. Notice the two bytes returned from a status 2 call: 80 0D The first byte indicates (as described in the Device Drivers manual) that a specific line termination character is enablray in this invokable will illicit a polite error message. Worse yet, an attempt to save a viewport of more than 255 characters using the status call will lock up Basic as the invokable module happily writes data into the middle of Basic itself. For thatnvokable is written. Status call 18 (for those who are not following along in the manual) saves the entire contents of the viewport into the buffer. Unfortunately, individual Basic strings are limited to 255 characters, and any attempt to use a string ar. Still Curious? You now have a program which will do all the status calls listed in the Standard Device Drivers manual. Ah, yes, you say: "What about status call 18, PRESERVE VIEWPORT?" The truth is, there is a little problem with the way that this ito the next line) and "backspace status" which determines if the backarrow is destructive (erases the character backed over) or non-destructive (so you can use the forward arrow copy feature). All this and more is yours to investigate with the status callany key". As you might expect, this is the mechanism which Basic uses to implement the ON KBD statement. Other status calls of interest include the one for "cancel status" (yes Virginia, you can avoid CTRL-X printing the backslash character and skipping r the "Any key" event, number 8 on your hit parade: 00 01 0B 67 F3 g s Same format, except with a different priority and different event handler address. In addition, there is no event character, since this event is set by the pressing of "he console driver, which flagged SOS to call Basic's event handler to shut down the current activity. Later on we will discuss how to change the attention character to something besides CTRL-C, which is guaranteed to baffle your friends. For now, considel is the last byte, the attention character itself. As you can see, it is HEX 03, which is also ASCII character 3, usually known as CTRL-C. Yes, all those times you pressed CTRL-C to stop a program or break a listing, you were setting an "event" within tsing up to a theoretical limit of 512K bytes. The important thing to remember is that you should not change the event handler addresses, since that is an easy way to cause the system to leap off into space, never to return. The real key value in this cal next three bytes compose the address of the event handler for this event. For those of you who wondered how Apple /// addresses all that memory, part of the answer is here. Three byte addresses are used throughout most of the system code to allow addreslook something like this: 01 01 0E 67 F3 03 g s Again, only the printable ASCII characters are listed. The rest will show up on your screen when you run the program. Note that the first two bytes are the priority and the event ID, and then, as described in the Drivers manual, status 6 gives the priority and event ID of the attention event, along with the address of the event handler which services the event, and the character code which triggers the event. The return from status 6 should ou fool with them. Specifically they are status 6 and 8, the "attention" and "any key" events. Events can be set in SOS to trigger interrupts to interpreters (like Basic) to inform the interpreter that some specific action is required or requested. Agaied. The second byte ("0D") is hex notation for decimal 13, or the CTRL-M (RETURN) character. Later on we'll see that this can be changed to any other character, for fun and profit. Now come two calls which are interesting, but fraught with danger if y reason, the "statuslen" array doesn't allow the use of that call. For those of you who are more adventurous, or who use viewports of less that 256 characters, consider the following: 41 IF stat=18 THEN GOSUB 125 43 IF stat=18 THEN GOSUB 140 125 vtemp= VPOS:htemp= HPOS 130 PRINT CHR$(26);CHR$(0);CHR$(0);CHR$(2);CHR$(26);CHR$(9);CHR$(24);CHR$(3) ;CHR$(12); 135 RETURN 140 TEXT:VPOS=vtemp:HPOS=htemp 145 RETURN 200 DATA 8,41,2,1,1,1,6,-1,5,-1,1,1,1,1,1,1,2,1,243 These changes RN to reconstruct the captured display: ";a$ 165 buf1$=MID$(buffer$,4,240) 170 HOME:PRINT CHR$(21);"5"; 172 FOR j=1 TO 3:VPOS=j:HPOS=1:FOR i=1 TO 40:PRINT MID$(buf1$,80*(j-1)+i,1); MID$(buf1$,80*(j-1)+i+40,1);:NEXT i:NEXT j 175 TEXT:RETUisually ajacent bytes split by a distance of half the viewport window. All that leads to the following adjustment of our program, to reconstruct the image from the scramble in the buffer: 75 IF stat=18 THEN GOSUB 160:GOSUB 140 160 INPUT"Press RETUr favorite, the Apple ///, is no exception. Because of the way the video is organized for accesses over its internal 16 bit bus (which also provides transparent access to extended address bytes), the characters are mapped in an alternating pattern, with vA0 B0 AF B3 B8 A0 B0 B1 A0 B5 B2 AF B2 B2 BA B6 A0 0 4 T Y L S 0 / 3 8 0 1 5 2 / 2 2 : 6 B1 B9 A0 A0 A0 A0 A0 A0 A0 1 9 Just a bunch of gibberish, right? Unfortunately, computers are eminently logical, and ou T X 0 0 R . I T 5 2 / B2 B2 BA B6 B0 AF B3 B8 A0 B0 B1 A0 B1 B8 A0 A0 A0 A0 A0 A0 A0 A0 C5 D4 A0 B0 2 2 : 6 0 / 3 8 0 1 1 8 E T 0 B0 B4 D4 D9 CC D3 A0 A0 A0 0 3 D3 C1 D5 AE C9 D4 A0 A0 B0 AF B3 B8 A0 B9 B3 A0 B5 B2 AF B2 B1 BA B1 A0 B3 A0 S A U . I T 0 / 3 8 9 3 5 2 / 2 1 : 1 3 A0 A0 A0 A0 A0 A0 A0 A0 D4 D8 A0 A0 B0 B0 A0 D2 AE C9 D4 A0 A0 A0 A0 B5 B2 AF A0 A0 A0 B5 B2 AF B2 B1 T X 0 0 T T S L S 5 2 / 2 1 BA B1 B0 AF B3 B8 A0 B9 B3 A0 B9 B3 A0 A0 A0 A0 A0 A0 A0 A0 C5 D4 A0 B0 B0 B3 : 1 0 / 3 8 9 3 9 3 E T 0 Y E B K N M A0 A0 A0 A0 A0 A0 CD C4 C6 C5 A0 C9 C5 A0 D2 C1 C5 A0 D4 CD A0 A0 CF A0 A0 A0 M D F E I E R A E T M O A0 A0 A0 A0 A0 A0 D4 D8 A0 A0 B0 B0 A0 D4 D4 D3 CC D3 0 A0 CC D3 A0 C1 C5 A0 A0 A0 A0 A0 A0 CF C9 C9 C4 D4 CD A0 O T P L S A E O I I D T M C3 C5 D4 C4 A0 C9 C5 A0 C5 C6 A0 A0 A0 A0 A0 A0 A0 A0 D9 C5 A0 C2 CB A0 CE CD C E T D I E E F EOF TEXT 00003 STATUS.LIST 05/23/82 19:31 05/23/82 19:31 933 TEXT 00004 TRY.LIST 05/23/82 20:16 05/23/82 20:16 1189 The resultant listing of the buffer (made by lines 50 through 72) will look something like this: 82 4F 02 A0 D4 D0 Aypes of status information. To give you an idea of how this works, imagine that the following three lines are at the top of the display when you run the program above with status function 18: TYPE BLKS NAME MODIFIED TIME CREATED TIME r limit of the buffer$ variable. Line 140 restores the cursor to its original position, and since we changed line 200 to indicate 243 characters expected (240 + 3 bytes of coded information) the program will list out the screen data as it does the other t using the Basic WINDOW command, but it doesn't hurt to see how console commands are use to accomplish the same purpose. In any case, setting up the window (which contains 240 characters) gives the status function something to read within the 255 characteto the program will make a special case of the "save viewport" call. Basically it works like this: line 125 saves the current cursor position, and line 130 sets up a window consisting of the first three lines of the screen. Similar action could be takenRN You can adjust the constants in line 72 to accomodate other viewport sizes. Note also that in line 170 the statement PRINT CHR$(21);"5"; is used to turn off several console options (like scrolling and new line) to insure the data is written back correctly. The TEXT statement in 175 sets everything back to normal. Getting Control Now that you have all this information, the immediate reaction is "how do I change things?" The following is a sample program which allow the use of the "control" call te reads from the keyboard? ";a$ 1305 GOSUB 5000 1310 IF yes THEN buffer$=CHR$(128):RETURN 1320 buffer$=CHR$(0):RETURN Two byte reads are a whole world by themselves. This is the way to set up your application to use the numeric keypad for speciaracter to ASCII 141 (128+13). Amaze your friends! Note also that Basic does not reset these values until you reboot, so if you set the value to something you can't type (or happen to forget), you're out of luck! 1300 INPUT"Do you want to do two by with the termination character routine is to remember that the "Open Apple" key adds 128 to the value of a given key value. Therefore, to change the function of the RETURN key to require "Open-Apple RETURN" is simply a matter of setting the termination chRN By contrast, control 2 above is nice and safe, and also serves to introduce the input test routine at line 5000, as follows: 5000 yes=1 5010 ans$=MID$(a$,1,1):IF ans$<>"Y" AND ans$<>"y" THEN yes=0 5020 RETURN One of the things you might enjoy5000 1215 IF NOT yes THEN 1250 1220 INPUT"ASCII value of termination character: ";a$ 1225 char=0:char=CONV(a$) 1230 IF char<1 OR char>255 THEN 1200 1235 buffer$=CHR$(128)+CHR$(char) 1240 RETURN 1250 buffer$=CHR$(0)+CHR$(0) 1255 RETUr as an exercise." In general you should only restore with a buffer loaded during a previous "preserve console status" call (Status Code 1, above). 1200 PRINT:INPUT"Do you want to terminate input with a specific character? " ;a$ 1210 GOSUB of 1110 REM the buffer to status table values 1120 PRINT:PRINT"Not implemented" 1125 errorcode=1 1130 RETURN This would normally be the "restore console status" function. Because it is both dangerous and undocumented, it is "left to the readel request to be handled separately. Here are the routines and commentary: 1000 buffer$=CHR$(0) 1010 RETURN This is just the "reset console" function which has no formal parameters. 1100 REM set sub$(buffer$,1,1) equal to $28 and set the rest T i 135 PRINT:PRINT line$:PRINT 140 GOTO 35 145 INVOKE 150 END As you can see, the main part of the program is somewhat similar to our "status" example above. The big exception is the ON GOSUB statement in line 80 which allows for each contro$(ASC(MID$(buffer$,i,1))) 110 char=TEN(hexvalue$):IF char<32 THEN char=char+128 115 char$=CHR$(char) 117 line$=char$+" " 120 PRINT USING"2a,x";MID$(hexvalue$,3,2); 125 IF i/26=INT(i/26) THEN PRINT:PRINT line$:line$="" 130 NEX1 00,2200,2300,2400,2500,2600,2700,2800 85 IF errorcode THEN PRINT"Control function not performed.":GOTO 35 90 PERFORM control(%ctrl,@buffer$)device$ 95 endlist=controllen(ctrl) 97 line$="" 100 FOR i=1 TO endlist 105 hexvalue$=HEXctrl$) 70 IF ctrl<0 OR ctrl>18 THEN PRINT"Control code out of range, try again":GOT O 35 75 IF controllen(ctrl)<0 THEN PRINT"Invalid control code, try again":GOTO 35 80 ON ctrl+1 GOSUB 1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,28) 15 DATA -1,40,2,1,1,0,6,-1,5,-1,1,1,1,1,1,1,-1,73,-1 20 INVOKE"/basic/request.inv" 25 FOR i=0 TO 18:READ controllen(i):NEXT 30 device$=".console" 35 INPUT"Control code: ";ctrl$ 55 errorcode=0 60 IF ctrl$="" THEN 145 65 ctrl=CONV(to modify the state of the console driver to your wishes. Remember, modifying certain things (like event handler addresses) can cause the system to crash, so try to keep it simple. With that warning, here's the magic incantation: 10 DIM controllen(1al functions, to read the state of the "Apple" keys, etc., etc., etc. More information is in the Device Drivers manual. If interest is high enough in these techniques, maybe it would make the subject of a future column. 1400 INPUT"Size of the type-ahead buffer: ";a$ 1405 IF a$="" THEN errorcode=1:RETURN 1410 size=CONV(a$) 1415 IF size<0 OR size>128 THEN PRINT"Invalid input, try again":GOTO 1400 1420 buffer$=CHR$(size) 1425 RETURN Type-ahead buffer size is interesting only in the abilitf the CONTROL-8 (display control characters) keyboard function. 2200 INPUT"Do you want the Retype function enabled? ";a$ 2205 IF a$="" THEN errorcode=1:RETURN 2210 GOSUB 5000 2215 IF yes THEN buffer$=CHR$(128):RETURN 2220 buffer$=CHR$(0) 2140 GOSUB 5000 2145 IF yes THEN buffer$=CHR$(192):RETURN 2150 buffer$=CHR$(128) 2155 RETURN This is a handy function for typing in passwords and other characters where selective display is desired. In addition, it allows programatic setting o of characters to the screen? ";a$ 2105 IF a$="" THEN errorcode=1:RETURN 2110 GOSUB 5000 2115 IF yes THEN 2130 2120 buffer$=CHR$(0) 2125 RETURN 2130 INPUT"Do you also want control characters to be echoed? ";a$ 2135 IF a$="" THEN 2100 ponsible for making sense of the entered characters. This might come in handy in conjunction with the console synchronizing function (chr$(22)) to wait a certain time and see what had been typed in that time period. 2100 INPUT"Do you want any echoing THEN buffer$=CHR$(128):RETURN 2020 buffer$=CHR$(0):RETURN No wait input is fun to play with because it bypasses buffering and waiting for RETURN and gives the inputting program whatever has accumulated since the last input request. The program is resaid for the attention event above goes double for the routine above. 1900 errorcode=1:RETURN Control call number 9 is reserved. 2000 INPUT"Do you want No-Wait input? ";a$ 2005 IF a$="" THEN errorcode=1:RETURN 2010 GOSUB 5000 2015 IF yesN(a$)<>3 THEN 1845 1855 buffer$=buffer$+a$ 1860 PRINT"Buffer is: "; 1865 FOR i=1 TO 5:PRINT USING"2a,x";MID$(HEX$(ASC(MID$(buffer$,i,1))),3,2);: NEXT 1870 INPUT" Ok? ";a$:GOSUB 5000 1875 IF yes THEN RETURN:ELSE:GOTO 1805 What was s0 buffer$=CHR$(pri) 1825 INPUT"Any-key Event ID: ";a$ 1830 IF a$="" THEN 1805 1835 event=CONV(a$):IF event<0 OR event>255 THEN 1825 1840 buffer$=buffer$+CHR$(event) 1845 INPUT"Any-key event handler address (three bytes): ";a$ 1850 IF LEter. 1700 errorcode=1:RETURN Control call number 7 is reserved. 1800 PRINT"Warning, Don't make a mistake!" 1805 INPUT"Any-key event priority: ";a$ 1810 IF a$="" THEN errorcode=1:RETURN 1815 pri=CONV(a$):IF pri<0 OR pri>255 THEN 1805 182N:ELSE:GOTO 1605 Here's where life gets dangerous. If you use this routine, you must first call attention status to get the priority, event id and address, and re-enter that information exactly. Only then can you feel free to change the attention characCONV(a$):IF code<1 OR code>255 THEN 1660 1670 buffer$=buffer$+CHR$(a$) 1675 PRINT"Buffer is: "; 1680 FOR i=1 TO 6:PRINT USING"2a,x";MID$(HEX$(ASC(MID$(buffer$,i,1))),3,2);: NEXT 1685 INPUT" Ok? ";a$:GOSUB 5000 1690 IF yes THEN RETURnt<0 OR event>255 THEN 1625 1640 buffer$=buffer$+CHR$(event) 1645 INPUT"Attention event handler address (three bytes): ";a$ 1650 IF LEN(a$)<>3 THEN 1645 1655 buffer$=buffer$+a$ 1660 INPUT"ASCII code of Attention character: ";a$ 1665 code=605 INPUT"Attention event priority: ";a$ 1610 IF a$="" THEN errorcode=1:RETURN 1615 pri=CONV(a$):IF pri<0 OR pri>255 THEN 1605 1620 buffer$=CHR$(pri) 1625 INPUT"Attention Event ID: ";a$ 1630 IF a$="" THEN 1605 1635 event=CONV(a$):IF evey to set it to zero (no type-ahead). 1500 buffer$=CHR$(0) 1510 RETURN This just flushes the type-ahead buffer (like CTRL-6) which is handy if you want to guarantee a certain input state or timing. 1600 PRINT"Warning, Don't make a mistake!" 12225 RETURN Retype allows the forward arrow key to copy characters into the buffer. This is the normal mode for Basic, but can be disallowed to provide pure cursor movement. 2300 INPUT"Do you want the Backspace function to be enabled? ";a$ 2305 IF a$="" THEN errorcode=1:RETURN 2310 GOSUB 5000 2315 IF yes THEN 2330 2320 buffer$=CHR$(0) 2325 RETURN 2330 INPUT"Do you also want backspace to be destructive? ";a$ 2335 IF a$="" THEN 2300 2340 GOSUB 5000 2345 IF yes THEN buffer$=e discouraged, however. There's lots to do above which can make your application development smoother and more friendly (and lots of time required to test everything out!) Homework! This has been quite an treatise on the use of the Apple /// console. 255 character buffer limit discussed earlier, it is not possible to restore a whole viewport. Further, the initial three byte code at the front of the buffer is undocumented, which makes it a little tough to create your own viewport definitions. Don't bping the character definitions is beyond the scope of this article, there is enough information in the Device Drivers manual to get you started. 2800 errorcode=1:RETURN The process of restoring a viewport is also left to the reader. Because of theions (max 8) 2715 errorcode=1:RETURN Even though it is not possible to download an entire character set using this invokable, control request 17 above does provide a mechanism for downloading eight characters at a time. Although the process for develore of the problem. See your friendly "download.doc" file on the Basic product disk for more details. 2700 PRINT"Not currently implemented" 2705 REM sub$(buffer$,1,1) contains the character count 2710 REM the rest is individual character definitable escape mode also. 2600 errorcode=1:RETURN Down-loading an entire character set is not implementable with this invokable because of the 255 character limit on the buffer. However, don't despair, since there is the great "download.inv" to take cag while you are developing programs which you might want to turn off during an application program, especially if you want to restrict the input to just the prompted locations. If you use destructive backspace and destructive cancel, it makes sense to distly waiting for who knows what. 2500 INPUT"Do you want Escape Mode enabled? ";a$ 2505 IF a$="" THEN errorcode=1:RETURN 2510 GOSUB 5000 2515 IF yes THEN buffer$=CHR$(128):RETURN 2520 buffer$=CHR$(0):RETURN Escape mode is another handy thinou are writing programs and want to cancel a line but then use the forward arrow to correct the mistake. However, it makes lots of sense in an application where the user might be confused by the backshash and the cursor sitting on the line below, expectana destructive (erasing) backspace for every character in the input buffer. The net effect of this is that the cursor snaps back to the exact place it was when you began to type that line, erasing everything as it goes. This is not particularly handy if yncel" is the most powerful feature of this routine. By now you have probably gotten accustomed to getting a backslash and then a carriage return and line feed when you press CTRL-X. When destructive cancel is turned on, the console driver instead issues 0 buffer$=CHR$(0) 2425 RETURN 2430 INPUT"Do you also want Cancel to be destructive? ";a$ 2435 IF a$="" THEN 2400 2440 GOSUB 5000 2445 IF yes THEN buffer$=CHR$(192):RETURN 2450 buffer$=CHR$(128) 2455 RETURN Turning on "destructive cae that what shows up on the screen is what is actually going to be input when he presses RETURN. 2400 INPUT"Do you want the Cancel function to be enabled? ";a$ 2405 IF a$="" THEN errorcode=1:RETURN 2410 GOSUB 5000 2415 IF yes THEN 2430 242CHR$(192):RETURN 2350 buffer$=CHR$(128) 2355 RETURN This is really handy for applications programs taking input from the keyboard using standard input statements. It, in connection with disabling the retype function, allows the naive user to be surThere are lots of other useful options in the console driver that will be covered next time, but in the meanwhile, here is a present/homework assignment which should give you some chuckles while proving that there is very little you can't do with SOS and Basic. Without further ado, try out the following: 5 INPUT"File to fill with assorted trash: ";file$ 10 IF file$="" THEN 230 15 OPEN#1,file$ 20 INPUT"How many lines of this trash do you want to create: ";line$ 25 line=0:line=CONV(line$) 3THEN index=vi-25:hiindex=hi-1:FOR j=1 TO 24:SUB$(c$,j,1)=MID$(a$ (index+j),hiindex,1):NEXT:PRINT rightscroll$;c$;:hi=hi-1:c$=bnk$:TEXT 102 RETURN 105 IF hi+80<=maxlenght THEN index=vi-25:hiindex=80+hi:FOR j=1 TO 24:SUB$(b$ ,j,1)=MID$(a$ NT a$(i):NEXT 70 hi=1:vi=24:TEXT 75 bnk$=" ":b$=bnk$:c$=bnk$ 80 GET a$:cursor=ASC(a$) 85 move=(cursor=8)+2*(cursor=21)+3*(cursor=10)+4*(cursor=11) 90 ON move+1 GOSUB 130,100,105,110,120 95 GOTO 80 100 IF hi>1 HR$(16)+CHR$(3)+CHR$(26)+CHR$(0)+CHR$(23)+CHR$(10)+CHR$(21)+"5 "+CHR$(22) 55 scrolldown$=CHR$(16)+CHR$(3)+CHR$(12)+CHR$(11)+CHR$(22) 60 HOME:PRINT CHR$(21);"5"; 65 FOR i=0 TO 23:IF LEN(a$(i))>80 THEN PRINT MID$(a$(i),1,80);:NEXT:ELSE PRI +CHR$(79)+CHR$(0)+CHR$(2)+CHR$(26) +CHR$(0)+CHR$(24)+CHR$(3)+CHR$(21)+"5"+CHR$(12)+CHR$(22) 45 rightscroll$=CHR$(23)+CHR$(1)+CHR$(26)+CHR$(0)+CHR$(0)+CHR$(2)+CHR$(26)+C HR$(0)+CHR$(24)+CHR$(3)+CHR$(21)+"5"+CHR$(12)+CHR$(22) 50 scrollup$=C;a$ 10 IF a$="" THEN 200 15 OPEN#1,a$ 20 maxlenght=0 25 ON EOF#1 GOTO 35 30 FOR i=0 TO 500:INPUT#1;a$(i):IF LEN(a$(i))>maxlenght THEN maxlenght=LEN(a $(i)):NEXT:ELSE:NEXT 35 lastrecord=i 40 leftscroll$=CHR$(23)+CHR$(255)+CHR$(26)lready scrolls down to allow more information to be printed. Next month we'll explore the following program in detail, and other programming tricks with the console, but for now, type and enjoy: 1 DIM a$(500) 5 INPUT"File name to scroll through: "lying .console to the filename prompt, for example) you get the sentences wrapped around because the lines are more than 80 characters long. How nice it would be if you could see them printed out and scroll horizontally to read them, just as the console ad young queen which neither of them talked to their grand-parents about. 4 Once a prince was repulsed by a pathetic but shy young tadpole which neither of them talked to their analyst about. Unfortunately if you print this file out on the screen (by repng flagpole climber which neither of them talked to their mother about. 2 Once a duke was completely overwhelmed by a pathetic but wholesome young tadpole which neither of them talked to their analyst about. 3 Once a duke was bored by a willing but wil1)*5+1)); " about." 210 NEXT i 220 CLOSE 230 END Running the little jewel above should create the following kind of file (be sure to run at least 50 lines): 1 Once a dowager duchess was impressed by a reluctant but enthusiastic you160 PRINT#1;" was ";b$(INT(RND(1)*5+1)); 170 PRINT#1;" by a ";c$(INT(RND(1)*5+1)); 180 PRINT#1;" but ";d$(INT(RND(1)*5+1)); 190 PRINT#1;" young ";e$(INT(RND(1)*5+1)); 200 PRINT#1;" which neither of them talked to their ";f$(INT(RND():NEXT 100 FOR i=1 TO 5:READ c$(i):NEXT 110 FOR i=1 TO 5:READ d$(i):NEXT 120 FOR i=1 TO 5:READ e$(i):NEXT 130 FOR i=1 TO 5:READ f$(i):NEXT 140 FOR i=1 TO line 145 PRINT#1; USING"3#,x";i; 150 PRINT#1;"Once a ";a$(INT(RND(1)*5+1)); wholesome","reserved","wild","enthusiastic","shy" 65 DATA "king","queen","tadpole","flagpole climber","lady marine" 70 DATA "mother","father","grand-parents","analyst","best friends" 80 FOR i=1 TO 5:READ a$(i):NEXT 90 FOR i=1 TO 5:READ b$(i0 IF line<1 THEN GOTO 5 45 DATA "duke","prince","frog","sanitation engineer","dowager duchess" 50 DATA "captivated","impressed","repulsed","bored","completely overwhelmed" 55 DATA "handsome","pathetic","eager","reluctant","willing" 60 DATA "(index+j),hiindex,1):NEXT:PRINT leftscroll$;b$;:hi=hi+1:b$= bnk$:TEXT 107 RETURN 110 IF vi24 THEN PRINT scrolldown$;MID$(a$(vi-25),hi,80);:vi=vi-1:TEXT 125 RETURN 130 IF cursor=27 THEN POP:GOTO 200:ELSE:RETURN 200 TEXT:PRINT CHR$(26);CHR$(0);CHR$(23); 210 CLOSE 220 END Be sure you type it in exactly as written, and be sure that "bnk$" in line 75 contains exactly 24 spaces between the quo,3,2);:" Ok? ";a$:5000yes::1605errorcode=1:%"Warning, Don't make a mistake!"" "Any-key event priority: ";a$a$=""errorcode=1:#pri=a$):pri<0pri>2551805buffer$=pri)!"Any-key Event ID: ";a$&a$=""1on event handler address (three bytes): ";a$ra$)<>31645wbuffer$=buffer$+a$-|"ASCII code of Attention character: ";a$&code=a$):code<1code>2551660buffer$=buffer$+a$)"Buffer is: ";4i=16:"2a,x";buffer$,i,1)))ke a mistake!"$E"Attention event priority: ";a$Ja$=""errorcode=1:#Opri=a$):pri<0pri>2551605Tbuffer$=pri)Y"Attention Event ID: ";a$^a$=""1605)cevent=a$):event<0event>2551625hbuffer$=buffer$+event)9m"Attenti 5000yesbuffer$=128):(buffer$=0):)x"Size of the type-ahead buffer: ";a$}a$=""errorcode=1:size=a$)8size<0size>128"Invalid input, try again":1400buffer$=size)buffer$=0)%@"Warning, Don't macharacter? ";a$ 5000yes12500"ASCII value of termination character: ";a$char=0:char=a$)char<1char>2551200buffer$=128)+char)buffer$=0)+0)>"Do you want to do two byte reads from the keyboard? ";a$:353 -1,40,2,1,1,0,6,-1,5,-1,1,1,1,1,1,1,-1,73,-1 buffer$=0)BL set sub$(buffer$,1,1)=$28 and rest of buffer to status table`:"Not implemented"eerrorcode=1jF:"Do you want to terminate input with a specific %ctrl,@buffer$)device$_endlist=controllen(ctrl)di=1endlist"ihexvalue$=buffer$,i,1)))-nchar=hexvalue$):char<32char=char+128schar$=char):x"2a,x,4a,a,2x,a";hexvalue$,3,2),under$,char$,up$;}i/26=i/26):i :z|}~ange, try again":35?Kcontrollen(ctrl)<0"Invalid control code, try again":35jPctrl+11000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,28006Uerrorcode"Control function not performed.":35#Zcontrol( controllen(19))under$=10)+8)+8)+8):up$=11)".d1/request.inv"i=018:controllen(i):device$=".console"#"Control code: ";ctrl$7errorcode=0<ctrl$=""145Actrl=ctrl$)AFctrl<0ctrl>18"Control code out of rd right through the file. If you have trouble, just wait until next month when we clear some of the murky water. Until then, there doesn't seem to be anything else that can console you, so have fun with your Apple ///! te marks. Then use the first program to create a file of junky messages. If you want, you can change the data statements to make up your own messages. Then use that same file name for the second program and use the arrow keys to scroll up, down, left an805)+event=a$):event<0event>25518250buffer$=buffer$+event)75"Any-key event handler address (three bytes): ";a$:a$)<>31845?buffer$=buffer$+a$D"Buffer is: ";4Ii=15:"2a,x";buffer$,i,1))),3,2);:N" Ok? ";a$:5000Syes::1805lerrorcode=1:%"Do you want No-Wait input? ";a$a$=""errorcode=1: 5000yesbuffer$=128):buffer$=0):?4"Do you want any echoing of characters to the screen? ";a$9a$=""errorcode=1: >5000C statuslen(19))under$=10)+8)+8)+8):up$=11)".D1/request.inv"i=018:statuslen(i):device$=".console"#"Status code: ";stat$$stat$=""100%stat=stat$)@&stat<0stat>18"Status code out of range, try again":3a$(vi),hi,80);:vi=vi+1:s6xvi>24scrolldown$;a$(vi-25),hi,80);:vi=vi-1:}cursor=27:200:::26);0);23);=hi-1:j=124:c$,j,1)=a$(index+j),hiindex,1)::rightscroll$;c$;:hi=hi-1:c$=bnk$:fihi+80<=maxlenghtindex=vi-25:hiindex=80+hi:j=124:b$,j,1)=a$(index+j),hiindex,1)::leftscroll$;b$;:hi=hi+1:b$=bnk$:k9nvi80a$(i),1,80);::a$(i):Fhi=1:vi=24:3Kbnk$=" ":b$=bnk$:c$=bnk$Pa$:cursor=a$)=Umove=(cursor=8)+2*(cursor=21)+3*(cursor=10)+4*(cursor=11)Zmove+1130,100,105,110,120_80tdhi>1index=vi-25:hiindex3)+21)+"5"+12)+22)\-rightscroll$=23)+1)+26)+0)+0)+2)+26)+0)+24)+3)+21)+"5"+12)+22)?2scrollup$=16)+3)+26)+0)+23)+10)+21)+"5"+22),7scrolldown$=16)+3)+12)+11)+22)<:21);"5";6Ai=023: a$(500)'"File name to scroll through: ";a$ a$=""200 #1,a$maxlenght=0 ž#135Ei=0500:#1;a$(i):a$(i))>maxlenghtmaxlenght=a$(i)):::#lastrecord=i^(leftscroll$=23)+255)+26)+79)+0)+2)+26)+0)+24)+er count: the rest is individual character definitions (max 8) errorcode=1: errorcode=1: yes=1/ans$=a$,1,1):ans$<>"Y"ans$<>"y"yes=0sbuffer$=192): buffer$=128) + "Do you want Escape Mode enabled? ";a$ a$=""errorcode=1: 5000 yesbuffer$=128): buffer$=0):( errorcode=1: "Not currently implemented"4 sub$(buffer$,1,1) contains the charactyesbuffer$=192):. buffer$=128)3 9` "Do you want the Cancel function to be enabled? ";a$e a$=""errorcode=1: j 5000o yes2430t buffer$=0)y 5~ "Do you also want Cancel to be destructive? ";a$ a$=""2400 5000 yeyesbuffer$=128):buffer$=0)<"Do you want the Backspace function to be enabled? ";a$ a$=""errorcode=1:  5000 yes2330 buffer$=0) 8 "Do you also want backspace to be destructive? ";a$ a$=""2300 $ 5000) yes2130Hbuffer$=0)M13000Zha$="{,|,~,}; selects; to new disk; J/2)=4:=+1:ۙ=44B$(J);:J=J+1I:1,180,22:2,280,21:2,2380,23:8A$(1000),B$(1000),C%(511),C$(20),name$(20):=10:=0UCA=128:LCA=UCA+32CT=15 IF PREFIX$= PREFIX$+MID$(B$(I),1OLUME NAME (/DISKNAME) OR DEVICE NAME (.Dx)"P12);::"80C";a$;:Zb$="CHANGING DISKS"$d=23:=0::"80C";b$;::12).n=12:=20:"MAKE A NEW MENU FOR DISK: ";N$xN$)<2110=N$ :210 I=1L(A$(I),A$))200B$(/ WAP /// SIG MENU.MAKER PROGRAM (v. 6.1) =".D1"210: Coldstart (320: Warmstart &*X=11000: TEXT SLOW-DOWN LOOP ,X.1 CHANGE DISK SUBROUTINE23œ202:2200<RFa$=" YOU MAY SELECT YOUR DISK BY V but shy young flagpole climber which neither of them talked to their best friends about. lesome young queen which neither of them talked to their analyst about. 49 Once a frog was completely overwhelmed by a pathetic but shy young flagpole climber which neither of them talked to their mother about. 50 Once a duke was captivated by a patheticwhich neither of them talked to their analyst about. 47 Once a sanitation engineer was bored by a willing but wholesome young lady marine which neither of them talked to their analyst about. 48 Once a duke was completely overwhelmed by a pathetic but whoh neither of them talked to their grand-parents about. 45 Once a duke was captivated by a eager but enthusiastic young king which neither of them talked to their father about. 46 Once a prince was completely overwhelmed by a eager but wild young tadpole 81+LCA):::: RebootN=THPOS:B$(I);XA<8A>11540bA-7640,660,690,720l:=THPOS:B$(I);v:520: 500THPOS=4:I/2=I/2)I=I-1I=IBOTM THPOS=44:I/2<>I/2)I=I+1I2=-1:I=I-2:IBOTM<30THPOS=44I=IBOTM/2)*2:=+IBOTM/2)-1:0=+IBOTM/2-.5):I=IBOTM:I/2=I/2)I=I-1 œ2120B=B$(I),16)," ")-1 B$(I),"BASIC 0")850B$(I),"TEXT 0")890  MENU.MAKER TEXT MODULESEG=0"MENU.MAKER"890&*X=11000: TEXT SLOW-DOWN LOOP ,X.1,180,22:2,280,21:2,2380,23:z:A$="LISTING "+B$(I),16,B)$=01:=0::"80C";A$;::12)>=23:=0::":/]:"End of Data Entry for Screen: ";screen$;bwritefile:"Output is stored in the file ";outfile$'g=23:=1:"Press any key to quit:";la$v{3 initialize tables (could be done from a file)first.input=0 itemsi=0itemssing for this field goes here'3000: add to output record string fieldnum@ code to process the finished record in outrec$ goes here ::"Record is: ";out.rec$'"Press any key to continue: ";:a$writefile4000recordnumX: display the data entry screen with defaultskescapecode=0:out.rec$=""nfieldnum=1items.s2000: process input for field=fieldnum ,vname$(i,0),1,1)="("input.req%(i)=-15xescapecodefieldnum=first.input:600::105/} extra proceh ! Screen data capture programname$(50,1),info%(50,2) 1000(:"Data Entry for Screen: ";screen$=#writefile:"with output stored in the file ";outfile$((=23:=1:"Press any key to begin:";-a$drecordnum=1327677i150012405l=ơ):: Routine to back up one directory level.a$=С,l-1) s=a$)a$=a$,s-1)a$,1)="/"5060:s=s-1 5030=a$240( MENU.MAKER 6.10 * Thanks to C.M.Davidson for his help!NOT FOUND.)"X=11000:X:::210Z a$="{,|,~,}; selects; back 1 level; G$:::320H: Error Routine 202:U=11:"79C";"BAD PATH ERROR (NO DISK IN DISK DRIVE OR DESIRED FILE ,2))=0"12";џ,6);:ٟ;$П,2))=>12" PM-":" AM-" 1830WW=1530 =26:=21 1600 &:WW=1:0 :SEG=1;".D1/S EG.F" SEG=1".D1/SEG.G"diskname$=3802  CATCH PASCAL TEXT FILES "JUNE":1750M$="JULY":1750M$="AUGUST":1750M$="SEPTEMBER":1750M$="OCTOBER":1750M$="NOVEMBER":1750M$="DECEMBER":1750826);"-";M$;" ";Ѡ,2));", ";"19";Р,2);" ";/П,2))=>13П,2))-12;џ,6);:1780$~240:=24:=0:"@ ..... "DATE.TIME.LINE" ....JM=Ҡ,4,2))BTM1630,1640,1650,1660,1670,1680,1690,1700,1710,1720,1730,1740^M$="JANUARY":1750hM$="FEBRUARY":1750rM$="MARCH":1750|M$="APRIL":1750M$="MAY":1750M$=B$(I),"CAT 0")1140*B$(I),"FONT 0")18504B$(I),"FOTO 0")1930>B$(I),"PASTXT 0")2070H540R\A$="RUNNING "+B$(I),16,B)f"79C";A$;:=0pB$(I),16,B) z::SEG=1".D1/SEG.T"t=+B$(I),16,B) yCT=CT+179C";"PRESS ANY KEY TO HALT LISTING"::202 1020#2,B$(I),16,B)ž#242:::1160Z=1#2;A$:"78A";A$Z=Z+1:Z>1842:::Z=1980*:=23:=0::"79C";"CONTINUE...?":1C$:C$<>"Y"C$<>"y"C$<>"N"C$<>"n"10sname$(i,0),name$(i,1)Uname$(i,0),1,1)=":"input.req%(i)=1:first.input=i*(first.input=0)+first.input,name$(i,0),1,1)="("input.req%(i)=-1j=02:info%(i,j):ji*screen$=name$(0,0):outfile$=name$(0,1) outlen=info%(0,0)123)+zip)+26)+0)+0)+2)+26)+zip-1)+23)+3)+21)+"5"+12)_.rightscroll$(1)=SYNC$+23)+1)+26)+0)+0)+2)+26)+0)+23)+3)+21)+"5"+12)?2scrollup$=16)+3)+26)+0)+23)+10)+21)+"5"+SYNC$,7scrolldown$=16)+record=i%sync$=22)m(leftscroll$(0)=SYNC$+23)+256-zip)+26)+80-zip)+0)+2)+26)+zip-1)+23)+3)+21)+"5"+12)a)leftscroll$(1)=SYNC$+23)+255)+26)+79)+0)+2)+26)+0)+23)+3)+21)+"5"+12)e-rightscroll$(0)=SYNC$+z+a$(500),rightscroll$(1),leftscroll$(1)'"File name to scroll through: ";a$ a$=""200 #1,a$maxlenght=0-"How many units to fast scroll by? ";zip ž#135Ei=0500:#1;a$(i):a$(i))>maxlenghtmaxlenght=a$(i)):::#last  =point . 22003 ( value$)out.rec$=out.rec$+value$ #2,recordnum;out.rec$>1:line$,point,1);:point=point-1:2330D=21point141<>92350 value$=line$ ::set.normal$;line$; :0K9:line$,point,1);::j=1150::line$,point,1);:j=1150::2105<32>1272270line$,point,1)=ŝ):line$,point,1);#point""line$,1,default$))=default$: line$;"set.edit$;%=1:point=1 4220eld,0))-1field.len=info%(field,2))<field.len<>0end.window=start.window+field.len-1:2060test=field+1Qtest>itemsinfo%(test,0)>rowend.window=79:field.len=80-start.window:2060\info%(test,0)=rowend.window=info%(test,1)-1:field.le  ":",""  6,1,0 ":State: ","CA"  8,1,-2 "(","FY1982"  0,0,0field=fieldnum value$=""input.req%(field)=01input.req%(field)<0value$=name$(field,1):row=info%(field,0)3start.window=info%(field,1)+name$(field,1)=""1600name$(field,1); @fieldE 7 "My First Screen",""  117,0,0! "Name and Address Entry",""  1,30,0 ":First Name: ",""  3,1,15 ":Last Name: ",""  3,40,20 "Address (free form)",""  5,1,0G:field=1itemsfield$=name$(field,0)field$,1,1)=":"1550field$,1,1)="("1600%=info%(field,0):=info%(field,1)name$(field,0); 1600%=info%(field,0):=info%(field,1)field$,2,field$)-1);name$(fioutfile$=""writefile=0:1055::writefile=1#2,outfile$,outlenset.edit$=21)+"0"$set.normal$=21)+"1"/& blank$ below contains 80 space characters])blank$=" "3)+12)+11)+SYNC$<:21);"5";6Ai=023:a$(i))>80a$(i),1,80);::a$(i):Fhi=1:vi=24:'Hblank24$=" " Ibnk$="""Ki=1zip:bnk$=bnk$+blank24$:Pa$:cursor=a$)[Umove=(cursor=8)+2*(cursor=21)+3*(cursor=10)+4*(cursor=11)+5*(cursor=136)+6*(cursor=149)Xb$=blank24$:t=1'Zmove+1130,100,105,110,120,135,140 _:80wdhi>tindex=vi-25:hiindex=hi-t:j=124:b$,t*j-t+1,t)=a$(index+j),hiindex,t)::hi=hi-t:rightscroll$((t=1));b$;fihi+80<=maxlenge "SOS mines" to find a number of useful things in the .CONSOLE driver that can make developing interesting applications a lot easier and more efficient. At the end of that article, which you should really read before this one if possible, a parting chall T H E T H I R D B A S I C by Taylor Pohlman Exploring Business Basic, Part 11 Last article we dug down deep in thopen#1,.printer output#1 list close as ";b$(1)*5+1));!#1;" by a ";c$(1)*5+1)); #1;" but ";d$(1)*5+1));"#1;" young ";e$(1)*5+1));K#1;" which neither of them talked to their ";f$(1)*5+1));" about."i"mother","father","grand-parents","analyst","best friends"Pi=15:a$(i):Zi=15:b$(i):di=15:c$(i):ni=15:d$(i):xi=15:e$(i):i=15:f$(i):i=1line#1;"3#,x";i;"#1;"Once a ";a$(1)*5+1)); #1;" w "captivated","impressed","repulsed","bored","completely overwhelmed":7 "handsome","pathetic","eager","reluctant","willing" 9< "wholesome","reserved","wild","enthusiastic","shy" BA "king","queen","tadpole","flagpole climber","lady marine" @F /"File to fill with assorted trash: ";file$ file$=""230 #1,file$A"How many lines of this trash do you want to create: ";line$line=0:line=line$)line<15D- "duke","prince","frog","sanitation engineer","dowager duchess"J2hi>zipt=zip:b$=bnk$ 100:(hi+79+zip<=maxlenghtt=zip:b$=bnk$ 105::26);0);23);htindex=vi-25:hiindex=80+hi:j=124:b$,t*j-t+1,t)=a$(index+j),hiindex,t)::hi=hi+t:leftscroll$((t=1));b$;k7nvi24scrolldown$;a$(vi-25),hi,80);:vi=vi-1}cursor=27:200enge was given in the form of a program listing without documentation or explanation. This time we will explore that program, and go even further into uses of the console features in constructing business oriented applications programs. Digging Out Tdow, the next command sequence (characters 26,0,23) puts the cursor at the bottom of this one-column window. There, printing a character 3 establishes the position as the lower right corner of the window. From now on, this will be the only console area wwide and 24 lines high in which to do the writing. Character sequence 26,79,0 addresses the cursor to column 79, line 0, and character 2 establishes this position as the upper right corner of a "window". Since cursor addressing is done relative to the winracter position to the left. This action leaves the rightmost column on the screen blank, which will later get filled with information previously off the screen. To create a place to put this data, the next two sets of commands create a window one column acter (decimal 22) which is used to start the action in step with the screen refresh. This helps to eliminate flicker. Next, character 23 is the command to horizontally shift the screen. The following character (255) determines that the shift is one chaLE driver, but here goes one example to help you through it: Line 41 defines the character codes necessary to set up scrolling horizontally to the left, one character position at a time. Here's how the character sequence works. First comes the sync char "+SYNC$ 55 scrolldown$=CHR$(16)+CHR$(3)+CHR$(12)+CHR$(11)+SYNC$ The lines above set up the scrolling commands to be issued to the console driver. It would be useful to follow along in your Standard Device Drivers manual in the section on the .CONSO)+CHR$(3)+CHR$(21)+"5"+CHR$(12) 46 rightscroll$(1)=SYNC$+CHR$(23)+CHR$(1)+CHR$(26)+CHR$(0)+CHR$(0)+CHR$(2)+C HR$(26)+CHR$(0)+CHR$(24)+CHR$(3)+CHR$(21)+"5"+CHR$(12) 50 scrollup$=CHR$(16)+CHR$(3)+CHR$(26)+CHR$(0)+CHR$(23)+CHR$(10)+CHR$(21)+"5 1 leftscroll$(1)=SYNC$+CHR$(23)+CHR$(255)+CHR$(26)+CHR$(79)+CHR$(0)+CHR$(2) +CHR$(26)+CHR$(0)+CHR$(24)+CHR$(3)+CHR$(21)+"5"+CHR$(12) 45 rightscroll$(0)=SYNC$+CHR$(23)+CHR$(zip)+CHR$(26)+CHR$(0)+CHR$(0)+CHR$(2) +CHR$(26)+CHR$(zip-1)+CHR$(24to set the rightmost limit) and "lastrecord" (used to set the bottom limit). 37 sync$=CHR$(22) 40 leftscroll$(0)=SYNC$+CHR$(23)+CHR$(256-zip)+CHR$(26)+CHR$(80-zip)+CHR$(0) +CHR$(2)+CHR$(26)+CHR$(zip-1)+CHR$(24)+CHR$(3)+CHR$(21)+"5"+CHR$(12) 4zip". 25 ON EOF#1 GOTO 35 30 FOR i=0 TO 500:INPUT#1;a$(i):IF LEN(a$(i))>maxlenght THEN maxlenght=LEN(a $(i)):NEXT:ELSE:NEXT 35 lastrecord=i The lines above read in the contents of the file into "a$" and set the values of "maxlenght" (used intent of the program. "Rightscroll$" and "leftscroll$" are string arrays which contain two versions of the scrolling commands for horizontal scrolling. One version will do a column at a time, and the other multiple columns, determined by the variable " many units to fast scroll by? ";zip The program starts with some initialization lines. The string array "a$" is used to hold the contents of the text file. Using the disk directly is possible, but presents some difficulties which would obscure the real, however, here's a new version with even better features (and some simplification). 1 DIM a$(500),rightscroll$(1),leftscroll$(1) 5 INPUT"File name to scroll through: ";a$ 10 IF a$="" THEN 200 15 OPEN#1,a$ 20 maxlenght=0 22 INPUT"Howhe mysterious program at the end of last month's article was designed to allow you to do four-way scrolling through text files by using a number of console features, especially windowing and horizontal scrolling. Rather than describe that previous programhich can be written to. The next two characters (decimal 21 and the literal "5") set up cursor movement options which will allow us to write data into this window very rapidly, since the "5" option has the effect of turning off scrolling and new-line, while leaving "wrap" and cursor advance intact. This means that if a single string is written into this window, the characters will spill down the screen, one per line. One 24-character string could fill the entire window, written with one print statement. izontal index ("hi") is greater than the left shift ("t") required. If everything is ok, then "index" is set to the top of the 24 lines of text to be scrolled, and the new left edge is calculated and assigned to "hiindex". Then a loop in this same line fng was to use the console horizontal shift and then fill in the empty space with the appropriate characters from the file. Here then are the routines which do the horizontal. Line 100 implements the left-arrow function by first checking to see if the hornght THEN index=vi-25:hiindex=80+hi:FOR j=1 TO 24:SUB$(b$ ,t*j-t+1,t)=MID$(a$(index+j),hiindex,t):NEXT:hi=hi+t:PRINT leftscroll$(( t=1));b$; 107 RETURN Here's where things get a bit sticky. Remember we said that the technique for scrollised to implement the "zip" mode we defined above, just watch! 100 IF hi>t THEN index=vi-25:hiindex=hi-t:FOR j=1 TO 24:SUB$(b$,t*j-t+1,t)=M ID$(a$(index+j),hiindex,t):NEXT:hi=hi-t:PRINT rightscroll$((t=1));b$; 102 RETURN 105 IF hi+80<=maxlef "move" correspond with left, right, down and up on the cursor keys. Values 5 and 6 represent the left and right arrow keys with the "open-Apple" key pressed. Remember that "open-Apple" adds 128 to the ASCII value of the key. This trick is going to be uing the logical expressions. This is really handy (Pascal users have something similar in the CASE statement). Once the "move" variable is calculated, then an ON ... GOSUB statement is used to go to the appropriate subroutine. Note that values 1,2,3,4 o0,100,105,110,120,135,140 95 TEXT:GOTO 80 The section above represents the major loop of the program. Here the cursor commands are accepted in line 80, and decoded into a command number in line 85. Be sure you understand how line 85 creates values ushe screen, for single column scroll and multiple column scroll respectively. 80 GET a$:cursor=ASC(a$) 85 move=(cursor=8)+2*(cursor=21)+3*(cursor=10)+4*(cursor=11)+5*(cursor=136)+ 6*(cursor=149) 88 b$=blank24$:t=1 90 ON move+1 GOSUB 13ther initialization. The variables "hi" and "vi" stand for horizontal and vertical indexes, which tell the program where in the text file is the lower lefthand corner of the screen. "Blank24$" and "bnk$" are areas to store data to be written rapidly to ts of each line on the screen, and that by disabling scroll, it is possible to write the screen completely full. 70 hi=1:vi=24:TEXT 72 blank24$=" " 73 bnk$="" 75 FOR i=1 TO zip:bnk$=bnk$+blank24$:NEXT These lines do furi=0 TO 23:IF LEN(a$(i))>80 THEN PRINT MID$(a$(i),1,80);:NEXT:ELSE PRI NT a$(i):NEXT The two lines above disable vertical scrolling and put the first 24 lines of the text file on the screen. Note that care is taken to put only the first 80 characterw are determined by the value of "zip". Scrolling to the right is handled in the same way, by setting up characters in "rightscroll". Check through those characters to make sure you understand what is happening. 60 HOME:PRINT CHR$(21);"5"; 65 FOR in this case, column 79, line 0) preparing us to print the missing string which will fill the blank space created by the horizontal shift. Notice also that line 40 is nearly identical, except that the position of the top left and bottom right of the windo This is much, much faster than individually positioning the cursor and then printing the characters one at a time. The last character in the string in line 41 (the form-feed character, decimal 12) serves to home the cursor to the top left of the window (ills "b$" with the appropriate contents of "a$", the array containing the file contents. The SUB$ function is used to increase the performance of this loop, by directly substituting characters in an existing string. With this complete, the horizontal index is adjusted by the width of the scroll, and then a print statement directs the special characters required to do the horizontal shift. Note that another logical expression (t=1) is used to pick the appropriate string from the two defined above. Immedikeys at an infinite number of Apple ///s has some details still to be worked out. Oh, well... Something Useful from All This Although scrolling on the screen is useful, and even fun, there are other, far more typical uses of the console features that m month's article, where a gibberish-generating program was described which is guaranteed to produce interesting things to scroll through. Some people have claimed that it can be used to create this column as well, but lining up that infinite number of mon(instead of simply saving them) and then load them into the scroll program. This works equally well with Visicalc print files, as long as the width is not over 255 characters. In addition, it you really want a text file to fool with, check back to lastmany Applewriter /// files, since it is easy to create enormous amounts of text without benefit of intervening carriage return characters. If you want to test the program with Applewriter or similar text files, you'll want to first print them out to disk s of fun playing with this program and the various text files you have laying around. One note of caution, however. This program because of the Basic limit of 255 characters maximum in a string, will not work with all text files. Among the examples are n scroll subroutine. 200 TEXT:PRINT CHR$(26);CHR$(0);CHR$(23); 210 CLOSE 220 END Last but not least, wrapup and conclusion, positioning the cursor to the bottom of the screen and terminating the program. Well, here's hoping that you have lotpen-Apple" cursor keys. Note that if the full "zip" increment on cursor movement is not possible, the routine reverts to the initial conditions, a horizontal shift of one, set in line 88. After setting the appropriate value, a gosub is executed to the maiaracters, and uses the "Escape" key (ASCII 27) as the way out of the routine. 135 IF hi>zip THEN t=zip:b$=bnk$ 137 GOSUB 100:RETURN 140 IF hi+79+zip<=maxlenght THEN t=zip:b$=bnk$ 142 GOSUB 105:RETURN Line 135 and 140 handle the case of the "Oharacters are printed and the appropriate substring is printed to the screen. Note that the MID$ function makes selecting 80 characters from the string very easy. 130 IF cursor=27 THEN POP:GOTO 200 132 RETURN Line 130 handles the case of stray ch,80);:vi=vi+1 115 RETURN 120 IF vi>24 THEN PRINT scrolldown$;MID$(a$(vi-25),hi,80);:vi=vi-1 125 RETURN Lines 110 and 120 are vertical scrolling, and therefore considerably easier. After checking to be sure that scrolling is allowed, the scroll conto one line. However, the consequence of breaking everything out neatly was considerably worse performance, and besides, after all these articles, you can probably make sense out of anything. 110 IF viitems OR info%(test,0)>row THEN end.window=79:field.len=80-star t.window:GOTO 2060 2035 IF info%(test,0)=row THEN end.window=info%(test,1)-1:field.len=end.wind ow-start.wetermine that actual input must take place, then the real work begins, as shown below: 2008 row=info%(field,0) 2010 start.window=info%(field,1)+LEN(name$(field,0))-1 2015 field.len=ABS(info%(field,2)) 2020 IF field.len<>0 THEN end.window=startw lines are fairly obvious. Using the "input.req%" array, we can quickly determine if the field is one requiring no or only default processing. Note that the string "value$" will be used to convey the result of this field's data entry process. Once we d accomplished in the subroutine at line 2000, and here's where things get a trifle tricky: 2000 field=fieldnum 2002 value$="" 2005 IF input.req%(field)=0 THEN RETURN 2006 IF input.req%(field)<0 THEN value$=name$(field,1):RETURN These first fesion about field definition, the routine above should prove very straight-forward. The next major task of our main program loop occurs at line 110, where an inner loop starts which process input from each field on the screen, one field at a time. This isGOTO 1600 1550 VPOS=info%(field,0):HPOS=info%(field,1) 1555 PRINT MID$(field$,2,LEN(field$)-1); 1560 IF name$(field,1)="" THEN 1600 1565 PRINT name$(field,1); 1600 NEXT field 1605 RETURN If you have followed along in the discus00 TEXT:HOME 1505 FOR field=1 TO items 1510 field$=name$(field,0) 1515 IF MID$(field$,1,1)=":" THEN 1550 1520 IF MID$(field$,1,1)="(" THEN 1600 1525 VPOS=info%(field,0):HPOS=info%(field,1) 1530 PRINT name$(field,0); 1535 of hard-coding it as was done in this example. In any case, line 100 begins the program's main loop for data entry. The first routine called is the subroutine at line 1500 which displays the screen according to the definitions. It looks like this: 15est of the program main loop, starting with line 25. Here and through line 45 we create a starter screen, which certainly could be more elaborate if wished. One thing that comes to mind is to prompt here for the name of the screen definition file insteadich may need to appear in the output for reference or to meet another program's requirements. That about wraps up the initalization, leaving us with a set of screen and input definitions for a simple data entry screen. Now let's go back and look at the rnght of two characters. The last example, on line 1775, is a default field which will appear in all output records. This is a useful option for including fields like dates, header data, etc. which the user should not be required to type each time, but whld, with no title (the ":" is its only definition) it will extend the entire lenght of the line, a full 80 characters of input space. Line 1765 is an example of a field with a default value, and also one (as indicated in line 1770) which has a required led lenght available to a variable lenght item, by looking ahead at what's next on the screen and adjusting accordingly. Once that is determined, line 2060 establishes the window in which data entry will take place for that item. Next is the printing of any default values, and the display (in inverse) of the field available for entry: 2065 line$=MID$(blank$,1,field.len) 2070 default$=name$(field,1):IF default$<>"" THEN SUB$(line$,1,LEN(default$) )=default$ 2075 INVERSE:HOME 2080 PRINT l be printed back into the window, this time with inverse off, to indicate that data entry is finished in that field. All of that excitement leads us back to the main loop, now at line 120, where the result of the field call is analysed. If "escape" was p20. Line 2305 processes the other option, full entry of whatever is in the window, no matter where the cursor is. As you can see, this occurs when either "Open-Apple Return" or "Tab" is pressed. "Set.normal$" turns advance back on, so that the value canoptions to signal completion. First, line 2300 processes the "Return" key, discarding anything to the right of where the return key was pressed. "Value$" is set to what's left, and "line$" is re-defined so that the actual data can be displayed in line 232350 2310 value$=line$ 2320 NORMAL:HOME:PRINT set.normal$;line$; 2325 POP:RETURN 2330 HPOS=point 2350 ON KBD GOTO 2200 2355 RETURN These lines wrap up the routine once the user is satisfied that the field is complete. There are several s the cursor keys for left and right arrow, first reprinting the current character and then resetting the pointer. 2300 IF KBD=13 THEN value$=MID$(line$,1,point-1):line$=MID$(value$,1,field.l en):GOTO 2320 2305 IF KBD<>141 AND KBD<>9 THEN 1 THEN INVERSE:PRINT MID$(line$,point,1);:point=poin t-1:GOTO 2330 2280 IF KBD=21 AND pointhat the ON KBD routine wasn't exited in the wrong state. Assuming there is room in the window, lines 2220 and 2250 update the pointer and advance the cursor to the new position. Then lines 2255 and 2260 clean up and return to the "blink" routine, awaitin 2255 ON KBD GOTO 2200 2260 RETURN After checking for control or special function characters in line 2205, the typed character is inserted into the "line$" string at the current cursor position, and the character is reprinted in inverse to be sure t is pressed. That sends the program off to line 2200: 2200 OFF KBD 2205 IF KBD<32 OR KBD>127 THEN 2270 2210 SUB$(line$,point,1)=CHR$(KBD) 2215 INVERSE:PRINT MID$(line$,point,1); 2220 IF pointX200300S=1:D=1:B=1570D$=""500 Y=X:S=ED$(D)=D$:640 X=Y440D=D+1:S=E:440D=D-1:X=0F$(X):X=0 J=1D D$=D$(J)790&J0 :œ6303DE=S+1:N$,S,1)=" "N$,S,1)=","S=S+1:580%Nž#2390 ^1000c: h#2;a$ma$rY=1150:Y0wB=B+1: Count the number of lines printed xB=15B=30355yB=60#3;12)zB=60B=1 {#3;a$|360B<=20#3;13)::410#3;12):Z=11000:ZI I=3d: PRINTER V. 1.0 ::=2::"PRINT.ALL v. 1.0":3=4:"Directory Name(s) or return to quit: ";n$N$)=0::"MENU.MAKER"430 X>0260I=11000:I:200: ,I=1X 14000 6#2,F$(I)@#3,".PRINTER" Jis one out, and some substantial re-writing of the field routines may be required, but I'll offer a copy of Quickfile /// to the earliest postmarked solution. Send a listing to Softalk marked "The Third Basic Solution", and the winning routine will be puburn" has been pressed. Normally these two different keys both return the same ASCII code, but the data entry routines above cry out for that distinction, which we provided in this article by using "Tab" and "Open-apple Return". It's not easy to figure thered a lot of esoteric goodies in the console driver. One of the least understood, but most powerful capabilities is the "two byte read", where you can programmatically get a second byte which among other things can indicate whether or not "Enter" or "Ret also, there is nothing sacred about any of the beginning of the program either. The subroutines could just as easily be used within a completely different environment to support a program's screen-handling needs. One last challenge Last article we covoutput record the value is to be placed (starting byte and lenght, for example). If you are really clever, you can modify the routine to accept multi-line fields. All these and more ideas will probably occur to you as you work with the routine. Rememberic? Does it have a fixed decimal place? Can it have a null value, or must some non-blank or non-zero value be used?) For fixed record layout output (like simulating records on a keypunch machine, yuck!) you might want to add fields to define where in the how you might incorporate these techniques into your own programs. Some things you might want to try in order to improve the program could include expanding the "info%" array to contain more information about editing (like: is the data alphabetic or numerF LEN(value$) THEN out.rec$=out.rec$+value$ 3005 RETURN 4000 PRINT#2,recordnum;out.rec$ 4010 RETURN Obviously, "real" data entry programs will have much more elaborate processing and editing functions built in. This example was only a guide to 3000. After all the fields are processed, lines 215 and 220 display it and if the file logging option was set originally, the subroutine at line 4000 writes the result in a file. Here are simple examples of what these routines could look like: 3000 IT$=N$,E,1):T$=" "T$=","610XE=E+1:E>N$)610:590bD$=N$,S,E-S)l:v:E>S+1600:D$="": œ770P=3:"Looking for ";34);D$;34);" directory." #1,D$=P3:"Reading from ";34);D$;34);" directory." lished as soon as possible in these pages. Keep koding with the kool konsole... >;:9853/&" NL64Ch5h6h3lh4m 0/L6H5H`g8640'%76,V^dKA;6hWhXhhhQlhRm e Nb YMH YhLSꈭTXHWH`gca` hhh5h66HH :5HHH) @  hhh g5ȱg6ȱg@ ɀL g eegghI8e556l6m `  hUhVh8 ㅊ eh֭VHUHk`HFBhhHHHH l5m6m6  ЙW5X6X6 ` 5`MD32KA;6hWhXhhhQlhRm e Nb YMH YhLSꈭTXHWH`g##6 >?Bi{Ci|) |=! "LL{@?>8(O\ F9 >{i 5|i6) 6|8 L5{ hhhh0 hWhXXL `L5ARTICLE12v$' 'NOTE )11/SCREEN.DATA.PGM   The Third Basic by Taylor Pohlman ca` hhh5h66HH :5HHH) @  hhh g5ȱg6ȱg@ ɀL g eegghI8e556l6m `  hUhVh8 ㅊ eh֭VHUHk`HFBREQNUM BUF "CONTROL CONTROL RETURN RETADR GETPARMS TPARMSERROR ROR STATUS STATUS BLDSTRN ,BUF |F GETPARMS1,-2 "(","FY1988"  0,0,0field=fieldnum value$=""input.req%(field)=01input.req%(field)<0value$=name$(field,1):row=info%(field,0)3start.window=info%(field,1)+name$(field,0))-1field.len=info%(field,2))<field.l 7 "My First Screen",""  117,0,0! "Name and Address Entry",""  1,30,0 ":First Name: ",""  3,1,15 ":Last Name: ",""  3,40,20 "Address (free form)",""  5,1,0  ":",""  6,1,0 ":State: ","CA"  8,ld,0)field$,1,1)=":"1550field$,1,1)="("1600%=info%(field,0):=info%(field,1)name$(field,0); 1600%=info%(field,0):=info%(field,1)field$,2,field$)-1);name$(field,1)=""1600name$(field,1); @fieldEile$,outlenset.edit$=21)+"0"$set.normal$=21)+"1"/& blank$ below contains 80 space charactersc)blank$=" "G:field=1itemsfield$=name$(fie9name$(i,0),1,1)=":"input.req%(i)=i:first.input=i,name$(i,0),1,1)="("input.req%(i)=-1j=02:info%(i,j):ji*screen$=name$(0,0):outfile$=name$(0,1) outlen=info%(0,0)1outfile$=""writefile=0:1055::writefile=1#2,outffor Screen: ";screen$;bwritefile:"Output is stored in the file ";outfile$'g=23:=1:"Press any key to quit:";la$v{3 initialize tables (could be done from a file)first.input=0 itemsi=1itemsname$(i,0),name$(i,1)'3000: add to output record string fieldnum> code to process the finished record in outrec$ goes here$::"Record is: ";out.rec$&"Press any key to continue:";:a$writefile4000recordnumX:/]:"End of Data Entry  327678i1500: Display the data entry screen with defaults kescapecode=0:out.rec$=""nfieldnum=1items,s2000: process input for field=fieldnum5xescapecodefieldnum=first.input:600::105/} Extra processing for this field goes here! screen data capture program+name$(50,1),info%(50,2),input.req%(50) 1000(:"Data Entry for Screen: ";screen$=#writefile:"with output stored in the file ";outfile$((=23:=1:"Press any key to begin:";-a$drecordnum=1FILWRITE FILWRITEGETRFNM RTRFNM ERROR ^ROR DOARRAY OARRAY  ERROR ?BUFPNT NT DEVINFO DEVINFO MOVESTR FILREAD FILREAD BUF :4 GETRFNM BUFPNT OJNT ERROR ROR DOARRAY e=TPARMSERROR uROR BUFPNT BMOVESTR REQNUM UUM BLDSTRN DSTRN BUF pia RETURN RETADR  GETPARMSFen<>0end.window=start.window+field.len-1:2060 20602info%(test,0)=rowend.window=info%(test,1)-1-field.len=end.window-start.window+1:2060test=field+1 2030% start.window,rowend.window,rowline$=blank$,1,field.len)Idefault$=name$(field,1):default$<>""line$,1,default$))=default$: line$"set.edit$;%=1:point=1 42200J9:line$,point,1);::j=1150::line$,point,1):j=1150::2105<32>1272270line$,point,1)=ŝ):lR",220(204::"79A";""; 2D=1:F=1 <#4;a$ FD=D+1 P#5;a$ZD=60#5;12)dD=60D=1nF=F+1::d$;::Y=1100:Y x13402  CATCH PASCAL TEXT FILES 202 :F*=08:"78C";"SORRY BUT MENU.MAKER CAN'T R".D1/MENU.MAKER",220 d$="" A$="PRINTING "+B$(I),16,B)=01:=0::"80C";A$;:#3,B$(I),16,B)Z=1#3;b$:"78A";b$Z=Z+1:Z=18:1290 1260 #4,B$(I),16,B)#5,".PRINTER"+ž#4#5;12):::".D1/MENU.MAKE30C$="N"C$="n"1160;:=23:=0::"79C";"PRESS ANY KEY TO HALT LISTING": $1020.202 8::Z=1B::=23:=0::"79C";"WOULD YOU LIKE A PRINTED COPY?":1C$:C$<>"Y"C$<>"y"C$<>"N"C$<>"n"1170*C$="N"C$="n"e One of disk 3BSB-03/04 for more information. We are pleased to bring you these excellent series of articles and their accompanying programs. We hope you enjoy them!! em!! sks that will contain all the articles written by Apple's Taylor Pohlman about Business Basic as found in Softalk Magazine. This disk is NOT self-booting but does include the WAP /// SIG Menu.Maker program. Please read "READ.ME. FIRST" on Sid 0 WELCOME! WAP /// SIG Public Domain Library Disk Category/Number : Business Basic/3BSB-05 Disk Format: This disk Is NOT self-booting This is the third of five di /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// SIG, Washington Apple Pi 12022 Parklawn Drive Rockville, MD. 20852 (301)-984-030 Article 12 is on Side Two of this disk! 1,point-1):line$=value$,1,field.len):2320 <>141<>92350 value$=line$ ::set.normal$;line$; :  =point . 22003 ( value$)out.rec$=out.rec$+value$ #2,recordnum;out.rec$ine$,point,1);#point1:line$,point,1);:point=point-1:2330D=21pointG$:::".D1/MENU.MAKER",320ž#1740#1;A$:A$)<4710A$,3,4)="TEXT"X=X+1710 :X>YN=P::7);"There are no text files in the ";34);D$;34);" directory." ::I=P::7);"Unable to locate and open ";34);D$;34);" directory." ::I( 3  +J FF tѤ `U t`*8`AB*0 B8` L=?՝ԝϝН ` 1`*x (DEHG 1h H J IFD`* H FFLx 7( hL8 989::m8ʥi,;Ɂ)˭5i ɠ)54`x* ,< ʝ88 (`…ʍ0Åˍ142;)5I)5i 4`)5;`xH)$ 45R8 h(`x ,<0 `Ld L)(I bL)8 ʪi)I8R & h:1ߠ*x (,< K 1x ` (`98  bLH8 xʍ6ʍ7hh)ɄJJRH88,< ʠʠ &,<0,80ʬ8ʠ6ʠ` N=    `H Wh (0­1í2L-. * <өхυ L"= N8 =i N% JL@ҭ"A N! xLC L 'Lp- >)AE)H ;LLW x0Lx:9i ՄԐhh, (MIPLIOKN`ȑȥ.- * ө<ѩ ϩ - (A= NL% AҩA N= ,>- JD)3E)X,qȑ ;?L x0LC L '5դԦ kˍ12/ *̍m%%#$  " ` L ``(%, ( *x (I  ) (j` DÈ` ȑ`! (`.-LLL$?`?` hh- (*J%/hh`դ8eԅԥ `)ߍQI "L), (3C> SHJI̍ƅԥDžծ*x (3'͝ )X@ @ ' (  L "x) Q(`x)(` 2H1H` (& ( ( (##D0C 3 "'*CFMRZ_ '058FV[fjsuw;Profile Driver -- Copyright (C) 1983 by Apple Computer Inc.`.PROFILE&%1  % &$0) `/0) `,.0L tHsH`! (xy```,.0L HH`Ln,/023x #) "# (```'+.`% (.L,/0x ('( `,.0L& (,.0L7 Đ`ʥ逅8n134nʐ3x1eʍ1,/p/H h(eʅ8ʅİLa )`Y)D00L:1?24n2")Copyright (C) 1983 by Apple Computer Inc. HH` (# (KXT .")"#)  #`,.$ ()-'( / 2010C$="N"C$="n"200;:=23:=0::"79C";"PRESS ANY KEY TO HALT LISTING": 20002,280,21 DF$(I)=D$+"/DISKNAME.DAT"F$(I)=D$+"/FLASHNAME.DAT"410:ۺ310 PRINTER v 1.0 p$ 900A$="PRINTING"+F$(I):$=01:=0::"80C";A$;::12)F=23:=0::"79C";"PRESS ANY KEY TO HALT PRINTING"::2,280,21 2000*:=23:=0::"79C";"CONTINUE...?":1C$:C$<>"Y"C$<>"y"C$<>"N"C$<>"n"#1,D$::"Processing directory ";34);D$;34);", please wait."; ž#1880*#1;A$:A$)<48104A$,3,4)<>"TEXT"810>X=X+1:".";HE=15:F$=A$,16,15)RF$,E,1)=" "E=E-1:850\F$(X)=D$+"/"+F$,E)f810p:  Pause(̠`x (̠` [   `L `` ``I FF x (̠%L#fowz*13579;=?ACFNWaehmpx "'+@\mrv{