Skip to content

Console I/O & embedded DATA

This page covers the everyday ways a d/BASIC program talks to a person and carries its own small tables of data: printing text and numbers, formatting numbers, reading what someone types, DATA tables built into the program, random numbers, the clock, and the ERROR, ERR and ERL statements. By the end you can write a complete console program that prints, prompts, reads and formats.

There are two kinds of data in a d/BASIC program:

  • values that already live inside the program: variables, arrays and DATA rows; and
  • values asked for from the outside world: typed at a console, delivered to a window program as an event, or fetched through an intent (an intent is a named request, such as "fill this rectangle" or "read this record", that the machine carries out however it can).

Keeping that boundary visible is what lets the same program be tested, and run on very different machines.

PRINT

Even the smallest statement deserves a good reference.

PRINT "HELLO"
PRINT 2 + 2

With no separator at the end, PRINT ends the line.

Semicolon: continue closely

PRINT "SCORE:"; Score%
PRINT "A"; "B"; "C"

A semicolon at the end keeps the line open, so the next PRINT continues it:

PRINT "LOADING";
PRINT ".";
PRINT ".";
PRINT "."

d/BASIC prints every number by one fixed rule, including the space that stands in for the sign, and that rule can make semicolon output look padded. Use PRINT USING, below, when the exact look matters.

Comma: move to the next print zone

PRINT "NAME", "SCORE", "RANK"
PRINT Name$, Score%, Rank%

Comma-separated output lines items up in fixed columns, which is handy for quick tables and the listings you remember. It is not a way to lay out pixels.

TAB and SPC

PRINT TAB(12); "COLUMN TWELVE"
PRINT "LEFT"; SPC(5); "RIGHT"

TAB(n) moves to column n of the console. SPC(n) prints n spaces.

Use a numeric picture, a template such as "###.##", when the shape of the number is part of the output:

PRINT USING "###.##"; Price#

A picture shows the alignment, sign, decimal places and overflow behavior right there in the source. d/BASIC formats it by its own fixed rules, so the compiled program file, .dbc, prints the same thing on every machine and never picks up the host's locale or floating-point printer.

Classic BASICs grew a sprawling picture grammar; d/BASIC deliberately narrows it to one portable form: exactly one literal picture, exactly one numeric field, and exactly one numeric value. The numeric field may use #, one decimal point, comma grouping, a leading +, a trailing -, **, $$, **$, or a closing run of exactly four or five ^ characters; _x puts one literal printable character into the output. Computed or repeating pictures, a second field or value, and the string fields !, & and \...\ are not accepted; the compiler stops and says so, rather than letting the result differ from one machine to the next.

INPUT

INPUT Age%
INPUT "YOUR NAME"; Name$
INPUT "X AND Y", X#, Y#

A prompt followed by ; behaves the way classic BASIC did: it prints the prompt and then ?. A prompt followed by , prints the prompt exactly, with no question mark. The line the user types is split at commas into fields, and each field is converted to the type of its target variable.

LINE INPUT reads one whole line into one string:

LINE INPUT "TELL ME A STORY"; Story$

Use LINE INPUT when commas are part of the text rather than separators between values.

Somewhere to read from is still required

INPUT, LINE INPUT and INKEY$ read from the console input service, the part of the host that supplies keystrokes. On a display with no source of input, they stop and say so rather than inventing keystrokes. Window programs normally receive keys through ON KEY instead.

INKEY$

INKEY$ looks at one pending console key without stopping to prompt:

K$ = INKEY$
IF LEN(K$) > 0 THEN PRINT "KEY: "; ASC(K$)

Window programs driven by events should prefer ON KEY, which leaves the host in charge of when events arrive.

DATA, READ, and RESTORE

DATA builds a small read-only table right into the program:

DATA "MERCURY", 57.9
DATA "VENUS", 108.2
DATA "EARTH", 149.6

FOR I% = 1 TO 3
  READ Planet$, Distance#
  PRINT Planet$; Distance#
NEXT I%

READ takes the values in the order they appear in the source and converts each one to the type of its target variable.

RESTORE rewinds to the beginning, or to a labelled or numbered line:

InnerPlanets:
DATA "MERCURY", "VENUS", "EARTH", "MARS"

READ First$
RESTORE InnerPlanets
READ Again$

This is an excellent fit for small lookup tables, level data, palettes and teaching examples. Large or changing application data belongs in arrays, in resources, or in the database side of the language, described in Database & Data Intents.

Random sequences

RND returns a SINGLE drawn from the same pseudo-random sequence Microsoft BASIC used, so old listings behave as they did. Its argument controls the sequence:

Form Effect
RND or RND(positive) advance and return the next value
RND(0) return the previous value again
RND(negative) reseed from that value and return the resulting repeatable value

The everyday form simply advances:

Roll% = INT(RND * 6) + 1

Seed the sequence on purpose, for repeatable tests or for sessions that differ:

RANDOMIZE 12345

RANDOMIZE with no argument does not stop to ask a person for a seed; it reseeds with d/BASIC's fixed, repeatable value. Use RANDOMIZE TIMER when the clock of whatever machine is running the program should vary the session. RANDOMIZE 0 is a real reseed, not a no-op.

A seed you choose is a feature when you need to reproduce a game, a simulation or a bug. Do not mistake this kind of randomness for the cryptographic kind.

Time

TIMER returns the time in seconds, counted the same way on every machine:

Started! = TIMER
' ...work...
Elapsed! = TIMER - Started!

The d/OS runtime, the program that runs your compiled code, maps TIMER onto whatever clock its host provides. (d/OS is the operating system that brings modern software to 8-bit home computers such as the Atari 800, the Commodore 64 and the Apple II.) A test host can supply a synthetic clock that ticks predictably; a desktop supplies real, steadily increasing time. Your source means the same thing either way.

Errors and source location

ERROR raises an error on purpose, by its error code:

ERROR 2401

The operand must be a single nonzero integer literal from 1 through 65535; a computed expression is not accepted. In d/BASIC, an operation that cannot go ahead is said to be refused: it stops and says exactly why. The error raised here goes to the active ON REFUSAL handler, the statement that names where such errors are handled; with no handler installed, the program stops and reports that exact error code.

ERR reports the code of the current error. ERL reports the numbered source line it happened on, when there is one:

ON REFUSAL GOTO CouldNotRead
' ...optional external operation...
END

CouldNotRead:
  PRINT "REFUSED "; ERR; " AT LINE "; ERL
  RESUME NEXT

Errors reported by name carry real source positions too; you do not need line numbers to get useful errors.

Files and databases continue in their own chapters

d/BASIC does not make a program portable by pretending that C:\, /home, a browser sandbox and a disk on d/OS are the same thing. Instead it gives two different jobs two explicit, portable boundaries:

  • Files & File Manipulation is about bytes stored under a name: mounts, directories, listing, reading, writing, copying, moving, renaming, the trash, and replacing a file all at once.
  • Database & Data Intents is about revisions of a thing with an identity: database sessions, snapshots, typed values, durable saves, publications, and the confirmation a save returns once the data is really stored.

The short memory aid is: FILE is bytes at a name; DATA is a revision of an identity.

Three good boundaries

  1. Keep calculations in procedures that do no input or output.
  2. Convert values from outside into your own records or objects at the edge of the program, as soon as they arrive.
  3. Treat the confirmation that an external save committed as the moment the data became durable, not the moment a button was pressed.

That discipline pays off on a tiny machine, a desktop and a browser for exactly the same reason: it separates what your program knows from what its environment promises.


Next: Errors, Refusals & Diagnostics →