1: Creating and running programs 2: Variables and constants 3: Loops and branches 4: Calling procedures 5: Data file handling PROC openfile: IF NOT EXIST("example") CREATE "example",A,int%,lng&,fp,str$ ELSE OPEN "example",A,int%,lng&,fp,str$ ENDIF PRINT "Current values:" show: PRINT "Assigning values" A.int%=1 A.lng&=&2**20 REM the 1st & avoids integer overflow A.fp=SIN(PI/6) PRINT "Give a value for the string:" INPUT A.str$ PRINT "New values:" show: ENDP PROC show: PRINT "integer=";A.int% PRINT "long=";A.lng& PRINT "float=";A.fp PRINT "string=";A.str$ GET ENDP PROC count: LOCAL reply% OPEN "example",A,f%,f&,f,f$ DO CLS AT 20,1 :PRINT "Record count=";COUNT AT 9,5 :PRINT "(A)dd a record" AT 9,7 :PRINT "(Q)uit" reply%=GET IF reply%=%q OR reply%=%Q BREAK ELSEIF reply%=%A OR reply%=%a add: ELSE BEEP 16,250 ENDIF UNTIL 0 ENDP PROC add: CLS PRINT "Enter integer field:"; INPUT A.f% PRINT "Enter long integer field:"; INPUT A.f& PRINT "Enter numeric field:"; INPUT A.f PRINT "Enter string field:"; INPUT A.f$ APPEND ENDP FIRST WHILE FIND("*BROWN*") PRINT a.name$, a.phone$ NEXT GET ENDWH PROC copyrec: OPEN "example",A,f%,f&,f,f$ TRAP DELETE "temp" REM If file doesn't exist, ignore error CREATE "temp",B,f%,f&,f,f$ PRINT "Copying EXAMPLE to TEMP" USE A REM the EXAMPLE file DO IF a.f%>30 and a.f<3.1415 b.f%=a.f% b.f&=a.f& b.f=a.f b.f$="Selective copy" USE B REM the TEMP file APPEND USE A ENDIF NEXT UNTIL EOF REM until End Of File CLOSE REM closes A; B becomes current CLOSE REM closes B ENDP p%=PEEKW($1c)+$1e POKEW p%,PEEKW(p%) or 1 p%=PEEKW($1c)+$1e POKEW p%,PEEKW(p%) and $fffe 6: Graphics PROC exgrey: DEFAULTWIN 1 REM enable grey gAT 0,40 :gGREY 1 :gLINEBY 480,0 REM grey only gAT 0,41 :gLINEBY 480,0 gAT 0,80 :gGREY 0 :gLINEBY 480,0 REM black only gAT 0,81 :gLINEBY 480,0 gAT 0,120 :gGREY 2 :gLINEBY 480,0 REM both planes gAT 0,121 :gLINEBY 480,0 GET gGREY 0 REM black only gCLS REM clear it GET ENDP PROC face: gFILL 120,120,0 REM set the entire face gMOVE 10,20 :gFILL 30,20,1 REM left eye gMOVE 70,0 :gFILL 30,20,1 REM right eye gMOVE -30,30 :gFILL 20,30,1 REM nose gMOVE -20,40 :gFILL 60,20,1 REM mouth GET ENDP PROC wink: gMOVE 10,20 REM move to left eye gFILL 30,14,2 REM invert most of the eye PAUSE 10 gFILL 30,14,2 REM invert it back again GET ENDP PROC brow: gGMODE 1 REM gLINEBY will now clear pixels gMOVE 10,8 :gLINEBY 100,0 gMOVE 0,4 :gLINEBY -100,0 gGMODE 0 GET ENDP PROC fonts: showfont:(4,15,"Mono 8x8") showfont:(5,25,"Roman 8") showfont:(6,38,"Roman 11") showfont:(7,53,"Roman 13") showfont:(8,71,"Roman 16") showfont:(9,81,"Swiss 8") showfont:(10,94,"Swiss 11") showfont:(11,109,"Swiss 13") showfont:(12,127,"Swiss 16") showfont:(13,135,"Mono 6x6") GET ENDP PROC showfont:(font%,y%,str$) gFONT font% gAT 20,y% :gPRINT font% gAT 50,y% :gPRINT str$ gAT 150,y% :gPRINT "!!!" ENDP PROC style: gAT 20,50 :gFONT 11 gSTYLE 12 :gPRINT "Attention!" GET ENDP PROC tmode: DEFAULTWIN 1 REM enable grey gFONT 11 :gSTYLE 0 gAT 160,0 :gFILL 160,80,0 REM Black box gAT 220,0 :gFILL 40,80,1 REM White box gAT 180,20 :gTMODE 0 :gPRINT "ABCDEFGHIJK" gAT 180,35 :gTMODE 1 :gPRINT "ABCDEFGHIJK" gAT 180,50 :gTMODE 2 :gPRINT "ABCDEFGHIJK" gAT 180,65 :gTMODE 3 :gPRINT "ABCDEFGHIJK" gGREY 1 gAT 160,80 :gFILL 160,80,0 REM Grey box gAT 220,80 :gFILL 40,80,1 REM White box gAT 180,100 :gTMODE 0 :gPRINT "ABCDEFGHIJK" gAT 180,115 :gTMODE 1 :gPRINT "ABCDEFGHIJK" gAT 180,130 :gTMODE 2 :gPRINT "ABCDEFGHIJK" gAT 180,145 :gTMODE 3 :gPRINT "ABCDEFGHIJK" GET ENDP PROC windows: LOCAL id% id%=gCREATE(60,40,240,30,1,1) gBORDER 0 :gAT 20,20 :gLINEBY 0,0 gPRINT " 20,20 (new)" GET gUSE 1 :gAT 20,20 :gLINEBY 0,0 gPRINT " 20,20 (default)" GET gUSE id% gGREY 1 REM draw grey gPRINT " Back" gGREY 0 gPRINT " (with grey)" GET ENDP PROC gsetw1: LOCAL a$(100),w%,h%,g$(1),factor%,info%(10) LOCAL margx%,margy%,chrw%,chrh%,defw%,defh% SCREENINFO info%() REM get text window information margx%=info%(1) :margy%=info%(2) chrw%=info%(7) :chrh%=info%(8) defw%=23*chrw%+2*margx% REM new default window width defh%=chrh%+2*margy% REM ... and height w%=gWIDTH :h%=gHEIGHT gSETWIN w%/4+margx%,h%/4+margy%,defw%,defh% SCREEN 23,1,1,1 REM text window PRINT "Text win:"; :GET gCREATE(w%*.1,h%*.1,w%*.8,h%*.8,1) REM new window gPATT -1,gWIDTH,gHEIGHT,0 REM shade it gAT 2,h%*.7 :gTMODE 4 gPRINT "Graphics window 2" gORDER 1,0 REM back to default+text window EDIT a$ REM you can see this edit gORDER 1,9 REM to background CLS a$="" PRINT "Hidden:"; GIPRINT "Edit in hidden edit box" EDIT a$ REM YOU CAN'T SEE THIS EDIT GIPRINT "" gORDER 1,0 :GET REM now here it is gUSE 1 REM graphics go to default window DO REM move default/text window around CLS PRINT "U,D,L,R,Quit"; g$=UPPER$(GET$) IF kmod=2 REM Shift key moves quickly factor%=10 ELSE factor%=1 ENDIF IF g$="U" gSETWIN gORIGINX,gORIGINY-factor% ELSEIF g$="D" gSETWIN gORIGINX,gORIGINY+factor% ELSEIF g$="L" gSETWIN gORIGINX-factor%,gORIGINY ELSEIF g$="R" gSETWIN gORIGINX+factor%,gORIGINY ENDIF UNTIL g$="Q" OR g$=CHR$(27) ENDP 7: Friendlier interaction PROC kget%: LOCAL k%,h$(9),a$(5) h$="nosciefgd" REM our hot-keys WHILE 1 k%=GET IF k%=$122 REM Menu key? mINIT mCARD "File","New",%n,"Open",%o,"Save",%s mCARD "Edit","Copy",%c,"Insert",-%i,"Eval",%e mCARD "Search","First",%f,"Next",%g,"Previous",%d k%=MENU IF k% AND (LOC(h$,CHR$(k%))<>0) REM MENU CHECK a$="proc"+CHR$(k%) @(a$): REM procn:, proco:, ... ENDIF REM END OF MENU CHECK ELSEIF k% AND $200 REM hot-key pressed directly? k%=k%-$200 REM remove Psion key code IF LOC(h$,CHR$(k%)) REM DIRECT HOT-KEY CHECK a$="proc"+CHR$(k%) @(a$): REM procn:, proco:, ... ENDIF REM END OF DIRECT HOT-KEY CHECK ELSE REM some other key RETURN k% ENDIF ENDWH ENDP PROC procn: ... ENDP PROC proco: ... ENDP IF k%<=%Z REM if upper case hot-key IF LOC(hu$,CHR$(k%)) a$="procu"+CHR$(k%) @(a$) :REM procua:, procuc:, ... ENDIF ELSE REM else lower case hot-key IF LOC(hl$,CHR$(k%)) a$="procl"+CHR$(k%) @(a$) :REM procla:, procld:, ... ENDIF ENDIF PROC dcheck: LOCAL c% c%=2 REM default to "Internal" dINIT "Disk Check" dCHOICE c%,"Disk:","A,Internal,B" IF DIALOG REM returns 0 if cancelled ... REM disk-check code ENDIF ENDP PROC delivery: LOCAL d&,t&,num&,wt d&=DAYS(DAY,MONTH,YEAR) DO t&=secs&: UNTIL t&=secs&: num&=1 :wt=10 dINIT "Delivery" dLONG num&,"Boxes",1,1000 dFLOAT wt,"Weight (kg)",0,10000 dDATE d&,"Date",d&,DAYS(31,12,1999) dTIME t&,"Time",0,0,DATETOSECS(1970,1,1,23,59,59) IF DIALOG REM returns 0 if cancelled ... REM rest of code ENDIF ENDP PROC secs&: RETURN HOUR*INT(3600)+MINUTE*60 ENDP PROC daytodat:(days&) LOCAL dyscent&(2),dateent%(4) LOCAL flags%,ax%,bx%,cx%,dx%,si%,di% dyscent&(1)=days& si%=ADDR(dyscent&()) :di%=ADDR(dateent%()) ax%=$0600 REM TimDaySecondsToDate fn. flags%=OS($89,ADDR(ax%)) REM TimManager int. IF flags% AND 1 RAISE (ax% OR $ff00) ELSE year%=PEEKB(di%)+1900 :month%=PEEKB(UADD(di%,1))+1 day%=PEEKB(UADD(di%,2))+1 :yrdy%=PEEKW(UADD(di%,6))+1 ENDIF ENDP PROC selact: dINIT "Select action" dTEXT "","Add",$402 dTEXT "","Copy",$402 dTEXT "","Review",$402 dTEXT "","Delete",$402 RETURN DIALOG ENDP 8: OPL and Solid State Disks PROC delx300: LOCAL a$(3),c% a$="MAB" :c%=1 REM default to "Internal" dINIT "Delete X300 data file" dCHOICE c%,"Disk:","Internal,A,B" IF DIALOG REM returns 0 if cancelled DELETE MID$(A$,c%,1)+":X300" ENDIF ENDP 9: Example programs PROC timer: LOCAL min&,sec&,secs&,i% CACHE 2000,2000 sec&=1 dINIT "Countdown timer" dLONG min&,"Minutes",0,59 dLONG sec&,"Seconds",0,59 dBUTTONS "Cancel",-27,"Start",13 IF DIALOG=13 STATUSWIN ON FONT 11,16 secs&=sec&+60*min& WHILE secs& PAUSE -20 REM a key gets us out IF KEY RETURN ENDIF secs&=secs&-1 AT 20,6 :PRINT NUM$(secs&/60,-2);"m" AT 24,6 :PRINT NUM$(mod&:(secs&,int(60)),-2);"s" ENDWH DO BEEP 5,300 PAUSE 10 IF KEY :BREAK :ENDIF i%=i%+1 UNTIL i%=10 ENDIF ENDP PROC mod&:(a&,b&) REM modulo function REM computes (a&)mod(b&) RETURN a&-(a&/b&)*b& ENDP PROC dice: LOCAL dice% DO CLS :PRINT "DICE ROLLING:" AT 1,3 :PRINT "Press a key to stop" DO dice%=(RND*6+1) AT 1,2 :PRINT dice% UNTIL KEY BEEP 5,300 dINIT "Roll again?" dBUTTONS "No",%N,"Yes",%Y UNTIL DIALOG<>%y ENDP PROC Birthday: LOCAL day&,month&,year&,DayInWk% DO dINIT dTEXT "","Enter your date of birth",2 dTEXT "","Use numbers, eg 23 12 1963",$202 dLONG day&,"Day",1,31 dLONG month&,"Month",1,12 dLONG year&,"Year",1900,2155 IF DIALOG=0 BREAK ENDIF DayInWk%=DOW(day&,month&,year&) CLS :PRINT DAYNAME$(DayInWk%),day&,month&,year& dINIT "Again?" dBUTTONS "No",%N,"Yes",%Y UNTIL DIALOG<>%y ENDP PROC files: GLOBAL nm$(255),ad1$(255),ad2$(255) GLOBAL ad3$(255),ad4$(255),tel$(255),title$(30) LOCAL g% OPEN "DATA",A,nm$,ad1$,ad2$,ad3$,ad4$,tel$ DO CLS dINIT "Select action" dTEXT "","Add new record",$402 dTEXT "","Find and edit a record",$402 g%=DIALOG IF g%=2 add: ELSEIF g%=3 edit: ENDIF UNTIL g%=0 CLOSE ENDP PROC add: nm$="" :ad1$="" :ad2$="" ad3$="" :ad4$="" :tel$="" title$="Enter a new record" IF showd%: APPEND ENDIF ENDP PROC edit: LOCAL search$(30),p% dINIT "Find and edit a record" dEDIT search$,"Search string",15 IF DIALOG FIRST IF FIND("*"+search$+"*")=0 ALERT("No matching records") RETURN ENDIF DO nm$=A.nm$ :ad1$=A.ad1$ :ad2$=A.ad2$ ad3$=A.ad3$ :ad4$=A.ad4$ :tel$=A.tel$ title$="Edit matching record" IF showd%: UPDATE :BREAK ELSE NEXT ENDIF FIND("*"+search$+"*") IF EOF ALERT("No more matching records") BREAK ENDIF UNTIL 0 ENDIF ENDP PROC showd%: LOCAL ret% dINIT title$ dEDIT nm$,"Name",25 dEDIT ad1$,"Street",25 dEDIT ad2$,"Town",25 dEDIT ad3$,"County",25 dEDIT ad4$,"Postcode",25 dEDIT tel$,"Phone",25 ret%=DIALOG IF ret% A.nm$=nm$ :A.ad1$=ad1$ :A.ad2$=ad2$ A.ad3$=ad3$ :A.ad4$=ad4$ :A.tel$=tel$ ENDIF RETURN ret% ENDP PROC reorder: LOCAL last%,e$(255),e%,lpos%,n$(128),c% n$="\dat\*.dbf" dINIT "Re-order Data file" dFILE n$,"Filename",0 IF DIALOG REM returns 0 if cancelled OPEN n$,a,a$ LAST :last%=POS IF COUNT>0 WHILE last%<>0 POSITION last% :e%=POS e$=UPPER$(a.a$) DO IF UPPER$(a.a$)s% s%=SECOND :se%=se%+1 IF se%=60 :se%=0:mi%=mi%+1 :ENDIF AT 17,8 PRINT "Mins",mi%,"Secs", IF se%<10 :PRINT "0"; :ENDIF PRINT se%;" "; ENDIF GOTO loop:: pause:: mINIT mCARD "Watch","Restart",%r,"Zero",%z,"Exit",%x k%=MENU IF k%=%r GOTO loop:: ENDIF UNTIL k%<>%z ENDP PROC label: LOCAL a%,b%,c%,d%,s$(128),s&,i$(17,255) s$="\dat\*.dbf" dINIT "Insert new field" dFILE s$,"Data file",0 dLONG s&,"Break at line (1-16)",1,16 IF DIALOG OPEN s$,A,a$,b$,c$,d$,e$,f$,g$,h$,i$,j$,k$,l$,m$,n$,o$,p$,q$ c%=COUNT :a%=1 WHILE a%<=c% AT 1,1 :PRINT "Entry",a%,"of",c%, IF A.q$="" REM Entry (hopefully) not too long i$(1)=A.a$ :i$(2)=A.b$ :i$(3)=A.c$ :i$(4)=A.d$ i$(5)=A.e$ :i$(6)=A.f$ :i$(7)=A.g$ :i$(8)=A.h$ i$(9)=A.i$ :i$(10)=A.j$ :i$(11)=A.k$ :i$(12)=A.l$ i$(13)=A.m$ :i$(14)=A.n$ :i$(15)=A.o$ :i$(16)=A.p$ d%=0 :b%=0 WHILE d%255... b%=b%+1 REM ...so it's 2 fields ENDIF ENDWH b%=17 WHILE b%>d% REM copy the fields down i$(b%)=i$(b%-1) :b%=b%-1 ENDWH i$(d%)="" REM and make an empty field A.a$=i$(1) :A.b$=i$(2) :A.c$=i$(3) :A.d$=i$(4) A.e$=i$(5) :A.f$=i$(6) :A.g$=i$(7) :A.h$=i$(8) A.i$=i$(9) :A.j$=i$(10) :A.k$=i$(11) :A.l$=i$(12) A.m$=i$(13) :A.n$=i$(14) :A.o$=i$(15) :A.p$=i$(16) A.q$=i$(17) ELSE PRINT "has too many fields" PRINT "Press a key..." :GET ENDIF UPDATE :FIRST a%=a%+1 ENDWH :CLOSE ENDIF ENDP PROC bounce: LOCAL posX%,posY%,changeX%,changeY%,k% LOCAL scrx%,scry%,info%(10) SCREENINFO info%() scrx%=info%(3) :scry%=info%(4) posX%=1 :posY%=1 changeX%=1 :changeY%=1 DO posX%=posX%+changeX% posY%=posY%+changeY% IF posX%=1 OR posX%=scrx% changeX%=-changeX% REM at edge ball changes direction BEEP 2, 600 REM low beep ENDIF IF posY%=1 or posY%=scry% REM same for y changeY%=-changeY% BEEP 2, 200 REM high beep ENDIF AT posX%,posY% :PRINT "0"; PAUSE 2 REM Try changing this AT posX%,posY% :PRINT " "; REM removes old `0' character k%=KEY UNTIL k% ENDP PROC circle: LOCAL a%(963),c&,d%,x&,y&,r&,h,y%,y1%,c2% dINIT "Draw a circle" x&=240 :dLONG x&,"Centre x pos",0,479 y&=80 :dLONG y&,"Centre y pos",0,159 r&=20 :dLONG r&,"Radius",1,120 h=1 :dFLOAT h,"Relative height",0,999 IF DIALOG a%(1)=x&+r& :a%(2)=y& :a%(3)=4*r& c&=1 :d%=2*r& :y1%=0 WHILE c&<=d% c2%=c&*2 :y%=-SQR(r&*c2%-c&**2)*h a%(2+c2%)=-2 :a%(3+c2%)=y%-y1% y1%=y% :c&=c&+1 ENDWH c&=1 WHILE c&<=d% c2%=c&*2 :y%=SQR(r&*c2%-c&**2)*h a%(2+a%(3)+c2%)=2 :a%(3+a%(3)+c2%)=y%-y1% y1%=y% :c&=c&+1 ENDWH gPOLY a%() ENDIF ENDP PROC circlef: LOCAL c&,d%,x&,y&,r&,h,y% dINIT "Draw a filled circle" x&=240 :dLONG x&,"Centre x pos",0,479 y&=80 :dLONG y&,"Centre y pos",0,159 r&=20 :dLONG r&,"Radius",1,120 h=1 :dFLOAT h,"Relative height",0,999 IF DIALOG c&=1 :d%=2*r& :gAT x&-r&,y& :gLINEBY 0,0 WHILE c&<=d% y%=-SQR(r&*c&*2-c&**2)*h gAT x&-r&+c&,y&-y% :gLINEBY 0,2*y% c&=c&+1 ENDWH ENDIF ENDP PROC tzoom: STATUSWIN OFF REM no status window zoom: REM display with zooming STATUSWIN ON,2 REM large status window zoom: STATUSWIN ON,1 REM and small zoom: ENDP PROC zoom: LOCAL font%(3),font$(3,20),style%(3) LOCAL g%,km%,zoom% zoom%=1 font%(1)=13 :font$(1)="(Mono 6x6)" :style%(1)=0 font%(2)=4 :font$(2)="(Mono 8x8)" :style%(2)=0 font%(3)=12 :font$(3)="(Swiss 16)" :style%(3)=16 g%=%z+$200 DO IF g%=%z+$200 IF km% AND 2 REM Shift-PSION-Z zoom%=zoom%-1 IF zoom%<1 :zoom%=3 :ENDIF ELSE REM PSION-Z zoom%=zoom%+1 IF zoom%>3 :zoom%=1 :ENDIF ENDIF FONT font%(zoom%),style%(zoom%) PRINT "Font=";font%(zoom%),font$(zoom%), PRINT "Style=";style%(zoom%) dispinfo: PRINT rept$("1234567890",15) gBORDER 0 ENDIF g%=GET km%=KMOD UNTIL g%=27 ENDP PROC dispinfo: LOCAL scrInfo%(10) SCREENINFO scrInfo%() PRINT "Left margin=";scrInfo%(1), AT 17,2 :PRINT "Top margin=";scrInfo%(2) PRINT "Screen width=";scrInfo%(3) AT 17,3 :PRINT "Screen height=";scrInfo%(4) PRINT "Char width=";scrInfo%(7) AT 17,4 :PRINT "Line height=";scrInfo%(8) ENDP PROC animate: LOCAL id%(5),i%,j%,s$(5,10),w%,h% w%=16 :h%=28 REM example width and height s$(1)="one" :s$(2)="two" :s$(3)="three" s$(4)="four" :s$(5)="five" :j%=1 WHILE j%<6 i%=gLOADBIT(s$(j%)) id%(j%)=gCREATE(0,0,w%,h%,0) gCOPY i%,0,0,w%,h%,3 gCLOSE i% :j%=j%+1 ENDWH i%=0 :gORDER 1,9 DO j%=(i%-5*(i%/5))+1 REM (i% MOD 5)+1 gVISIBLE OFF REM previous window gUSE id%(j%) REM new window gSETWIN i%,20 REM position it gORDER id%(j%),1 REM make foreground gVISIBLE ON REM make visible i%=i%+1 :PAUSE 2 UNTIL KEY OR (i%>(480-w%)) REM screen edge ENDP PROC main: local ret%,sndHand% ret%=IOOPEN(sndHand%,"SND:",-1) REM open the device if ret%<0 print "Failed to start" print err$(err) get else icecream:(sndHand%) ioclose(sndHand%) endif ENDP PROC icecream:(sndHand%) local notes1%(4),notes2%(14) local s1stat%,len1%,len2% REM define 1st voice notes1%(1)=1048 :notes1%(2)=96 REM freq, duration notes1%(3)=524 :notes1%(4)=48 len1%=2 REM number of notes in voice 1 REM define 2nd voice notes2%(1)=1048 :notes2%(2)=16 notes2%(3)=1320 :notes2%(4)=16 notes2%(5)=1568 :notes2%(6)=16 notes2%(7)=2092 :notes2%(8)=16 notes2%(9)=1568 :notes2%(10)=16 notes2%(11)=1320 :notes2%(12)=16 notes2%(13)=1048 :notes2%(14)=48 len2%=7 REM number of notes in voice 2 IOC(sndhand%,1,s1stat%,notes1%(),len1%) REM voice 1 asynchronous IOW(sndHand%,2,notes2%(),len2%) REM voice 2 synchronous IOWAITSTAT s1stat% ENDP 10: Error handling 11: Advanced topics APP myapp0 TYPE $1000 ICON "\opd\me" ENDA PROC start: GLOBAL a%(6),k% STATUSWIN ON :FONT 11,16 PRINT "Q to Quit" PRINT " or press Delete in" PRINT " the System screen" DO k%=getk%: PRINT CHR$(k%); UNTIL (k% AND $ffdf)=%Q REM Quick way to do uppercase ENDP PROC getk%: DO GETEVENT a%() IF a%(1)=$404 IF LEFT$(GETCMD$,1)="X" endit: ENDIF ENDIF UNTIL a%(1)<256 RETURN a%(1) ENDP PROC endit: STOP ENDP APP myapp3 TYPE $1003 ICON "\opd\me" ENDA PROC start: GLOBAL a%(6),k%,w$(128) STATUSWIN ON :FONT 11,16 :w$=CMD$(2) fset:(CMD$(3)) PRINT "Q to Quit" PRINT " or press Delete in" PRINT "the System screen" PRINT " or create/swap files in" PRINT "the System screen" DO k%=getk%: PRINT CHR$(k%); UNTIL (k% AND $ffdf)=%Q ENDP PROC getk%: LOCAL t$(1) DO GETEVENT a%() IF a%(1)=$404 w$=GETCMD$ t$=LEFT$(w$,1) w$=MID$(w$,2,128) IF t$="X" endit: ELSEIF t$="C" OR t$="O" TRAP CLOSE IF ERR CLS :PRINT ERR$(ERR) GET :CONTINUE ENDIF fset:(t$) ENDIF ENDIF UNTIL a%(1)<256 RETURN a%(1) ENDP PROC fset:(t$) LOCAL p%(6) IF t$="C" TRAP DELETE w$ REM SYS.SCREEN DOES ANY "OVERWRITE?" TRAP CREATE w$,A,A$ ELSEIF t$="O" TRAP OPEN w$,A,A$ ENDIF IF ERR CLS :PRINT ERR$(ERR) GET :STOP ENDIF SETNAME w$ ENDP PROC endit: STOP ENDP PROC myicon: gCREATE(0,0,48,48,1,1) gBORDER $200 gAT 6,28 gPRINT "me!" gSAVEBIT "me" ENDP PROC beepon: local a%(6) print "Hello" call($6c8d) :gupdate while 1 do getevent a%() if a%(1)=$404 :stop :endif :REM closedown until a%(1)=$403 :REM machine ON call($198d,0,0) :gupdate beep 5,300 :pause 10 :beep 5,500 call($198d,100,0) :gupdate endwh ENDP CACHEHDR ADDR(hdr%()) IF hdr%(10)=0 PRINT "No cache created yet" RETURN ENDIF IF hdr%(8)=0 rem MRU zero? PRINT "None cached currently" RETURN ENDIF rec%(1)=0 rem MRU first DO CACHEREC ADDR(rec%()),rec%(1) rem less recently used proc PRINT PEEK$(ADDR(rec%(8))),rec%(7) rem name and size UNTIL rec%(1)=0 PROC sprite: LOCAL bit$(6,6),sprId% crBits: REM create bitmap files gAT gWIDTH/2,0 gFILL gWIDTH/2,gHEIGHT,0 REM fill half of screen sprId%=CREATESPRITE bit$(1)="" :bit$(2)="" bit$(3)="cross" REM black cross, pixels inverted bit$(4)="" :bit$(5)="" :bit$(6)="" APPENDSPRITE 5,bit$(),0,0 REM cross for half a second bit$(1)="" :bit$(2)="" :bit$(3)="" bit$(4)="" :bit$(5)="" :bit$(6)="" APPENDSPRITE 5,bit$(),0,0 REM blank for half a second DRAWSPRITE gWIDTH/2-5,gHEIGHT/2-5 REM animate the sprite BUSY "flash cross, c",3 REM no offset REM ('c' for central) GET bit$(3)="box" REM black box, pixels inverted CHANGESPRITE 2,5,bit$(),0,0 REM in 2nd bitmap-set BUSY "cross/box, c/c",3 REM central/central GET CHANGESPRITE 2,5,bit$(),40,0 REM offset by 40 pixels right BUSY "cross/box, c/40",3 REM central/40 GET bit$(3)="" REM Remove the cross in set 1 CHANGESPRITE 1,3,bit$(),0,0 REM display for 3/10 seconds BUSY "flash box, 40",3 REM box at offset 40 still GET bit$(3)="cross" CHANGESPRITE 1,5,bit$(),0,0 REM cross centralised - set 1 bit$(3)="box" CHANGESPRITE 2,5,bit$(),0,0 REM box centralised - set 2 BUSY "Escape quits" DO POSSPRITE RND*(gWIDTH-11),RND*(gHEIGHT-11) REM move sprite randomly PAUSE -20 REM once a second UNTIL KEY = 27 CLOSESPRITE sprId% ENDP PROC crBits: REM create bitmap files if they don't exist IF NOT EXIST("cross.pic") OR NOT EXIST("box.pic") gCREATE(0,0,11,11,1,1) gAT 5,0 :gLineBy 0,11 gAT 0,5 :gLineBy 11,0 gSAVEBIT "cross" gCLS gAT 0,0 gBOX gWIDTH,gHEIGHT gSAVEBIT "box" gCLOSE gIDENTITY ENDIF ENDP PROC ioType: LOCAL ret%,fName$(128),txt$(255),address% LOCAL handle%,mode%,k% PRINT "Filename?", :INPUT fName$ : CLS mode%= $0400 OR $0020 REM open=$0000, text=$0020, share=$0400 ret%=IOOPEN(handle%,fName$,mode%) IF ret%<0 showErr:(ret%) RETURN ENDIF address%=ADDR(txt$) WHILE 1 k%=KEY IF k% REM if keypress IF k%=27 REM Esc pressed RETURN REM otherwise wait for a key ELSEIF GET=27 RETURN REM Esc pressed ENDIF ENDIF ret%=IOREAD(handle%,address%+1,255) IF ret%<0 IF ret%<>-36 REM NOT EOF showErr:(ret%) ENDIF BREAK ELSE POKEB address%,ret% REM leading byte count PRINT txt$ ENDIF ENDWH ret%=IOCLOSE(handle%) IF ret% showErr:(ret%) ENDIF PAUSE -100 :KEY ENDP PROC showErr:(val%) PRINT "Error",val%,err$(val%) GET ENDP PROC iotest: GLOBAL x1%,x2%,y1%,y2% LOCAL i%,h$(2),a$(5) x1%=2 :y1%=2 x2%=25 :y2%=5 REM our test screensize SCREEN x2%-x1%,y2%-y1%,x1%,y1% AT 1,1 PRINT "Text window IO test" PRINT "Psion-Esc quits" h$="cr" REM our hot-keys DO i%=GET IF i%=$122 REM Menu key mINIT mCARD "Set","Rect",%r mCARD "Sense","Cursor",%c i%=MENU IF i% AND INTF(LOC(h$,CHR$(i%))) a$="proc"+chr$(i%) @(a$): ENDIF ELSEIF i% AND $200 REM hot-key i%=(i%-$200) i%=LOC(h$,CHR$(i%)) REM One of ours? IF i% a$="proc"+MID$(h$,i%,1) @(a$): ENDIF REM ignore other weird keypresses ELSE REM some other key, so return it PRINT CHR$(i%); ENDIF UNTIL 0 ENDP PROC procc: LOCAL a& a&=iocurs&: PRINT "x";1+(a& AND &ffff); PRINT "y";1+(a&/&10000); ENDP PROC procr: LOCAL xx1%,yy1%,xx2%,yy2% LOCAL xx1&,yy1&,xx2&,yy2& dINIT "Clear rectangle" dLONG xx1&,"Top left x",1,x2%-x1% dLONG yy1&,"Top left y",1,y2%-y1% dLONG xx2&,"Bottom left x",2,x2%-x1% dLONG yy2&,"Bottom left y",2,y2%-y1% IF DIALOG xx1%=xx1&-1 :xx2%=xx2&-1 yy1%=yy1&-1 :yy2%=yy2&-1 iorect:(xx1%,yy1%,xx2%,yy2%) ENDIF ENDP PROC iocurs&: LOCAL a%(4),a& REM don't change the order of these! a%(1)=x1% :a%(2)=y1% a%(3)=x2% :a%(4)=y2% IOW(-2,8,a%(),a%()) REM 2nd a% is ignored RETURN a& ENDP PROC iorect:(xx1%,yy1%,xx2%,yy2%) LOCAL i%,a%(6) i%=2 :REM "clear rect" option a%(1)=xx1% :a%(2)=yy1% a%(3)=xx2% :a%(4)=yy2% IOW(-2,7,i%,a%()) ENDP PROC alm: LOCAL h%,a&(2),a$(64),b$(65),d&,t&,t2&,a%,r%,s% r%=IOOPEN(h%,"ALM:",0) IF r%<0 :RAISE r% :ENDIF d&=DAYS(DAY,MONTH,YEAR) REM today t&=DATETOSECS(1970,1,1,HOUR,MINUTE,0) DINIT "Set alarm" DTIME t&,"Time",0,0,DATETOSECS(1970,1,1,23,59,59) DDATE d&,"Date",d&,DAYS(31,12,2049) DTIME t2&,"Alarm advance time",2,0,86399 DEDIT a$,"Message" IF DIALOG a&(2)=86400*(d&-25567)+t& a&(1)=a&(2)-t2& b$=a$+CHR$(0) REM zero-terminate the string IOC(h%,2,s%,a&(),#UADD(ADDR(b$),1)) ENDIF IOCLOSE(h%) ENDP PROC dtmf: LOCAL h%,a$(24),b$(25),z%,r%,a%(2) r%=IOOPEN(h%,"SND:",0) IF r%<0 :RAISE r% :ENDIF dINIT dEDIT a$,"Dial" IF DIALOG a%(1)=8+(256*8) a%(2)=48 b$=a$+CHR$(0) r%=IOW(h%,10,#UADD(ADDR(b$),1),a%()) IF r%<0 :RAISE r% :ENDIF ENDIF r%=IOCLOSE(h%) IF r%<0 :RAISE r% :ENDIF ENDP PROC recorda:(pstat%,inname$,size%) LOCAL name$(128) name$=inname$+chr$(0) CALL($2186,UADD(ADDR(name$),1),size%,0,0,pstat%) ENDP PROC recordc: CALL($2386) ENDP PROC recordw%:(inname$,size%) LOCAL name$(128),p%,ret% p%=PEEKW($1c)+6 REM address of saved flags after CALL name$=inname$+chr$(0) ret%=CALL($2286,UADD(ADDR(name$),1),size%) IF PEEKW(p%) AND 1 REM carry set for error RETURN ret% OR $FF00 REM return error ENDIF ENDP PROC playa:(pstat%,inname$,ticks%,vol%) LOCAL name$(128) name$=inname$+chr$(0) CALL($1E86,UADD(ADDR(name$),1),ticks%,vol%,0,pstat%) ENDP PROC playc: CALL($2086) ENDP PROC playw%:(inname$,ticks%,vol%) LOCAL name$(128),p%,ret% p%=PEEKW($1c)+6 REM address of saved flags after CALL name$=inname$+chr$(0) ret%=CALL($1F86,UADD(ADDR(name$),1),ticks%,vol%) IF PEEKW(p%) AND 1 REM carry set for error RETURN ret% OR $FF00 REM return error ENDIF ENDP PROC record:(file$,time%) LOCAL sstat%,kstat%,key%(4),size%,ret%,signals% size%=time%*4 recorda:(ADDR(sstat%),file$,size%) REM async record IOC(-2,1,kstat%,key%()) REM async key read WHILE 1 IOWAIT REM wait for recording to complete, or a key IF sstat%<>-46 REM if sound no longer pending IOCANCEL(-2) REM cancel key read IOWAITSTAT kstat% REM wait for cancellation IF sstat%<0 gIPRINT "Error recording:"+err$(sstat%) ENDIF BREAK ELSEIF kstat%<>-46 REM else if key pressed recordc: REM cancel record IOWAITSTAT sstat% REM wait for cancellation gIPRINT "Cancelled" BREAK ELSE REM some async request made outside this PROC signals%=signals%+1 REM save it for later ENDIF ENDWH WHILE signals% IOSIGNAL REM put back foreign signals signals%=signals%-1 ENDWH ENDP PROC dbfDesc: LOCAL ax%,bx%,cx%,dx%,si%,di% LOCAL info%(4),len%,psrc%,pdest% ODBINFO info%() bx%=PEEKW(info%(2)) REM handle of logical file B ax%=$1700 REM DbfDescRecordRead IF OS($d8,ADDR(ax%)) and 1 RETURN ax% OR $ff00 REM return the error ENDIF REM the descriptive record has length ax% REM and is at address peekW(uadd(info%(2),8)) IF ax%=0 RETURN 0 REM no DescRecord ENDIF len%=ax%+2 REM length of the descriptive REM record read + 2-byte header psrc%=PEEKW(uadd(info%(2),8)) pdest%=PEEKW(uadd(info%(3),8)) CALL($a1,0,len%,0,psrc%,pdest%) REM copy to C's buffer cx%=len% bx%=PEEKW(info%(3)) REM handle of logical file C ax%=$1800 REM DbfDescRecordWrite IF OS($d8,ADDR(ax%)) and 1 RETURN ax% OR $ff00 ENDIF RETURN 0 REM success ENDP local pcell% rem pointer to cell LOCAL pcelln% rem new pointer to cell LOCAL p% rem general pointer LOCAL n% rem general integer ONERR e1 pcell%=ALLOC(2+2*8) rem holds an integer and rem 2 8-byte floats initially IF pcell%=0 RAISE -10 rem out of memory; go to e1:: ENDIF POKEW pcell%,2 rem store integer 2 at start of cell rem ie. no. of floats POKEF UADD(pcell%,2),2.72 rem store float 2.72 POKEF UADD(pcell%,10),3.14 rem store float 3.14 ... pcelln%=REALLOC(pcell%,2+3*8) rem space for 3rd float IF pcelln%=0 RAISE -10 rem out of memory ENDIF pcell%=pcelln% rem use new cell address n%=PEEKW(pcell%) rem no. of floats in cell POKEF UADD(pcell%,2+n%*8),1.0 rem 1.0 after 3.14 POKEW pcell%,n%+1 rem one more float in cell ... pcelln%=ADJUSTALLOC(pcell%,2,8) rem open gap before 2.72 IF pcell%=0 RAISE -10 rem out of memory ENDIF pcell%=pcelln% rem use new cell address POKEF UADD(pcell%,2),1.0 rem store 1.0 before 2.72 POKEW pcell%,4 rem 4 floats in cell now ... p%=UADD(pcell%,LENALLOC(pcell%)) rem byte after cell end p%=USUB(p%,8) rem address of final float POKEF p%,90000.1 rem overwrite with 90000.1 RAISE 0 rem clear ERR value e1:: FREEALLOC pcell% rem free any cell created IF err<>0 ... rem display error message etc ENDIF RETURN ERR 12: Overview 13: Alphabetic listing PROC scale: LOCAL freq,n% REM n% relative to middle A n%=3 REM start at middle C WHILE n%<16 freq=440*2**(n%/12.0) REM middle A = freq 440Hz BEEP 8,512000/freq-1.0 n%=n%+1 IF n%=4 OR n%=6 OR n%=9 OR n%=11 OR n%=13 n%=n%+1 ENDIF ENDWH ENDP PROC Birthday: LOCAL d&,m&,y&,dWk% DO dINIT dTEXT "","Date of birth",2 dTEXT "","eg 23 12 1963",$202 dLONG d&,"Day",1,31 dLONG m&,"Month",1,12 dLONG y&,"Year",1900,2155 IF DIALOG=0 :BREAK :ENDIF dWk%=DOW(d&,m&,y&) CLS :PRINT DAYNAME$(dWk%), PRINT d&,m&,y& dINIT dTEXT "","Again?",$202 dBUTTONS "No",%N,"Yes",%Y UNTIL DIALOG<>%y ENDP PROC deadline: LOCAL a%,b%,c%,deadlin& LOCAL today&,togo% PRINT "What day? (1-31)" INPUT a% PRINT "What month? (1-12)" INPUT b% PRINT "What year? (19??)" INPUT c% deadlin&=DAYS(a%,b%,1900+c%) today&=DAYS(DAY,MONTH,YEAR) togo%=deadlin&-today& PRINT togo%,"days to go" GET ENDP PROC dir: LOCAL d$(128) d$=DIR$("M:\DAT\*.DBF") WHILE d$<>"" PRINT d$ d$=DIR$("") ENDWH GET ENDP DO AT 10,5 :PRINT "Calc:", TRAP INPUT n$ IF n$="" :CONTINUE :ENDIF IF ERR=-114 :BREAK :ENDIF CLS :AT 10,4 PRINT n$;"=";EVAL(n$) UNTIL 0 PROC gamma:(v) LOCAL c c=3E8 RETURN 1/SQR(1-(v*v)/(c*c)) ENDP PROC modifier: LOCAL k%,mod% PRINT "Press a key" :k%=GET CLS :mod%=KMOD PRINT "Key code",k%,"with" IF mod%=0 PRINT "no modifier" ENDIF IF mod% AND 2 PRINT "Shift down" ENDIF IF mod% AND 4 PRINT "Control down" ENDIF IF mod% AND 8 PRINT "Psion down" ENDIF IF mod% AND 16 PRINT "Caps Lock on" ENDIF ENDP PROC SEQ: LOCAL g$(1) WHILE 1 PRINT "S: set seed to 1" PRINT "Q: quit" PRINT "other key: continue" g$=UPPER$(GET$) IF g$="Q" BREAK ELSEIF g$="S" PRINT "Setting seed to 1" RANDOMIZE 1 PRINT "First random no:" ELSE PRINT "Next random no:" ENDIF PRINT RND ENDWH ENDP PROC rectest: LOCAL n$(20) OPEN "name",A,name$ PRINT "Enter name:", INPUT n$ IF RECSIZE<=(1022-LEN(n$)) A.name$=n$ APPEND ELSE PRINT "Won't fit in record" ENDIF ENDP PROC rndvals: LOCAL i% PRINT "Random test values:" DO PRINT RND i%=i%+1 GET UNTIL i%=10 ENDP PROC trivial: LOCAL t%(2),u%,ax% t%(1)=$c032 REM xor al,al t%(2)=$cb REM retf ax%=$1ab u%=usr(addr(t%(1)),ax%,0,0,0) REM returns (ax% AND $FF00) PRINT u% REM 256 ($100) GET ENDP A: Summary for experienced OPL users proc slowdn: local i%,j print "Slow down S3a" call($138b) rem "unmark as active" while 1 i%=10 :j=j+1 while i% :i%=i%-1 :endwh if j=300000 j=0 :pause 2 else pause 1 endif endwh endp PROC scrinfo:(pinfo%) SCREENINFO #pinfo% ENDP PROC font:(font%,style%) FONT font%,style% ENDP LOCAL err%,info%(10),... TRAP LOADM "S3aprocs" IF ERR=0 OR ERR=-104 rem if not 'Incompatible translator' error rem or if already loaded, then in normal mode err%=ERR font%=$9a rem system font font:(font%,16) rem mono-ised style scrInfo:(ADDR(info%)) marginX%=info%(1) rem pixels from left of screen marginY%=info%(2) rem pixels from top of screen chrW%=info%(7) rem character width in pixels chrH%=info%(8) rem character height in pixels screenX%=gWIDTH/chrW% rem char screen width screenY%=(gHEIGHT+1)/chrH% rem char screen height IF err%-104 rem if loaded here UNLOADM "S3aprocs" ENDIF ELSE rem else on Series 3 or rem in compatibility mode rem so just use fixed values marginX%=0 rem no margins on Series 3 marginY%=0 chrW%=6 rem default console char width chrH%=9 rem ...and height screenX%=40 rem character columns screenY%=9 rem character rows font%=1 rem font ID = 1 on Series 3 ENDIF B: Operators and logical expressions C: Serial/parallel ports and printing PROC prints: OPEN "clients",A,a$ LOPEN "PAR:A" PRINT "Printing..." DO IF LEN(A.a$) LPRINT A.a$ ENDIF NEXT UNTIL EOF LPRINT CHR$(12); :LCLOSE PRINT "Finished" :GET ENDP PROC rsset:(baud%,parity%,data%,stop%,hand%,term&) LOCAL frame%,srchar%(6),dummy%,err% frame%=data%-5 IF stop%=2 :frame%=frame% OR 16 :ENDIF IF parity% :frame%=frame% OR 32 :ENDIF srchar%(1)=baud% OR (baud%*256) srchar%(2)=frame% OR (parity%*256) srchar%(3)=(hand% AND 255) OR $1100 srchar%(4)=$13 POKEL ADDR(srchar%(5)),term& err%=IOW(-1,7,srchar%(1),dummy%) IF err% :RAISE err% :ENDIF ENDP PROC test: PRINT "Testing port settings" LOPEN "TTY:A" LOADM "rsset" rsset:(8,0,8,1,0,&0) LPRINT "Port OK" :LPRINT PRINT "Finished" :GET LCLOSE ENDP PROC testread: LOCAL ret%,pbuf%,buf$(255),end%,len% PRINT "Test reading from serial port" LOPEN "TTY:A" LOADM "rsset" REM receive at 2400 without h/shake rsset:(11,0,8,1,0,&04002000) REM Control-Z or CR pBuf%=ADDR(buf$) DO REM read max 255 bytes, after leading count byte len%=255 ret%=IOW(-1,1,#UADD(pbuf%,1),len%) POKEB pbuf%,len% REM len% = length actually read REM including terminator char end%=LOC(buf$,CHR$(26)) REM non-zero for Control-Z IF ret%<0 and ret%<>-43 BEEP 3,500 PRINT PRINT "Serial read error: ";ERR$(ret%) ENDIF IF ret%<>-43 REM if received with terminator POKEB pbuf%,len%-1 REM remove terminator PRINT buf$ REM echo with CRLF ELSE PRINT buf$; REM echo without CRLF ENDIF UNTIL end% PRINT "End of session" :PAUSE -30 :KEY ENDP D: Character codes