ISTUG-BBS

Date: 1987
Type: Program
Platform(s): TS 2068
Tags: BBS

ISTUG-BBS is a bulletin board system written entirely in BASIC for the unexpanded TS2068, allowing remote callers to read and leave messages, chat with the sysop, and scan bulletins via a modem connection. The program uses machine code routines at fixed addresses (26724 for receive, 26766 for transmit, and 26715 for status polling) to handle serial communication through port 115, with modem control via port 119 (CODE “w”). Message storage uses a DIM m$(41,600) string array holding up to 40 messages of 600 characters each, with a parallel DIM d$(560) array for 14-character date/time stamps. The sysop editor, entered by pressing SYMBOL SHIFT, supports reading, deleting, writing, and saving the message base to tape using SAVE “BBSmsgbase” DATA m$(). The system clock is read from the three-byte frame counter at addresses 23672–23674 and converted to hours/minutes for time-on-line tracking.


Program Analysis

Program Structure

The program is organized as a collection of named subroutines, with line numbers stored in BASIC variables rather than hard-coded into GO TO and GO SUB statements. The initialization block at line 17601820 assigns all major entry points to variables:

  • nl = 30 (send newline)
  • sm = 41 (send message, also doubles as the message count limit)
  • beep = 70 (audible beep)
  • menu = 250 (main menu)
  • cls = 360 (clear screen)
  • con = 540 (continue/press enter prompt)
  • ret (dynamic return address, set before branching)

The main execution flow starts at line 10 with GO TO VAL "1760", runs initialization, then enters the sysop editor at 1490. Normal callers enter at line 170 after an incoming call is detected. The program uses ON ERR GO TO extensively for both error recovery and as a flow-control mechanism (e.g., redirecting to the menu on input errors).

Machine Code Interface

Serial communication is handled entirely through three machine code routines at fixed RAM addresses, initialized at line 1790:

VariableAddressPurpose
rcv26724Receive one character; returns ASCII code via USR
xmt26766Transmit one character; called before each OUT 115,c
26715(literal)Poll modem status; returns 0, 1, 2, or 3 for TX/RX ready flags

Characters are received with CHR$ USR rcv and transmitted by first calling RANDOMIZE USR xmt then OUT 115,CODE c$. The modem control register is accessed via port mc (CODE “w” = 119). A form-feed character (ASCII 12) is sent over the modem via OUT 115,12 at line 360 to clear the caller’s terminal screen.

Message Storage

The message base uses a two-dimensional string array DIM m$(41,600) declared at line 1800, where slot 41 (sm) is reserved as a scratch/metadata record. Each message record is structured as:

  • Columns 1–31: “TO: ” header with recipient name
  • Columns 33–64: “From: ” header with sender name
  • Column 65 onward: message body text (up to 534 characters)
  • A CHR$ 3 (ETX) byte marks the end of the message body

Date/time stamps are stored in a separate flat string d$ with 14-character slots per message (indexed as d$(y*14-13 TO y*14)). The entire message base is saved to tape with SAVE "BBSmsgbase" DATA m$() from the sysop editor.

Clock and Timing

The system clock is read from the frame counter at addresses 23672–23674 (the standard three-byte ticker) at line 1180, converted to hours and minutes, and compared against the session start time stored in temp. The clock can be set by the sysop via the “E” editor command, which POKEs new values back into 23672–23674 at lines 18551860. Midnight rollover is handled at line 1180 with a day counter increment.

Sysop Editor

The sysop editor is entered by pressing SYMBOL SHIFT from most program states (detected as INKEY$=" STEP " — the token representation of that key combination). It is protected by ON ERR RESET at line 1470, which resets error handling to prevent callers from accidentally or intentionally entering the editor via error conditions. The editor flag ed is set to NOT PI (i.e., 0, false) for normal operation and to a non-zero value when the sysop is active, allowing the same code paths (message writing, quick scan) to behave differently for the sysop.

Data Transmission Loop

Sending a string stored in p$ is handled by the subroutine at line 50, which iterates character by character, calling the transmit machine code routine and then OUT 115 for each. A special case exists in the message display loop at line 490: when a CHR$ 3 (ETX) is encountered in the message body, transmission stops early, preventing garbage after the message terminator from being sent to the caller.

Input Handling and Backspace

Several input loops implement a software backspace by detecting CHR$ 8 from the caller and decrementing the loop index x by 2 (one for the current position, one for the NEXT x increment). This pattern appears in name input (line 980), message addressing (line 620), and message body input (line 670).

Notable Techniques and Idioms

  • VAL "number" is used extensively in GO TO and GO SUB as a memory optimization, avoiding storage of integer line-number literals.
  • SGN PI is used as a constant 1 throughout (since PI > 0, SGN PI = 1), saving token space over the literal 1.
  • NOT PI evaluates to 0 (false), used to initialize boolean-style flags like ed.
  • The ret variable acts as a computed return address: it is set to a target line number before calling a subroutine, and the subroutine ends with GO TO ret, enabling reuse of single routines from multiple call sites without nesting GO SUB.
  • The bulletin, menu text, logon screen, and user list are all stored as DATA statements and sent via a generic READ/GO SUB sm loop at line 1070, with the first DATA value being the item count.
  • Line 600 uses LET m$(y,LEN d$)=CHR$ PILEN d$ is 560 (14×40), and CHR$ PI is CHR$ 3 since INT PI = 3, pre-placing an ETX terminator.

Bugs and Anomalies

  • At line 430, the loop FOR x=SGN x TO PI uses SGN x as the start value. Since x is carried over from prior usage, this is not always 1; if x happened to be 0 the loop would start at 0, potentially writing outside the intended 1–3 character input buffer c$=" ".
  • At line 550, GO TO VAL "550" creates an infinite tight loop with no timeout or escape path for the caller; only an error or disconnect can break out of the “press ENTER” prompt if the caller does not send a carriage return.
  • The variable sm is used both as the subroutine entry point for “send message” (line 41) and as the message array size limit (41), creating a naming collision that is intentional but potentially confusing.
  • Line 1550 does LET ed=nl before jumping to the leave-message routine. Since nl is the line number 30, this sets ed to 30 rather than a true/false flag, which the message-writing code at line 600 interprets as truthy, redirecting to the sysop message path — this appears intentional for sysop-mode message leaving.

Content

Appears On

Related Products

Bulletin board system for the unexpanded TS2068. Works with TS2050 modem and TS2040 printer. Holds 40 535-character messages; has “chat...

Related Articles

Related Content

Image Gallery

Source Code

    0 REM CODE FLASH w NEW O<>CODE FLASH w NEW \  >=CODE FLASH w NEW ( POKE FLASH sO AND CONTINUE AND 8 POKE FLASH w NEW \  >=CODE FLASH w NEW ( POKE y OPEN #s<>CODE FLASH w NEW \  >=CODE FLASH w NEW ( POKE STR$ !$!,T]USR ] OR *K\>) GO SUB LEN LPRINT >PEEK  PLOT #>XPEEK  LIST #>PEEK  REM STR$ z GO SUB LEN LPRINT +s( RANDOMIZE <>> OPEN #w>" OPEN #w>@ OPEN #w>{ OPEN #w>7 OPEN #w<> \* PEH SOFTWARE 1986   
   10 GO TO VAL "1760"
   20 REM send a nl= NEW LINE 
   30 POKE 23692,255: PRINT : RANDOMIZE USR xmt: OUT 115,CODE l$: RETURN 
   40 REM PRINT TO caller
   50 GO SUB nl: PRINT p$;: FOR x=SGN PI TO LEN p$: RANDOMIZE USR xmt: OUT 115,CODE p$(x): NEXT x: RETURN 
   60 REM BEEP 
   70 FOR x=9 TO 2 STEP -SGN PI: BEEP .2,15: NEXT x: RETURN 
   80 REM test FOR sysop access 
   90 IF IN mc<128 THEN GO TO VAL "1160"
  100 IF INKEY$="c" OR INKEY$="C" THEN GO TO VAL "810"
  110 IF INKEY$=" STEP " THEN GO TO VAL "1470"
  120 GO TO ret
  130 REM CLOSE # modem 
  140 GO SUB VAL "1710": IF ed THEN LET ed=NOT PI
  150 OUT mc,34: OUT mc,ed
  160 REM test FOR IN call 
  170 GO SUB VAL "1200": PRINT AT 17,27;t$(2): LET ret=VAL "180": GO TO VAL "110"
  180 IF IN mc=5 THEN GO TO 170
  190 REM start/set on LINE time 
  200 RANDOMIZE USR 26834: PAUSE ret: ON ERR GO TO VAL "1160": GO SUB beep: LET temp=hr*60+min: LET l$=CHR$ 13: RANDOMIZE USR 26788: LET p$="Hello"+l$+"Hello is this 2 lines Y/N": GO SUB sm
  210 LET c$=CHR$ USR rcv: GO SUB nl: IF c$="y" OR c$="Y" THEN GO TO VAL "930"
  220 IF c$="n" OR c$="N" THEN LET l$=CHR$ 10: RANDOMIZE USR 26782: GO TO VAL "930"
  230 GO TO 210
  240 REM menu 
  250 RESTORE VAL "1260": ON ERR GO TO VAL "1670": GO SUB cls: GO SUB VAL "1070"
  260 LET p$="(C,G,L,Q,R,T,U)? ": GO SUB sm: LET c$=CHR$ USR rcv: PRINT c$: GO SUB nl
  270 IF c$="c" OR c$="C" THEN GO TO VAL "810"
  280 IF c$="g" OR c$="G" THEN GO TO VAL "1120"
  290 IF c$="l" OR c$="L" THEN GO TO VAL "580"
  300 IF c$="q" OR c$="Q" THEN LET p$="use CONTROL C to Abort Scan.": GO SUB sm: GO TO VAL "760"
  310 IF c$="r" OR c$="R" THEN GO SUB nl: GO TO VAL "420"
  320 IF c$="t" OR c$="T" THEN GO SUB VAL "1200": GO SUB sm: GO TO VAL "260"
  330 IF c$="u" OR c$="U" THEN GO TO VAL "1100"
  340 GO TO VAL "260"
  350 REM CLS SCREEN$ ,12=FF 
  360 CLS : OUT 115,12: RETURN 
  370 REM FORMAT & READ header 
  380 LET p1=32: LET p2=64: FOR x=5 TO p2: IF m$(y,x)=l$ AND x<=32 THEN LET p1=x: LET x=39
  390 IF m$(y,x)=l$ AND x<=64 THEN LET p2=x: LET x=64
  400 NEXT x: LET p$="Message :"+STR$ y+"  "+d$(y*14-13 TO y*14)+l$+m$(y, TO p1)+m$(y,33 TO p2): RETURN 
  410 REM READ msg 
  420 LET p$="Message 1 to 40, Menu=0 >? ": GO SUB sm: LET c$="   ": ON ERR GO TO menu
  430 FOR x=SGN x TO PI: LET c$(x)=CHR$ USR rcv: IF c$(2)=l$ OR c$(PI)=l$ THEN GO TO VAL "460"
  440 IF (c$(x)<"0") OR (c$(x)>"9") THEN GO TO VAL "420"
  450 NEXT x: IF LEN c$>2 THEN GO TO VAL "420"
  460 GO SUB nl: LET y=VAL c$: IF NOT y THEN GO TO menu
  470 IF y>=sm OR m$(y,1)=" " THEN GO TO VAL "1700"
  480 GO SUB 370: LET p$=p$+m$(y,65 TO )
  490 GO SUB cls: PRINT ''"Working": FOR x=SGN PI TO LEN p$: LET c=CODE p$(x): IF c=3 THEN GO TO VAL "520"
  500 RANDOMIZE USR xmt: OUT 115,c
  510 NEXT x: LET x=x-SGN PI
  520 GO SUB nl: PRINT p$( TO x): LPRINT " READ  msg. "+STR$ y: GO TO VAL "420"
  530 REM con= CONTINUE 
  540 GO SUB nl: LET p$="Press <ENTER> when ready": GO SUB sm
  550 IF CHR$ USR rcv=l$ THEN GO TO ret
  560 GO TO VAL "550"
  570 REM leave message 
  580 GO SUB cls: LET p$="Is this message for Sysop Y/N>": GO SUB sm: LET c$=CHR$ USR rcv: IF c$="y" OR c$="Y" THEN GO TO VAL "1740"
  590 GO SUB nl: FOR y=SGN PI TO VAL "40": IF m$(y,1)<>" " THEN NEXT y: GO TO VAL "1680"
  600 LET m$(y,LEN d$)=CHR$ PI: IF ed THEN GO TO VAL "1610"
  610 LPRINT "Left msg. #";y: LET p$="Who gets Mess. "+STR$ y+"?": GO SUB sm: GO SUB nl: LET m$(y)="TO: ": FOR x=5 TO 31
  620 LET m$(y,x)=CHR$ USR rcv: IF m$(y,x)=CHR$ 8 AND x>=5 THEN LET x=x-2: NEXT x
  630 IF m$(y,x)=l$ THEN GO TO VAL "650"
  640 PRINT m$(y,x);: NEXT x: LET m$(y,x)=l$
  650 LET m$(y,33 TO )="From: "+n$: LET p$="Input Message (534 chars max).. <CONTROL C> to save.": GO SUB sm: GO SUB nl
  660 LET ret=VAL "700": FOR x=CODE "A" TO VAL "599"
  670 LET c=USR rcv: IF c=8 AND (x>=65) THEN LET x=x-2: NEXT x
  680 LET m$(y,x)=CHR$ c: PRINT CHR$ c;: IF c=3 THEN GO TO VAL "710"
  690 GO TO 90
  700 NEXT x
  710 LET p3=x: LET p$="Message"+(" full and" AND x>=VAL "599")+" saved.": GO SUB sm: GO SUB VAL "740": IF ed THEN LET ed=p3: GO TO VAL "1750"
  720 GO TO VAL "790"
  730 REM FORMAT date/time 
  740 GO SUB VAL "1200": LET d$(y*14-13 TO y*14)=p$: RETURN 
  750 REM Quick scan 
  760 LET ret=VAL "770": FOR y=SGN PI TO 40: IF m$(y,1)<>" " THEN GO SUB 370: GO SUB sm: IF NOT ed THEN GO TO 90
  770 IF IN 115=3 THEN GO TO VAL "260"
  780 NEXT y: IF ed THEN GO TO VAL "1650"
  790 LET ret=menu: GO TO con
  800 REM chat 
  810 LET p$="Paging sysop....": GO SUB sm: FOR x=SGN x TO VAL "144": IF INKEY$="" THEN PRINT ".";: RANDOMIZE USR xmt: OUT 115,46: BEEP .1,15: NEXT x: LET p$="Sorry, all we found were cobwebs": GO SUB sm: LPRINT "Tried chat": PAUSE CODE "c": GO TO menu
  820 GO SUB cls: LET p$=n$+"entering chat mode": GO SUB sm: GO SUB nl: POKE VAL "23658",ed: PRINT "SYMBL SHIFT/ STEP TO LEAVE CHAT."
  830 IF INKEY$=" STEP " THEN GO TO VAL "1470"
  840 LET p1=ed: LET p2=ed
  850 LET x=USR 26715: LET p2=x AND (x=1 OR x=3): LET p1=x AND (x=2 OR x=3)
  860 IF p1 THEN LET c=USR rcv: PRINT CHR$ c;: IF c=CODE l$ THEN PRINT '">";
  870 IF p2 AND INKEY$<>"" THEN GO TO 890
  880 GO TO 830
  890 IF p2 THEN LET c$=INKEY$: PRINT c$;: OUT 115,CODE c$: FOR x=NOT PI TO PI: NEXT x: IF c$=CHR$ 13 THEN RANDOMIZE USR xmt: OUT 115,62
  900 IF INKEY$<>"" THEN GO TO 900
  910 GO TO 830
  920 REM send logon SCREEN$ 
  930 RESTORE VAL "1290": GO SUB cls: GO SUB VAL "950": LET ret=VAL "1050": GO TO con
  940 REM send bulletin 
  950 RESTORE VAL "1330": GO SUB cls: GO SUB VAL "1070"
  960 REM INPUT callers name 
  970 GO SUB beep: LET p$="Who's calling?"+l$: GO SUB sm: LET n$="                          ": RANDOMIZE USR xmt: OUT 115,5: FOR x=SGN x TO LEN n$
  980 LET n$(x)=CHR$ USR rcv: IF n$(x)=CHR$ 8 AND (x>=2) THEN LET x=x-2: NEXT x
  990 IF x<SGN PI THEN GO TO VAL "970"
 1000 IF n$(x)=l$ THEN GO TO VAL "1020"
 1010 PRINT n$(x);: NEXT x
 1020 LET n$=n$( TO x-SGN PI)+l$: IF LEN n$<5 THEN GO TO VAL "970"
 1030 LET p$=n$+"Correct (Y/N) >": GO SUB sm: LET c$=CHR$ USR rcv
 1040 IF c$="n" OR c$="N" THEN GO TO VAL "970"
 1050 GO SUB nl: GO SUB 1200: LPRINT n$'p$( TO 14): GO TO menu
 1060 REM send SCREEN$ DATA 
 1070 READ y: LET ret=VAL "1080": FOR y=SGN PI TO y: READ p$: GO SUB sm: GO TO 90
 1080 NEXT y: RETURN 
 1090 REM user LIST 
 1100 RESTORE VAL "1370": GO SUB cls: GO SUB VAL "1070": LET ret=menu: GO TO con
 1110 REM quit BBS 
 1120 GO SUB cls
 1130 RESTORE VAL "1430": GO SUB VAL "1070"
 1140 LET c$=CHR$ USR rcv: IF c$="n" OR c$="N" THEN GO TO menu
 1150 READ p$: GO SUB sm: GO SUB VAL "1200": GO SUB sm: LPRINT p$'': OUT mc,64: OUT mc,0
 1160 OUT mc,0: GO TO VAL "140"
 1170 REM timer 
 1180 LET time=VAL "((PEEK 23672+256*PEEK 23673+65536*PEEK 23674)/3600)": LET hr=INT (time/60): LET min=INT (time-hr*60): IF hr>=24 THEN LET hr=NOT PI: LET dy=dy+SGN PI: GO SUB VAL "1850"
 1190 RETURN 
 1200 GO SUB 1180: LET time=INT ((hr*60+min)-temp)
 1210 LET p1=INT (time/60): LET p2=INT (time-(p1*60)): IF p1<0 THEN LET p1=p1+24
 1220 LET c=SGN PI: GO SUB 1240: LET c=2: LET p1=hr: LET p2=min: GO SUB 1240
 1230 LET p$=STR$ mo+"-"+STR$ dy+"-"+STR$ yr+";"+t$(2)+"  Online "+t$(1)+l$: RETURN 
 1240 LET t$(c)=("0" AND LEN STR$ p1=SGN PI)+STR$ p1+":"+("0" AND LEN STR$ p2=SGN PI)+STR$ p2: RETURN 
 1250 REM menu DATA 
 1260 DATA 10,"    I.S.T.U.G.'s TIMEX-BOARD","","<C>hat","<G>oodby","<L>eave a Message"
 1270 DATA "<Q>uick Scan messages","<R>ead message","<T>ime on","<U>sers list",""
 1280 REM logon DATA 
 1290 DATA 11,"  WELCOME TO I.S.T.U.G.'s BBS","-------------------------------","using an unexpanded Timex 2068","","Settings:","Duplex: Full   Word Size: 7","Parity: Even   Stop Bits: 1",""
 1300 DATA "","Open 24hrs a day, 7 days a week",""
 1310 DATA ""
 1320 REM bull DATA 
 1330 DATA 8,"Mad Programmer: Paul Holmgren","Igor Sysop: Willie Jones","","**** >>>  -Bullentin-   <<< **** "
 1340 DATA "","Keep your Modem's warm and stay","tuned to the I.S.T.U.G. BBs",""
 1350 DATA ""
 1360 REM user DATA 
 1370 DATA 8,""
 1380 DATA ""
 1390 DATA ""
 1400 DATA ""
 1410 DATA "","If we missed you please leave","Sysop a mess. and you will be","added to our list"
 1420 REM quit DATA 
 1430 DATA 8,"","The Indiana Sinclair Timex","","Users Group hopes you enjoyed"
 1440 DATA "","our little Bulletin Board.","","Are you ready to leave Y/N >","Goodby. Hanging up now"
 1450 DATA ""
 1460 REM edit 
 1470 ON ERR RESET 
 1480 LET p$="Commander Sysop taking control, Please Stand By": GO SUB sm
 1490 CLS : PRINT "SYSOP EDITOR"''"C heck Time"'"D elete a msg."'"E stablish correct time"'"H ang up"'"L eave a msg."'"M ain Menu"'"Q uick Scan Msg. base"'"R ead Msg."'"S ave messages"''"(C,D,E,H,L,M,Q,R,S)"
 1500 POKE VAL "23658",VAL "8": PAUSE ed: LET c$=INKEY$
 1510 IF c$="C" THEN GO SUB VAL "1200": PRINT p$( TO 14): GO TO VAL "1650"
 1520 IF c$="D" THEN INPUT "DELETE msg. #?: ";x: PRINT "Msg. # ";x;" deleted": LET m$(x)="": LET p$="": GO SUB VAL "740": GO TO VAL "1650"
 1530 IF c$="E" THEN GO SUB VAL "1840"
 1540 IF c$="H" THEN GO TO VAL "1120"
 1550 IF c$="L" THEN LET ed=nl: GO TO VAL "590"
 1560 IF c$="M" THEN GO TO menu
 1570 IF c$="Q" THEN LET ed=nl: GO TO VAL "750"
 1580 IF c$="R" THEN INPUT " READ Msg. #? ";y: CLS : GO SUB VAL "370": PRINT p$'m$(y,CODE "A" TO ): GO TO VAL "1650"
 1590 IF c$="S" THEN LET m$(sm)=d$: SAVE "BBSmsgbase" DATA m$()
 1600 GO TO VAL "1490"
 1610 CLS : LET ed=NOT PI: INPUT " SYMBL SHIFT/ STEP  TO STOP :"'"Msg. TO ? ";p$: LET m$(y)="To :"+p$+l$: LET m$(y,CODE "!" TO )="From : Sysop Willie"+l$: GO SUB VAL "740": GO SUB VAL "370": PRINT p$: LET p$=""
 1620 INPUT LINE c$: IF c$=" STEP " THEN GO TO VAL "1640"
 1630 LET p$=p$+c$+l$: PRINT c$: IF LEN p$<=VAL "535" THEN GO TO VAL "1620"
 1640 LET m$(y,CODE "A" TO )=p$+CHR$ PI: PRINT 
 1650 LET ed=NOT PI: PRINT " NEXT ?": PAUSE ed: GO TO VAL "1490"
 1660 REM error trapped messages 
 1670 ON ERR RESET : LET p$="Sorry "+n$+" A bug has Bit you.": GO SUB sm: GO SUB beep: GO TO menu: REM ?=control g=Beep 
 1680 IF ed THEN PRINT "I,m full, delete something first": GO TO VAL "1650"
 1690 LET p$="Message base full right now."+l$+"Please try later": LPRINT '"  I'm full. Do something. SOS"'': GO SUB sm: GO TO con
 1700 LET ret=VAL "420": LET p$="Sorry no message "+STR$ y+". Try again": GO SUB sm: GO TO con
 1710 REM idle SCREEN$ 
 1720 CLS : PRINT AT VAL "7",VAL "7";"The I.S.T.U.G. BBS";AT VAL "10",PI+PI;"Scanning Phone LINE "'''''''"  PEH SOFTWARE: 10-11-86": RETURN 
 1730 REM LPRINT sysop msg 
 1740 GO SUB cls: LET y=sm: LET m$(y)="": LET ed=y: GO TO VAL "650"
 1750 LPRINT n$;m$(sm,CODE "A" TO ed): LET ed=NOT PI: GO TO menu
 1760 REM init, 40 msg. base 
 1770 PAPER NOT PI: BORDER NOT PI: INK VAL "9": CLS 
 1780 PRINT '" STEP from most modes will GO TO SYSOP edit menu"
 1790 LET rcv=VAL "26724": LET xmt=VAL "26766": DIM t$(2,5): LET temp=PI: LET mc=CODE "w"
 1800 LET nl=VAL "30": LET sm=VAL "41": LET beep=VAL "70": LET menu=VAL "250": LET cls=VAL "360": LET con=VAL "540": LET l$=CHR$ 13: DIM m$(sm,VAL "600"): LET ed=NOT PI
 1810 INPUT "Add a message base? ";p$: IF p$="y" OR p$="Y" THEN PRINT "Start Message Base Tape.": LOAD "" DATA m$()
 1820 LET d$=m$(sm): GO TO VAL "1490"
 1830 REM FORMAT & POKE clock 
 1840 INPUT "Month  1-12 ";mo,"Day  1-31 ";dy,"Hour  00-23 ";hr,"Minute ";min,"Year  86 ";yr
 1850 LET x=VAL "(hr*3600+min*60)*60": LET y=INT (x/65536): POKE 23674,y
 1860 LET p1=x-y*65536: LET x=INT (p1/256): POKE 23673,x: POKE 23672,p1-x*256: RETURN 
 1870 REM SAVE 
 1880 CLEAR : SAVE "bbs" LINE PI: GO TO VAL "1760"

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top