Input/Output

Alice Pascal performs input and output using functions and procedures that are built-in. This means that Alice has defined the subprograms for you -- all you have to do is call them.

Because of the unusual definition of Pascal, many of the built-in routines can do things that user-written routines are not capable of. In particular, they can take a varying number of arguments, and these arguments may be of any type. The Write and Writeln procedures take parameters with formatting information tagged onto them. See the descriptions of Write and Writeln for details.

I/O operations use file variables, as described in Chapter 3. Just as normal variables have to be initialized with values before they can be used, file variables must be initialized by associating them with files. Once a file variable has been initialized, an I/O operation that references the file variable causes I/O on the associated file.

The assign Procedure

The assign procedure associates a filename with a particular file variable. All access to the file through that file variable will operate on the file whose name is given in the assign. The format of assign is

assign(filevar, filename)

where filevar is a previously declared file variable and filename is a string giving the name of the file to be used. For example,

assign(initfile,'myprog.ini');

would cause subsequent references to initfile to refer to the disk file 'myprog.ini'.

Reset, Rewrite, Append, Update and Close

The following four routines are used to set up access to files, and de-access them. The three functions reset, rewrite, and append all "open" a file, that is, they make the file directly accessible to the program.

At any given time, a file is "positioned" at a certain distance from its beginning, and the position of this "file pointer" changes as the file is read or written. Initially, the file pointer is set to the beginning of a file (for reset or rewrite, or to the end (for append).

The reset Procedure

The behavior of the reset procedure depends on the setting of the +b flag on the Alice command line.

If you do not specify +b, the reset procedure initializes a file variable with a file that you only intend to read. If you try to write on that file, you will get an error.

If you do specify the +b option, reset opens the file for reading writing, and random access.

The full format of reset is

reset(filevar,filename);

where filevar is a file variable declared in the variable declaration section and filename is a string giving the name of the file that should be associated with the file variable. For example,

reset(indata,'myfile');

associates the file myfile with the file variable indata. From this point onward, you can perform input operations on indata to read from myfile (and output operations to write to it, if the +b flag is set).

Note that reset does an implicit assign of the filename to the file variable. If the file name string is omitted, Alice will use whatever filename was last assigned to that file variable. If no filename has been assigned, a new filename is formed out of the variable name and a unique hexadecimal suffix. For example,

reset(stuff);

associates the file name stuffX (where X is some hexadecimal number) with the file variable stuff.

The file name string can have the special format

'?:filename'

This tells Alice to search for the given file on several drives. The search begins on the current drive, then goes to other drives on the system. Note that this format is not supported in Turbo Pascal.

If you wish to be compatible with Turbo Pascal, you should do the assign separately and omit the filename argument from the call to reset. For example,

reset(userdata,'employee.rec');

would become

assign(userdata,'employee.rec');
reset(userdata);

The rewrite Procedure

The rewrite procedure is like reset except that rewrite initializes a file that the program only intends to write on. The format of rewrite is

rewrite(filevar,filename);

For example,

rewrite(outdata,'info');

associates the file info with the file variable outdata.

Note that rewrite does an implicit assign of the filename to the file variable. If the file name string is omitted, Alice will use whatever filename was last assigned to that file variable. If no filename has been assigned, a new filename is formed out of the variable name and a unique hexadecimal suffix.

If the given file does not exist, it will be created. If the given file already exists, its current contents will be destroyed by the rewrite operation and data written to the file will overwrite whatever was previously there.

If you wish to be compatible with Turbo Pascal, you should do the assign separately and omit the filename argument from the call to rewrite. For example,

rewrite(userdata,'employee.rec');

would become .codebeg 10 assign(userdata,'employee.rec'); rewrite(userdata);

The append Procedure

The append procedure is exactly like rewrite except that it does not destroy the current contents of the file. For example,

append(appdata,'oldfile');

associates the file oldfile with the file variable appdata.

Note that append does an implicit assign of the filename to the file variable. If the file name string is omitted, Alice will use whatever filename was last assigned to that file variable. If no filename has been assigned, a new filename is formed out of the variable name and a unique hexadecimal suffix.

Any output written to appdata will be appended to the current contents of the file (i.e., added on to the end).

If you wish to be compatible with Turbo Pascal, you should do the assign separately and omit the filename argument from the call to append. For example,

append(userdata,'employee.rec');

would become

assign(userdata,'employee.rec');
append(userdata);

Update(filevar,filename)

The Update procedure acts must like reset when the +b option is enabled. It opens an existing file for read, write and random I/O. This routine is not in Turbo Pascal.

Close(filevar);

This routine closes the file associated with the specified file variable. This causes all data that has not yet been transferred to disk to be written out, and prevents subsequent access to the file through the file variable.

When you get rid of a file variable (for example, by leaving the part of your program in which that variable is active), the file is automatically closed for you by Alice. Alice will also close any files that are left open when your program terminates. The close procedure is provided so that you can close files whenever you need to (this is often necessary because ALICE only allows you to have a certain number of files open at one time).

Closing a text file without an end of line marker on the end causes one to be written to the file. This does not happen if the +b flag is specified on the Alice command line.

Flush(filevar);

When you write data to a disk file, it is first temporarily stored in a special part of the computer's memory (called a "buffer"). It is sometimes important to write the data in this buffer to the disk during the running of a program. The flush procedure does this. (Note that closing a file (see close) will do this for you, and that it's unusual for you to have to do it yourself). [Found in TURBOLIB.AP]

FilePos(filevar)

This routine returns the position of the "file pointer" for the specified file. The filevar is a file variable of any type The return value is an integer telling where the filepointer for the given file is located; this value is a count of the number of objects that are before the filepointer. Thus a file that has just been accessed using reset or rewrite has a file position of zero.

If a file is positioned beyond record maxint (32767), an error results. [Found in TURBOLIB.AP] (See LongFilePos for an alternative that returns a large value as a real number).

FileSize(filevar) returns the number of objects in the

file, where an "object" is an element of the file's component type. For a file of char or a text, this is thus the size of the file in bytes.

The value returned is an integer; if a file contains more than maxint records, an error condition results. This often happens when the size of the objects making up the file is small (for example file of byte, or a text file). See LongFileSize for an alternative that returns a large value as a real number).

[Found in TURBOLIB.AP]

Seek(filevar, n)

This procedure positions the filepointer for the file specified by filevar to the n'th component of the file. The value n is of type integer; see LongSeek for a version that takes a real number as a long file pointer. This routine is similar to setnext, but it does a lazy-io style get on the file so that the next call to read obtains the n'th component rather than the contents of the current component before the seek.

LongFilePos(filevar)

This function returns the position of the "file pointer" for the specified file. The filevar is a file variable of any type, and return value is a real number telling where the filepointer for the given file is located. This value is a count of the number of objects that are before the filepointer; thus, a file that has just been accessed using reset or rewrite is has a file position of zero. This routine is equivalent to FilePos, but it can handle larger because it returns a real number. [Found in TURBOLIB.AP]

LongFileSize(filevar)

This function returns the number of objects contained in the file specified by filevar, where filevar is a file variable of any type. This routine is equivalent to FileSize, but it returns a real number and can thus deal with much larger files. Note that the file must currently be active. [Found in TURBOLIB.AP]

LongSeek(filevar, n)

This procedure positions the filepointer for the file specified by filevar to the n'th component of the file. The argument n is of type real. This routine is identical to Seek, but it can seek further through the use of the real argument. [Found in TURBOLIB.AP]

IOChecking and IOResult

The IOChecking routine controls user i/o checking;

IOChecking(1);

turns it on, while

IOChecking(0);

turns it off.

When user i/o checking is off, all errors are handled by Alice; you will receive a message whenever such an error occurs.

When user i/o checking is on, i/o errors do not stop the program from executing. However, all subsequent input will be suspended until you call the function IOResult. Calling this function will allow i/o to continue normally (even though the result of the function may be discarded). A zero value from IOResult indicates that the most recent i/o operation was successful; other return values indicate various types of errors. IOResult will return zero after it's been read once, until another error occurs.

Possible error codes are:

1 - file does not exist 2 - file not available for input 3 - file not available for output 4 - file not open 5 - file not set for random i/o $10 - bad numeric read $99 - read past EOF $F0 - write error (full disk)

Note that these codes are in hex. Turbo Pascal supports some additional codes, so if you're moving your program from Alice to Turbo Pascal be sure to refer to the Turbo Pascal Manual for details as to their meaning. Error status should be checked after calls to read, get, write, put, close, reset, rewrite, update, append, and seek.

Predefined File Variables

In addition to file variables that are explicitly declared in the program, there are some file variables that are automatically declared for every program. These are

input
output
Kbd

By default, input is associated with the keyboard (in a buffered, line-at-a-time mode) and output is associated with the display screen. For example, anything that you write to output will normally be printed out on the display screen. However, you can use reset to associate input with a file (so that input will be taken from the file instead of being typed in) and you can use rewrite or append to associate output with a file (so that output will be written to the file instead of being displayed on the screen).

The Kbd variable is an input variable also associated with the keyboard. Input from Kbd is done raw, which is to say one character at a time. This is similar to the input done by the routine Get_Char. The main difference is that special IBM function key codes are input as a single byte with Get_Char, while they come as two bytes when reading from Kbd. In this case, the first character is an escape character (chr(27)) and the second character is the special code for the key. See the IBM-PC Technical Reference or Turbo Pascal manuals for details.

Reading and Writing

Declaring a file variable automatically declares an associated buffer variable. The name of the buffer variable is the name of the file variable followed by a caret (^) and the type of the buffer variable is the same as the type of data that is stored in the file.

When reset is executed to position a particular file variable, the associated buffer variable is assigned the value of the first element in the file (if such an element exists). This value can then be assigned in the normal way. For example, we might have

var
    intfile : file of integer;
    i : integer;
begin
reset(intfile);
i := intfile^;

This assigns the first integer in intfile to the variable i.

The procedure get obtains the next element in a file that has been initialized with reset. The procedure takes the name of the file variable that is associated with the file you wish to read, as in

get(intfile);

The element that get obtains is placed into the buffer variable. Thus the following code reads the first 100 elements from intfile into an array named iarr.

reset(intfile);
for i := 1 to 100 do begin
    iarr[i] := intfile^ ;
    get(intfile);
    end;

At the end of this code, intfile^ will hold the 101st element of intfile.

Writing is done in a similar way. When a file variable is initialized with rewrite or append, the file buffer and the buffer variable are cleared. The first step in writing a value is to assign the value to the buffer variable. For example, we might say

intfile^ := i;

The put procedure writes the contents of the buffer variable to the file buffer (and so to the output file). The following piece of code writes the first 100 elements of the array iarr to the file associated with intfile.

rewrite(intfile);
for i := 1 to 100 do begin
    intfile^ := iarr[i];
    put(intfile);
    end;

Note that the use of buffer variables, get, and put is not supported in Turbo Pascal. Therefore, if you plan to move a program to Turbo Pascal at any time in the future, you should make sure to use read and write instead of get and put.

The eof Function

The eof function determines whether or not a particular file has reached end-of-file. eof returns a Boolean value: true if the file really is at end-of-file, and false otherwise. For example,

while not eof(intfile) do begin
    i := intfile^;
    get(intfile)
    end;

reads through intfile element by element.

eof may be applied to both input and output files. Output files are always at end-of-file, so eof is always true. Input files reach eof when the get procedure discovers that there are no more elements to get. This means that you have tried to get something beyond the last element of the file. When you issue such a get, the buffer variable will become undefined and eof will become true. Should you attempt to get again, an error will occur.

SeekEof(filevar)

This routine is similar to eof, but it first skips over blanks and tabs in the specified file. [Found in TURBOLIB.AP]

Text Files

In order to make it easier to read and write text, Pascal offers a number of special subprograms that may be used on files that have been declared to have the type text.

The read Procedure

The read procedure may be applied to any text file. The simplest form of read is

read(filevar,variable);

where filevar is a file variable initialized with reset and variable is an integer, real, character, or string type.

If the variable has the type char, read(f,v) is equivalent to

v := f^;
get(f);

If the variable is integer or real, read will read through the text character by character, collecting a number. It will skip over leading blanks, tabs, and new-lines if necessary, but the first character after the white space must be a digit or a sign (+ or -). It will continue collecting characters until it finds one that cannot be part of the appropriate type of number. The collected value will be returned in the argument variable. For example,

var
    i : integer;
    f : text;
  ...
read(f,i);

reads an integer from f and stores it in i. The read procedure will let you read integers (i.e. numbers without decimals or exponents) into real variables.

If read is passed a string variable, it will read in text character by character until all the elements in the string have received characters or the end of the text line is reached. If the line is too long to fit in the string, read will only read enough characters to fill the string up; the rest of the line can be read by other calls to read. If the line is too short, the StrEnd marker will be placed in the string after the last character read.

A more complicated form of read is

read(f,v1,v2,v3,...);

This is equivalent to

read(f,v1);
read(f,v2);
read(f,v3);
   ...

read can be used in connection with files that are not declared as text. In this case,

read(f,v);

is equivalent to

v := f^;
get(f);

where v is a variable whose type matches the type of the elements in the file being read.

If the file variable argument is omitted, read will read from the input file variable. In other words,

read(v1,v2,v3,...);

is equivalent to

read(input,v1,v2,v3,...);

This will read input typed from the keyboard unless you have associated input with a file by calling reset.

The eoln Function

The eoln function returns a Boolean value indicating whether or not you have reached the end of an input line. If eoln returns true, the last read operation reached the new-line character that marks the end of a text line.

The argument of eoln is a text file variable. If no argument is specified, input is assumed. A typical use of eoln might be

var
    chararr : packed array [1..80] of char;
    c : char;
  ...
i := 1;
while not eoln(fv) do begin
    read(fv,c);
    chararr[i] := c;
    i := i + 1;
    end;

This reads characters into c and stores those characters in the array chararr until the end of the line has been reached.

SeekEoln(filevar)

This routine is similar to eoln, but first skips blanks and tabs in the specified file. [Found in TURBOLIB.AP]

The readln Procedure

The readln function is similar to read, but it is used to read everything on the current input line up to and including the new-line character on the end. File arguments to readln must be of type text. More technically, readln satisfies the following conditions.

readln(v1,v2,v3,...);

is equivalent to

readln(input,v1,v2,v3,...);

(so input is the default file variable if none is specified).

readln(fv,v1,v2,...);

is equivalent to

read(fv,v1,v2,...);
readln(fv);

This means that readln reads things into variables using the same conventions that read does. It also means that you don't have to issue readln at the very beginning of the input line -- you can have several reads first and then a readln.

readln(fv);

is equivalent to

while not eoln(fv) do begin
    get(fv);
    end;
get(fv);

This means that when readln has filled all its arguments, it will skip through everything else on the input line until it finds the new-line on the end, and will then read the new-line as well. This sets things up for a new input line (essentially ``flushing'' whatever remains of the old input line).

As a special Alice extension, readln takes an optional string constant that will be used as a prompt for input. For example,

readln('Enter a value for x: ',x);

prints out

Enter a value for x:

and then waits you to enter an appropriate value.

Reading from the Terminal

Input is only read from the terminal when the program calls for it, and at that time Alice reads an entire line. This is slightly different than reading from a file, since Pascal file input is always one character ahead of the read function. When you are entering an input line, you may correct typing mistakes with backspacing. Nothing from the input line is passed to the program until you press [ENTER].

The eof and eoln functions may actually perform a read operation on the terminal to see if there is a character waiting to be read. This can cause some problems. For example, suppose you have

while not eof do begin
    writeln('Enter integer:');
    read(i);
       ...
    end;

The call to eof causes Alice to read an entire line of input from the terminal. This happens before the writeln instruction writes out the prompt for input. You may have to rewrite programs slightly to get the prompt in the right place.

You can create an explicit ``end-of-file'' condition by pressing [F6] as the first character of an input line. You do not have to press [ENTER].

If you ask read or readln to read a number from the terminal but they find something non-numeric, they throw away the rest of the input line and keep looking for a number. For example, suppose you say

read(i,j,k);

and enter the input line

15 b 68

The variable i gets the 15, then a warning is printed indicating that Alice expected numeric input but found a b. Alice will read in another line of input to get values for j and k.

When Borland deviations (+b) are enabled a special case exists for numeric input. If eoln is true at the start of the read or readln, the input routine will return immediately without setting the value of the variable. This allows null input to imply a default. Under these circumstances, all further calls to read will return immediately until a readln has been done to clear the end of line status.

The write Procedure

The write procedure corresponds to read. Its standard format is

write(fv,exp1,exp2,exp3,...);

where fv is a text file variable and the expn are expressions of set, string scalar/ordinal or real type. If the file variable is omitted, the standard file output is assumed.

If an argument is an integer expression, its value will be output in the usual ASCII representation.

If an argument is a real expression, its value will be output using scientific notation (i.e. a number between 1 and 10 followed by an appropriate scaling exponent).

If an argument is a Boolean expression, the word true or false will be output, as appropriate.

If an argument is a char expression, the value will be output as a single ASCII character. Similarly, if an argument is a string type, it will be output as is.

write can write enumerated type values and sets in readable forms. For example, if you have

type
    color = (red,blue,green);
        ...
    write(red);

Alice will write out the word red. Similarly, a set will be written as a list of values surrounded by square brackets.

All expressions for write may have a field width specified as

:m

following the expression. m may be a positive integer expression. For example, we might have

write(i:5);

This tells how many characters should be used in printing the value. Integers will be printed with the given number of characters, padded on the left with blanks if necessary. If the integer requires more characters to print than the specified field width, the field will be expanded until the integer fits. In other words, the field width you specify is a minimum width, not an absolute.

Real numbers will be printed with the given number of characters, using scientific notation. This means a number containing a decimal point, followed by an e followed by an integer giving a power of 10. For example,

1.00e2

is used to represent 100.0.

Characters, strings, and Boolean values will be padded on the left with blanks, as appropriate. Again, the field will be expanded if the output is too large to fit in the specified field width. However, if the field width m is smaller than the length of a string, only the first m characters of the string will be output.

Real expressions may have a second specifier :n, as in

write(x:m:n);

This specifies the precision of the output value -- how many digits will be printed after the decimal point. If a precision is specified, the number will be written in standard (not scientific) notation. For example,

write(100.0:8:3);

would write out

b100.000

The b shows where a padding blank would be added.

Note that if no field width is given, Alice attempts to print real numbers in a nice format. This means that they are printed in normal decimal fashion (for example, ``12.645'') when possible, and in scientific notation otherwise. Note that for portable output, you should use field widths the Pascal standard defines rules for that type of output.

When an integer is written with no field width, Alice places a space before the integer so that statements like:

writeln( 10, 20, 30 );

produce readable output. This space can be avoided by using a field width of zero. If Borland deviations are enabled (+b), then the space is not output.

All other writable data types are printed in exactly the amount of space necessary if no field width is provided.

write may also be used to write values to files that do not have the text type. In this case,

write(f,v);

is equivalent to

f^ := v;
put(f);

where v is a value of the type that the output file is declared to contain.

The writeln Procedure

The writeln procedure works exactly like write, except that it adds a new-line character to the end of the output after it has finished writing out all its arguments. The effect is to finish off a line of text. writeln may be called without arguments, as in

for i := 1 to LEN do begin
    write(intarr[i]);
    end;
writeln;

The for loop writes out a number of values from the array intarr. All these values will be written to the same text line of the output file variable. After this is done, the writeln procedure is called to end the output line with a new-line character. writeln may only be used on text files.

The page Procedure

The procedure call

page(fv);

causes a form-feed character to be written to the text file fv. When the file is printed, this will cause a jump to a new page.

If the argument fv is omitted, the file output is assumed, and thus a call to page with no arguments clears the display screen.

Alternative Terminal I/O

The I/O routines we have discussed so far are found in most versions of Pascal. Alice Pascal also has a number of non-standard routines for performing I/O. Some of these are unique to Alice while some are derived from Turbo Pascal. In the rest of the manual, we will usually indicate the package where each subprogram originated. If we do not, the subprogram can be taken as ``standard'' Pascal.

bool := Char_Waiting;

This function returns a Boolean value indicating whether or not there is a character waiting to be read from the keyboard. It returns ``true'' if there is a character waiting and ``false'' otherwise. Char_Waiting is unique to Alice, and its use is discouraged.

bool := KeyPressed;

This is exactly the same as Char_Waiting. However, KeyPressed is recognized by Turbo Pascal.

Cursor_To(Row,Column);

This procedure moves the cursor to a particular position on the terminal screen. Row is an integer giving the row to which the cursor should be moved. The top row is numbered 0. Column is an integer giving the column to which the cursor should be moved. The leftmost column is numbered 0. Thus Cursor_To(0,0) puts the cursor in the upper left hand corner while Cursor_To(13,40) moves the cursor to about the middle of the screen. Cursor_To is unique to Alice.

GoToXY(Column,Row);

This procedure is exactly like Cursor_To except that the top row is numbered 1 and the leftmost column is numbered 1. Note also that the row and column numbers are in the opposite order. GotoXY is recognized by Turbo Pascal.

c := Get_Char;

This function gets a single character from the keyboard. If there isn't an input character already waiting, Get_Char waits for one to be entered. Unlike read and readln, Get_Char obtains a character immediately -- it does not wait for an entire line to be entered. Get_Char cannot detect end-of-file. Get_Char returns special codes for the non-ASCII keys on the IBM-PC keyboard. These keys all return codes of ordinal value 128 or greater. Get_Char is unique to Alice.

You should avoid mixing calls to Get_Char and Char_Waiting with calls to standard I/O functions like readln, get, writeln, etc., since they perform I/O in entirely different ways. (Standard I/O functions buffer I/O, while Get_Char does not.)

i := ScrXY(code);

This function returns integer values that provide information about the terminal screen. ScrXY is unique to Alice. The code argument is an integer indicating what kind of information you want.

ScrXY(1) -- tells how many rows the screen has.

ScrXY(2) -- tells how many columns the screen has.

ScrXY(3) -- tells the height of the current graphics screen in pixels

ScrXY(4) -- tells the width of the current graphics screen in pixels

ScrXY(5) -- tells the number of colors currently available in this mode

ScrXY(7) -- returns 1 if a monochrome adapter is installed, 0 for color

ScrXY(8) -- returns 1 if a color monitor is installed, 0 for monochrome

ScrXY(-1) -- row of current cursor position (top=0).

ScrXY(-2) -- column of current cursor position (left=0).

Set_Attr(code);

This procedure is used to set terminal attributes when your program is writing output. Set_Attr is unique to Alice. The argument of Set_Attr is an integer indicating the attribute you want to set (color, bold face, reverse video, etc.). The integer is interpreted as a bit pattern, according to the following key:

Bits 0-2 (values 1-7)

color; on a monochrome screen, 1 means underlining; color codes are

0 -- black

1 -- blue

2 -- green

3 -- cyan

4 -- red

5 -- magenta

6 -- brown

7 -- white

Bit 3 (value 8)

bold face (brighter for color)

Bit 5 (value 32)

"reverse video" (black on white background)

Bit 6 (value 64)

black on colored background; color given by bits 0-2

Bit 7 (value 128)

blinking output

For example, a code of octal 054 would give reverse video bold red.

ClrEol;

This routine clears the screen from the current cursor position to the end of the line, using the current attribute for the clear. The cursor position does not change. This is from Turbo Pascal.

ClrScr;

This routine clears the entire screen, and positions the cursor at the top left corner of the display. The current attribute is used for the clear. This is from Turbo Pascal.

CrtInit;

This routine does nothing in Alice, and is included primarily for compatibility with Turbo Pascal. Historically, this routine would send an "initialization string" to the terminal used in a CP/M environment. Since this is all unnecessary on a PC, there is no real need to call this routine. [Found in TURBOLIB.AP]

CrtExit;

This routine does nothing in Alice, and is included primarily for compatibility with Turbo Pascal. Historically, this routine would send a "de-initialization string" to the terminal used in a CP/M environment. Since this is all unnecessary on a PC, there is no real need to call this routine. [Found in TURBOLIB.AP]

DelLine;

This procedure erases the current line on the display, and scrolls the text below that line up to fill the gap. The bottom line of the display is cleared, using the current attribute. This is from Turbo Pascal.

InsLine;

This procedure scrolls the current line and all the lines below it downward, and clears the current line to blanks in the current attribute. The cursor remains on the newly-vacated line. This is from Turbo Pascal.

TextColor(color);

This routine sets the color for to use for any characters written to the display. The color value is an integer, in the range 0..15. If you would like the text to blink, add 16 to the color value. This is from Turbo Pascal. The colors and the blink attribute are all defined in the file TURBOLIB.AP.

TextBackground(color);

This routine sets the color for to use for the background when writing text to the display. The color value is an integer, in the range 0..7. This is from Turbo Pascal. The colors are all defined in the file TURBOLIB.AP.

TextMode(n)

This routine sets the display to text mode. The argument is optional; if specified, it is interpreted as follows:

0 Black and White, 40 columns 1 Color, 40 columns 2 Black and White, 80 columns 3 Color, 80 columns 7 Monochrome adapter

There are definitions for these values in TURBOLIB.AP.

If no argument is specified, the last text mode to have been set is set again. If no text mode has previously been set, mode 3 is used.

Note that in TextMode, all output to the display is done through the BIOS; this means that the normal blinking cursor will appear on the screen, and that the full 25 line display is available for output.

Text written in this mode is saved when a program is suspended, and may be examined using the view command.

Window(x1,y1,x2,y2);

This procedure re-maps all subsequent text output so that it fits within the box whose upper left corner is at (x1, y1) and whose lower right corner is at (x2, y2). (x1, y1) is treated as the new origin; thus ClrEol, for example will only clear to the rightmost edge of the window. All arguments are of type integer and the coordinate system used is the same as that of GotoXY.

Keep in mind that these screen coordinates are absolute, and do not depend on the screen being 23 lines, 25 lines, or 9 lines high.

WhereX;

This function returns the current column of the cursor (in the range 1..80 or 1..40, depending on the screen mode). See also ScrXY. [Found in TURBOLIB.AP]

WhereY;

This function returns the current row of the cursor (in the range 1..25, 1..23 or 1..9, depending on whether i/o is being done in TextMode, normal mode, or debug mode). See also ScrXY. [Found in TURBOLIB.AP]

LowVideo;

This procedure causes subsequent output to the display to be displayed at low (i.e. normal) intensity. See NormVideo and HighVideo, below. This Routine is from Turbo Pascal.

NormVideo;

This procedure causes subsequent output to the display to be displayed at high intensity. This unusual choice is consistent with Turbo Pascal; however, you will probably find LowVideo a better setting in most cases.

HighVideo

This routine is equivalent to NormVideo (i.e. it sets high intensity mode on for the display). This routine is undocumented in Turbo Pascal, but is used in programs provided by Borland itself.

Sound Support

Sound(n)

This routine causes a tone of frequency n cycles per second to be emitted rom the speaker. sound(0) will turn off all sound. See also nosound. This Routine is from Turbo Pascal.

NoSound;

This routine turns off all sound from the speaker. It is equivalent to sound(0). [Found in TURBOLIB.AP]

Graphics

The following routines all deal with graphics on the PC.

A standard PC Color/Graphics Adapter (CGA) supports a variety of display modes. There are four text modes (see TextMode and related routines) which display text characters only, and there are three graphics modes which are capable of displaying both graphical images and text.

The first graphics mode, set by the GraphColorMode procedure, is medium resolution colour. The display becomes a 320 x 200 array of dots (pixels), and each pixel can be one of four colors.

The procedure GraphMode also sets up a 320 x 200 pixel graphics screen, but the colors are chosen to look distinct on black and white monitors. This mode is known as medium resolution black and white.

The third mode is high resolution (640 x 200 in a single color). This mode is set by the routine HiRes.

Many of the graphics routines take a parameter called color. This color will be in the range 0..3 for GraphMode mode and GraphColorMode, and in the range 0..1 in HiRes. In cases where the color may be 0 or 1, 0 selects the "background" color and 1 selects the "foreground" color; the default is a white foreground on a black background. In four-color mode, 0 is still the "background" color, while the colors corresponding to values 1..3 are determined by the choice of "palette".

In HiRes mode, you can use the procedure HiResColor(color) to set the foreground color, which may be any value in the range 0..15 (see the color definitions in TURBOLIB.AP). The background color in HiRes mode is always 0 (black). The default HiRes foreground color in Alice Pascal is white, but Turbo Pascal defaults to black, so it is a good idea to set the foreground color after HiRes.

In GraphColorMode, you can use GraphBackground(color) to set the background color to any of the 16 possible colors (again, see the color definitions in TURBOLIB.AP). The palette routine can be used to select one of four possible palettes, and the color specified in the drawing routines selects a color from that palette (with 0 always being the same as the background color).

In GraphMode, you can still use some colors. The background color is still set by GraphBackground, and may be any of the 16 possible colors. The palette available is more limited; see the palette routine for details.

Note that setting any of the graphics modes (using GraphMode, GraphColorMode, or HiRes) will cause the screen to be cleared. Note also that any attempt to do graphics on a Monochrome display adapter will produce an error. Your programs should query the type of display adapter with ScrXY.

Palette(num)

This routine selects which of the color palettes is to be used. In GraphColorMode, the selection is:

Palette 0 Green Red Brown Palette 1 Cyan Magenta Light Gray Palette 2 Light Green Light Red Yellow Palette 3 Light Cyan Light Magenta White

The colors listed above are for color values of 1, 2 and 3; color zero is always the background color (see GraphBackground).

In GraphMode, the selection is more limited:

Palette 0 Blue Red Light Gray Palette 1 Light Blue Light Red White

There are two graphics primitives, Plot and Draw. Both assume that the x coordinate is horizontal, and the y coordinate is vertical, with the origin (0, 0) being the top left corner of the screen.

Plot(x, y, color)

This routine sets the point at location (x, y) to be the specified color.

Draw(x1, y1, x2, y2, color)

This routine draws a line from (x1, y1) to (x2, y2) in the given color. This routine is extremely fast. Note that the Turtle Graphics libraries replace this routine with another of the same name (see the documentation on Turtle Graphics for details).

Some examples would be in order:

GraphColorMode;
GraphBackground(14);
Palette(2);
Plot(13, 27, 1);
Delay(1000);
Plot(13, 27, 0);

would cause the screen to go into 320 x 200 mode, and set the screen background color to be Yellow. It would then plot a Light Green point at (13, 27). It would then wait for approximately 1 second (see Delay) and then set that point back to the background color (in this case, Yellow).

GraphWindow(x1, y1, x2, y2)

This routine changes the origin or plotting procedures and alters the clipping window. The new origin is at x1, y1 and the new clipping window is the rectangle with upper left hand corner at the origin and upper right hand corner at x2, y2.

The change or origin means that all coordinates will have the new origin added too them. The clipping window causes lines draw to coordinates outside the rectangle to be clipped, which means that only the portion of the line that falls within the rectangle is drawn.

For example,

GraphWindow(10, 10, 100, 100);
Draw(0, 0, 200, 200);

will cause a line to be drawn from (10, 10) to (100, 100).

All arguments are of type integer; x is the column and y is the row.

Special Features of GraphMode

The GraphMode routine has a set of optional parameters. Note that these parameters are not supported in the Turbo Pascal version of GraphMode, and so using them will make it more difficult to move your program from Alice to Turbo.

These additional parameters, if specified, cause all subsequent graphics output to be done using the ROM BIOS "set pixel" routines. This will be considerably slower, but has the advantage that you can use your program with a wide variety of display adapters (provided, of course, that they are supported by your BIOS).

The full form of the call to GraphMode is:

GraphMode(mode, width, height, colors, rows, cols, segment, size);

where mode is the ROM BIOS video mode to set (default is 4, i.e. 320 x 200 color graphics), width and height are the screen size in pixels (default 320, 200), colors is the maximum color supported in this mode of the adapter (default 3), and rows and cols are the number of character rows and columns on the screen (default 25, 40). You only need to specify as many arguments as necessary (the defaults will be used for unspecified arguments).

The segment is the segment address of the display, and size is the number of bytes of storage that the screen occupies. The defaults for both these values are zero. These values are used to copy the graphics screen away to a buffer when a program using graphics is suspended. If segment and size are 0, no graphics buffer is created. For example, the values for the IBM CGA are $B800 for segment and 16000 for size.

Direct Access I/O

The reset routine initializes a file variable for reading only. The rewrite and append routines initialize a file variable for writing only. If you want to write a program that can read and write to the same file, you must use direct access I/O routines or enable the Borland deviations (+b option). The direct access routines come from Watcom Pascal.

The update procedure initializes a file variable for both reading and writing by direct access. It has the form

update(filevar,filename);

This associates the file filename with the file variable filevar. Initializing a file variable for direct access I/O does not let you add new elements to the end of the file, but it lets you read and write existing elements in any order.

The update call performs an automatic

get(filevar);

to read the first element in the file. This means that the buffer variable filevar^ will contain the value of the first element in the file.

To move to any other element in the file, you use the setnext routine. This has the form

setnext(filevar,record);

where filevar is a file variable initialized for direct access I/O and record is an integer indicating the number of the file element to which you want to move. The element at the beginning of the file is number 0. Thus

setnext(filevar,1);

will move to the second element in the file. Note that unlike seek, setnext does not do an automatic get, so the file buffer does not contain the selected element of the file after the call. This means that a call to read will read the contents of the old file buffer variable, so you must be careful to do a get if you intend to read the selected element. There is no such problem if you plan to write, as both put and write will output to the selected element.

Block Oriented I/O

The BlockRead and BlockWrite routines read and write 128-byte blocks. Their use is as follows:

BlockRead(filevar, variable, nrecs)

This routine reads a number of 128-byte records into the region of memory. The number of records is specified by the integer nrecs. The file the records are read from are specified by the file variable filevar. The records are stored in the specified variable.

BlockWrite(filevar, variable, nrecs)

This routine writes a number of 128-byte records to the file specified by the file variable filevar. The number of records is specified by the integer nrecs. The records are written from the specified variable.

The BlockRead and BlockWrite routines are identical to the procedures of the same names in Turbo Pascal, except that the optional fourth parameter is not included. In Turbo, this is an integer var parameter giving the number of records actually read or written. If this parameter is needed, the source for both BlockRead and BlockWrite can be modified; see TURBOLIB.AP. For both BlockRead and BlockWrite, the filevar may be a file of any type of variable. Quite often this will be

file of array[1..128] of byte

and in this case normal read and write will perform a similar function to these block routines.