This chapter is under development, so don't be too excited about the paragraph below!
This chapter tells you how the source of a valid GNU Pascal program should look like. You can use it as tutorial about the GNU Pascal language, but since the main goal is to document all special GPC features, implementation-dependent stuff, etc., expect a steep learning curve.
This chapter does not cover how to compile your programs and to produce an executable--this is discussed above in section GNU Pascal Command Options.
A source file accepted by GNU Pascal may contain up to one program, zero or more ISO-style Modules, and/or zero or more UCSD-style Units, Units and Modules can be mixed in one project.
One trivial example for a valid GPC source file follows. Note that the below may either be in one source file, or else the Unit and the Program may be in separate source files.
Unit Foo; Interface Procedure Hello; Implementation Procedure Hello; begin (* Hello *) writeln ( 'Hello, world!' ); end (* Hello *); end. Program Bar; uses Foo; begin Hello; end.
A generic GNU Pascal program looks like the following:
Program name ( Input, Output ); import part declaration part begin statement part end.
While the program parameters (usually `Input, Output') are obligatory in ISO Pascal if you want to use `readln' and `writeln', they are optional in GNU Pascal. However if you give parameters to the program headline, they work like ISO requires.
The import part consists either of an ISO-style `import' specification or a UCSD/Borland-style `uses' clause. While `import' is intended to be used with interfaces exported by ISO-10206 Extended Pascal `Modules' and `uses' is intended to be used with `Units', this is not enforced. (See also section uses, section import.)
The declaration part consists of constant, type, variable, procedure, and function declarations in free order.
As an extension, GPC supports a "declaring statement" which can be used in the statement part to declare variables (see section Var).
A generic GNU Pascal Unit looks like the following:
Unit name; Interface import part interface part Implementation implementation part initialization part end.
The name of the unit should coincide with the name of the file with the extension `.pas' or `.p' stripped. (If not, you can tell GPC the file name with `uses foo in 'bar.pas'', see section uses.)
The import part is either empty or contains a `uses' clause to import other Units. It may also consist of an ISO-style `import' specification. Note that the implementation part is not preceeded by a second import part in GPC (see section import).
The interface part consists of constant, type, and variable declarations, procedure and function headings which may be freely mixed.
The implementation part is like the declaration part of a program, but the headers of procedures and functions may be abbreviated: Parameter lists and function return values may be omitted for procedures and functions already declared in the interface part.
The initialization part may be missing, or it may be a `begin' followed by one or more statements, such that the Unit has a statement part between this `begin' and the final `end'. Alternatively, a Unit may have ISO-style Module initializers and finalizers, see section to begin, section to end.
Note that GPC does not check whether all interface declarations are resolved in the same Unit. Procedures and functions which are in fact not used may be omitted, and/or procedures and functions may be implemented somewhere else, even in a different language.
(Under construction. If you are familiar with Extended Pascal Modules, please help!)
Besides `Integer', GNU Pascal supports a large zoo of integer types. Some of them you will find in other compilers, too, but most are GNU extensions, introduced for particular needs. Many of these types are synonyms for each other. In total, GPC provides 20 built-in integer types, plus seven families you can play with. (Four of these "families" are signed and unsigned, packed and unpacked Subrange types; the others are explained below.)
See also: section Subrange Types.
For most purposes, you will always use `Integer', a signed integer type which has the "natural" size of such types for the machine. On most machines GPC runs on, this is a size of 32 bits, so `Integer' usually has a range of `-2147483648..2147483647' (see section Integer).
If you need an unsigned integer type, the "natural" choice is `Cardinal', also called `Word'. Like `Integer', it has 32 bits on most machines and thus a range of `0..4294967295' (see section Cardinal, section Word).
These natural integer types should be your first choice for best performance. For instance on an Intel X86 processor operations with `Integer' usually work faster than operations with shorter integer types like `ShortInt' or `ByteInt' (see below).
`Integer', `Cardinal', and `Word' define the three "main branches" of GPC's integer types. You won't always be able to deal with the natural size; sometimes something smaller or longer will be needed. Especially when interfacing with libraries written in other languages such as C, you will need equivalents for their integer types.
The following variants of `Integer', `Cardinal' and `Word' are guaranteed to be compatible to the integer types of GNU C. The sizes, however, are not guaranteed. They are just typical values currently used on most platforms, but they may be actually shorter or increase in the future.
(signed) (unsigned) GNU C equivalent typical size (bits) ByteInt ByteCard Byte [un]signed char 8 ShortInt ShortCard ShortWord [unsigned] short int 16 Integer Cardinal Word [unsigned] int 32 MedInt MedCard MedWord [unsinged] long int 32 LongInt LongCard LongWord [unsinged] long long int 64
Since we don't know whether `LongInt' will always remain the "longest" integer type available--maybe GNU C will get `long long long int', one day, which we will support as `LongLongInt'---we have added the synonym `LongestInt' for the longest available singed integer type, and the same holds for `LongestCard' and `LongestWord'.
In some situations you will need an integer type of a well-defined size. For this purpose, GNU Pascal provides tree families of signed and unsinged integer types. The type
Integer ( 42 )
is guaranteed to have a precision of 42 bits. In a realistic context, you will most often give a power of two as the number of bits, and the machine you will need it on will support variables of that size. If this is the case, the specified precision will simultaneously be the amount of storage needed for variables of this type.
In short: If you want to be sure that you have a signed integer with 32 bits width, write `Integer ( 32 )', not just `Integer' which might be bigger. The same works with `Cardinal' and `Word' if you need unsigned integer types of well-known size.
If you care about ISO compliance, only use `Integer' and subranges of `Integer'.
Some of GPC's non-ISO integer types exist in Borland Pascal, too: `Byte', `ShortInt', `Word', and `LongInt'. The sizes of these types, however, are not the same as in Borland Pascal. Even for `Byte' this is not guaranteed (while probable, though).
When designing GNU Pascal, we thought about compatibility to Borland Pascal. Since GNU Pascal is (at least) a 32-bit compiler, `Integer' must have (at least) 32 bits. But what to do with `Word'? Same size as `Integer' (like in BP) or 16 bits (like in BP)? We decided to make `Word' the "natural-sized" unsigned integer type, thus making it (at least) 32 bits wide. Similarly, we decided to give `LongInt' twice the size of `Integer' (like in BP) rather than making it 32 bits wide (like in BP). So `LongInt' has 64 bits, and `ShortInt' has 16 bits on the Intel X86 platforms.
On the other hand, to increase compatibility to Borland Pascal and Delphi, GPC provides the alias name `Comp' for `LongInt' (64 bits on Intel X86) and `SmallInt' for `ShortInt' (16 bits on Intel X86). Note that BP treads `Comp' as a "real" type and allows assignments like `MyCompVar:= 42.0'. Since we don't consider this a feature, GPC does not copy this behaviour.
Here is a summary of all integer types defined in GPC. The sizes and ranges are only typical values, valid on some, but not all platforms. Compatibility to GNU C however is guaranteed (to the extend of the GNU General Public License, of course ;-).
To specify the number of bits, use
See also: section Subrange Types.
GNU Pascal supports Standard Pascal's subrange types:
Type MonthInt = 1..12; Capital = 'A'..'Z'; ControlChar = ^A..^Z; (* `^A' = `chr ( 1 )' is an extension *)
To increase performance, variables of such a type are aligned in a way which makes them fastest to access by the CPU. As a result, `1..12' occupies 4 bytes of storage on an Intel X86 compatible processor.
For if you want to save storage at the expense of speed, GPC provides a `packed' variant of these as an extension:
Type MonthInt = packed 1..12;
A variable of this type occupies the shortest possible (= addressable) space in memory--one byte on an Intel X86 compatible processor.
See also: section packed.
(Under construction.)
(Under construction.)
GNU Pascal supports all operators of ISO Pascal and Borland Pascal. In addition, you can define your own operators according to the Pascal-SC (PXSC) syntax.
The following table lists all built-in GNU Pascal operators, ordered by precedence: `:=' has lowest precedence, `not' highest. As usual, the precedence of operators can be superseeded with parentheses.
:= < = > in <> >= <= + - or +< -< +> -> * / div mod and shl shr xor *< /< *> /> pow ** not & @
The Pascal-SC (PXSC) operators `+<', `-<', `+>', `->', `*<', `/<', `*>', and `/>' are not yet implemented into GNU Pascal but may be defined by the user (see below).
GNU Pascal allows the definition of binary operators according to the Pascal-SC (PXSC) syntax. The following "scalar product" example illustrates how to do this:
Type Vector = record x, y: Real; end (* Vector *); Operator * ( a, b: Vector ) s: Real; (* or: `= s: Real' *) begin (* Vector * Vector *) s:= a.x * b.x + a.y * b.y; ^end (* Vector * Vector *); Var u, v: Vector; a: Real; [...] a:= u * v;
Between the closing parenthesis of the argument list and the result variable, GPC allows an optional equal sign. This is not allowed in PXSC, but it is consistent with Extended Pascal's function return variable definitions, where the equal sign is obligatory (but optional in GPC).
The argument types needn't be equal, and the name of the operator may be an identifier instead of a known symbol. You cannot define new symbols in GPC.
The PXSC operators `+>', `+<', etc. for exact numerical calculations currently are not implemented in GPC, but you can define them. If you write a module which really implements these operators, please send it to us, so we can include it into the next distribution. Also, the other real-type operators do not meet the requirements of PXSC; a module which fixes that would be a welcome contribution.
(And if you know more about modules in Pascal-SC than just their existence, please contact us either! We could probably easily implement them if we knew how they look like. Something quite close to Pascal-SC modules already is implemented as "GNU specific modules".)
Schemata are types that depend on one or more variables, called "discriminants". They are an ISO-10206 Extended Pascal extension.
Type RealArray ( n: Integer ) = array [ 1..n ] of Real;
The type `RealArray' in this example is called a Schema with the discriminant `n'. To declare a variable of such a type, write
Var Foo: RealArray ( 42 );
Schema-typed variables "know" about their discriminants. They can be accessed just like record fields:
writeln ( Foo.n ); (* yields 42 *)
While types of variables must always have specified discriminants (which may be other variables), pointers to schema variables may be without a discriminant:
Type RealArrayPtr = ^RealArray; Var Bar: RealArrayPtr;
When applying `New' to such a pointer, you must specify the intended value of the discriminant as a parameter:
New ( Bar, 137 );
As a GNU extension, the above can also be written as
Bar:= New ( RealArrayPtr, 137 );
Schemata are not limited to arrays. They can be of any type that normally requires constant values in its definition, for instance subrange types, or records containing arrays etc. (Sets do not yet work.)
To finish this section, here is a somewhat exotic example:
Type ColorType = ( red, green, blue ); ColoredInteger ( Color: ColorType ) = Integer;
A `ColoredInteger' behaves just like an ordinary integer, but it has an additional property `Color' which can be accessed like a record field.
Var Foo: ColoredInteger ( green ); [...] Foo:= 7; if Foo.Color = red then inc ( Foo, 2 ) else Foo:= Foo div 3;
GPC allows to increment, decrement, compare, and subtract pointers or to use them in `for' loops just like the C language.
Var A: array [ 1..7 ] of Char; p, q: ^Char; i: Integer; [...] for p:= @A [ 1 ] to @A [ 7 ] do p^:= 'x'; p:= @A [ 7 ]; q:= @A [ 3 ]; while p > q do begin p^:= 'y'; dec ( p ); end (* while *); p:= @A [ 7 ]; q:= @A [ 3 ]; i:= q - p; (* yields 4 *)
Incrementing a pointer by one means to increment the address it contains by the size of the variable it is pointing to. For typeless pointers (`Pointer'), the address is incremented by one instead.
Similar things hold when decrementing a pointer.
Subtracting two pointers yields the number of variables pointed to between both pointers, i.e. the difference of the addresses divided by the size of the variables pointed to. The pointers must be of the same type.
In some cases, especially when interfacing with other languages, Pascal's strong typing can be an obstacle. To temporarily circumvent this, GPC (and other Pascal compilers) defines explicit "type casts".
There are two kinds of type casts, value type casts and variable type casts.
Value type casts
To convert a value of one data type into another type, you can use the target type like the name of a function that is called. The value to be converted can be a variable or an expression.
An example:
Var Ch: Char; i: Integer; [...] i := Integer (Ch);
Another, more complicated, example:
Type CharPtr = ^Char; CharArray = array [ 0..99 ] of Char; CharArrayPtr = ^CharArray; Var Foo1, Foo2: CharPtr; Bar: CharArrayPtr; [...] {$X+} { We need extended syntax in order to use "Succ" on a pointer } Foo1 := CharPtr ( Bar ); Foo2 := CharPtr ( Succ ( Bar ) );
However, because of risks involved with type casts, explained below, you should try to avoid type casts whenever possible -- and it should be possible in most cases. For instance, the first example above could use the built-in function "Ord" instead of the type cast:
i := Ord (Ch);
The assignments in the second example could be written in the following way without any type casts:
Foo1 := @Bar^ [ 0 ]; Foo2 := @Bar^ [ 1 ];
Value type casting only works between certain types: either between different ordinal types (including integer types), or between different real types, or between different pointer types. In each case, the actual value, i.e. the ordinal or numeric value or the address pointed to, respectively, is preserved in the cast.
Note: It is also possible to cast from an integer into a real type. This is a consequence of the fact that integer values are generally automatically converted to real values when needed.
Note: In the case of pointers, a warning is issued if the dereferenced target type requires a bigger alignment than the dereferenced source type (see section Alignment).
Variable type casts
It is also possible to temporarily change the type of a variable, without converting its contents in any way. This is called variable type casting.
The syntax is the same as for value type casting. This can be confusing, as the example below shows.
The type-casted variable is still the same variable (memory location) as the original one, just with a different type. Outside of the type cast, the variable keeps its original type.
There are some important differences between value and variable type casting:
program TypeCastingTraps; { Declare a real type and an integer type of the same size, and some variables of these types we will need. } Type RealType = ShortReal; IntegerType = Integer ( BitSizeOf ( RealType ) ); Var i, i1, i2, i3, i4, i5: IntegerType; r, r1, r2, r3, r4: RealType; begin { First part: Casting integer into real types. } { Start with some integer value } i := 42; { First attempt to cast. Here, an lvalue is casted, so this must be a variable type cast. Therefore, the bit pattern of the value of i is transferred unchanged into r1 which results in a silly value of r1. } IntegerType (r1) := i; { Second try. Here we cast an expression -- though a trivial one --, rather than a variable. So this can only be a value type cast. Therefore, the numeric value is preserved, i.e. r2 = 42.0 . } r2 := RealType (i+0); { Third way. In this last example, a variable is casted, and the result is used as an expression, not as an lvalue. So this could be either a value or variable type cast. However, there is a rule that value type casting is preferred if possible. So r3 will contain the correct numeric value, too. } r3 := RealType (i); { Of course, you do not need any casts at all here. A simple assignment will work because of the automatic conversion from integer to real types. So r4 will also get the correct result. } r4 := i; { Now the more difficult part: Casting real into integer types. } { Start with some real value. } r := 41.9; { Like the first attempt above, this one does a variable type cast, preserving bit patterns, and leaving a silly value in i1. } RealType (i1) := r; { The second try from above does not work, because an expression of type real is to be casted into an integer which is not allowed. } { i2 := IntegerType (r+0); } { Third way. This looks just like the third way in the first part which was a value type cast. But -- surprise! Since value type casting is not possible from real into integer, this really does a variable type casting, and the value of i3 is silly again! This difference in behaviour shows some of the hidden traps in type casting. } i3 := IntegerType (r); { As often, it is possible to avoid type casts altogether and convert real types into integers easily by other means, i.e. by using the built-in functions "Round" or "Trunc", depending on the mode of rounding one wants. } i4 := Round (r); { 42 } i5 := Trunc (r); { 41 } end.
When dealing with objects (see section Object-orientated Programming), it is often necessary--and safe--to cast a pointer to an object into a pointer to a more specialized (derived) object. In future releases, GPC will provide an operator `as' for a safer approach to this problem.
See also: section absolute, section Alignment, section Endianness, section Object-orientated Programming, section ord, section chr, section round, section trunc.
GNU Pascal follows the object model of Borland Pascal 7.0. The ANSI draft Object Pascal language and the Delphi language (also called "Object Pascal" by Borland) are currently not implemented, but planned for future versions of GPC.
The syntax for an object type declaration is as follows:
Type fooParentPtr = ^fooParent; fooPtr = ^foo; fooParent = object Destructor Fini; virtual; Procedure bar ( c: Real ); virtual; Procedure baz ( b, a, z: Char ); (* not virtual *) end (* FooParent *) foo = object ( fooParent ) x, y: Integer; Constructor Init ( a, b: Integer ); Destructor Fini; virtual; z: Real; Procedure bar ( c: Real ); virtual; (* overrides `fooParent.bar' *) Function baz: Boolean; (* new function *) end (* foo *);
Remarks:
A pointer to `fooParent' may be assigned the address of a `foo' object. A `fooParent' formal `Var' parameter may get a `foo' object as the actual parameter. In such cases, a call to a `virtual' method calls the child's method, whereas a call to a non-`virtual' method selects the parent's one:
Var MyFooParent: fooParentPtr; SomeFoo: foo; [...] SomeFoo.Init ( 4, 2 ); MyFooParent:= @SomeFoo; MyFooParent^.bar ( 3.14 ); (* calls `foo.bar' *) MyFooParent^.baz ( 'b', 'a', 'z' ); (* calls `fooParent.baz' *) if SomeFoo.baz then (* calls `foo.baz' *) writeln ( 'Baz!' );
In a method, an overwritten method of a parent object can be called either prefixing it with the parent type name, or using the keyword `inherited':
Procedure foo.bar ( c: Real ); begin (* foo.bar *) z:= c; inherited bar ( z ); (* Or: fooParent.bar ( z ) *) end (* foo.bar *);
Use `fooParent.bar ( z )' if you want to be sure that this method is called, even if somebody decides not to derive `foo' directly from `fooParent' but to have some intermediate object. If you want to call the method `bar' of the immediate parent--whether it be `fooParent' or whatever--use `inherited bar ( z )'.
To allocate an object on the heap, use `New' in one of the following manners:
Var MyFoo: fooPtr; [...] New ( MyFoo, Init ( 4, 2 ) ); MyFooParent:= New ( fooPtr, Init ( 4, 2 ) );
The second possibility has the advantage that `MyFoo' needn't be a `fooPtr' but can also be a `fooParentPtr', i.e. a pointer to an ancestor of `foo'.
Destructors can and should be called within Dispose:
Dispose ( MyFooParent, Fini );
The standardized GNU compiler back-end makes it relatively easy to share libraries between GNU Pascal and other GNU compilers. On UNIX-like platforms (not on MS-DOS-like platforms), the GNU compiler back-end usually complies to the standards defined for that system, so communication with other compilers should be easy, too.
In this chapter we discuss how to import libraries written in other languages, and how to import libraries written in GNU Pascal from other languages. While the examples will specialize to compatibility to GNU C, generalization is straightforward if you are familiar with the other language in question.
To use a function written in another language, you need to provide an external declaration for it--either in the program, or in the interface part of a Unit, or an Interface Module.
Let's say you want to use the following C library from Pascal:
/* foobar.c */ #include <unistd.h> int foo = 1; void bar ( void ) { sleep ( foo ); } /* bar */ /* foobar.h */ extern int foo; extern void bar ( void );
Then your program can look like this:
Program TestFoo; (*$L foobar.c *) (* Or: `foobar.o' if you don't have the source *) Var foo: asmname 'foo' Integer; Procedure Bar; asmname 'bar'; begin foo:= 42; Bar; (* Take a break :*) end.
Or, if you want to provide a `FooBar' Unit:
Unit FooBar; Interface Var foo: asmname 'foo' Integer; Procedure Bar; asmname 'bar'; Implementation (* empty *) end.
You can either link your program manually with `foobar.o' or put a compiler directive `(*$L foobar.o *)' into your program (planned for Units, too), and then GPC cares about the linking. If you have the source of the "FooBar" library (you always have it if it is Free Software), you can even write `(*$L foobar.c *)' in the program (like above). Then GPC will also link with `foobar.o', but in addition GPC will run the C compiler whenever `foobar.c' has changed if `--automake' is given, too.
While it is convenient for most applications, there is no must to give the C function `bar' the name `Bar' in Pascal; you can name it as you like.
For external functions completely written in lowercase there is the shortcut `C' or `C_language' for `asmname 'bar''. For external functions written with one uppercase letter and the others in lowercase, you can use `external' or `extern' instead of `asmname 'Bar''. Since GPC internally converts all identifiers to this notation, `external' is the natural choice when importing other Pascal functions.
Caution: This syntax (`C', `asmname' and such) is subject to change, especially for variables.
Some libraries provide a `main' function and require your program's "main" to be named differently. To achive this with GPC, invoke it with an option `--gpc-main="GPCmain"' (where "GPCmain" is an example how you might want to name the program). You can also write it into your source as a directive `(*$pascal-main="GPCmain" *)'.
The `.o' files produced by GPC are in the same format as those of all other GNU compilers, so there is no problem in writing libraries for other languages in Pascal. To use them, you will need to write kind of interface--a header file in C. However there are some things to take into account, especially if your Pascal Unit exports objects:
Procedure FooBAR; asmname 'FooBAR'; (* Works like a `forward' declaration *) Procedure FooBAR; begin (* FooBAR *) writeln ( 'FooBAR' ); end (* FooBAR *);This one can be imported from C with `extern void FooBar()'.
Type SizeInt = Integer ( BitSizeOf ( Pointer ) ); VMT = record ObjectSize: SizeInt; (* Size of object in bytes. *) NegObjectSize: SizeInt; (* Its negative. *) Fun: array [ 1..n ] of Procedure; (* Pointers to the virtual functions. *) end (* VMT *);You can call a virtual method of an object from C if you explicitly declare this `struct' and explicitly dereference the `Fun' array. The VMT of an object `FooBAR' is an external (in C sense) variable `vmt_Foobar' internally.
Below is a pascal source of the declarations in GPC's run time library. A file `gpc.pas' with the same contents is included in the GPC distribution in the same directory as `libgcc.a'. (To find out the correct directory for your installation type `gpc -print-libgcc-file-name' at the command prompt.)
{ Copyright (C) 1998 Free Software Foundation, Inc. This file is part of GNU Pascal Library. Pascal declarations of the GPC RTS that are visible to each program. The GNU Pascal Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU Pascal Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU Pascal Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } { Author: Frank Heckenbach <frank@pascal.gnu.de> } { Note about "protected var" parameters: Since const parameters in GPC can be passed by value OR by reference internally, possibly depending on the system, "const foo*" parameters to C functions *cannot* reliably declared as "const" in Pascal. However, Extended Pascal's "protected var" can be used since this guarantees passing by reference. Note about the "GPC_" prefix: This is inserted so that some identifiers don't conflict with the built-in ones. Sometimes, the built-in ones do exactly the same as the ones declared here, but often enough, they contain some "magic", so they should be used instead of the plain declarations here. In general, routines with a "GPC_" prefix should not be called from programs. They are subject to change or disappering in future GPC versions. } unit gpc; interface { ================= PROGRAM INITIALIZATION AND TERMINATION ================ } { Setup and final routines, from setup.c } procedure GPC_Setup; asmname '_p_setup'; procedure GPC_Final; asmname '_p_final'; { Top level entrypoint and RTS initialization, from rt0.c } type PCString = ^CString; var Environment : asmname '_p_envp' PCString; procedure GPC_Initialize (ArgumentCount: Integer; Arguments, Environment: PCString); asmname '_p_initialize'; procedure GPC_Finalize; asmname '_p_finalize'; { Miscellaneous routines for extended pascal support, from misc.c } type ProcPtr = ^Procedure; procedure GPC_Halt (ExitCode: Integer); asmname '_p_halt'; procedure GPC_Collect (Proc: ProcPtr; Run_ID: Integer); asmname '_p_collect'; procedure GPC_Run_Constructors; asmname '_p_run_constructors'; { Error handling functions, from error.c } var { BP compatible InOutRes variable } GPC_InOutRes : asmname '_p_inoutres' Integer; { CString parameter to some error messages, NOT the text of the error message } GPC_InOutRes_Str : asmname '_p_inoutres_str' CString; { Error number (after runtime error) or exit status (after Halt) or 0 (during program run and after succesfull termination). } ExitCode : asmname '_p_exitcode' Integer; { Non-nil after runtime error, nil otherwise. } ErrorAddr : asmname '_p_erroraddr' Pointer; function Get_Error_Message (n: Integer): CString; asmname '_p_errmsg'; function Get_Check_Error_Message (n: Integer; Format: CString): CString; asmname '_p_check_errmsg'; procedure Print_Message (str: CString; n: Integer; Warning: Boolean); asmname '_p_prmessage'; procedure GPC_RunError (n: Integer); asmname '_p_runerror'; procedure Runtime_Error (n: Integer); asmname '_p_error'; procedure Runtime_Error_Integer (n: Integer; i: MedInt); asmname '_p_error_integer'; procedure Runtime_Error_CString (n: Integer; s: CString); asmname '_p_error_string'; procedure Internal_Error (n: Integer); asmname '_p_internal_error'; procedure Internal_Error_Integer (n: Integer; i: MedInt); asmname '_p_internal_error_integer'; procedure IO_Error (n: Integer); asmname '_p_io_error'; procedure IO_Error_CString (n: Integer; s: CString); asmname '_p_io_error_string'; procedure Check_InOutRes; asmname '_p_check_inoutres'; function GPC_IOResult : Integer; asmname '_p_ioresult'; procedure Runtime_Report (msg: CString); asmname '_p_report'; procedure Runtime_Report_Integer (msg: CString; i: MedInt); asmname '_p_report_integer'; procedure Runtime_Report_CString (msg: CString; s: CString); asmname '_p_report_string'; { =========================== MEMORY MANAGEMENT =========================== } { Boolean constants about endianness and alignment } const Bits_Big_Endian = {$ifdef __BITS_LITTLE_ENDIAN__} False {$else}{$ifdef __BITS_BIG_ENDIAN__} True {$else}{$error Bit endianness is not defined!} {$endif}{$endif}; Bytes_Big_Endian = {$ifdef __BYTES_LITTLE_ENDIAN__} False {$else}{$ifdef __BYTES_BIG_ENDIAN__} True {$else}{$error Byte endianness is not defined!} {$endif}{$endif}; Words_Big_Endian = {$ifdef __WORDS_LITTLE_ENDIAN__} False {$else}{$ifdef __WORDS_BIG_ENDIAN__} True {$else}{$error Word endianness is not defined!} {$endif}{$endif}; Need_Alignment = {$ifdef __NEED_ALIGNMENT__} True {$else} False {$endif}; { UCSD Pascal `MoveLeft' and `MoveRight' transfer procedures, from move.pas } procedure GPC_MoveLeft (const Source; var Dest; Count: SizeType); asmname '_p_moveleft'; procedure GPC_MoveRight (const Source; var Dest; Count: SizeType); asmname '_p_moveright'; { Heap manipulation, from heap.c } { A "few" other versions of New are still overloaded magically } function GPC_Malloc (Size: Integer): Pointer; asmname '_p_malloc'; function GPC_New (Size: Integer): Pointer; asmname '_p_new'; procedure GPC_Dispose (aPointer: Pointer); asmname '_p_dispose'; procedure GPC_Mark (var aPointer: Pointer); asmname '_p_mark'; procedure GPC_Release (aPointer: Pointer); asmname '_p_release'; { ======================== STRING HANDLING ROUTINES ======================= } { String handling routines, from string.c } type GPC_String (Capacity: Cardinal) = record Length: 0..Capacity; Chars: array [1..Capacity] of Char end; (*@@ AnyString parameters are not yet implemented, the following is only a draft*) TChars = array [0..MaxInt] of Char; PChars = ^TChars; AnyString_Type = ( AnyString_Long, AnyString_Undiscriminated, AnyString_Short, AnyString_Fixed, AnyString_CString, AnyString_Object ); (*@@ only formally for now*)Undiscriminated_String = ^String; (*@@ to be designed*)String_Object = object end; { When a const or var AnyString parameter is passed, internally these records are passed as const parameters. Value AnyString parameters are passed like value string parameters. } Const_AnyString = record Length: Integer; Chars: PChars end; Var_AnyString = record Capacity: Integer; Chars: PChars; case StringType: AnyString_Type of AnyString_Long: (PLong_Length: ^Integer); AnyString_Undiscriminated: (PUndiscriminated_String: ^Undiscriminated_String); AnyString_Short: (PShort_Length: ^Byte); AnyString_Object: (PString_Object: ^String_Object) end; function GPC_String_Operations (Opcode, ArgumentMask: Integer; ...): Integer; asmname '_p_string'; procedure GPC_WriteStr (StringType: Integer; Str1: PChars; ...); asmname '_p_writestr'; procedure GPC_ReadStr (Str: PChars; StrLength, Count: Integer; ...); asmname '_p_readstr'; function GPC_Val_ByteInt_Check (Source: PChars; StrLength, Flags: Integer; var Result: ByteInt; Min, Max: ByteInt ): Integer; asmname '_p_val_byteint_check'; function GPC_Val_ShortInt_Check (Source: PChars; StrLength, Flags: Integer; var Result: ShortInt; Min, Max: ShortInt ): Integer; asmname '_p_val_shortint_check'; function GPC_Val_Integer_Check (Source: PChars; StrLength, Flags: Integer; var Result: Integer; Min, Max: Integer ): Integer; asmname '_p_val_integer_check'; function GPC_Val_MedInt_Check (Source: PChars; StrLength, Flags: Integer; var Result: MedInt; Min, Max: MedInt ): Integer; asmname '_p_val_medint_check'; function GPC_Val_LongInt_Check (Source: PChars; StrLength, Flags: Integer; var Result: LongInt; Min, Max: LongInt ): Integer; asmname '_p_val_longint_check'; function GPC_Val_ByteCard_Check (Source: PChars; StrLength, Flags: Integer; var Result: ByteCard; Min, Max: ByteCard ): Integer; asmname '_p_val_bytecard_check'; function GPC_Val_ShortCard_Check (Source: PChars; StrLength, Flags: Integer; var Result: ShortCard; Min, Max: ShortCard): Integer; asmname '_p_val_shortcard_check'; function GPC_Val_Cardinal_Check (Source: PChars; StrLength, Flags: Integer; var Result: Cardinal; Min, Max: Cardinal ): Integer; asmname '_p_val_cardinal_check'; function GPC_Val_MedCard_Check (Source: PChars; StrLength, Flags: Integer; var Result: MedCard; Min, Max: MedCard ): Integer; asmname '_p_val_medcard_check'; function GPC_Val_LongCard_Check (Source: PChars; StrLength, Flags: Integer; var Result: LongCard; Min, Max: LongCard ): Integer; asmname '_p_val_longcard_check'; function GPC_Val_ByteInt_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: ByteInt ): Integer; asmname '_p_val_byteint_nocheck'; function GPC_Val_ShortInt_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: ShortInt ): Integer; asmname '_p_val_shortint_nocheck'; function GPC_Val_Integer_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: Integer ): Integer; asmname '_p_val_integer_nocheck'; function GPC_Val_MedInt_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: MedInt ): Integer; asmname '_p_val_medint_nocheck'; function GPC_Val_LongInt_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: LongInt ): Integer; asmname '_p_val_longint_nocheck'; function GPC_Val_ByteCard_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: ByteCard ): Integer; asmname '_p_val_bytecard_nocheck'; function GPC_Val_ShortCard_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: ShortCard): Integer; asmname '_p_val_shortcard_nocheck'; function GPC_Val_Cardinal_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: Cardinal ): Integer; asmname '_p_val_cardinal_nocheck'; function GPC_Val_MedCard_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: MedCard ): Integer; asmname '_p_val_medcard_nocheck'; function GPC_Val_LongCard_NoCheck (Source: PChars; StrLength, Flags: Integer; var Result: LongCard ): Integer; asmname '_p_val_longcard_nocheck'; function GPC_Val_ShortReal (Source: PChars; StrLength, Flags: Integer; var Result: ShortReal): Integer; asmname '_p_val_shortreal'; function GPC_Val_Real (Source: PChars; StrLength, Flags: Integer; var Result: Real ): Integer; asmname '_p_val_real'; function GPC_Val_LongReal (Source: PChars; StrLength, Flags: Integer; var Result: LongReal ): Integer; asmname '_p_val_longreal'; { String handling routines, from rtsstr.pas } { A string type that is used for function results and local variables, as long as undiscriminated strings are not allowed there. The default size of 2048 characters should be enough for file names on any system, but can be changed when necessary. This should be at least as big as MAXPATHLEN. } const TStringSize = 2048; type TString = String (TStringSize); TStringBuf = array [0 .. TStringSize] of Char; function GPC_UpCase (ch : Char) : Char; asmname '_p_gpc_upcase'; function GPC_LoCase (ch : Char) : Char; asmname '_p_gpc_locase'; function BP_UpCase (ch : Char) : Char; asmname '_p_bp_upcase'; function BP_LoCase (ch : Char) : Char; asmname '_p_bp_locase'; procedure UpCaseString (var s : String); asmname '_p_upcase_string'; procedure LoCaseString (var s : String); asmname '_p_locase_string'; function UpCaseStr (const s : String) : TString; asmname '_p_upcase_str'; function LoCaseStr (const s : String) : TString; asmname '_p_locase_str'; function Pos (SubStr, Str : String) : Integer; asmname '_p_pos'; function LastPos (SubStr, Str : String) : Integer; asmname '_p_lastpos'; function StrLen (Src : CString) : SizeType; asmname '_p_strlen'; function StrEnd (Src : CString) : CString; asmname '_p_strend'; function StrScan (Src : CString; Ch : Char) : CString; asmname '_p_strscan'; function StrRScan (Src : CString; Ch : Char) : CString; asmname '_p_strrscan'; function StrDup (Src : CString) : CString; asmname '_p_strdup'; function StrCmp (s1, s2 : CString) : Integer; asmname '_p_strcmp'; function StrCaseCmp (s1, s2 : CString) : Integer; asmname '_p_strcasecmp'; function NewCString (const Source : String) : CString; asmname '_p_newcstring'; function StrPCopy (Dest : CString; const Source : String) : CString; asmname '_p_strpcopy'; procedure StrCCopy (Source : CString; var Dest : String); asmname '_p_strccopy'; procedure GPC_Insert (const Source: String; var Dest : String; Index : Integer; Truncate : Boolean); asmname '_p_insert'; procedure GPC_Delete (var s : String; Index, Count : Integer); asmname '_p_delete'; { ========================= FILE HANDLING ROUTINES ======================== } { Extended pascal binding routines, from bind.c } const { from types.h } Binding_Name_Length = 255; type AnyFile = Text; (*@@ create "AnyFile" parameters*) { from ../doc/extend.texi :-} GPC_BindingType = {@@packed} record Bound : Boolean; Extensions_Valid : Boolean; Writable : Boolean; Readable : Boolean; Executable : Boolean; Existing : Boolean; { Binding points to an existing file } Directory : Boolean; { Binding points to an existing directory; Existing is False then } Error : Integer; { Unused currently } Size : Integer; { number of elements or -1 } CFile : Pointer; { allows binding a Pascal file to a C file } Name : String (Binding_Name_Length); end; procedure GPC_Bind ( var aFile: AnyFile; protected var aBinding: BindingType); asmname '_p_bind'; procedure GPC_Binding (protected var aFile: AnyFile; var aBinding: BindingType); asmname '_p_binding'; procedure GPC_Unbind ( var aFile: AnyFile); asmname '_p_unbind'; procedure GPC_Clear_Binding ( var aBinding: BindingType); asmname '_p_clearbinding'; { NOTE: These functions are hacks! They WILL vanish soon, to be replaced by something better. Use it only to emulate BP's CRT TFDD (and only if you understand these acronyms ;-) -- fh } type t_InFunc = function (var PrivateData; var Buffer; Size: Integer; var Result: Integer) : Integer; type t_OutFunc = function (var PrivateData; const Buffer; Size: Integer; var Result: Integer) : Integer; procedure hack_SetInFunc (var aFile: AnyFile; InFunc : t_InFunc ; PrivateData: Pointer); C; procedure hack_SetOutFunc (var aFile: AnyFile; OutFunc: t_OutFunc; PrivateData: Pointer); C; { bind a filename to an external file, from fassign.pas } procedure GPC_Assign (var T : AnyFile; const Name : String); asmname '_p_assign'; procedure GPC_Internal_Assign (var T : AnyFile; Name : CString; NameLength : Integer); asmname '_p_internal_assign'; procedure Assign_CFile (var T : AnyFile; CFile : Pointer); asmname '_p_assign_cfile'; { Generic file handling routines and their support, from file.c } { Flags that can be ORed into FileMode. The default value of FileMode is FileMode_Reset_ReadWrite. Sorry for the somewhat confusing values, they are meant to be compatible to BP (as far as BP supports this). } const FileMode_Reset_ReadWrite = 2; { Allow writing to files opened with Reset } FileMode_Rewrite_WriteOnly = 4; { Do not allow reading from files opened with Rewrite } FileMode_Extend_WriteOnly = 8; { Do not allow reading from files opened with Extend } type StatFS_Buf = record BlockSize, BlocksTotal, BlocksFree : LongestInt; FilesTotal, FilesFree : Integer end; var GPC_FileMode : asmname '_p_filemode' Integer; procedure GPC_Flush ( var aFile: AnyFile); asmname '_p_flush'; function GPC_GetFile (protected var aFile: AnyFile): Pointer; asmname '_p_getfile'; procedure GPC_InitFDR ( var aFile: AnyFile; Name: CString; Size, Flags: Integer); asmname '_p_initfdr'; { Various other versions of Reset, Rewrite and Extend are still overloaded magically } procedure GPC_Rewrite ( var aFile: AnyFile; FileName: CString; Length: Integer); asmname '_p_rewrite'; procedure GPC_Extend ( var aFile: AnyFile; FileName: CString; Length: Integer); asmname '_p_extend'; procedure GPC_Reset ( var aFile: AnyFile; FileName: CString; Length: Integer); asmname '_p_reset'; procedure GPC_Close ( var aFile: AnyFile); asmname '_p_close'; function GPC_FileName (protected var aFile: AnyFile): CString; asmname '_p_filename'; procedure GPC_Erase ( var aFile: AnyFile); asmname '_p_erase'; procedure GPC_Rename ( var aFile: AnyFile; NewName: CString); asmname '_p_rename'; Procedure GPC_ChDir (Path : CString); asmname '_p_chdir'; Procedure GPC_MkDir (Path : CString); asmname '_p_mkdir'; Procedure GPC_RmDir (Path : CString); asmname '_p_rmdir'; function GPC_StatFS (Path : CString; var Buf : StatFS_Buf) : Integer; asmname '_p_statfs'; { Random access file routines, from randfile.c } function GPC_GetSize ( var aFile: AnyFile): Integer; asmname '_p_getsize'; procedure GPC_Truncate ( var aFile: AnyFile); asmname '_p_truncate'; procedure GPC_DefineSize ( var aFile: AnyFile; NewSize: Integer); asmname '_p_definesize'; procedure GPC_SeekAll ( var aFile: AnyFile; NewPlace: Integer); asmname '_p_seekall'; procedure GPC_SeekRead ( var aFile: AnyFile; NewPlace: Integer); asmname '_p_seekread'; procedure GPC_SeekWrite ( var aFile: AnyFile; NewPlace: Integer); asmname '_p_seekwrite'; procedure GPC_SeekUpdate ( var aFile: AnyFile; NewPlace: Integer); asmname '_p_seekupdate'; function GPC_Empty (protected var aFile: AnyFile): Boolean; asmname '_p_empty'; procedure GPC_Update ( var aFile: AnyFile); asmname '_p_update'; function GPC_LastPosition ( var aFile: AnyFile): Integer; asmname '_p_lastposition'; function GPC_Position ( var aFile: AnyFile): Integer; asmname '_p_position'; { Block input/output routines for untyped files, from block.c } { Versions with only 3 parameters are still overloaded magically } (*@@*)procedure GPC_BlockRead (var aFile: File; var Buf: Void; Count: Cardinal; var Result: Cardinal); asmname '_p_blockread'; (*@@*)procedure GPC_BlockWrite (var aFile: File; protected var Buf: Void; Count: Cardinal; var Result: Cardinal); asmname '_p_blockwrite'; { Routines to read various things from files, from read.c } procedure GPC_TextRead (var aFile: Text; Count: Integer; ...); asmname '_p_read'; procedure GPC_Get (var aFile: AnyFile); asmname '_p_get'; function GPC_EOF (var aFile: AnyFile): Boolean; asmname '_p_eof'; function GPC_EOLn (var aFile: Text): Boolean; asmname '_p_eoln'; procedure GPC_LazyTryget (var aFile: AnyFile); asmname '_p_lazytryget'; procedure GPC_LazyGet (var aFile: AnyFile); asmname '_p_lazyget'; procedure GPC_LazyUnget (var aFile: AnyFile); asmname '_p_lazyunget'; { Routines to output various things, from write.c } procedure GPC_Page (var aFile: Text); asmname '_p_page'; procedure GPC_TextWrite (var aFile: Text; Count: Integer; ...); asmname '_p_write'; procedure GPC_Put (var aFile: AnyFile); asmname '_p_put'; { File name routines, from filename.pas } { Define directory and path separators for different systems: PathSeparator: the separator of multiple paths, e.g. in the PATH environment variable DirSeparator: the separator of the directories within a full file name DirSeparators: a set of all possible directory and drive name separators ExtSeparator: the separator of a file name extension DirSelf: the name of a directory in itself DirParent: the name of the parent directory NullDeviceName: the full file name of the null device TTYDeviceName: the full file name of the current TTY ConsoleDeviceName: the full file name of the system console. On Dos systems, this is the same as the TTY, but on systems that allow remote login, this is a different thing and may reach a completely different user than the one running the program, so use with care. } {$ifdef __OS_DOS__} const PathSeparator = ';'; DirSeparator = '\'; DirSeparators = [':', '\', '/']; ExtSeparator = '.'; DirSelf = '.'; DirParent = '..'; NullDeviceName = 'nul'; TTYDeviceName = 'con'; ConsoleDeviceName = 'con'; {$else} const PathSeparator = ':'; DirSeparator = '/'; DirSeparators = ['/']; ExtSeparator = '.'; DirSelf = '.'; DirParent = '..'; NullDeviceName = '/dev/null'; TTYDeviceName = '/dev/tty'; ConsoleDeviceName = '/dev/console'; {$endif} function Slash2OSDirSeparator (const s : String) : TString; asmname '_p_slash2osdirseparator'; function OSDirSeparator2Slash (const s : String) : TString; asmname '_p_osdirseparator2slash'; function Slash2OSDirSeparator_CString (s : CString) : CString; asmname '_p_slash2osdirseparator_cstring'; function OSDirSeparator2Slash_CString (s : CString) : CString; asmname '_p_osdirseparator2slash_cstring'; function GetCurrentDirectory : TString; asmname '_p_get_current_directory'; function GetTempDirectory : TString; asmname '_p_get_temp_directory'; function GetTempFileName : TString; asmname '_p_get_temp_file_name'; function GetTempFileName_CString : CString; asmname '_p_get_temp_file_name_cstring'; function FileExists (const FileName : String) : Boolean; asmname '_p_file_exists'; function DirectoryExists (const FileName : String) : Boolean; asmname '_p_directory_exists'; function FSearch (const FileName, DirList : String) : TString; asmname '_p_fsearch'; function FSearch_Executable (const FileName, DirList : String) : TString; asmname '_p_fsearch_executable'; function ExpandEnvironment (var s : String) : Boolean; asmname '_p_expand_environment'; function FExpand (const Path : String) : TString; asmname '_p_fexpand'; procedure FSplit (const Path : String; var Dir, Name, Ext : String); asmname '_p_fsplit'; function DirFromPath (const Path : String) : TString; asmname '_p_dir_from_path'; function NameFromPath (const Path : String) : TString; asmname '_p_name_from_path'; function ExtFromPath (const Path : String) : TString; asmname '_p_ext_from_path'; function OpenDir (Name : CString) : Pointer; C; function ReadDir (Dir : Pointer) : TString; asmname '_p_readdir'; function CloseDir (Dir : Pointer) : Integer; asmname '_p_closedir'; { ========================= MATHEMATICAL ROUTINES ========================= } { Int and Frac routines for real numbers, from intfrac.pas } function GPC_Frac (val: LongestReal): LongestReal; asmname '_p_frac'; function GPC_Int (val: LongestReal): LongestReal; asmname '_p_int'; { Transcendental functions for Reals, from math.c } function Real_Arctan (x: Real): Real; asmname '_p_arctan'; function Real_Sqrt (x: Real): Real; asmname '_p_sqrt'; function Real_Ln (x: Real): Real; asmname '_p_ln'; function Real_Exp (x: Real): Real; asmname '_p_exp'; function Real_Sin (x: Real): Real; asmname '_p_sin'; function Real_Cos (x: Real): Real; asmname '_p_cos'; function Real_Pow (x: Real; y: Integer): Real; asmname '_p_pow'; function Real_Expon (x, y: Real): Real; asmname '_p_expon'; { Transcendental functions for LongReals, from emath.c } function LongReal_Arctan (x: LongReal): LongReal; asmname '_pp_arctan'; function LongReal_Sqrt (x: LongReal): LongReal; asmname '_pp_sqrt'; function LongReal_Ln (x: LongReal): LongReal; asmname '_pp_ln'; function LongReal_Exp (x: LongReal): LongReal; asmname '_pp_exp'; function LongReal_Sin (x: LongReal): LongReal; asmname '_pp_sin'; function LongReal_Cos (x: LongReal): LongReal; asmname '_pp_cos'; function LongReal_Pow (x: LongReal; y: Integer): LongReal; asmname '_pp_pow'; function LongReal_Expon (x, y: LongReal): LongReal; asmname '_pp_expon'; { Library functions for complex type arguments, from zmath.c } function Complex_Polar (Length, Theta: Real): Complex; asmname '_p_polar'; function Complex_Arg (z: Complex): Real; asmname '_p_arg'; function Complex_Arctan (z: Complex): Complex; asmname '_p_z_arctan'; function Complex_Sqrt (z: Complex): Complex; asmname '_p_z_sqrt'; function Complex_Ln (z: Complex): Complex; asmname '_p_z_ln'; function Complex_Exp (z: Complex): Complex; asmname '_p_z_exp'; function Complex_Sin (z: Complex): Complex; asmname '_p_z_sin'; function Complex_Cos (z: Complex): Complex; asmname '_p_z_cos'; function Complex_Pow (z: Complex; y: Integer): Complex; asmname '_p_z_pow'; function Complex_Expon (z: Complex; y: Real): Complex; asmname '_p_z_expon'; { ================== OPERATIONS ON CERTAIN BUILT-IN TYPES ================= } { Operations for SET type, from set.c } type Set_Vector = MedCard; { from set.h } function GPC_Card (var aSet: Set_Vector; aLow, aHigh: Integer): MedInt; asmname 'rts_card'; procedure GPC_DumpSet (var aSet: Set_Vector; aLow, aHigh, Level: Integer; Name: CString); asmname '_p_dumpset'; { Time and date routines for Extended Pascal, from time.c } const { from types.h } GPC_Date_Length = 11; GPC_Time_Length = 8; type GPC_Date_String = array [1..GPC_Date_Length] of Char; GPC_Time_String = array [1..GPC_Time_Length] of Char; { from ../doc/extend.texi :-} GPC_TimeStamp = {@@packed} record DateValid, TimeValid : Boolean; Year : Integer; Month : 1 .. 12; Day : 1 .. 31; DayOfWeek : 0 .. 6; { 0 means Sunday } Hour : 0 .. 23; Minute : 0 .. 59; Second : 0 .. 59; MicroSecond : 0 .. 999999 end; function DayOfWeek (Day, Month, Year : Integer) : Integer; asmname '_p_dayofweek'; procedure GPC_GetTimeStamp (var aTimeStamp: TimeStamp); asmname '_p_gettimestamp'; procedure GPC_Date (protected var aTimeStamp: TimeStamp; var Result: GPC_Date_String); asmname '_p_date'; procedure GPC_Time (protected var aTimeStamp: TimeStamp; var Result: GPC_Time_String); asmname '_p_time'; { Random number routines, from random.c } procedure GPC_Randomize; asmname '_p_randomize'; function GPC_RandReal : LongestReal; asmname '_p_randreal'; function GPC_RandInt (Max : LongestCard) : LongestCard; asmname '_p_randint'; implementation end.