Go to the first, previous, next, last section, table of contents.


The Programmer's Guide to GPC

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.

Source Structures

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.

The Source Structure of Programs

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).

The Source Structure of UCSD/Borland Pascal Units

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.

The Source Structure of ISO-10206 Extended Pascal Modules

(Under construction. If you are familiar with Extended Pascal Modules, please help!)

Data Types

Integer Types

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.

"Natural" Integer 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).

"Main Branch" Integer Types

`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'.

Integer Types with Specified Size

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.

Compatibility to other Pascal compilers

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.

Summary of Integer Types

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 ;-).

section ByteInt
signed 8-bit integer type, `-128..128',
compatible to `signed char' in GNU C.
section ByteCard
unsigned 8-bit integer type, `0..255',
compatible to `unsigned char' in GNU C.
section ShortInt
signed 16-bit integer type, `-32768..32767',
compatible to `short int' in GNU C.
section ShortCard
unsigned 16-bit integer type, `0..65535',
compatible to `unsigned short int' in GNU C.
section Integer
signed 32-bit integer type, `-2147483648..2147483647',
compatible to `int' in GNU C.
section Cardinal
unsigned 32-bit integer type, `0..4294967295',
compatible to `unsigned int' in GNU C.
section MedInt
signed 32-bit integer type, `-2147483648..2147483647',
compatible to `long int' in GNU C.
section MedCard
unsigned 32-bit integer type, `0..4294967295',
compatible to `unsigned long int' in GNU C.
section LongInt
signed 64-bit integer type, `-9223372036854775808..9223372036854775807',
compatible to `long long int' in GNU C.
section LongCard
unsigned 64-bit integer type, `0..18446744073709551615',
compatible to `unsigned long long int' in GNU C.
section LongestInt
signed 64-bit integer type, `-9223372036854775808..9223372036854775807'.
section LongestCard
unsigned 64-bit integer type, `0..18446744073709551615'.
section Comp
signed 64-bit integer type, `-9223372036854775808..9223372036854775807'.
section SmallInt
signed 16-bit integer type, `-32768..32767'.

To specify the number of bits, use

`Integer ( n )'
signed n-bit integer type.
`Cardinal ( n )'
unsigned n-bit integer type.
`Word ( n )'
unsigned n-bit integer type.

See also: section Subrange Types.

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.

Endianness

(Under construction.)

Alignment

(Under construction.)

Operators

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.

Built-in Operators

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).

User-defined Operators

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".)

Schema Types

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 Pascal extension, the above can also be written as

  Bar:= New ( RealArrayPtr, 137 );

The allocated variable behaves like any other schema variable.

  Var
    i: Integer;

  [...]

  for i:= 1 to Bar^.n do
    Bar^ [ i ]:= 42;

Since the schema variable "knows" its size, pointers to schemata can be disposed just like other pointers:

  Dispose ( Bar );

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;

Pointer Arithmetics

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.

Type Casts

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.

Object-orientated Programming

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 );

Interfacing with Other Languages

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.

Importing Libraries from Other Languages

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.

It is important that data types of both languages are mapped correctly onto each other. C's `int', for instance, translates to GPC's `Integer', and C's `unsigned long' to `MedCard'. For a complete list of integer types with their C counterparts, see section Integer Types.

In some cases it can be reasonable to translate a C pointer parameter to a Pascal `var' parameter. 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.

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" *)'.

Exporting GPC Libraries to Other Languages

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:

Run Time Library--Pascal Declarations

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.)

{
Pascal declarations of the GPC RTS that are visible to each program.

This unit contains Pascal declarations of many RTS routines which can
be called from programs. Some other declarations that should not
normally be called from programs, are contained in the unit `Internal'.
Some of these routines correspond to functions built into the compiler,
such as most of the file operations; the declarations here should only
be used if the built-in functions are not applicable for some reason.
Other routines, like many file name and string routines, are not built
in, so the declarations from this unit can be used. Don't copy the
declarations from this unit into your programs, but rather include
this unit with a `uses' statement. The reason is that the internal
declarations, e.g. the `asmnames', may change, and this unit will be
changed accordingly. @@In the future, this unit might be included into
every program automatically, so there will be no need for a `uses'
statement to make the declarations here available.

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.

Copyright (C) 1998-99 Free Software Foundation, Inc.

Author: Frank Heckenbach <frank@pascal.gnu.de>

This file is part of GNU Pascal Library. 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.
}

unit GPC;

interface

type
  AnyFile = Text; (*@@ create `AnyFile' parameters*)
  PAnyFile = ^AnyFile;

const
  MaxLongInt = High (LongInt);

  { Maximum size of a variable }
  MaxVarSize = MaxInt;

{ ====================== RUNTIME ERROR HANDLING ETC. ====================== }

type
  PCStrings = ^TCStrings;
  TCStrings = array [0 .. MaxVarSize] of CString;

var
  ProcessID   : asmname '_p_pid'  Integer;
  CParamCount : asmname '_p_argc' Integer;
  CParameters : asmname '_p_argv' PCStrings;
  Environment : asmname 'environ' PCStrings;

{ Error handling functions, from error.pas }

var
  { BP compatible InOutRes variable }
  GPC_InOutRes : asmname '_p_inoutres' Integer;

  { CString parameter to some error messages, NOT the text of the error
    message (this can be obtained with GetErrorMessage) }
  GPC_InOutResStr : asmname '_p_inoutres_str' CString;

  { Error number (after runtime error) or exit status (after Halt) or
    0 (during program run and after succesful termination). }
  ExitCode : asmname '_p_exitcode' Integer;

  { Non-nil after runtime error, nil otherwise. Does not give the actual
    address of the code where the error occurred. }
  ErrorAddr : asmname '_p_erroraddr' Pointer;

  { @@ Temporary! Don't use under normal conditions! }
  ErrorProc : asmname '_p_errorproc' ^procedure;

function  GetErrorMessage                 (n : Integer) : CString;                   asmname '_p_errmsg';
function  GetCheckErrorMessage            (n : Integer; Format : CString) : CString; asmname '_p_check_errmsg';
procedure RuntimeError                    (n : Integer);                             asmname '_p_error';
procedure RuntimeErrorInteger             (n : Integer; i : MedInt);                 asmname '_p_error_integer';
procedure RuntimeErrorCString             (n : Integer; s : CString);                asmname '_p_error_string';
procedure InternalError                   (n : Integer);                             asmname '_p_internal_error';
procedure InternalErrorInteger            (n : Integer; i : MedInt);                 asmname '_p_internal_error_integer';
procedure RuntimeWarning                  (Message : CString);                       asmname '_p_warning';
procedure RuntimeWarningInteger           (Message : CString; i : MedInt);           asmname '_p_warning_integer';
procedure RuntimeWarningCString           (Message : CString; s : CString);          asmname '_p_warning_string';

{ Internal routine for `RunError' calls from the program }
procedure GPC_RunError                    (n : Integer);                             asmname '_p_runerror';

procedure StartTempIOError;                                                          asmname '_p_start_temp_io_error';
function  EndTempIOError : Integer;                                                  asmname '_p_end_temp_io_error';
procedure IOError                         (n : Integer);                             asmname '_p_io_error';
procedure IOErrorCString                  (n : Integer; s : CString);                asmname '_p_io_error_string';
function  GPC_IOResult : Integer;                                                    asmname '_p_ioresult';
function  GetIOErrorMessage : CString;                                               asmname '_p_get_io_error_message';
procedure CheckInOutRes;                                                             asmname '_p_check_inoutres';
procedure GPC_Halt (aExitCode : Integer);                                            asmname '_p_halt';

{ For GNU malloc }
procedure HeapWarning                     (s : CString);                             asmname '_p_heap_warning';

{ For signal handlers }
procedure PrintMessage (Message : CString; n : Integer; Warning : Boolean);          asmname '_p_prmessage';

{ =========================== MEMORY MANAGEMENT =========================== }

{ `MoveLeft', `MoveRight' and `Move' 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';
procedure GPC_Move      (const Source; var Dest; Count : SizeType); asmname '_p_move';

function  MemCmp  (const s1, s2; Size : SizeType) : Integer; asmname 'memcmp';
function  MemComp (const s1, s2; Size : SizeType) : Integer; asmname 'memcmp';

{ Heap manipulation, from heap.c }

{ GPC implements both Mark/Release and Dispose. Both can be mixed freely
  in the same program. Dispose should be preferred, since it's faster. }

type
  GetMemType  = ^function (Size : SizeType) : Pointer;
  FreeMemType = ^procedure (aPointer : Pointer);

var
  GetMemPtr  : asmname '_p_getmem_ptr'  GetMemType;
  FreeMemPtr : asmname '_p_freemem_ptr' FreeMemType;

{ GetMemPtr and FreeMemPtr point to these routines by default }
function  Default_GetMem  (Size : SizeType) : Pointer; asmname '_p_default_malloc';
procedure Default_FreeMem (aPointer : Pointer);        asmname 'free';

{ GPC_GetMem and GPC_FreeMem call the actual routines through GetMemPtr and FreeMemPtr }
function  GPC_GetMem  (Size : SizeType) : Pointer;     asmname '_p_malloc';
procedure GPC_FreeMem (aPointer : Pointer);            asmname '_p_free';

{ GPC_New and GPC_Dispose call GPC_GetMem and GPC_FreeMem, but also do the
  stuff necessary for Mark and Release. Therefore, GPC_GetMem and GPC_FreeMem
  should not be called directly when using Mark and Release. GetMem and
  FreeMem in a Pascal program will call GPC_New and GPC_Dispose internally,
  not GPC_GetMem and GPC_FreeMem. }
function  GPC_New     (Size : SizeType) : Pointer;     asmname '_p_new';
procedure GPC_Dispose (aPointer : Pointer);            asmname '_p_dispose';

{ ReleaseF will return the number of pointers released. While Release
  discards this information, it can be used e.g. during debugging to
  verify that all allocated memory blocks are correctly disposed, and
  no memory leaks exist. }
procedure GPC_Mark    (var aPointer : Pointer);        asmname '_p_mark';
function  ReleaseFunc (aPointer : Pointer) : Integer;  asmname '_p_release';

{ C heap management routines. NOTE: when using Release, CFreeMem must not
  be used but for pointers allocated by CGetMem. }
function  CGetMem     (Size : SizeType) : Pointer;                     asmname 'malloc';
procedure CFreeMem    (aPointer : Pointer);                            asmname 'free';
function  ReAlloc     (aPointer : Pointer; Size : SizeType) : Pointer; asmname 'realloc';

{ Routines to handle endianness, from endian.pas }

{ 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};

{ Convert single variables from or to little or big endian format.
  For records and arrays, this has to be done for each component separately!
  Currently, ConvertFromFooEndian and ConvertToFooEndian are the same, but
  this might not be the case on middle-endian machines. So it's better to
  provide and use different names. }
procedure ReverseBytes            (var Buf; Count : SizeType);                                asmname '_p_reversebytes';
procedure ConvertFromLittleEndian (var Buf; Count : SizeType);                                asmname '_p_convertlittleendian';
procedure ConvertFromBigEndian    (var Buf; Count : SizeType);                                asmname '_p_convertbigendian';
procedure ConvertToLittleEndian   (var Buf; Count : SizeType);                                asmname '_p_convertlittleendian';
procedure ConvertToBigEndian      (var Buf; Count : SizeType);                                asmname '_p_convertbigendian';

{ Combine the conversion with file block read/write routines }
function  BlockReadLittleEndian   (var aFile : File; var   Buf; Count : SizeType) : SizeType; asmname '_p_blockread_littleendian';
function  BlockReadBigEndian      (var aFile : File; var   Buf; Count : SizeType) : SizeType; asmname '_p_blockread_bigendian';
function  BlockWriteLittleEndian  (var aFile : File; const Buf; Count : SizeType) : SizeType; asmname '_p_blockwrite_littleendian';
function  BlockWriteBigEndian     (var aFile : File; const Buf; Count : SizeType) : SizeType; asmname '_p_blockwrite_bigendian';

{ ======================== STRING HANDLING ROUTINES ======================= }

{ String handling routines, from gstrings.pas }

type
  TChars = packed array [1 .. 1] of Char;
  PChars = ^TChars;

  GPC_PString = ^GPC_String;
  GPC_String (Capacity : Cardinal) = record
    Length : 0 .. Capacity;
    Chars  : packed array [1 .. Capacity + 1] of Char
  end;

  (* Not yet implemented
  StringObject = object { Abstract }
    function  GetCapacity : Integer;           virtual;
    procedure SetLength (NewLength : Integer); virtual;
    function  GetLength : Integer;             virtual;
    function  GetFirstChar : PChars;           virtual;
  end;
  *)

  (*@@ AnyString parameters are not yet implemented, the following is only a draft*)
  AnyStringType = (AnyStringLong,
                   AnyStringUndiscriminated,
                   AnyStringShort,
                   AnyStringFixed,
                   AnyStringCString,
                   AnyStringObject);

  (*@@ only formally for now*)UndiscriminatedString = ^String;

  { 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. }
  ConstAnyString = record
    Length : Integer;
    Chars  : PChars
  end;

  VarAnyString = record
    Capacity : Integer;
    Chars    : PChars;
    Truncate : Boolean;
  case StringType            : AnyStringType of
    AnyStringLong            : (PLongLength            : ^Integer);
    AnyStringUndiscriminated : (PUndiscriminatedString : ^UndiscriminatedString);
    AnyStringShort           : (PShortLength           : ^Byte);
    AnyStringFixed           : (CurrentLength          : Integer);
    (* AnyStringObject          : (PStringObject          : ^StringObject) *)
  end;

{ TString is 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;
  SpaceCharacters = [' ', #9];

type
  TString    = String (TStringSize);
  TStringBuf = packed array [0 .. TStringSize] of Char;
  PString    = ^String;
  CharSet    = set 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  IsUpCase        (ch : Char) : Boolean;                                 asmname '_p_isupcase';
function  IsLoCase        (ch : Char) : Boolean;                                 asmname '_p_islocase';
function  IsAlphaNum      (ch : Char) : Boolean;                                 asmname '_p_isalphanum';
function  IsAlphaNumUnderscore (ch : Char) : Boolean;                            asmname '_p_isalphanumunderscore';

function  Pos             (const SubStr, Str : String) : Integer;                asmname '_p_pos';
function  LastPos         (const SubStr, Str : String) : Integer;                asmname '_p_lastpos';
function  CharPos         (const Chars : CharSet; const Str : String) : Integer; asmname '_p_charpos';
function  LastCharPos     (const Chars : CharSet; const Str : String) : Integer; asmname '_p_lastcharpos';

function  PosFrom         (const SubStr, Str : String; From : Integer) : Integer;                asmname '_p_posfrom';
function  LastPosTill     (const SubStr, Str : String; Till : Integer) : Integer;                asmname '_p_lastpostill';
function  CharPosFrom     (const Chars : CharSet; const Str : String; From : Integer) : Integer; asmname '_p_charposfrom';
function  LastCharPosTill (const Chars : CharSet; const Str : String; Till : Integer) : Integer; asmname '_p_lastcharpostill';

function  IsPrefix        (const Prefix, s : String) : Boolean;                  asmname '_p_isprefix';
function  IsSuffix        (const Suffix, s : String) : Boolean;                  asmname '_p_issuffix';

function  CStringLength      (Src : CString) : SizeType;                            asmname '_p_strlen';
function  CStringEnd         (Src : CString) : CString;                             asmname '_p_strend';
function  CStringNew         (Src : CString) : CString;                             asmname '_p_strdup';
function  CStringComp        (s1, s2 : CString) : Integer;                          asmname '_p_strcmp';
function  CStringCaseComp    (s1, s2 : CString) : Integer;                          asmname '_p_strcasecmp';
function  CStringLComp       (s1, s2 : CString; MaxLen : SizeType) : Integer;       asmname '_p_strlcmp';
function  CStringLCaseComp   (s1, s2 : CString; MaxLen : SizeType) : Integer;       asmname '_p_strlcasecmp';
function  CStringCopy        (Dest, Source : CString) : CString;                    asmname '_p_strcpy';
function  CStringCopyEnd     (Dest, Source : CString) : CString;                    asmname '_p_strecpy';
function  CStringLCopy       (Dest, Source : CString; MaxLen : SizeType) : CString; asmname '_p_strlcpy';
function  CStringMove        (Dest, Source : CString; Count : SizeType) : CString;  asmname '_p_strmove';
function  CStringCat         (Dest, Source : CString) : CString;                    asmname '_p_strcat';
function  CStringLCat        (Dest, Source : CString; MaxLen : SizeType) : CString; asmname '_p_strlcat';
function  CStringCharPos     (Src : CString; Ch : Char) : CString;                  asmname '_p_strscan';
function  CStringLastCharPos (Src : CString; Ch : Char) : CString;                  asmname '_p_strrscan';
function  CStringPos         (Str, SubStr : CString) : CString;                     asmname '_p_strpos';
function  CStringLastPos     (Str, SubStr : CString) : CString;                     asmname '_p_strrpos';
function  CStringCasePos     (Str, SubStr : CString) : CString;                     asmname '_p_strcasepos';
function  CStringLastCasePos (Str, SubStr : CString) : CString;                     asmname '_p_strrcasepos';
function  CStringUpCase      (s : CString) : CString;                               asmname '_p_strupper';
function  CStringLoCase      (s : CString) : CString;                               asmname '_p_strlower';
function  CStringIsEmpty     (s : CString) : Boolean;                               asmname '_p_strempty';
function  NewCString         (const Source : String) : CString;                     asmname '_p_newcstring';
function  CStringCopyString  (Dest : CString; const Source : String) : CString;     asmname '_p_cstringcopystring';
procedure CopyCString        (Source : CString; var Dest : String);                 asmname '_p_copycstring';

function  NewString       (const s : String) : PString;                          asmname '_p_newstring';
procedure DisposeString   (p : PString);                                         asmname '_p_dispose';

procedure SetString       (var s : String; Buffer : PChar; Count : Integer);     asmname '_p_set_string';
function  StringOfChar    (Ch : Char; Count : Integer) = s : TString;            asmname '_p_string_of_char';

procedure TrimLeft        (var s : String);                                      asmname '_p_trimleft';
procedure TrimRight       (var s : String);                                      asmname '_p_trimright';
procedure TrimBoth        (var s : String);                                      asmname '_p_trimboth';
function  TrimLeftStr     (const s : String) : TString;                          asmname '_p_trimleft_str';
function  TrimRightStr    (const s : String) : TString;                          asmname '_p_trimright_str';
function  TrimBothStr     (const s : String) : TString;                          asmname '_p_trimboth_str';

{ Internal routines for the string operators }

{ Compare strings for equality without padding }
function  StrEQ (s1 : PChar; Length1 : Integer; s2 : PChar; Length2 : Integer) : Boolean;    asmname '_p_eq';

{ Compare strings for `less-than' without padding }
function  StrLT (s1 : PChar; Length1 : Integer; s2 : PChar; Length2 : Integer) : Boolean;    asmname '_p_lt';

{ Compare strings for equality, padding the shorter string with spaces }
function  StrEQPad (s1 : PChar; Length1 : Integer; s2 : PChar; Length2 : Integer) : Boolean; asmname '_p_str_eq';

{ Compare strings for `less-than', padding the shorter string with spaces }
function  StrLTPad (s1 : PChar; Length1 : Integer; s2 : PChar; Length2 : Integer) : Boolean; asmname '_p_str_lt';

{ Internal routine for Index/Pos }
function  GPC_Index (s1 : PChar; Length1 : Integer; s2 : PChar; Length2 : Integer) : Integer; asmname '_p_index';

{ Internal routine for Trim }
function  GPC_Trim (Src : PChar; SrcLength : Integer; Dest : PChar) : Integer; asmname '_p_trim';

{ Internal routine for SubStr/Copy }
function  GPC_SubStr (Src : PChar; SrcLength, Position, Count : Integer; Dest : PChar; Truncate : Boolean) : Integer; asmname '_p_substr';

function  GetStringCapacity (const s : String) : Integer;                        asmname '_p_get_string_capacity';

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';

{ Under development }
function VarAnyStringLength (var s : VarAnyString) : Integer; asmname '_p_var_anystring_length';
function VarAnyStringSetLength (var s : VarAnyString; NewLength : Integer) : Integer; asmname '_p_var_anystring_setlength';
procedure AnyStringTFDD_Reset (var f : AnyFile; var Buf : ConstAnyString); asmname '_p_anystring_tfdd_reset';
procedure AnyStringTFDD_Rewrite (var f : AnyFile; var Buf : VarAnyString); asmname '_p_anystring_tfdd_rewrite';
procedure StringTFDD_Reset (var f : AnyFile; var Buf : ConstAnyString; const s : String); asmname '_p_string_tfdd_reset';
procedure StringTFDD_Rewrite (var f : AnyFile; var Buf : VarAnyString; var s : String); asmname '_p_string_tfdd_rewrite';

{ ========================= TIME HANDLING ROUTINES ======================== }

{ Time and date routines for Extended Pascal, from time.pas }

const { from types.h }
  GPC_Date_Length = 11;
  GPC_Time_Length = 8;

type
  UnixTimeType = LongInt; { This is hard-coded in the compiler. Do not change here. }
  MicroSecondTimeType = LongInt;

  GPC_Date_String = packed array [1 .. GPC_Date_Length] of Char;
  GPC_Time_String = packed array [1 .. GPC_Time_Length] of Char;

  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;

var
  MonthName : external array [1 .. 12] of String [9];
  MonthLength : external array [1 .. 12] of Integer;

function  GetDayOfWeek        (Day, Month, Year : Integer) : Integer;                                          asmname '_p_dayofweek';
procedure UnixTimeToTimeStamp (UnixTime : UnixTimeType; var aTimeStamp : TimeStamp);                           asmname '_p_unix_time_to_time_stamp';
function  TimeStampToUnixTime (protected var aTimeStamp : TimeStamp) : UnixTimeType;                           asmname '_p_time_stamp_to_unix_time';
procedure GPC_GetTimeStamp    (var aTimeStamp : TimeStamp);                                                    asmname '_p_gettimestamp';
function  GetMicroSecondTime : MicroSecondTimeType;                                                            asmname '_p_get_micro_second_time';

{ Is the year a leap year? }
function  IsLeapYear (Year : Integer) : Boolean; asmname '_p_is_leap_year';

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';

{ from times.c }

procedure Sleep               (Seconds : Integer);                                                             asmname '_p_sleep';
procedure UnixTimeToTime      (UnixTime : UnixTimeType; var Year, Month, Day, Hour, Minute, Second : Integer); asmname '_p_unix_time_to_time';
function  TimeToUnixTime      (Year, Month, Day, Hour, Minute, Second : Integer) : UnixTimeType;               asmname '_p_time_to_unix_time';

{ MicroSecond can be null and is ignored then }
function  GetUnixTime         (var MicroSecond : Integer) : UnixTimeType;                                      asmname '_p_get_unix_time';
function  GetCPUTime          (var MicroSecond : Integer) : Integer;                                           asmname '_p_get_cpu_time';

{ ========================= FILE HANDLING ROUTINES ======================== }

{ Extended pascal binding routines, from bind.c }

const { from types.h }
  Binding_Name_Length = 255;

type
  CFilePtr = Pointer;

  { The standard fields are Bound and Name. The others are extensions. }
  GPC_BindingType = {@@packed} record
                      Bound             : Boolean;
                      Force             : Boolean;      { Can be set to allow binding to non-writable files or directories }
                      Extensions_Valid  : Boolean;
                      Readable          : Boolean;
                      Writable          : Boolean;
                      Executable        : Boolean;
                      Existing          : Boolean;      { Binding points to an existing file }
                      Directory         : Boolean;      { Binding points to an existing directory; `Existing' is False then }
                      Size              : LongInt;      { Number of elements or -1 }
                      AccessTime,                       { Time of last access }
                      ModificationTime,                 { Time of last modification }
                      ChangeTime        : UnixTimeType; { Time of last inode change }
                      User,                             { User ID of owner }
                      Group,                            { Group ID of owner }
                      Mode,                             { Protection mode, cf. ChMod }
                      INode             : Integer;      { Unix INode number }
                      CFile             : CFilePtr;     { 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 GetBinding       (protected var aFile : AnyFile;           var aBinding : BindingType); asmname '_p_binding';
procedure GPC_Unbind       (          var aFile : AnyFile);                                       asmname '_p_unbind';
procedure ClearBinding     (          var aBinding : BindingType);                                asmname '_p_clearbinding';

{ TFDD interface, subject to change! }

const
  NoHandle = - 1;

type
  TOpenMode   = (foReset, foRewrite, foAppend, foSeekRead, foSeekWrite, foSeekUpdate);
  TOpenFunc   = function  (var PrivateData; Mode : TOpenMode) : Integer; { must return a handle or NoHandle }
  TSelectProc = procedure (var PrivateData; var SelectRead, SelectWrite, SelectExcept : Boolean);
  TReadFunc   = function  (var PrivateData; var   Buffer; Size : SizeType) : SizeType;
  TWriteFunc  = function  (var PrivateData; const Buffer; Size : SizeType) : SizeType;
  TFileProc   = procedure (var PrivateData);
  TFlushProc  = TFileProc;
  TCloseProc  = TFileProc;
  TDoneProc   = TFileProc;

procedure AssignTFDD (var f : AnyFile;
                      OpenFunc    : TOpenFunc;
                      SelectProc  : TSelectProc;
                      ReadFunc    : TReadFunc;
                      WriteFunc   : TWriteFunc;
                      FlushProc   : TFlushProc;
                      CloseProc   : TCloseProc;
                      DoneProc    : TDoneProc;
                      PrivateData : Pointer);       asmname '_p_assign_tfdd';

procedure SetTFDD (var f : AnyFile;
                   OpenFunc    : TOpenFunc;
                   SelectProc  : TSelectProc;
                   ReadFunc    : TReadFunc;
                   WriteFunc   : TWriteFunc;
                   FlushProc   : TFlushProc;
                   CloseProc   : TCloseProc;
                   DoneProc    : TDoneProc;
                   PrivateData : Pointer);          asmname '_p_set_tfdd';

procedure GetTFDD    (var f : AnyFile;
                      var OpenFunc    : TOpenFunc;
                      var SelectProc  : TSelectProc;
                      var ReadFunc    : TReadFunc;
                      var WriteFunc   : TWriteFunc;
                      var FlushProc   : TFlushProc;
                      var CloseProc   : TCloseProc;
                      var DoneProc    : TDoneProc;
                      var PrivateData : Pointer);   asmname '_p_get_tfdd';

{ Default TFDD routines for files. @@ OpenFunc and CloseProc still missing. }
function  F_Read     (var aFile; var   Buffer; Size : SizeType) : SizeType; asmname '_p_f_read';
function  F_Read_TTY (var aFile; var   Buffer; Size : SizeType) : SizeType; asmname '_p_f_read_tty';
function  F_Write    (var aFile; const Buffer; Size : SizeType) : SizeType; asmname '_p_f_write';
procedure F_Flush    (var aFile);                                           asmname '_p_f_flush';

{ file routines, from files.pas }

type
  Natural = 1 .. MaxInt;
  IOSelectEvents = (SelectReadOrEOF, SelectRead, SelectEOF, SelectWrite, SelectException, SelectAlways);

const
  IOSelectEventMin = (*Low (IOSelectEvents);*)SelectReadOrEOF;
  IOSelectEventMax = Pred (SelectAlways);

type
  IOSelectType = record
    f : PAnyFile;
    Wanted : set of IOSelectEvents;
    Occurred : set of IOSelectEventMin .. IOSelectEventMax
  end;

{ Waits for one of several events to happen. Returns when one or more of the
  wanted events for one of the files occur. If they have already occurred
  before calling the function, it returns immediately. MicroSeconds can
  specify a timeout. If it is 0, the function will return immediately,
  whether or not an event has occurred. If it is negative, the function
  will wait forever until an event occurs. The Events parameter can be null,
  in which case the function only waits for the timeout. If any of the file
  pointers (f) in Events are nil or the files pointed to are closed, they
  are simply ignored for convenience.

  It returns the index of one of the files for which any event has occurred.
  If events have occurred for several files, is it undefined which of these
  file's index is returned. If no event occurs until the timeout, 0 is
  returned. If an error occurs or the target system does not have a select()
  system call and Events is not null, a negative value is returned. In the
  Occurred field of the elements of Events, events that have occurred are
  set. The state of events not wanted is undefined.

  The possible events are:
  SelectReadOrEOF: the file is at EOF or data can be read now.
  SelectRead: data can be read now.
  SelectEOF: the file is at EOF.
  SelectWrite: data can be written now.
  SelectException: an exception occurred on the file.
  SelectAlways: if this is set, *all* requested events will be checked for
  this file in any case. Otherwise, checks may be skipped if already another
  event for this or another file was found.

  Notes:
  Checking for EOF (just like the EOF function) requires some reading
  ahead which can be avoided by setting SelectReadOrEOF instead of
  SelectRead and SelectEOF. If this is followed by, e.g., a BlockRead
  with 4 parameters, the last parameter will be 0 if and only the file
  is at EOF, and otherwise, data will be read directly from the file
  without reading ahead and buffering.

  SelectAlways should be set for files for which events are considered
  to be of higher priority than others. Otherwise, if one is interested
  in just any event, not setting SelectAlways may be a little faster. }
function IOSelect     (var   Events : array [m .. n : Natural] of IOSelectType; MicroSeconds : MicroSecondTimeType) : Integer; asmname '_p_ioselect';

{ A simpler interface to SelectIO for the most common use. Waits for
  SelectReadOrEOF on all files and returns an index. }
function IOSelectRead (const Files  : array [m .. n : Natural] of PAnyFile;     MicroSeconds : MicroSecondTimeType) : Integer; asmname '_p_ioselectread';

procedure GPC_Assign  (var T : AnyFile; const Name : String); asmname '_p_assign';
procedure AssignFile  (var T : AnyFile; const Name : String); asmname '_p_assign';
procedure AssignCFile (var T : AnyFile; CFile : CFilePtr);    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 them). }
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 }

{ File mode constants that are ORed for BindingType.Mode and ChMod.
  The values below are valid for all OSs (as far as supported). If
  the OS uses different values, they're converted internally. }
const
  fmSetUID           = 8#4000;
  fmSetGID           = 8#2000;
  fmSticky           = 8#1000;
  fmUserReadable     = 8#400;
  fmUserWritable     = 8#200;
  fmUserExecutable   = 8#100;
  fmGroupReadable    = 8#40;
  fmGroupWritable    = 8#20;
  fmGroupExecutable  = 8#10;
  fmOthersReadable   = 8#4;
  fmOthersWritable   = 8#2;
  fmOthersExecutable = 8#1;

type
  StatFSBuffer = record
    BlockSize, BlocksTotal, BlocksFree : LongestInt;
    FilesTotal, FilesFree : Integer
  end;

var
  GPC_FileMode : asmname '_p_filemode' Integer;

  { Open text files as binary. Only relevant on systems like Dos where
    this makes a difference. }
  TextFilesBinary : asmname '_p_textfiles_binary' Boolean;

procedure GPC_Flush    (          var aFile : AnyFile);                                        asmname '_p_flush';
function  GPC_GetFile  (protected var aFile : AnyFile) : CFilePtr;                             asmname '_p_getfile';

{ 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';
procedure CloseFile    (          var aFile : (*@@Any*)File);                                        asmname '_p_close';
function  FileName_CString (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';
(*@@IO critical*) procedure ChMod        (          var aFile : AnyFile; Mode : Integer);                        asmname '_p_chmod';
procedure GPC_SetFileTime  (      var aFile : AnyFile; Time : UnixTimeType);                   asmname '_p_set_file_time';
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';
(*@@IO critical*) procedure StatFS       (Path : CString; var Buf : StatFSBuffer);                               asmname '_p_statfs';

{ Checks if data are available to be read from aFile. This is similar to
  `not EOF (aFile)', but does not block on "files" that can grow, like TTYs
  or pipes. }
function  CanRead      (var aFile : AnyFile) : Boolean;                                        asmname '_p_canread';

{ 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';

{ 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 output various things, from write.c }

procedure GPC_Page      (var aFile : Text);                       asmname '_p_page';
procedure GPC_Put       (var aFile : AnyFile);                    asmname '_p_put';

{ File name routines, from filename.pas }

{
  Define constants for different systems:

  OSDosFlag:         flag to indicate whether the target system is Dos

  QuotingCharacter:  the character used to quote wild cards and other
                     special characters (#0 if not available)

  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

  DirRoot:           the name of the root directory

  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.

  EnvVarCharsFirst:  the characters accepted at the beginning of the name of
                     an environment variable without quoting

  EnvVarChars:       the characters accepted in the name of an environment
                     variable without quoting

  PathEnvVar:        the name of the environment variable which (usually)
                     contains the executable search path

  ShellEnvVar:       the name of the environment variable which (usually)
                     contains the path of the shell executable

  ShellExecCommand:  the option to the (default) shell to execute the
                     command specified in the following argument

  ConfigFileMask:    a mask for the option file name as returned by
                     ConfigFileName

  FileNamesCaseSensitive:
                     flag to indicate whether file names are case sensitive
}

{$ifdef __OS_DOS__}

const
  OSDosFlag              = True;
  QuotingCharacter       = #0;
  PathSeparator          = ';';
  DirSeparator           = '\';
  DirSeparators          = [':', '\', '/'];
  ExtSeparator           = '.';
  DirRoot                = '\';
  DirSelf                = '.';
  DirParent              = '..';
  NullDeviceName         = 'nul';
  TTYDeviceName          = 'con';
  ConsoleDeviceName      = 'con';
  EnvVarCharsFirst       = ['A' .. 'Z', 'a' .. 'z', '_'];
  EnvVarChars            = EnvVarCharsFirst + ['0' .. '9'];
  PathEnvVar             = 'PATH';
  ShellEnvVar            = 'COMSPEC';
  ShellExecCommand       = '/c';
  ConfigFileMask         = '*.cfg';
  FileNamesCaseSensitive = False;

{$else}

const
  OSDosFlag              = False;
  QuotingCharacter       = '\';
  PathSeparator          = ':';
  DirSeparator           = '/';
  DirSeparators          = ['/'];
  ExtSeparator           = '.';
  DirRoot                = '/';
  DirSelf                = '.';
  DirParent              = '..';
  NullDeviceName         = '/dev/null';
  TTYDeviceName          = '/dev/tty';
  ConsoleDeviceName      = '/dev/console';
  EnvVarCharsFirst       = ['A' .. 'Z', 'a' .. 'z', '_'];
  EnvVarChars            = EnvVarCharsFirst + ['0' .. '9'];
  PathEnvVar             = 'PATH';
  ShellEnvVar            = 'SHELL';
  ShellExecCommand       = '-c';
  ConfigFileMask         = '.*';
  FileNamesCaseSensitive = True;

{$endif}

const
  NewLine = {$char-escapes} "\n" {$no-char-escapes}; { the separator of lines within a file }
  WildCardChars = ['*', '?', '[', ']'];
  FileNameSpecialChars = (WildCardChars + SpaceCharacters + ['{', '}', '$', QuotingCharacter]) - DirSeparators;

type
  DirPtr = Pointer;

  PPStrings = ^TPStrings;
  TPStrings (Count: Cardinal) = array [1 .. Count] of ^String;

  GlobBuffer = record
    Count    : Integer;
    Result   : PCStrings;
    Internal : Pointer
  end;

{ libc system call }
function  CSystem (CmdLine : CString) : Integer;                           asmname 'system';

{ Like CSystem, but reports execution errors via the IOResult mechanism,
  returns only the exit status of the executed program. }
(*@@IO critical*)function  Execute (CmdLine : CString) : Integer;                           asmname '_p_execute';

{ Get an environment variable. If it does not exist, GetEnv returns the
  empty string, which can't be distinguished from a variable with an empty
  value, while CGetEnv returns nil then. Note, Dos doesn't know empty
  environment variables, but treats them as nonexisting. }
function  GetEnv  (const EnvVar : String) : TString;                       asmname '_p_getenv';
function  CGetEnv (EnvVar : CString) : CString;                            asmname {$ifdef __OS_DOS__} '_p_cgetenv' {$else} 'getenv' {$endif};

{ If s is of the form var=value, the environment variable with the name var
  is set to value. A previous value, if any, is overwritten. The function
  returns 0 on success, and something else otherwise. NOTE: s is NOT copied
  automatically, so unless it's a constant, a copy of the actual variable
  made with CStringNew/NewCString should be passed to this function. }
function  PutEnv  (s : CString) : Integer;                                 asmname 'putenv';

{ Convert ch to lower case if FileNamesCaseSensitive is False, leave it
  unchanged otherwise. }
function  FLoCase (ch : Char) : Char;                                      asmname '_p_flocase';

{ Change a file name to use the OS dependent directory separator }
function  Slash2OSDirSeparator (const s : String) : TString;               asmname '_p_slash2osdirseparator';

{ Change a file name to use '/' as directory separator }
function  OSDirSeparator2Slash (const s : String) : TString;               asmname '_p_osdirseparator2slash';

{ Like Slash2OSDirSeparator for CStrings -- NOTE: overwrites the CString }
function  Slash2OSDirSeparator_CString (s : CString) : CString;            asmname '_p_slash2osdirseparator_cstring';

{ Like OSDirSeparator2Slash for CStrings -- NOTE: overwrites the CString }
function  OSDirSeparator2Slash_CString (s : CString) : CString;            asmname '_p_osdirseparator2slash_cstring';

{ Add a DirSeparator to the end of s, if there is not already one and
  s denotes an existing directory }
function  AddDirSeparator (const s : String) : TString;                    asmname '_p_adddirseparator';

{ Like AddDirSeparator, but also if the directory does not exist }
function  ForceAddDirSeparator (const s : String) : TString;               asmname '_p_forceadddirseparator';

{ Remove all trailing DirSeparators from s, if there are any, as long as
  removing them doesn't change the meaning (i.e., they don't denote the
  root directory. }
function  RemoveDirSeparator (const s : String) : TString;                 asmname '_p_removedirseparator';

{ Returns the current directory using OS dependent directory separators }
function  GetCurrentDirectory     : TString;                               asmname '_p_get_current_directory';

{ Returns a directory suitable for storing temporary files using OS dependent
  directory separators. If found, the result always ends in DirSeparator.
  If no directory is found, an empty string is returned. }
function  GetTempDirectory        : TString;                               asmname '_p_get_temp_directory';

{ Returns a non-existing file name in GetTempDirectory. If no temp
  directory is found, i.e. GetTempDirectory returns the empty string,
  a runtime error is raised. }
function  GetTempFileName         : TString;                               asmname '_p_get_temp_file_name';

{ The same as GetTempFileName, but returns a CString allocated from the heap. }
function  GetTempFileName_CString : CString;                               asmname '_p_get_temp_file_name_cstring';

{ Get the external file name }
function  FileName (var f : AnyFile) : TString;                            asmname '_p_file_name';

{ Returns true if the given file name is an existing file }
function  FileExists      (const FileName : String) : Boolean;             asmname '_p_file_exists';

{ Returns true if the given file name is an existing directory }
function  DirectoryExists (const FileName : String) : Boolean;             asmname '_p_directory_exists';

{ If a file of the given name exists in one of the directories given in
  DirList (separated by PathSeparator), returns the full path, otherwise
  returns an empty string. If FileName already contains an element of
  DirSeparators, returns Slash2OSDirSeparator (FileName) if it exists. }
function  FSearch (const FileName, DirList : String) : TString;            asmname '_p_fsearch';

{ Like FSearch, but only find executable files. Under Dos, if not found,
  the function tries appending '.com', '.exe' and '.bat', so you don't have
  to specify these extensions in FileName (and with respect to portability,
  it might be preferable to not do so). }
function  FSearchExecutable (const FileName, DirList : String) : TString;  asmname '_p_fsearch_executable';

{ Replaces all occurrences of `$FOO' and `~' in s by the value of the
  environment variables FOO or HOME, respectively. If a variable is not
  defined, the function returns False, and s contains the name of the
  undefined variable (or the empty string if the variable name is invalid,
  i.e., doesn't start with a character from EnvVarCharsFirst). Otherwise,
  if all variables are found, s contains the replaced string, and True is
  returned. }
function  ExpandEnvironment (var s : String) : Boolean;                    asmname '_p_expand_environment';

{ Expands the given path name to a full path name. Relative paths are
  expanded using the current directory, and occurrences of DirSelf and
  DirParent are removed. Under Dos, it converts the result to lower
  case and removes a trailing ExtSeparator (except in a trailing DirSelf
  or DirParent), like Dos does. If the directory, i.e. the path without
  the file name, is invalid, the empty string is returned. }
function  FExpand       (const Path : String) : TString;                   asmname '_p_fexpand';

{ Like FExpand, but unquotes the directory before expanding it, and
  quotes WildCardChars again afterwards. Does not check if the directory
  is valid (because it may contain wild card characters). }
function  FExpandQuoted (const Path : String) : TString;                   asmname '_p_fexpandquoted';

{ FExpands Path, and then removes the current directory from it, if it
  is a prefix of it. If OnlyCurDir is set, the current directory will
  be removed only if Path denotes a file in, not below, it. }
function  RelativePath (const Path : String; OnlyCurDir, Quoted : Boolean) : TString; asmname '_p_relative_path';

{ Is s a UNC filename? (Dos only, otherwise always returns False) }
function  isUNC (const s : String) : Boolean;                              asmname '_p_isunc';

{ Splits a file name into directory, name and extension }
procedure FSplit (const Path : String; var Dir, Name, Ext : String);       asmname '_p_fsplit';

{ Functions that extract one or two of the parts from FSplit. DirFromPath
  returns DirSelf + DirSeparator if the path contains no directory. }
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  NameExtFromPath (const Path : String) : TString;                 asmname '_p_name_ext_from_path';

{ Start reading a directory. If successful, a pointer is returned that can
  be used for subsequent calls to ReadDir and finally CloseDir. On failure,
  nil is returned. }
function  OpenDir  (Name : CString) : DirPtr;                              C;

{ Reads one entry from the directory Dir, and returns the file name. On
  errors or end of directory, the empty string is returned. }
function  ReadDir  (Dir : DirPtr) : TString;                               asmname '_p_readdir';

{ Closes a directory opened with OpenDir. Returns 0 on success, anything
  else on error. }
function  CloseDir (Dir : DirPtr) : Integer;                               asmname '_p_closedir';

{ Returns the first position of a non-quoted character of CharSet in s,
  or 0 if no such character exists. }
function  FindNonQuotedChar (Chars : CharSet; const s : String; From : Integer) : Integer; asmname '_p_findnonquotedchar';

{ Returns the first occurence of SubStr in s that is not quoted at the
  beginning, or 0 if no such occurence exists. }
function  FindNonQuotedStr (const SubStr, s : String; From : Integer) : Integer; asmname '_p_findnonquotedstr';

{ Does a string contain non-quoted wildcard characters? }
function  HasWildCards (const s : String) : Boolean;                       asmname '_p_haswildcards';

{ Does a string contain non-quoted wildcard characters, braces or spaces? }
function  HasWildCardsOrBraces (const s : String) : Boolean;               asmname '_p_haswildcardsorbraces';

{ Insert quoting QuotingCharacter into s before any special characters }
function  QuoteFileName (const s : String; const SpecialCharacters : CharSet) : TString; asmname '_p_quote_filename';

{ Remove quoting QuotingCharacter from s }
function  UnQuoteFileName (const s : String) : TString;                    asmname '_p_unquote_filename';

{ Splits Str at non-quoted spaces and expands non-quoted braces like bash
  does. The result and its entries should be Disposed after usage. }
function  BraceExpand (const Str : String) : PPStrings;                    asmname '_p_braceexpand';

{ Tests if a file name matches a shell wildcard pattern (?, *, []) }
function  FileNameMatch (const Pattern, Name : String) : Boolean;          asmname '_p_filenamematch';

{ FileNameMatch with BraceExpand }
function  MultiFileNameMatch (const Pattern, Name : String) : Boolean;     asmname '_p_multifilenamematch';

{ File name globbing }
{ GlobInit is implied by Glob and MultiGlob, not by GlobOn and MultiGlobOn.
  GlobOn and MultiGlobOn must be called after GlobInit, Glob or MultiGlob.
  MultiGlob and MultiGlobOn do brace expansion, Glob and GlobOn do not.
  GlobFree frees the memory allocated by the globbing functions and
  invalidates the results in Buf. It should be called after globbing. }
procedure GlobInit    (var Buf : GlobBuffer);                              asmname '_p_globinit';
procedure Glob        (var Buf : GlobBuffer; Pattern : CString);           asmname '_p_glob';
procedure GlobOn      (var Buf : GlobBuffer; Pattern : CString);           asmname '_p_globon';
procedure MultiGlob   (var Buf : GlobBuffer; Pattern : String);            asmname '_p_multiglob';
procedure MultiGlobOn (var Buf : GlobBuffer; Pattern : String);            asmname '_p_multiglobon';
procedure GlobFree    (var Buf : GlobBuffer);                              asmname '_p_globfree';

{ Return a file name suited for a configuration file.
  Under Unix, it is made up of '$HOME/.' plus the base name (without
  directory) of the running program (as returned by ParamStr (0)) plus 'rc',
  if Global is False (this is meant for user-specific configuration),
  and of '/etc/' plus base name plus 'rc' if Global is True (system-wide
  configuration).
  Under Dos, it is composed of the directory and base name of the running
  program plus '.cfg', regardless of Global.
  If Name is not empty, it will be used instead of the base name of the
  running program. }
function  ConfigFileName (Name : String; Global : Boolean) : TString;      asmname '_p_config_file_name';

{ ========================= MATHEMATICAL ROUTINES ========================= }

const
  Pi = 3.14159265358979323846264338327950288419716;

{ Int and Frac routines for real numbers, from math.pas }

function GPC_Frac (x : LongestReal) : LongestReal; asmname '_p_frac';
function GPC_Int  (x : LongestReal) : LongestReal; asmname '_p_int';

{ Transcendental functions for Reals and LongReals, from maths.c }

function Real_Arctan     (x : Double)                : Double;   asmname '_p_arctan';
function Arctan2         (y, x : Double)             : Double;   asmname '_p_arctan2';
function Real_Sqrt       (x : Double)                : Double;   asmname '_p_sqrt';
function Real_Ln         (x : Double)                : Double;   asmname '_p_ln';
function Real_Exp        (x : Double)                : Double;   asmname '_p_exp';
function Real_Sin        (x : Double)                : Double;   asmname '_p_sin';
function SinH            (x : Double)                : Double;   asmname '_p_sinh';
function Real_Cos        (x : Double)                : Double;   asmname '_p_cos';
function CosH            (x : Double)                : Double;   asmname '_p_cosh';
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';

{ Extended Pascal `**' operator }
function Real_Power      (x, y : Double)             : Double;   asmname '_p_expon';
function LongReal_Power  (x, y : LongReal)           : LongReal; asmname '_pp_expon';

{ from math.pas }

function Real_Pow        (x : Double; y : Integer)   : Double;   asmname '_p_pow';
function LongReal_Pow    (x : LongReal; y : Integer) : LongReal; asmname '_pp_pow';

{ Library functions for complex type arguments, from math.pas }

function Complex_Polar  (Length, Theta : Double)   : Complex; asmname '_p_polar';
function Complex_Arg    (z : Complex)              : Double;  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_Power  (z : Complex; y : Double)  : Complex; asmname '_p_z_expon';

{ Random number routines, from random.c }

{ RandomizePtr, RandRealPtr and RandIntPtr point to these routines by default }
procedure Default_Randomize;                                 asmname '_p_default_randomize';
function  Default_RandReal : LongestReal;                    asmname '_p_default_randreal';
function  Default_RandInt (Max : LongestCard) : LongestCard; asmname '_p_default_randint';

{ GPC_Randomize, GPC_RandReal and GPC_RandInt call the actual routines through RandomizePtr, RandRealPtr and RandIntPtr }
procedure GPC_Randomize;                                 asmname '_p_randomize';
function  GPC_RandReal : LongestReal;                    asmname '_p_randreal';
function  GPC_RandInt (Max : LongestCard) : LongestCard; asmname '_p_randint';

type
  RandomizeType = ^procedure;
  RandRealType  = ^function : LongestReal;
  RandIntType   = ^function (Max : LongestCard) : LongestCard;

var
  RandomizePtr : asmname '_p_randomize_ptr' RandomizeType;
  RandRealPtr  : asmname '_p_randreal_ptr'  RandRealType;
  RandIntPtr   : asmname '_p_randint_ptr'   RandIntType;

implementation

end.


Go to the first, previous, next, last section, table of contents.