Input/Output

# 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 `read`s 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 `exp` n 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.