Using and Maintaining GNU Pascal


@emergencystretch 10em@hfuzz 5pt@vfuzz@hfuzz

Using and Maintaining GNU Pascal

Jan-Jaap van der Heijden,

Peter Gerwinski,

Frank Heckenbach

Last updated May 2000

for version 20000527 (GCC version 2.95.x) Copyright (C) 1988, 1996-2000 Free Software Foundation, Inc.

For GPC version 20000527 (GCC version 2.95.x)

Published by the Free Software Foundation
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the sections entitled "GNU General Public License", "The GNU Manifesto" and "Funding for Free Software" are included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that the sections entitled "GNU General Public License", "The GNU Manifesto" and "Funding for Free Software" and this permission notice, may be included in translations approved by the Free Software Foundation instead of in the original English.

Welcome to GNU Pascal...

... the free 32/64-bit Pascal compiler of the GNU compiler family, GNU CC or GCC. It combines a Pascal front-end with the proven GNU C back-end for code generation and optimization. Other compilers of the family currently include compilers for the Ada, C, C++, Objective C, and FORTRAN languages. Unlike utilities such as p2c, this is a true compiler, not just a converter.

This version of GPC corresponds to GCC version 2.95.x.

The purpose of the GNU Pascal project is to produce a Pascal compiler (called GNU Pascal or GPC) which

Pascal was originally designed for teaching. GNU Pascal provides a smooth way to proceed to challenging programming tasks without learning a completely different language.

The current release implements Standard Pascal (ISO 7185, level 1), a large subset of Extended Pascal (ISO 10206, aiming for full compliance), is highly compatible to Borland Pascal (version 7.0) with some Delphi extensions, and provides a lot of useful GNU extensions.

This documentation contains

If you are familiar with Standard Pascal (ISO 7185) programming, you can probably just go ahead and try to compile your programs. Also, most of the ISO Extended Pascal Standard (ISO 10206) is implemented into GNU Pascal. The Extended Pascal features still missing from GPC are qualified module import, protected module export variables, set types with variable bounds, structured value initializers and expressions as subrange lower bounds.

If you are a Borland Pascal programmer, you should probably start reading the QuickStart guide from BP to GNU Pascal, see section From Borland Pascal to GNU Pascal. If you are curious about the new features GPC offers, you can read about them in the Programmer's Guide to GPC (see section The Programmer's Guide to GPC) and in the alphabetical GPC Language Reference (see section The Alphabetical GPC Language Reference).

And, please, think about how you can contribute to the GNU Pascal project, too. Please support our work by contributing yours in form of example programs, bug reports, documentation, or even actual improvements of the compiler.

You can find the current To-Do list on the GPC home page in the WWW at

@uref{http://agnes.dida.physik.uni-essen.de/~gnu-pascal/todo.html}.

Installing GNU Pascal

This chapter covers:

The preferred way to distribute GNU software is distribution of the source code. However, it can be a non-trivial exercise to build GNU Pascal on some non-UNIX systems, so we also provide ready-to-run binaries for a number of platforms. See section Installation instructions for a GPC binary distribution how to install a binary distribution.

GPC is based on GNU CC; you will need the GCC sources to build it. It must be the same version as the one GPC is implemented with. Although you need GCC to build the GNU Pascal compiler, you don't need GCC to compile Pascal programs once GNU Pascal is installed. Because GNU Pascal shares its backend with GNU CC, it should run on any system supported by GNU CC. A full list of platforms supported by GNU CC can be found in section `Installation' in "Using and Porting GNU CC".

Here is the generic procedure for installing GNU Pascal on a UNIX system. See section Configuration dependent compilation notes for extra information needed to install GPC on certain platforms.

  1. Unpack the source distributions. From a directory of your choice (e.g. `/usr/local/src'), unpack the GNU CC and GNU Pascal source distributions. This will create separate subdirectories for GCC and GPC. `cd' to the GPC directory (`/usr/local/src/gpc' in the example above) and move the contents (a subdirectory `p') to the GCC directory (for instance `usr/local/src/gcc-2.8.1'). Next, go to the GCC source directory and apply the GCC patch required by GNU Pascal:
    % patch -s -p1 < p/diffs/gcc-2.8.1.diff
    
    Note 1: If you omit this step, `configure' (see below) will prompt you for doing this automatically. Note 2: In the example above, GCC version 2.8.1 is assumed. If your version of GCC is other than 2.8.1, you have to get and apply the appropriate patch. If you run the patch automatically from `configure', it will detect and work with some versions of EGCS. Note 3: All changes to GCC are surrounded by `#ifdef GPC .. #endif', so they should not interfere when you build a C compiler from this source tree. It is possible, though not required, to build the compiler in a directory other than the one containing the sources. (If you do that, you do not need to write into the GCC source directory and can build GPC for more than one platform from the same source tree.) In that case, you need a `make' that understands the VPATH variable. GNU make does, although at least GNU make version 3.71 has a bug in the way it treats VPATH. GNU make version 3.75 is known to work. If you have built GNU Pascal previously in the same directory for a different target machine, do `make distclean' to delete all files that might be invalid. One of the files this deletes is `Makefile'; if `make distclean' complains that `Makefile' does not exist, it probably means that the directory is already suitably clean.
  2. Configuring and building GNU CC GNU Pascal is automatically configured with GNU CC. Configuration of GNU CC is treated in depth in section `Chapter 4' in "Using and Porting GNU CC". Chdir to the GCC object directory. (This can be a directory of your choice, including the GCC source directory.) From there, run the `configure' script in the GCC source directory. If both directories are the same, the command
    % ./configure
    
    is sufficient to configure GCC in most cases. If they are different, something like
    % ../gcc-2.8.1/configure
    
    will do the job. This creates all the necessary config files, links and Makefile in the GCC object directory.
  3. The standard directory for installing GNU CC and GNU Pascal is `/usr/local/lib'. If you want to install its files somewhere else, specify `--prefix=dir' when you run `configure'. Here dir is a directory name to use instead of `/usr/local' for all purposes with one exception: the directory `/usr/local/include' is searched for header files no matter where you install the compiler. To override this name, use the `--local-prefix' option below.
  4. Specify `--local-prefix=dir' if you want the compiler to search directory `dir/include' for locally installed header files instead of `/usr/local/include'. You should specify `--local-prefix' only if your site has a different convention (not `/usr/local') for where to put site-specific files. Do not specify `/usr' as the `--local-prefix'! The directory you use for `--local-prefix' must not contain any of the system's standard header files. If it did contain them, certain programs would be miscompiled (including GNU Emacs, on certain targets), because this would override and nullify the header file corrections made by the fixincludes script.
  5. Make sure the Bison parser generator is installed. (This is unnecessary if the Bison output files `c-parse.c', `cexp.c', `p/parse.c', and `p/parse.h' are more recent than `c-parse.y', `cexp.y', and `p/parse.y' and you do not plan to change the `.y' files.) Bison versions older than Sept 8, 1988 will produce incorrect output for `c-parse.c'.
  6. If you have chosen a configuration for GNU Pascal which requires other GNU tools (such as GAS or the GNU linker) instead of the standard system tools, install the required tools in the build directory under the names `as', `ld' or whatever is appropriate. This will enable the compiler to find the proper tools for compilation of the program `enquire'. Alternatively, you can do subsequent compilation using a value of the PATH environment variable such that the necessary GNU tools come before the standard system tools.
  7. Once you are satisfied with the configuration as determined by `configure', you can build the Pascal compiler:
    % make LANGUAGES=pascal
    
    (Just `make' would also build the C++ and Objective C compilers). Notice that this procedure will build the C compiler too, because that is used to compile the GPC runtime library. Optionally, you may supply CFLAGS, LDFLAGS or RTSFLAGS. CFLAGS is used for compiler and RTS, RTSFLAGS are for RTS only, i.e.: `make CFLAGS="-O2" RTSFLAGS=-Wall'
  8. When everything compiles, you can verify what the `make -n pascal.install' command does, and if you are satisfied run it without the `-n' option to install the compiler `gpc1', front end `gpc', run time system `libgpc.a' to the same place where `gcc' was installed. This installation process does not overwrite existing copies of `libgcc.a' or `specs', should they exist. You can also install GPC as part of the complete GNU compiler suite using "make install" as described in the GCC installation docs.

Configuration dependent compilation notes

MS-DOS with DJGPP

You cannot build GNU CC (or GNU Pascal) by itself on MS-DOS or a compatible system; it will not compile under any MS-DOS compiler except itself. The official MS-DOS port of GCC is called DJGPP, and it is available from `simtel.coast.net' and it has mirrors all over the world. The `configure' script is replaced by an MS-DOS batch file called `configure.bat' wich does essentially the same. Detailed instructions are in the file `config/msdos/README.dj' of the GNU Pascal source distribution.

MS-DOS or OS/2 with EMX

EMX is a free 32-bit DOS extender which adds some properties of UNIX to MS-compatible DOS and IBM's OS/2 operating systems. You can find it, for example, via anonymous `ftp' on the server `ftp.uni-stuttgart.de' in the directory `pub/systems/os2/emx*'.

Due to the limitation of the command line to 128 characters we don't know a way to compile GPC for EMX under DOS; you need OS/2 instead. If you succeed to compile GPC for EMX on a DOS system, please let us know. (However you can compile GPC for DJGPP on a DOS system.)

To compile under OS/2 you need EMX 0.9d and the patched source files for GCC 2.8.1. The sources assume that the system will be compiled on an HPFS filesystem although the Makefiles can be easily modified for FAT16. The GCC backend requires dmake 3.8 to compile whereas the GPC parts of the systems are compiled with GNU Make 3.7 or later.

  1. Unzip the source for GCC from the root directory, and rename the resulting directory `gcc-2.8' to `gpc'.
      cd \
      unzip c:\gccsrc1
      unzip c:\gccsrc2
      unzip c:\gccsrc3
      ren \emx\gnu\gcc-2.8 gpc
    
  2. Unpack the source for GPC from the `emx\gnu' directory, so it will go into the gpc subdirectory. Unlike other EMX sources, the GPC source must not be extracted from the root directory.
      cd \emx\gnu
      unzip c:\gpc-21s.zip
    
  3. If you are working on a drive different from `d:' and/or if you want to compile the compiler with optimization and/or without debugging information (recommended), edit `\emx\gnu\gpc\dostage1.cmd' to refer to your drive and to have the `CFLAGS' you want, e.g. `CFLAGS="-g -O2"' instead of `CFLAGS=-g'.
  4. You will also want to apply the patches for gcc. To do this you will need GNU Patch (also known as Larry Wall's Patch), which should be available from the normal OS/2 `ftp' archives, e.g. `hobbes.nmsu.edu' in the `/pub/os2/unix/dev' directory. Make sure you rename `patch.exe' to a filename that won't conflict with the built in OS/2 `patch' command. EM recommends using `lwpatch.exe' in his `\emx\doc\build.doc' file. Apply the diff:
      cd \emx\gnu\gpc
      set emxopt=-t
      lwpatch --prefix=~ < p\diffs\gcc-2.8.1.diff
      set emxopt=
    
  5. Compile GPC using the `compile.cmd' script.
      cd \emx\gnu\gpc\p
      compile
    
  6. To install, move the GPC files into place.
      cd \emx\gnu\gpc
      copy gpc*.exe \emx\bin
      copy gpc.a \emx\lib
    

Windows NT and Windows 95 with cygwin32

cygwin32 is a project to make it easy to port UNIX applications to machines which run an OS which supports the Win32 API--i.e. Microsoft Windows 95 and Windows NT. Currently, cygwin32 is in beta stage; it is available from `ftp://ftp.cygnus.com/pub/gnu-win32/' Don't use gcc sources from the cygwin32 distribution. These are not just modified from FSF `gcc-2.8.1' to support the Windows 95/NT target, they are the "current development release", and too different from FSF GCC to be compatible with GNU Pascal, which is based on FSF sources.

Currently, cygwin32 is not self-hosting: the preferred way to build the cygwin32-gpc binary is to use a UNIX system with a cygwin32 targeting cross-compiler. See section Crossbuilding a compiler.

Building and Installing a cross-compiler

GNU Pascal can function as a cross-compiler for many machines, but not all. Also, only a few combinations have been tested. If you need information about GNU tools in a cross-configuration, `ftp://ftp.cygnus.com/pub/embedded/crossgcc/' is the place to be.

Since GNU Pascal generates assembler code, you probably need a cross-assembler that GNU Pascal can run, in order to produce object files. If you want to link on other than the target machine, you need a cross-linker as well. You also need header files and libraries suitable for the target machine that you can install on the host machine.

Steps of Cross-Compilation

To compile and run a program using a cross-compiler involves several steps:

It is most convenient to do all of these steps on the same host machine, since then you can do it all with a single invocation of GNU Pascal. This requires a suitable cross-assembler and cross-linker. For some targets, the GNU assembler and linker are available.

Configuring GNU CC as a cross-compiler

No special actions have to be taken to configure GNU Pascal as a cross-compiler. Cross-compiler specific configuration is done only for GCC. Section 4.2 of "Using and Porting GNU CC" deals with cross-configurations in great detail. Once cross-binutils and a C library for the target machine are in place, GCC can be configured (from the GCC object directory). Suppose we are on a FreeBSD system and want a cross-compiler that produces code that runs on MS-DOS:

% ../gcc-2.8.1/configure --prefix=/usr --target=i386-go32

This creates all the necessary config files, links and Makefile in the GCC object directory. Now, proceed with the compilation and installation process like in the case of the native configuration described before. Do not remove files from the GCC object directory; the cross-compiler is used to compile the GNU Pascal runtime system (RTS) for the target system.

Building the Pascal cross-compiler

Once you have verified the C cross-compiler, the Pascal cross-compiler can be configured and built. Note that the `configure' script does not require any cross-compiler related switches because GPC inherits all of this from GNU CC.

Sample output for a FreeBSD->msdos cross configuration:

--------------------------------------------------------------------------
Configuration summary:
  Building a i386-go32 cross-compiler hosted by i386-unknown-freebsd2.1.0

  GPC sources in:         ../gpc-2.0
  GCC sources in:         ../gcc-2.8.1
  GCC object code in:     ../gcc
  GCC version:            2.8.1

  Compiler for GPC:       gcc
  Compiler for libgpc.a:  i386-go32-gcc
  Compiler flags:         -g -O

  Cross-ar utility:       i386-go32-ar
  Cross-ranlib utility:   i386-go32-ranlib

  Installation path:      /usr/bin, /usr/lib/gcc-lib/i386-go32/2.8.1
--------------------------------------------------------------------------

Now, type `make' to build the compiler and runtime system.

Building a cross-compiler requires cross-binutils for your target, i386-go32 in this examples. If `configure' is not able to find `i386-go32-ar' and/or `i386-go32-ranlib', you may have to run it again with again with --with-ar=your-cross-ar or --with-ranlib=your-cross-ranlib switches.

Then, `make' and `make install' the cross-compiler like you would for a native configuration.

Crossbuilding a compiler.

Yet another possibility is crossbuilding : Using a cross-compiler to build GNU Pascal results in a compiler binary that runs on the cross-target platform. A possible reason why anybody would want to do this, is when the platform on which you want to run the GNU Pascal compiler, is not self-hosting. An example is cygwin32.

To crossbuild GNU Pascal, you have to install a cross-compiler for your target first. This is covered in chapter 4 of "Using and Porting GNU CC". Assuming you want to build a native cygwin32 Pascal compiler on a FreeBSD system, configure GCC:

% ../gcc-2.8.1/configure --prefix=/usr --build=i386-freebsd \
	--host=i386-cygwin32 --target=i386-cygwin32

Build it:

% make CFLAGS=-O2 LANGUAGES=c

Now, configure and build GPC. The output of `configure' should look like:

--------------------------------------------------------------------------
Configuration summary:
  Building a i386-cygwin32 cross-compiler hosted by i386-cygwin32

  GPC sources in:         ../gpc-2.0
  GCC sources in:         ../gcc-2.8.1
  GCC object code in:     ../gcc
  GCC version:            2.8.1

  Compiler for GPC:       i386-cygwin32-gcc
  Compiler for libgpc.a:  i386-cygwin32-gcc
  Compiler flags:         -g -O

  Cross-ar utility:       i386-cygwin32-ar
  Cross-ranlib utility:   i386-cygwin32-ranlib

  Installation path:      /usr/bin, /usr/lib/gcc-lib/i386-cygwin32/2.8.1
--------------------------------------------------------------------------

Now, type `make' to build the compiler and runtime system.

Again, `configure' should be able to detect and configure this setup without additional flags. If not, specify `--with-ar', `--with-ranlib', `--with-gcc' and/or `--with-rtsgcc' as appropriate.

A cross-built compiler must be installed by hand.

Installation instructions for a GPC binary distribution

To install a binary distribution, cd to the main directory and unpack the archive while preserving the stored directory structure. In concrete, to install a ZIP archive under DOS with PKunzip, `cd' the the appropriate directory (usually `\' for EMX, `\DJGPP' for DJGPP), then type

  C:\> pkunzip -d archive

where archive is the name of the distribution file. To install a `.tar.gz' archive under a UNIX compatible system, become root, then extract the archive from the root of the filesystem:

  # tar xzf archive.tar.gz

If you are using a `tar' utility other than GNU tar, it might be necessary to do the above in two steps:

  # gzip -d archive.tar.gz
  # tar xf archive.tar

Binary distributions include `libgcc.a' and `specs', files that are normally part of GCC. If you have GCC installed, they will be replaced unless you manually install the archive.

New Features of GNU Pascal

General Changes Since The Previous Beta Release

There's a large number of bug fixes, too many to mention here. They are listed in the `Fixed Bugs' section of the GPC To-Do list @uref{http://agnes.dida.physik.uni-essen.de/~gnu-pascal/todo.html}. The most important bugs fixed include the unit/module initialization in the wrong order, and not working at all on some systems, the global goto bug, some "two-unit bugs" and a number of BP compatibility issues.

There's a number of new or changed features which are listed in the following. Features without further description refer to new routines or options.

This release of GPC has been cleaned up substantially. Consequently, a few old and obsolete features have been dropped or replaced by clearer, more flexible or otherwise more useful ones. This might lead to minor problems with old programs, but we suppose they're very rare (many programmers might not even know about the old features) and easy to overcome. The most important ones are listed here, the rest of them is contained in the following sections and marked with `(@)'.

Compiler and RTS Built-in Declarations

Some of the following declarations are built into the compiler, others are declared in the `GPC' module.

A few of the units (in particular: CRT, GMP and RegEx) require libraries. The sources of the libraries, with small patches where necessary, as well as binaries for i586-pc-linux-gnu, i586-pc-linux-gnulibc1, m68k-linux, sparc-sun-solaris2, i386-pc-go32, i386-pc-cygwin32 and i386-pc-mingw32 are available from
@uref{ftp://agnes.dida.physik.uni-essen.de/gnu-pascal/libs/}

Demo Programs

There is a number of new demo programs to demonstrate some features of the compiler and the units. The demo programs are part of source and binary GPC distributions. After installation, they can be found in `<prefix>/doc/gpc/demos/'.

The demo programs contained in the GPC documentation are now installed in `<prefix>/doc/gpc/docdemos/', ready to be compiled.

Test Suite

The test suite is used to verify that all features of GPC work as expected and to reproduce bugs reported. Test programs for bugs found by users and for new features are constantly added. The test suite is part of source, not binary, GPC distributions.

Legend

@multitable {xxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}

  • `(@)': @tab minor backward-incompatibility
  • `(B)': @tab BP compatibility
  • `(D)': @tab Delphi compatibility
  • `(G)': @tab GPC compatibility :-) Have fun, The GNU Pascal Development Team

    GNU Pascal Command Line Options

    GPC is a command-line compiler, i.e., to compile a program you have to invoke `gpc' passing it the name of the file you want to compile, plus options.

    GPC supports all command-line options that GCC knows. For a complete reference and descriptions of all options, see section `GCC Command Options' in the GCC manual. Below, you will find a list of the additional options that GPC supports, and a list of GPC's most important options (including some of those supported by GCC as well).

    You can mix options and file names on the command line. For the most part, the order doesn't matter. Order does matter, e.g., when you use several options of the same kind; for example, if you specify `-L' more than once, the directories are searched in the order specified. Note: Since many options have multiletter names; multiple single-letter options may not be grouped as is possible with many other programs: `-dr' is very different from `-d -r'.

    Many options have long names starting with `--' or, completely equivalent `-f'. E.g., `--mixed-comments' is the same as `-fmixed-comments'. Some options tell GPC when to give warnings, i.e. diagnostic messages that report constructs which are not inherently erroneous but which are risky or suggest there may have been an error. Those options start with `-W'.

    Most GPC specific options can also be changed during one compilation by using compiler directives in the source, e.g. `{$X+}' or `{$extended-syntax}' for `--extended-syntax' (see section Compiler Directives And The Preprocessor).

    GPC understands the same environment variables GCC does (see section `Environment Variables Affecting GCC' in the GCC manual). In addition, GPC recognizes `GPC_EXEC_PREFIX' with the same meaning that `GCC_EXEC_PREFIX' has to GCC. GPC also recognizes `GCC_EXEC_PREFIX', but `GPC_EXEC_PREFIX' takes precedence.

    GPC options besides those of GCC.

    The following table lists the command line options GPC understands in addition to those understood by GCC.

    --standard-pascal-level-0
    Reject conformant arrays and anything besides ISO-7185 Standard Pascal.
    --standard-pascal
    Reject anything besides ISO-7185 Standard Pascal.
    --extended-pascal
    Reject anything besides ISO-10206 Extended Pascal.
    --object-pascal
    Reject anything besides (the implemented parts of) ANSI draft Object Pascal.
    --borland-pascal
    Try to emulate Borland Pascal, version 7.0.
    --delphi
    Try to emulate Borland Pascal, version 7.0, with some Delphi extensions.
    --pascal-sc
    Be strict about the implemented Pascal-SC extensions.
    --gnu-pascal
    Undo the effect of a previous `--foo-pascal', `--delphi' or `--pascal-sc' switch.
    --lines
    (Unimplemented switch for debugging).
    --debug-tree
    (Internal directive for debugging the compiler).
    --debug-gpi
    (Internal directive for debugging the compiler).
    --debug-source
    (Internal directive for debugging the compiler).
    --progress-messages
    Output source file names and line numbers while compiling.
    --progress-bar
    Output number of processed lines while compiling.
    --autolink
    Automatically link object files provided by Units/Modules or `{$L ...}' (default).
    --no-autolink
    Do not automatically link object files provided by Units/Modules/`{$L ...}'.
    --automake
    Automatically compile changed Units/Modules/`{$L ...}' files and link the object files provided.
    --no-automake
    Same as `--no-autolink'.
    --autobuild
    Automatically compile all Units/Modules/`{$L ...}' files and link the object files provided.
    --no-autobuild
    Same as `--no-autolink'.
    --amtmpfile
    (Internal switch used for AutoMake).
    --extended-syntax
    Enable certain `dangerous' features such as ignoring function results, pointer arithmetics or using `CString's as strings (same as `{$X+}').
    --no-extended-syntax
    Disable the dangerous features enabled by `--extended-syntax' (default; same as `{$X-}').
    --signed-char
    Let `Char' be a signed type.
    --no-signed-char
    Let `Char' be an unsigned type.
    --unsigned-char
    Let `Char' be an unsigned type.
    --no-unsigned-char
    Let `Char' be a signed type.
    --short-circuit
    Guarantee short-circuit Boolean evaluation (default; same as `{$B-}').
    --no-short-circuit
    Do not guarantee short-circuit Boolean evaluation (same as `{$B+}').
    --mixed-comments
    Allow comments like `{ ... *)' as required in ISO Pascal (default in Standard Pascal mode).
    --no-mixed-comments
    Ignore `{' and `}' within `(* ... *)' comments and vice versa (default).
    --nested-comments
    Allow nested comments like `{ { } }' and `(* (* *) *)'.
    --no-nested-comments
    Do not allow nested comments (default).
    --delphi-comments
    Allow Delphi style `//' comments (default).
    --no-delphi-comments
    Do not allow Delphi style `//' comments.
    --macros
    Expand macros (default).
    --no-macros
    Do not expand macros (default with `--borland-pascal' or `--delphi').
    --ignore-function-results
    Do not complain when a function is called like a procedure.
    --no-ignore-function-results
    Complain when a function is called like a procedure (default).
    --borland-char-constants
    Allow for Borland-style character constants like `#27' or `^L' (default).
    --no-borland-char-constants
    Reject Borland-style character constants like `#27' or `^L' (default in Standard Pascal mode).
    --truncate-strings
    Truncate strings being assigned to other strings of too short capacity..
    --no-truncate-strings
    Treat string assignments to other strings of too short capacity as errors..
    --exact-compare-strings
    Do not blank-pad strings for comparisons.
    --no-exact-compare-strings
    Blank-pad strings for comparisons.
    --io-checking
    Do automatic run-time checks after I/O operations (same as `{$I+}').
    --no-io-checking
    Do not check I/O operations automatically (same as `{$I-}').
    --write-clip-strings
    In write statements, truncate strings exceeding their field width (`Write (SomeLongString : 3)').
    --no-write-clip-strings
    Do not truncate strings exceeding their field width.
    --write-real-blank
    Output a blank in front of positive reals in exponential form (default).
    --no-write-real-blank
    Do not output a blank in front of positive reals in exponential form.
    --write-capital-exponent
    Write real exponents with a capital `E'.
    --no-write-capital-exponent
    Write real exponents with a lowercase `e'.
    --transparent-file-names
    Derive external file names from variable names.
    --no-transparent-file-names
    Do not derive external file names from variable names (default).
    --field-widths
    Comma-separated list of default field widths for Integer, Real, Boolean, LongInt, LongReal.
    --no-field-widths
    Reset the default field widths.
    --pedantic
    Warn about everything rejected in some dialect, e.g. redefinition of its keywords.
    --no-pedantic
    Don't give pedantic warnings.
    --stack-checking
    Enable stack checking (same as `{$S+}').
    --no-stack-checking
    Disable stack checking (same as `{$S-}').
    --typed-address (same as `{$T+}')
    Make the result of the address operator typed (default).
    --no-typed-address (same as `{$T-}')
    Make the result of the address operator an untyped pointer.
    --setlimit
    Define the range for `set of Integer' etc..
    --gpc-main
    External name for the program's entry point (default: `main').
    --interface-only
    Compile only the interface part of a Unit/Module and exit.
    --implementation-only
    Do not produce a GPI file; only compile the implementation part.
    --executable-file-name
    Name for the output file, if specified; otherwise derive from main source file name.
    --unit-path
    Directories where to look for Unit/Module sources.
    --no-unit-path
    Forget about directories where to look for Unit/Module sources.
    --object-path
    Directories where to look for additional object (and source) files.
    --no-object-path
    Forget about directories where to look for additional object (and source) files.
    --executable-path
    Path where to create the executable file.
    --no-executable-path
    Create the executable file in the directory where the main source is (default).
    --unit-destination-path
    Path where to create object and GPI files.
    --no-unit-destination-path
    Create object and GPI files in the current directory (default).
    --object-destination-path
    Path where to create additional object files.
    --no-object-destination-path
    Create additional object files in the current directory (default).
    --no-default-paths
    Do not add a default path to the unit and object path.
    --gpi-destination-path
    (Internal switch used for AutoMake).
    --uses
    Add an implicit `uses' clause.
    --cidefine
    Define a case-insensitive macro.
    --csdefine
    Define a case-sensitive macro.
    -Wwarnings
    Enable warnings (same as `{$W+}').
    -Wno-warnings
    Disable warnings (same as `{$W-}').
    -Wfield-name-problem
    Warn about ignored field names in initializers (default).
    -Wno-field-name-problem
    Do not warn about ignored field names in initializers.
    -Wtyped-const
    Warn about misused of typed constants as initialized variables (default).
    -Wno-typed-const
    Do not warn about misused of typed constants as initialized variables.
    -Wnear-far
    Warn about use of useless `near' or `far' directives (default).
    -Wno-near-far
    Do not warn about use of useless `near' or `far' directives.
    -Wmixed-comments
    Warn about mixed comments like `{ ... *)'.
    -Wno-mixed-comments
    Do not warn about mixed comments.
    -Wnested-comments
    Warn about nested comments like `{ { } }'.
    -Wno-nested-comments
    Do not warn about nested comments.

    The most commonly used options to GPC

    As the most simple example, calling

    gpc foo.pas
    

    tells GPC to compile the source file `foo.pas' and to produce an executable of the default name which is `foo.exe' on EMX, `a.exe' on DJGPP, and `a.out' on most other platforms.

    Users familiar with BP, please note that you have to give the file name extension `.pas': GPC is a common interface for a Pascal compiler, a C, ObjC and C++ compiler, an assembler, a linker, and perhaps an Ada and a FORTRAN compiler. From the extension of your source file GPC figures out which compiler to run. GPC recognizes Pascal sources by the extension `.pas', `.p', `.pp' or `.dpr'. GPC also accepts source files in other languages (e.g., `.c' for C) and calls the appropriate compilers for them. Files with the extension `.o' or without any special recognized extension are considered to be object files or libraries to be linked.

    Another example:

    gpc -O2 -Wall --executable-file-name --automake --unit-path=units foo.pas
    

    This will compile the source file `foo.pas' to an executable named `foo' (`--executable-file-name') with fairly good optimization (`-O2'), warning about possible problems (`-Wall'). If the program uses units or imports modules, they will be searched for in a directory called `units' (`--unit-path') and automatically compiled and linked (`--automake').

    The following table lists the most commonly used options to GPC.

    --automake
    Check whether modules/units used must be recompiled and do the recompilation when necessary.
    --unit-path=dir[:dir...]
    Search the given directories for units and object files.
    --object-path=dir[:dir...]
    Search the given directories for object files.
    --unit-destination-path=dir
    Place units compiled into the directory dir. The default is the current directory.
    --object-destination-path=dir
    Place object files compiled into the directory dir. The default is the directory given with `--unit-destination-path'.
    --executable-path=dir
    Place the executable compiled into the directory dir. The default is the main source file's directory.
    -o file
    Place output in file file. This applies regardless to whatever sort of output is being produced, whether it be an executable file, an object file, an assembler file, etc. Since only one output file can be specified, it does not make sense to use `-o' when compiling more than one input file, unless you are producing an executable file as output.
    --executable-file-name[=name]
    Derive the executable file name from the source file name, or use name as the executable file name. The difference to the `-o' option is that `--executable-file-name' considers the `--executable-path', while `-o' does not and accepts a file name with directory. Furthermore, `--executable-file-name' only applies to executables, not to other output formats selected.
    -Ldir
    Search the directory dir for libraries. Can be given multiple times.
    -Idir
    Search the directory dir for include files. Can be given multiple times.
    -llibrary
    Search the library named library when linking. This option must be placed on the command line after all source or object files or other libraries that reference the library.
    -O[n]
    Select the optimization level. Without optimization (or `-O0' which is the default), the compiler's goal is to reduce the compilation time and to make debugging produce the expected results. Statements are independent: if you stop the program with a breakpoint between statements, you can then assign a new value to any variable or change the program counter to any other statement in the same routine and get exactly the results you would expect from the source code. With optimization, the compiler tries to reduce code size and execution time. The higher the value of n, the more optimizations will be done, but the longer the compilation will take. If you use multiple `-O' options, with or without n, the last such option is the one that is effective.
    -g
    Produce debugging information suitable for `gdb'. Unlike some other compilers, GNU Pascal allows you to use `-g' with `-O'. The shortcuts taken by optimized code may occasionally produce surprising results: some variables you declared may not exist at all; flow of control may briefly move where you did not expect it; some statements may not be executed because they compute constant results or their values were already at hand; some statements may execute in different places because they were moved out of loops. Nevertheless it proves possible to debug optimized output. This makes it reasonable to use the optimizer for programs still in the testing phase.
    -s
    Remove all symbol table and relocation information from the executable. Note: this has no influence on the performance of the compiled executable.
    -Wall
    Give warnings for a number of constructs which are not inherently erroneous but which are risky or suggest there may have been an error. There are additional warning options not implied by `-Wall', see the GCC warning options (see section `Options to Request or Suppress Warnings' in the GCC manual), while `-Wall' only warns about such constructs that should be easy to avoid in programs. Therefore, we suggest using `-Wall' on most sources.
    -Werror
    Turn all warnings into errors.
    -S
    Stop after the stage of compilation proper; do not assemble. The output is in the form of an assembler code file for each source file. By default, the assembler file name for a source file is made by replacing the extension with `.s'.
    -c
    Compile and assemble the source files, but do not link. The output is in the form of an object file for each source file. By default, the object file name for a source file is made by replacing the extension with `.o'.
    -static
    On systems that support dynamic linking, this prevents linking with the shared libraries, i.e. forces static linking. On other systems, this option has no effect.
    -Dmacro[=defn]
    Define the macro and conditional macro as defn (or as `1' if defn is omitted).
    -b machine
    The argument machine specifies the target machine for compilation. This is useful when you have installed GNU Pascal as a cross-compiler.
    -v
    Print (on standard error) the commands executed to run the stages of compilation. Also print the version number of the compiler driver program and of the preprocessor and the compiler proper.
    --standard-pascal-level-0
    --standard-pascal
    --extended-pascal
    --object-pascal
    --borland-pascal
    --pascal-sc
    GNU Pascal supports the features of several different Pascal standards and dialects. By default, they are all enabled. These switches tell GPC to restrict itself to the features of the specified standard. It does not enable any additional features. Warnings about constructs which would be legal in the specified dialect (e.g. assignment to a typed constant with `--borland-pascal') are suppressed. By default, GNU Pascal allows redefinition of keywords. Each of these switches causes GNU Pascal to forbid the redefinition of keywords of the specified standard. Valid ISO Standard Pascal programs should compile properly with or without `--standard-pascal'. However, without this option, certain GNU extensions and Pascal features from other dialects are supported as well. With this option, they are rejected. These options are not intended to be useful; they exist only to satisfy pedants who would otherwise claim that GNU Pascal fails to support the ISO Standard or is not really compatible to Borland Pascal, or whatever. We recommend, rather, that users take advantage of the extensions of GNU Pascal and disregard the limitations of other compilers.
    -pedantic-errors
    Produce errors rather than warnings for portability violations. Unlike in C, this does not imply the `-pedantic' option, so you can, for instance, use `-pedantic-errors' without `-pedantic', but with `--extended-pascal'.
    --gpc-main=name
    Name the entry point of the main program `name' instead of `main' on the linker level. This is useful, e.g., when working with some C libraries which define their own `main' function and require the program's main entry point to be named differently.

    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 Line 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/BP style units. Units and modules can be mixed in one project.

    One trivial example for a valid GPC source file follows. Note that the code below may either be in one source file, or else the unit and the program may be in separate source files.

    unit DemoUnit;
    
    interface
    
    procedure Hello;
    
    implementation
    
    procedure Hello;
    begin
      Writeln ('Hello, world!')
    end;
    
    end.
    
    program UnitDemo;
    
    uses DemoUnit;
    
    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.
    

    The Program headline may be omitted in GPC, but a warning will be given except in `--borland-pascal' mode.

    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. GPC will warn about such missing parameters in `--extended-pascal' mode. 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 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 do, section to end do.

    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.

    A unit exports everything declared in the interface section. The exported interface has the name of the unit and is compatible with Extended Pascal module interfaces since GPC uses the same code to handle both.

    The Source Structure of ISO-10206 Extended Pascal Modules

    @@ Description missing here

    A module can have one or more `export' clauses and the name of an `export' clause doesn't have to be equal to the name of the module.

    Sample module code with separate interface and implementation parts:

    module DemoModule interface;  { interface part }
            
    export DemoModule = (FooType, SetFoo, GetFoo);
    
    type
      FooType = Integer;
    
    procedure SetFoo (f : FooType);
    function  GetFoo : FooType;
    
    end.
    
    module DemoModule implementation;  { implementation part }
    
    import
      StandardInput;
      StandardOutput;
    
    var
      Foo : FooType;
    
    { Note: the effect is the same as a `forward' directive would have:
      parameter lists and return types are not allowed in the
      declaration of exported routines, according to EP. In GPC, they
      are allowed, but not required. }
    procedure SetFoo;
    begin
      Foo := f
    end;
    
    function GetFoo;
    begin
      GetFoo := Foo
    end;
    
    to begin do
      begin
        foo := 59;
        Writeln ('Just an example of a module initializer. See comment below')
      end;
    
    to end do
      begin
        Foo := 0;
        Writeln ('Goodbye')
      end;
            
    end.
    

    Alternatively the module interface and implementation may be combined as follows:

    module DemoMod2; { Alternative method }
    
    export Catch22 = (FooType, SetFoo, GetFoo);
    
    type
      FooType = Integer;
    
    procedure SetFoo (f : FooType);
    function  GetFoo : FooType;
    
    end; { note: this end is required here, even if the
           module-block below would be empty. }
    
    var
      Foo : FooType;
    
    procedure SetFoo;
    begin
      Foo := f
    end;
    
    function GetFoo;
    begin
      GetFoo := Foo
    end;
    
    end.
    

    Either one of the two methods may be used like this:

    program ModuleDemo (Output);
    
    import DemoModule;
            
    begin
      SetFoo (999);
      Writeln (GetFoo);
    end.
    
    program ModDemo2 (Output);
    
    import Catch22 in 'demomod2.pas';
            
    begin
      SetFoo (999);
      Writeln (GetFoo);
    end.
    

    Somewhat simpler GPC modules are also supported. Note: This is not supported in the Extended Pascal standard.

    This is a simpler module support that does not require exports, imports, module headers etc.

    These non-standard simple GPC modules look like (does not have an export part, does not have a separate module-block, does not use import/export features.)

    module DemoMod3;
    
    type
      FooType = Integer;
    
    var
      Foo : FooType;
    
    procedure SetFoo (f : FooType);
    begin
      Foo := f
    end;
    
    function GetFoo : FooType;
    begin
      GetFoo := Foo;
    end;
    
    end.
    
    program ModDemo3 (Output);
    
    { Manually do the "import" from DemoMod3 }
    type
      FooType = Integer;
    
    procedure SetFoo (f : FooType); external;
    function  GetFoo : FooType;     external;
    
    begin
      SetFoo (999);
      Writeln (GetFoo)
    end.
    

    Module initialization and finalization:

    The to begin do module initialization and to end do module finalization constructs now work on every target.

    By the way: The "GPC specific" module definition is almost identical to the PXSC standard. With an additional keyword `global' which puts a declaration into an export interface with the name of the module, it will be the same. @@This is planned.

    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.

    The Processor's 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).

    The main branch of 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.
    program IntegerTypesDemo (Output);
    
    var
      ByteVar : Byte;
      ShortIntVar : ShortInt;
      Foo : MedCard;
      Big : LongestInt;
    
    begin
      ShortIntVar := 1000;
      Big := MaxInt * ShortIntVar;
      ByteVar := 127;
      Foo := 16#deadbeef
    end.
    

    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

    Endianness means the order in which the bytes of a value larger than one byte are stored in memory. This affects, e.g., integer values and pointers while, e.g., arrays of single-byte characters are not affected. The GPC `String' schema, however, contains `Capacity' and `Length' fields before the character array. These fields are integer values larger than one byte, so the `String' schema is affected by endianness.

    Endianness depends on the hardware, especially the processor. The most common forms are:

    Little-endian
    Little-endian machines store the least significant byte on the lowest memory address (the word is stored little-end-first). E.g., if the 32 bit value $deadbeef is stored on memory address $1234 on a little-endian machine, the following bytes will occupy the memory positions:
    Address  Value
    --------------
    $1234    $ef
    $1235    $be
    $1236    $ad
    $1237    $de
    
    Examples for little-endian machines are Intel and compatible microprocessors and Alpha processors.
    Big-endian
    Big-endian machines store the most significant byte on the lowest memory address (the word is stored big-end-first). E.g., if the 32 bit value $deadbeef is stored on memory address $1234 on a big-endian machine, the following bytes will occupy the memory positions:
    Address  Value
    --------------
    $1234    $de
    $1235    $ad
    $1236    $be
    $1237    $ef
    
    Examples for big-endian machines are the Sparc and Motorola m68k processor families and most RISC processors. Big-endian byte order is also used in the Internet protocols.

    Note: There are processors which can run in both little-endian and big-endian mode, e.g. the MIPS processors. A single program, however, (unless it uses special machine code instructions) will always run in one endianness.

    Under normal circumstances, programs do not need to worry about endianness, the processor handles it by itself. Endianness becomes important when exchanging data between different machines, e.g. via binary files or over a network. To avoid problems, one has to choose the endianness to use for the data exchange. E.g., the Internet uses big-endian data, and most known data formats have a specified endianness (usually that of the processor on which the format was originally created). If you define your own binary data format, you're free to choose the endianness to use.

    To deal with endianness, GPC predefines the symbol `__BYTES_LITTLE_ENDIAN__' on little-endian machines and `__BYTES_BIG_ENDIAN__' on big-endian machines. Besides, the Run Time System defines the constant `BytesBigEndian' as False on little-endian machines and True on big-endian machines.

    There are also the symbols `__BITS_LITTLE_ENDIAN__', `__BITS_BIG_ENDIAN__', `__WORDS_LITTLE_ENDIAN__', `__WORDS_BIG_ENDIAN__' and the constants `BitsBigEndian' and `WordsBigEndian' which concern the order of bits within a byte (e.g., in packed records) or of words within multiword-numbers, but these are usually less important.

    The Run Time System also contains a number of routines to convert endianness and to read or write data from/to binary files in a given endianness, independent of the processor's endianness. These routines are described in the RTS reference (see section Run Time Library--Pascal Declarations), under `endianness'. The demo program `endiandemo.pas' contains an example on how to use these routines.

    Alignment

    (Under construction.)

    Pointer Types

    (Under construction.)

    GPC also suports pointers to procedures or function and calls through them. This is a non-standard feature.

    program ProcPtrDemo (Output);
    
    type
      ProcPtr = ^procedure (Integer);
    
    var
      PVar : ProcPtr;
    
    procedure WriteInt (i : Integer);
    begin
      Writeln ('Integer: ', i : 1)
    end;
    
    begin
      { Let PVar point to function WriteInt }
      PVar := &WriteInt;
    
      { Call the function by dereferencing the function pointer }
      PVar^ (12345)
    end.
    

    Procedural and Functional Types

    (Under construction.)

    BP has procedural and functional types:

    type
      CompareFunction = function (Key1, Key2 : String) : Integer;
    
    function Sort (Compare : CompareFunction);
    begin
      ...
    end;
    

    Standard Pascal has procedural and functional parameters:

    function Sort (function Compare (Key1, Key2 : String) : Integer);
    begin
      ...
    end;
    

    Both ways have pros and cons, e.g. in BP you can save, compare, trade, etc. procedural values, or build arrays of them, while the SP way does not require a type declaration and prevents problems with uninitialized or invalid pointers (which in BP will usually crash the program).

    GPC supports both ways. An important feature of Standard Pascal (but not BP) that GPC also supports is the possibility to pass local routines as procedural or functional parameters, even if the called routine is declared far remote. The called routine can then call the passed local routine and it will have access to the original caller's local variables.

    program LocalProceduralParameterDemo;
    
    procedure CallProcedure (procedure Proc);
    begin
      Proc
    end;
    
    procedure MainProcedure;
    var LocalVariable : Integer;
    
      procedure LocalProcedure;
      begin
        Writeln (LocalVariable)
      end;
    
    begin
      LocalVariable := 42;
      CallProcedure (LocalProcedure)
    end;
    
    begin
      MainProcedure
    end.
    

    Variant Records

    GPC supports variant records like in EP and BP. The following construction is not allowed in Extended Pascal, but in BP and GPC:

    type
      PersonRec = record
        Age : Integer;
        case EyeColor : (Red, Green, Blue, Brown) of
          Red, Green  : (WearsGlasses : Boolean);
          Blue, Brown : (LengthOfLashes : Integer);
        end;
      end;
    

    In EP, the variant field needs a type identifier, which, of course, also works in GPC:

    type
      EyeColorType = (Red, Green, Blue, Brown);
      PersonRec = record
        Age : Integer;
        case EyeColor : EyeColorType of
          Red, Green  : (WearsGlasses : Boolean);
          Blue, Brown : (LengthOfLashes : Integer);
        end;
      end;
    

    Initial values to type denoters

    A type may be initialized to a value of expression when it is declared, like a variable, as in:

    program TypeVarInitDemo;
    type
      Int10   = Integer value 10;
      FooType = Real;
      MyType  = Char value Pred ('A');
      EType   = (a, b, c, d, e, f, g) value d;
    
    const
      Answer = 42;
    
    var
      ii  : Int10;                    { Value of ii set to 10 }
      ch  : MyType  value Pred ('z');
      aa  : Integer value Answer + 10;
      foo : FooType value Sqr (Answer);
      e1  : EType;                    { value set to d }
      e2  : EType value g;            { value set to g }
    begin
    end.
    

    Extended Pascal requires the type initializers to be constant expressions. GPC allows any valid expression.

    Note, however, that the expressions that affect the size of storage allocated for objects (e.g. the length of arrays) may contain variables only inside functions or procedures.

    GPC evaluates the initial values used for the type when an identifier is declared for that type. If a variable is declared with a type-denoter that uses a type-name which already has an initial value the latter initialization has precedence.

    @@ GPC does not know how to calculate constant values for math functions in the runtime library at compile time, e.g. `Exp (Sin (2.4567))', so you should not use these kind of expressions in object size expressions. (Extended Pascal allows this.)

    Restricted types

    GPC supports `restricted' types, defined in Extended Pascal. A value of a restricted type may be passed as a value parameter to a formal parameter possessing its underlying type, or returned as the result of a function. A variable of a restricted type may be passed as a variable parameter to a formal parameter possessing the same type or its underlying type. No other operations, such as accessing a component of a restricted type value or performing arithmetic, are possible.

    program RestrictedDemo;
    
    type
      UnrestrictedRecord = record
        a : Integer;
      end;
      RestrictedRecord =  restricted UnrestrictedRecord;
    
    var
      r1 : UnrestrictedRecord;
      r2 : RestrictedRecord;
      i : restricted Integer;
      k : Integer;
    
      function AccessRestrictedRecord (p : UnrestrictedRecord) : RestrictedRecord;
      var URes : UnrestrictedRecord;
      begin
        { The parameter is treated as unrestricted, even though the actual
          parameter may be a restricted object }
        URes.a := p.a;
        { It is legal to assign a return value }
        AccessRestrictedRecord := URes;
      end;
    
    begin
       r1.a := 354;
    
       { Assigning a restricted return value to a restricted object }
       { @@ Verify if this should really be allowed????? }
       r2 := AccessRestrictedRecord (r1);
    
       { Passing a restricted object to unrestericted formal parameter is ok }
       r2 := AccessRestrictedRecord (r2);
    
       {$ifdef BUG}
       { *** The following are illegal *** }
       r2.a := 100;    { field access }
       r1 := r2;       { assignment source is restricted }
       r2 := r1;       { assignment target is restricted }
       r1 := AccessRestrictedRecord (r2); { assigning a restricted return
                                             value to an unrestricted object }
       i  := 16#ffff;  { assignment target is restricted }
       k  := i + 2;    { arithmetic with restricted value }
       {$endif}
    end.
    

    How to declare simple and structured constants

    @@ simple constants missing

    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 (re-)definition of operators according to the Pascal-SC (PXSC) standard. The following vector addition example illustrates how to do this:

    program OperatorDemo;
    
    type
      Vector3 = record
        x, y, z : Real;
      end;
    
    var
      a, b, c : Vector3;
    
    operator + (u, v : Vector3) w : Vector3;
    begin
      w.x := u.x + v.x;
      w.y := u.y + v.y;
      w.z := u.z + v.z;
    end;
    
    begin
      c := a + b
    end.
    

    Between the closing parenthesis of the argument list and the result variable (`w' in the above example), 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 also 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. 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 as well! 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".)

    Procedure And Function Parameters

    Parameters declared as `protected' or `const'

    All the following works in GPC:

    procedure Foo (protected a, b, c : Integer);    { 3 arguments }
    procedure Foo (a, b, c, protected : Integer);   { 4 arguments }
    procedure Foo (a, b, protected, c : Integer);   { 4 arguments }
    procedure Foo (protected : Integer);            { 1 argument  }
    procedure Foo (var protected : Integer);        { 1 argument  }
    procedure Foo (protected protected : Integer);  { 1 argument  }
    

    Furthermore, GPC supports const, according to BP, which is equivalent to either protected or protected var, up to the compiler's discretion.

    The Standard way to pass arrays of variable size

    (Under construction.)

    A feature of Standard Pascal level 1.

    BP's alternative to Conformant Arrays

    Borland Pascal "open array" formal parameters are implemented into GPC. Within the function body, they have integer type index with lower bound 0.

    In constrast to conformant arrays (which are not supported by BP), open arrays allow any ordinal type as the index of the actual parameter (which is useful, e.g., if you want to be able to pass values of any enumeration type). However, they lose information about the lower bound (which is a problem, e.g., if you want to return information to the caller that relates to the actual array index, like the function `IOSelect' in the Run Time System does).

    EP's Schema Types including `String'

    Schemata are types that depend on one or more variables, called discriminants. They are an ISO-10206 Extended Pascal feature.

    type
      RealArray (n : Integer) = array [1 .. n] of Real;
      Matrix (n, m : PositiveInteger) = array [1 .. n, 1 .. m] of Integer;
    

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

    The discriminants of every global or local schema variable are initialized at the beginning of the procedure, function or program where the schema variable is declared.

    Schema-typed variables "know" about their discriminants. Discriminants can be accessed just like record fields:

      Writeln (Foo.n); { yields 42 }
    

    Schemata may be passed as parameters. While types of schema variables must always have specified discriminants (which may be other variables), formal parameters (by reference or by value) may be of a schema type without specified discriminant. In this, the actual parameter may posses any discriminant. The discriminants of the parameters get their values from the actual parameters.

    Also, pointers to schema variables may be declared 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;
    
    begin
      for i := 1 to Bar^.n do
        Bar^[i] := 42;
    end;
    

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

    References to the schema discriminants are allowed, and the with statement is also allowed, so one can say:

    program WithSchemaDemo;
    type
      RealArray (n : Integer) = array [1 .. n] of Real;
    var
      MyArray : RealArray (42);
    begin
      Writeln (MyArray.n);  { writes 42 }
      with MyArray do
        Writeln (n);        { writes 42 }
    end.
    

    Finally, here is a somewhat exotic example. Here, a `ColoredInteger' behaves just like an ordinary integer, but it has an additional property `Color' which can be accessed like a record field.

    program ExoticSchemaDemo;
    
    type
      ColorType = (Red, Green, Blue);
      ColoredInteger (Color : ColorType) = Integer;
    
    var
      Foo : ColoredInteger (Green);
    
    begin
      Foo := 7;
      if Foo.Color = red then
        Inc (Foo, 2)
      else
        Foo := Foo div 3
    end.
    

    An important schema is the predefined `String' schema (according to Extended Pascal). It has one predefined discriminant identifier Capacity. GPC implements the String schema as follows:

    type
      String (Capacity : Cardinal) = record
        Length : Cardinal;
        Chars  : packed array [1 .. Capacity + 1] of Char
      end;
    

    The Capacity field may be directly referenced by the user, the Length field is referenced by a predefined string function Length (Str) and contains the current string length. Chars contains the chars in the string. The Chars and Length fields cannot be directly referenced by a user program.

    If a formal value parameter is of type `String' (with or without discriminant), the actual parameter may be either a String schema, a fixed string (character array), a single character, a string literal or a string expression. If the actual parameter is a `String' schema, it is copied for the parameter in the usual way. If it is not a schema, a `String' schema is created automatically, the actual parameter is copied to the new variable and the Capacity field of the new variable is set to the length of the actual parameter.

    Actual parameters to `var' parameters of type `String' must be `String' schemata, not string literals or character arrays.

    program StringDemo (Output);
    
    type
      SType = String (10);
      SPtr  = ^String;
    
    var
      Str  : SType;
      Str2 : String (100000);
      Str3 : String (20) value 'string expression';
      DStr : ^String;
      ZStr : SPtr;
      Len  : Integer value 256;
      Ch   : Char value 'R';
    
    { `String' accepts any length of strings }
    procedure foo (z : String);
    begin
      Writeln ('Capacity : ', z.Capacity);
      Writeln ('Length   : ', Length (z));
      Writeln ('Contents : ', z);
    end;
    
    { Another way to use dynamic strings }
    procedure Bar (SLen : Integer);
    var
      LString : String (SLen);
      FooStr  : type of LString;
    begin
      LString := 'Hello world!';
      Foo (LString);
      FooStr := 'How are you?';
      Foo (FooStr);
    end;
    
    begin
      Str  := 'KUKKUU';
      Str2 := 'A longer string variable';
      New (DStr, 1000);  { Select the string Capacity with `New' }
      DStr^ := 'The maximum length of this is 1000 chars';
      New (ZStr, Len);
      ZStr^ := 'This should fit here';
      Foo (Str);
      Foo (Str2);
      Foo ('This is a constant string');
      Foo ('This is a ' + Str3);
      Foo (Ch);  { A char parameter to string routine }
      Foo (");  { An empty string }
      Foo (DStr^);
      Foo (ZStr^);
      Bar (10000);
    end.
    

    In the above example, the predefined procedure New was used to select the capacity of the strings. Procedure Bar also has a string whose size depends of the parameter passed to it and another string whose type will be the same as the type of the first string, using the type of construct.

    All string and character types are compatible as long as the destination string is long enough to hold the source in assignments. If the source string is shorter than the destination, the destination is automatically blank padded if the destination string is not of string schema type.

    Pointer Arithmetics

    Address operator: The address operator is @ in BP. Implemented into GPC as an alternative to &.

    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 BP object extensions are almost fully implemented into GPC. This includes inheritance, virtual and non-virtual methods, constructors, destructors, pointer compatibility, extended `New' syntax (with constructor call and/or as a Boolean function), extended `Dispose' syntax (with destructor call).

    The Borland object model is different from the ISO draft, but it will not be too difficult now to implement that too (plus the Borland Delphi Object Extensions which are quite similar to the ISO draft).

    The syntax for an object type declaration is as follows:

    program ObjectDemo;
    
    type
      Str100 = String (100);
    
      FooParentPtr = ^fooParent;
      FooPtr = ^foo;
    
      FooParent = object
        constructor Init;
        destructor Done; virtual;
        procedure Bar (c : Real); virtual;
        function Baz (b, a, z : Char) : Str100;  { not virtual }
      end;
    
      Foo = object (FooParent)
        x, y : Integer;
        constructor Init (a, b : Integer);
        destructor Done; virtual;
        procedure Bar (c : Real); virtual;  { overrides `FooParent.Bar' }
        z : Real;  { GPC extension: data fields after methods }
        function Baz : Boolean;  { new function }
      end;
    
    constructor FooParent.Init;
    begin
      Writeln ('FooParent.Init')
    end;
    
    destructor FooParent.Done;
    begin
      Writeln ('I"m also done.')
    end;
    
    procedure FooParent.Bar (c : Real);
    begin
      Writeln ('FooParent.Bar (', c, ')')
    end;
    
    function FooParent.Baz (b, a, z : Char) = s : Str100;
    begin
      WriteStr (s, 'FooParent.Baz (', b, ', ', a, ', ', z, ')')
    end;
    
    constructor Foo.Init (a, b : Integer);
    begin
      inherited Init;
      x := a;
      y := b;
      z := 3.4;
      FooParent.Bar (1.7)
    end;
    
    destructor Foo.Done;
    begin
      Writeln ('I"m done.');
      inherited Done
    end;
    
    procedure Foo.Bar (c : Real);
    begin
      Writeln ('Foo.Bar (', c, ')')
    end;
    
    function Foo.Baz : Boolean;
    begin
      Baz := True
    end;
    
    var
      Ptr : FooParentPtr;
    
    begin
      Ptr := New (FooPtr, Init (2, 3));
      Ptr^.Bar (3);
      Dispose (Ptr, Done);
      New (Ptr, Init);
      with Ptr^ do
        Writeln (Baz ('b', 'a', 'z'))
    end.
    

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

    Compiler Directives And The Preprocessor

    GPC, like UCSD and BP, treats comments beginning with a `$' immediately following the opening `{' or `(*' as a compiler directive. As in Borland Pascal, {$...} and (*$...*) are equivalent. When a single character plus a `+' or `-' follows, this is also called a compiler switch. All these directives are case-insensitive (but some of them have case-sensitive arguments). Directives are local and can change during one compilation (except include files etc. where this makes no sense).

    In general, compiler directives are compiler-dependent. (E.g., only the include directive {$I FileName} is common to UCSD and BP.) Because of BP's popularity, GPC supports all of BP's compiler directives (and ignores those that are unnecessary on its platforms -- these are those not listed below), but it knows a lot more directives.

    Some BP directives are -- of course not by chance -- just an alternative notation for C preprocessor directives. But there are differences: BP's conditional definitions (`{$define Foo}') go into another name space than the program's definitions. Therefore you can define conditionals and check them via {$ifdef Foo}, but the program will not see them as an identifier `Foo', so macros do not exist in Borland Pascal.

    GPC does support macros, but disables this feature when the `--no-macros' option or the dialect option `--borland-pascal' or `--delphi' is given, to mimic BP's behaviour. Therefore, the following program will react differently when compiled with GPC without special options and with, e.g., the `--borland-pascal' option (and in the latter case, it behaves the same as when compiled with BP).

    program MacroDemo;
    
    const Foo = 'Borland Pascal';
    
    {$define Foo 'Default'}
    
    begin
      Writeln (Foo)
    end.
    

    Of course, you should not rely on such constructs in your programs. To test if the program is compiled with GPC, you can test the `__GPC__' conditional, and to test the dialect used in GPC, you can test conditionals like `__BORLAND_PASCAL__'.

    In general, almost every GPC specific command line option (see section GPC options besides those of GCC.) can be turned into a compiler directive:

    --foo       {$foo}
    --no-foo    {$no-foo}
    -Wbar       {$W bar}     { note the space after the `W' }
    -Wno-bar    {$W no-bar}
    

    The following table lists some such examples as well as all those directives that do not correspond to command-line options or have syntactical alternatives (for convenience and/or BP compatibility).

    --[no-]short-circuit   $B+ $B- like in Borland Pascal:
                                   $B- means short-circuit Boolean
                                   operators; $B+ complete evaluation
    
    --[no-]io-checking     $I+ $I- like in Borland Pascal:
                                   enable/disable I/O checking
    
    --[no-]stack-checking  $S+ $S- like in Borland Pascal:
                                   enable/disable stack checking
    
    --[no-]typed-address   $T+ $T- like in Borland Pascal:
                                   make the result of the address
                                   operator and the Addr function a
                                   typed or untyped pointer
    
    -W[no-]warnings        $W+ $W- enable/disable warnings. Note: in
                                   `--borland-pascal' mode, the
                                   short version is disabled because
                                   $W+/$W- has a different meaning in
                                   Borland Pascal (which can safely be
                                   ignored in GPC), but the long version
                                   is still available.
    
    --[no-]extended-syntax $X+ $X- mostly like in Borland Pascal:
                                   enable/disable extended syntax
                                   (ignore function return values,
                                   operator definitions, `PChar',
                                   pointer arithmetics, ...)
    
    --borland-pascal               disable or warn about GPC features
    --extended-pascal              not supported by the standard or
    --pascal-sc                    dialect given, do not warn about its
    etc.                           "dangerous" features (especially BP).
                                   The dialect can be changed during one
                                   compilation via directives like,
                                   e.g., `{$borland-pascal}'.
    
    {$M Hello!}                    write message `Hello!' to
                                   standard error during compilation. In
                                   `--borland-pascal' mode, it is
                                   ignored it if only numbers follow
                                   (for compatibility to Borland
                                   Pascal's memory directive)
    
    {$define FOO}                  like in Borland Pascal:
    or                             define FOO (for conditional compilation)
    {$CIDefine FOO}                (case-insensitively)
    
    --cidefine=FOO                 the same on the command line
    
    {$CSDefine FOO}                define FOO case-sensitively
    
    -D FOO                         the same on the command line
    or                             Note: `--define' on the command
    --csdefine=FOO                 line is case-sensitive like in GCC,
    or                             but `{$define}' in the source code
    --define=FOO                   is case-insensitive like in BP
    
    {$define loop while True do}   define `loop' to be `while True do'
    or                             as a macro like in C. The name of the
    {$CIDefine loop ...}           macro is case-insensitive. Note:
                                   Macros are disabled in
                                   `--borland-pascal' mode because BP
                                   doesn't support macros.
    
    --cidefine="loop=..."          the same on the command line
    
    {$CSDefine loop ...}           define a case-sensitive macro
    
    --csdefine="loop=..."          the same on the command line
    or
    --define="loop=..."
    
    {$I FileName}                  like in Borland Pascal:
                                   include `filename.pas' or `filename.p'
                                   (the name is converted to lowercase)
    
    {$undef FOO}                   like in Borland Pascal: undefine FOO
    
    {$ifdef FOO}                   conditional compilation
      ...                          (like in Borland Pascal).
    {$else}                        Note: GPC predefines the symbol
      ...                          `__GPC__' (with two leading
    {$endif}                       and trailing underscores).
    
    {$include "filename.pas"}      include (case-sensitive)
    
    {$include <filename.pas>}      the same, but don't search in the
                                   current directory
    

    ...and all the other C preprocessor directives.

    You also can use C-style preprocessor directives, e.g. `#include', but this is deprecated, e.g. because of possible conflicts with Borland Pascal style `#42' character constants. Besides, in the Pascal style, e.g. `{$include "foo.bar"}', there may be more than one directive in the same line.

    Routines Built-in or in the Run Time System

    In this section we describe the routines and other declarations that are built into the compiler or part of the Run Time System, sorted by topics.

    File Routines

    Extended Pascal treats files quite differently from Borland Pascal. GPC supports both forms, even in mixed ways, and provides many extensions.

    @@ A lot missing here

    Note that Prospero's Pascal defaults to creating the file if it does not exists! You need to use Prospero's local addition of setting b.Existing to True to work-around this. GPC does not behave like this.

    String Operations

    In the following description, s1 and s2 may be arbitrary string expressions, s is a variable of string type.

    WriteStr (s, write-parameter-list)
    ReadStr (s1, read-parameter-list)
    Write to a string and read from a string. The parameter lists are identical to `Write'/`Read' from Text files. The semantics is closely modeled after file I/O.
    Index (s1, s2)
    If s2 is empty, return 1 else if s1 is empty return 0 else returns the position of s2 in s1 (an integer).
    Length (s1)
    Return the length of s1 (an integer from 0 .. s1.Capacity).
    Trim (s1)
    Returns a new string with spaces stripped of the end of s.
    SubStr (s1, i)
    SubStr (s1, i, j)
    Return a new substring of s1 that contains j characters starting from i. If j is missing, return all the characters starting from i.
    EQ (s1, s2)
    NE (s1, s2)
    LT (s1, s2)
    LE (s1, s2)
    GT (s1, s2)
    GE (s1, s2)
    Lexicographic comparisons of s1 and s2. Returns a boolean result. Strings are not padded with spaces.
    s1 = s2
    s1 <> s2
    s1 < s2
    s1 <= s2
    s1 > s2
    s1 >= s2
    Lexicographic comparisons of s1 and s2. Returns a boolean result. The shorter string is blank padded to length of the longer one, but only in `--extended-pascal' mode.

    GPC supports string catenation with the + operator or the `Concat' function. All string-types are compatible, so you may catenate any chars, fixed length strings and variable length strings.

    program ConcatDemo (Input, Output);
    
    var
      Ch   : Char;
      Str  : String (100);
      Str2 : String (50);
      FStr : packed array [1 .. 20] of Char;
    
    begin
       Ch := '$';
       FStr := 'demo';  { padded with blanks }
       Write ('Give me some chars to play with: ');
       Readln (Str);
       Str := '^' + 'prefix:' + Str + ':suffix:' + FStr + Ch;
       Writeln (Concat ('Le', 'ng', 'th'), ' = ', Length (Str));
       Writeln (Str)
    end.
    

    Note: The length of strings in GPC is limited only by the range of `Integer' (at least 32 bits, i.e., 2 GB), or the available memory, whichever is smaller. :-)

    When trying to write programs portable to other EP compilers, it is however save to assume a limit of about 32 KB. At least Prospero's Extended Pascal compiler limits strings to 32760 bytes. DEC Pascal limits strings to 65535 bytes.

    Accessing Command Line Arguments

    GPC supports access to the command line arguments with the BP compatible ParamStr and ParamCount functions.

    The program below accesses the command line arguments.

    program CommandLineArgumentsDemo (Output);
    
    var
      Counter : Integer;
    
    begin
      Writeln ('This program displays command line arguments one per line.');
      for Counter := 0 to ParamCount do
        Writeln ('Command line arg ', Counter, ' is `', ParamStr (Counter), "")
    end.
    

    Memory Management Routines

    Besides the standard `New' and `Dispose' routines, GPC also allows BP style dynamic memory management with GetMem and FreeMem:

      GetMem (MyPtr, 1024);
      FreeMem (MyPtr, 1024);
    

    GPC also supports function style call to GetMem:

      MyPtr := GetMem (1024);
    

    (see also: New in context of Object Orientated Programming)

    One somehow strange feature of Borland is not supported: You cannot free parts of a variable with FreeMem, while the rest is still used and can be free later by another FreeMem call:

    type
      Vector = array [0 .. 1023] of Integer;
      VecPtr = ^Vector;
    
    var
      p, q : VecPtr;
    
      ...
     
      GetMem (p, 1024 * SizeOf (Integer));
      q := @p^[512];
      ...
      FreeMem (p, 512 * SizeOf (Integer));
      ...
      FreeMem (q, 512 * SizeOf (Integer));
    

    Operations for Integer and Ordinal Types

    Complex Number Operations

    @@ A lot missing here

    The following sample programs illustrates most of the Complex type operations.

    program ComplexDemo (Output);
    
    var
      z1, z2 : Complex;
      Len, Angle : Real;
    
    begin
      z1 := Cmplx (2, 1);
      Writeln;
      Writeln ('Complex number z1 is: (', Re (z1) : 1, ',', Im (z1) : 1, ')');
      Writeln;
      z2 := Conjugate(z1); { GPC extension }
      Writeln ('Conjugate of z1 is: (', Re (z2) : 1, ',', Im (z2) : 1, ')');
      Writeln;
      Len   := Abs (z1);
      Angle := Arg (z1);
      Writeln ('The polar representation of z1 is: Length=', Len : 1,
               ', Angle=', Angle : 1);
      Writeln;
      z2 := Polar (Len, Angle);
      Writeln ('Converting (Length, Angle) back to (x, y) gives: (',
               Re (z2) : 1, ',', Im (z2) : 1, ')');
      Writeln;
      Writeln ('The following operations operate on the complex number z1');
      Writeln;
      z2 := ArcTan (z1);
      Writeln ('arctan (z1) = (', Re (z2), ', ', Im (z2), ')');
      Writeln;
      z2 := z1 ** 3.141;
      Writeln ('z1 ** 3.141 =', Re (z2), ', ', Im (z2), ')');
      Writeln;
      z2 := Sin (z1);
      Writeln ('sin (z1) = (', Re (z2), ', ', Im (z2), ')');
      Writeln ('(cos, ln, exp, sqrt and sqr exist also.)');
      Writeln;
      z2 := z1 pow 8;
      Writeln ('z1 pow 8 = (', Re (z2), ', ', Im (z2), ')');
      Writeln;
      z2 := z1 pow (-8);
      Writeln ('z1 pow (-8) = (', Re (z2), ', ', Im (z2), ')');
    end.
    

    Set Operations

    @@ A lot missing here

    GPC supports Standard Pascal set operations. In addition it supports the Extended Pascal set operation symmetric difference

    (set1 >< set2) operation whose result consists of those elements which are in exactly one of the operannds.

    It also has a function that counts the elements in the set: `a := Card (set1)'.

    Date And Time Routines

    procedure GetTimeStamp (var t : TimeStamp);
    function Date (t : TimeStamp) : packed array [1 .. DateLength] of Char;
    function Time (t : TimeStamp) : packed array [1 .. TimeLength] of Char;

    DateLength and TimeLength are implementation dependent constants.

    GetTimeStamp (t) fills the record `t' with values. If they are valid, the Boolean flags are set to True.

    TimeStamp is a predefined type in the Extended Pascal standard. It may be extended in an implementation, and is indeed extended in GPC. For the full definition of `TimeStamp', see section TimeStamp.

    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 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:

    File `callc.c':
    
    #include <unistd.h>
    #include "callc.h"
    
    int foo = 1;
    
    void bar (void)
    {
      sleep (foo);
    }
    
    File `callc.h':
    
    /* Actually, we wouldn't need this header file, and could instead
       put these prototypes into callc.c, unless we want to use callc.c
       also from other C source files. */
    
    extern int foo;
    extern void bar (void);
    

    Then your program can look like this:

    program CallCDemo;
    
    {$L callc.c}  { Or: `callc.o' if you don't have the source }
    
    var
      foo : Integer; asmname 'foo'; external;
    
    procedure Bar; asmname 'bar';
    
    begin
      foo := 42;
      Bar
    end.
    

    Or, if you want to provide a `CallCUnit' unit:

    unit CallCUnit;
    
    interface
    
    var
      foo : Integer; asmname 'foo'; external;
    
    procedure Bar; asmname 'bar';
    
    implementation
    
    {$L callc.c}  { Or: `callc.o' if you don't have the source }
    
    end.
    
    program CallCUDemo;
    
    uses CallCUnit;
    
    begin
      foo := 42;
      Bar
    end.
    

    You can either link your program manually with `callc.o' or put a compiler directive `{$L callc.o}' into your program or unit, and then GPC takes care of correct linking. If you have the source of the C library (you always have it if it is Free Software), you can even write `{$L callc.c}' in the program (like above). Then GPC will also link with `callc.o', but in addition GPC will run the C compiler whenever `callc.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.

    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:

    Notes for debugging

    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 a `units' subdirectory of the directory containing `libgcc.a'. (To find out the correct directory for your installation, type `gpc --print-file-name=units' on the command line.)

    {
    Pascal declarations of the GPC RTS that are visible to each program.
    
    This unit contains Pascal declarations of many RTS routines which
    are not built into the compiler and can be called from programs.
    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 may 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.
    
    Copyright (C) 1998-2000 Free Software Foundation, Inc.
    
    Author: Frank Heckenbach <frank@pascal.gnu.de>
    
    This file is part of GNU Pascal.
    
    GNU Pascal is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    
    GNU Pascal 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 General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with GNU Pascal; see the file COPYING.  If not, write to the
    Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.
    
    As a special exception, if you link this file with files compiled
    with a GNU compiler to produce an executable, this does not cause
    the resulting executable to be covered by the GNU General Public
    License. This exception does not however invalidate any other
    reasons why the executable file might be covered by the GNU General
    Public License.
    }
    
    {$gnu-pascal}
    
    module GPC interface;
    
    export
      GPC = all;
      GPC_SP = (eread (*@@not really, but an empty export doesn't
      work*));
      GPC_EP = (eread (*@@not really, but an empty export doesn't
      work*));
      GPC_BP = (MaxLongInt, ExitCode, ErrorAddr, Pos);
      GPC_Delphi = (MaxLongInt, Int64, ExitCode, ErrorAddr, Pos,
                    SetString, StringOfChar, TextFile, AssignFile,
                    CloseFile);
    
    const
      MaxLongInt = High (LongInt);
    
      { Maximum size of a variable }
      MaxVarSize = MaxInt;
    
    type
      Int64 = Integer (64);
    
    { ====================== MEMORY MANAGEMENT ======================= }
    
    { 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. }
    
    { C heap management routines. NOTE: if Release is used anywhere in
      the program, CFreeMem and CReAllocMem may not be used for pointers
      that were not allocated with CGetMem. }
    function  CGetMem     (Size : SizeType) : Pointer; asmname 'malloc';
    procedure CFreeMem    (aPointer : Pointer); asmname 'free';
    function  CReAllocMem (aPointer : Pointer; NewSize : SizeType) :
      Pointer; asmname 'realloc';
    
    type
      GetMemType     = ^function (Size : SizeType) : Pointer;
      FreeMemType    = ^procedure (aPointer : Pointer);
      ReAllocMemType = ^function (aPointer : Pointer; NewSize :
      SizeType) : Pointer;
    
    { These variables can be set to user-defined routines for memory
      allocation/deallocation. GetMemPtr may return nil when
      insufficient memory is available. GetMem/New will produce a
      runtime error then. }
    var
      GetMemPtr     : GetMemType; asmname '_p_getmem_ptr'; external;
      FreeMemPtr    : FreeMemType; asmname '_p_freemem_ptr'; external;
      ReAllocMemPtr : ReAllocMemType; asmname '_p_reallocmem_ptr';
      external;
    
      { Points to the lowest byte of heap used }
      HeapBegin : Pointer; asmname '_p_heap_begin'; external;
    
      { Points to the highest byte of heap used }
      HeapHigh  : Pointer; asmname '_p_heap_high'; external;
    
    const
      UndocumentedReturnNil = Pointer (- 1);
    
    procedure ReAllocMem (var aPointer : Pointer; NewSize : SizeType);
      asmname '_p_reallocmem';
    
    { Returns the number of pointers that would be released. aPointer
      must
      have been marked with Mark. For an example of its usage, see the
      HeapMon unit. }
    function  ReleaseCount (aPointer : Pointer) : Integer;
      asmname '_p_releasecount';
    
    { Routines to handle endianness, from endian.pas }
    
    { Boolean constants about endianness and alignment }
    
    const
      BitsBigEndian  = {$ifdef __BITS_LITTLE_ENDIAN__} False
                       {$else}{$ifdef __BITS_BIG_ENDIAN__} True
                       {$else}{$error Bit endianness is not defined!}
                       {$endif}{$endif};
    
      BytesBigEndian = {$ifdef __BYTES_LITTLE_ENDIAN__} False
                       {$else}{$ifdef __BYTES_BIG_ENDIAN__} True
                       {$else}{$error Byte endianness is not defined!}
                       {$endif}{$endif};
    
      WordsBigEndian = {$ifdef __WORDS_LITTLE_ENDIAN__} False
                       {$else}{$ifdef __WORDS_BIG_ENDIAN__} True
                       {$else}{$error Word endianness is not defined!}
                       {$endif}{$endif};
    
      NeedAlignment  = {$ifdef __NEED_ALIGNMENT__} True
                       {$else} False {$endif};
    
    { Convert single variables from or to little or big endian format.
      This only works for a single variable or a plain array of a simple
      type. For more complicated structures, 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. Therefore, we provide different names. }
    procedure ReverseBytes            (var Buf; ElementSize, Count :
      SizeType); asmname '_p_reversebytes';
    procedure ConvertFromLittleEndian (var Buf; ElementSize, Count :
      SizeType); asmname '_p_convertlittleendian';
    procedure ConvertFromBigEndian    (var Buf; ElementSize, Count :
      SizeType); asmname '_p_convertbigendian';
    procedure ConvertToLittleEndian   (var Buf; ElementSize, Count :
      SizeType); asmname '_p_convertlittleendian';
    procedure ConvertToBigEndian      (var Buf; ElementSize, Count :
      SizeType); asmname '_p_convertbigendian';
    
    { Read a block from a file and convert it from little or
      big endian format. This only works for a single variable or a
      plain array of a simple type, note the comment for
      `ConvertFromLittleEndian' and `ConvertFromBigEndian'. }
    (*@@iocritical*)procedure BlockReadLittleEndian   (var aFile : File;
      var   Buf; ElementSize, Count : SizeType);
      asmname '_p_blockread_littleendian';
    (*@@iocritical*)procedure BlockReadBigEndian      (var aFile : File;
      var   Buf; ElementSize, Count : SizeType);
      asmname '_p_blockread_bigendian';
    
    { Write a block variable to a file and convert it to little or big
      endian format before. This only works for a single variable or a
      plain array of a simple type. Apart from this, note the comment
      for `ConvertToLittleEndian' and `ConvertToBigEndian'. }
    (*@@iocritical*)procedure BlockWriteLittleEndian  (var aFile : File;
      const Buf; ElementSize, Count : SizeType);
      asmname '_p_blockwrite_littleendian';
    (*@@iocritical*)procedure BlockWriteBigEndian     (var aFile : File;
      const Buf; ElementSize, Count : SizeType);
      asmname '_p_blockwrite_bigendian';
    
    { Read and write strings from/to binary files, where the length is
      stored in the given endianness and with a fixed size (64 bits),
      and therefore is independent of the system. }
    (*@@iocritical*)procedure ReadStringLittleEndian  (var f : File; var
      s : String); asmname '_p_ReadStringLittleEndian';
    (*@@iocritical*)procedure ReadStringBigEndian     (var f : File; var
      s : String); asmname '_p_ReadStringBigEndian';
    (*@@iocritical*)procedure WriteStringLittleEndian (var f : File;
      const s : String); asmname '_p_WriteStringLittleEndian';
    (*@@iocritical*)procedure WriteStringBigEndian    (var f : File;
      const s : String); asmname '_p_WriteStringBigEndian';
    
    { =================== STRING HANDLING ROUTINES =================== }
    
    { String handling routines, from string.pas }
    
    type
      AnyFile = Text; (*@@ create `AnyFile' parameters*)
      PAnyFile = ^AnyFile;
    
    { 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. It should be at least as big as MAXPATHLEN. }
    
    const
      TStringSize = 2048;
      SpaceCharacters = [' ', #9];
      NewLine = "\n"; { the separator of lines within a string }
      LineBreak = {$ifdef __OS_DOS__} "\r\n" {$else} "\n" {$endif};
      { the separator of lines within a file }
    
    type
      TString    = String (TStringSize);
      TStringBuf = packed array [0 .. TStringSize] of Char;
      PString    = ^String;
      CharSet    = set of Char;
      PCStrings  = ^TCStrings;
      TCStrings  = array [0 .. MaxVarSize div SizeOf (CString)] of
      CString;
    
    var
      CParamCount : Integer; asmname '_p_argc'; external;
      CParameters : PCStrings; asmname '_p_argv'; external;
    
    function  MemCmp      (const s1, s2; Size : SizeType) : Integer;
      asmname 'memcmp';
    function  MemComp     (const s1, s2; Size : SizeType) : Integer;
      asmname 'memcmp';
    function  MemCompCase (const s1, s2; Size : SizeType) : Boolean;
      asmname '_p_memcmpcase';
    
    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;                    
      attribute (const); asmname '_p_isupcase';
    function  IsLoCase        (ch : Char) : Boolean;                    
      attribute (const); asmname '_p_islocase';
    function  IsAlphaNum      (ch : Char) : Boolean;                    
      attribute (const); asmname '_p_isalphanum';
    function  IsAlphaNumUnderscore (ch : Char) : Boolean;               
      attribute (const); asmname '_p_isalphanumunderscore';
    function  IsPrintable     (ch : Char) : Boolean;                    
      attribute (const); asmname '_p_isprintable';
    
    function  StrEqualCase    (const s1, s2 : String) : Boolean;
      asmname '_p_strequalcase';
    
    function  Pos             (const SubString, aString : String) :
      Integer; asmname '_p_pos';
    function  LastPos         (const SubString, aString : String) :
      Integer; asmname '_p_lastpos';
    function  PosCase         (const SubString, aString : String) :
      Integer; asmname '_p_poscase';
    function  LastPosCase     (const SubString, aString : String) :
      Integer; asmname '_p_lastposcase';
    function  CharPos         (const Chars : CharSet; const aString :
      String) : Integer; asmname '_p_charpos';
    function  LastCharPos     (const Chars : CharSet; const aString :
      String) : Integer; asmname '_p_lastcharpos';
    
    function  PosFrom         (const SubString, aString : String; From :
      Integer) : Integer; asmname '_p_posfrom';
    function  LastPosTill     (const SubString, aString : String; Till :
      Integer) : Integer; asmname '_p_lastpostill';
    function  PosFromCase     (const SubString, aString : String; From :
      Integer) : Integer; asmname '_p_posfromcase';
    function  LastPosTillCase (const SubString, aString : String; Till :
      Integer) : Integer; asmname '_p_lastpostillcase';
    function  CharPosFrom     (const Chars : CharSet; const aString :
      String; From : Integer) : Integer; asmname '_p_charposfrom';
    function  LastCharPosTill (const Chars : CharSet; const aString :
      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  IsPrefixCase    (const Prefix, s : String) : Boolean;
      asmname '_p_isprefixcase';
    function  IsSuffixCase    (const Suffix, s : String) : Boolean;
      asmname '_p_issuffixcase';
    
    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         (aString, SubString : CString) :
      CString; asmname '_p_strpos';
    function  CStringLastPos     (aString, SubString : CString) :
      CString; asmname '_p_strrpos';
    function  CStringCasePos     (aString, SubString : CString) :
      CString; asmname '_p_strcasepos';
    function  CStringLastCasePos (aString, SubString : 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';
    
    function  GetStringCapacity (const s : String) : Integer;
      asmname '_p_get_string_capacity';
    
    { A short cut for a common use of WriteStr as a function }
    function  Integer2String (i : Integer) : TString;
      asmname '_p_Integer2String';
    
    type
      TChars = packed array [1 .. 1] of Char;
      PChars = ^TChars;
    
      { Under development. Interface subject to change. Use with
      caution. }
      { 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;
    
      { Capacity is the allocated space (used internally). Count is the
        actual number of environment strings. The CStrings array
        contains the environment strings, terminated by a nil pointer,
        which is not counted in Count. @CStrings can be passed to libc
        routines like execve which expect an environment (see
        GetCEnvironment). }
      PEnvironment = ^TEnvironment;
      TEnvironment (Capacity : Integer) = record
        Count : Integer;
        CStrings : array [1 .. Capacity + 1] of CString
      end;
    
    var
      Environment : PEnvironment; asmname '_p_environment'; external;
    
    { 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 CStringGetEnv returns nil then. Note,
      Dos doesn't know empty environment variables, but treats them as
      non-existing, and does not distinguish case in the names of
      environment variables. However, even under Dos, empty environment
      variables and variable names with different case can now be set
      and used within GPC programs. }
    function  GetEnv (const EnvVar : String) : TString;
      asmname '_p_getenv';
    function  CStringGetEnv (EnvVar : CString) : CString;
      asmname '_p_cstringgetenv';
    
    { Sets an environment variable with the name given in VarName to the
      value
      Value. A previous value, if any, is overwritten. }
    procedure SetEnv (const VarName, Value : String);
      asmname '_p_setenv';
    
    { Un-sets an environment variable with the name given in VarName. }
    procedure UnSetEnv (const VarName : String); asmname '_p_unsetenv';
    
    { Returns @Environment^.CStrings, converted to PCStrings, to be
      passed to
      libc routines like execve which expect an environment. }
    function  GetCEnvironment : PCStrings; asmname '_p_getcenvironment';
    
    { ================= RUNTIME ERROR HANDLING ETC. ================== }
    
    { Error handling functions, from error.pas }
    
    const
      ERead = 413;
      EWrite = 414;
      EWriteReadOnly = 422;
    
    var
      { Error number (after runtime error) or exit status (after Halt)
      or
        0 (during program run and after succesful termination). }
      ExitCode : Integer; asmname '_p_exitcode'; external;
    
      { Contains the address of the code where a runtime occurred, nil
        if no runtime error occurred. }
      ErrorAddr : Pointer; asmname '_p_erroraddr'; external;
    
      { Error message }
      ErrorMessageString : TString; asmname '_p_errormessagestring';
      external;
    
    function  GetErrorMessage                 (n : Integer) : CString;
      asmname '_p_errmsg';
    procedure RuntimeError                    (n : Integer);            
      attribute (noreturn); asmname '_p_error';
    procedure RuntimeErrorInteger             (n : Integer; i : MedInt);
      attribute (noreturn); asmname '_p_error_integer';
    procedure RuntimeErrorCString             (n : Integer; s :
      CString);                attribute (noreturn);
      asmname '_p_error_string';
    procedure InternalError                   (n : Integer);            
      attribute (noreturn); asmname '_p_internal_error';
    procedure InternalErrorInteger            (n : Integer; i : MedInt);
      attribute (noreturn); 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';
    procedure DebugStatement                  (const FileName : String;
      Line : Integer); asmname '_p_debug_statement';
    
    (*iocritical*)procedure IOError                         (n :
      Integer); asmname '_p_io_error';
    (*iocritical*)procedure IOErrorInteger                  (n :
      Integer; i : MedInt); asmname '_p_io_error_integer';
    (*iocritical*)procedure IOErrorCString                  (n :
      Integer; s : CString); asmname '_p_io_error_string';
    (*iocritical*)procedure IOErrorFile                     (n :
      Integer; protected var f : AnyFile); asmname '_p_io_error_file';
    function  GetIOErrorMessage : CString;
      asmname '_p_get_io_error_message';
    procedure CheckInOutRes; asmname '_p_check_inoutres';
    
    { Registers a procedure to be called to restore the terminal for
      another process that accesses the terminal, or back for the
      program itself. Used e.g. by the CRT unit. The procedures must
      allow for being called multiple times in any order, even at the
      end of the program (see the comment for RestoreTerminal). }
    procedure RegisterRestoreTerminal (ForAnotherProcess : Boolean;
      procedure Proc); asmname '_p_RegisterRestoreTerminal';
    
    { Unregisters a procedure registered with RegisterRestoreTerminal.
      Returns False if the procedure had not been registered, and True
      if it had been registered and was unregistered successfully. }
    function UnregisterRestoreTerminal (ForAnotherProcess : Boolean;
      procedure Proc) : Boolean; asmname '_p_UnregisterRestoreTerminal';
    
    { Calls the procedures registered by RegisterRestoreTerminal. When
      restoring the terminal for another process, the procedures are
      called in the opposite order of registration. When restoring back
      for the program, they are called in the order of registration.
    
      `RestoreTerminal (True)' will also be called at the end of the
      program, before outputting any runtime error message. It can also
      be used if you want to write an error message and exit the program
      (especially when using e.g. the CRT unit). For this purpose, to
      avoid side effects, call RestoreTerminal immediately before
      writing the error message (to StdErr, not to Output!), and then
      exit the program (e.g. with Halt). }
    procedure RestoreTerminal (ForAnotherProcess : Boolean);
      asmname '_p_RestoreTerminal';
    
    { Executes a command line. Reports execution errors via the IOResult
      mechanism and returns the exit status of the executed program.
      Execute calls RestoreTerminal with the argument True before and
      False after executing the process, ExecuteNoTerminal does not. }
    (*@@IO critical*)function  Execute (const CmdLine : String) :
      Integer; asmname '_p_execute';
    (*@@IO critical*)function  ExecuteNoTerminal (const CmdLine :
      String) : Integer; asmname '_p_executenoterminal';
    
    procedure AtExit (procedure Proc); asmname '_p_atexit';
    
    procedure SetReturnAddress (Address : Pointer);
      asmname '_p_SetReturnAddress';
    procedure RestoreReturnAddress; asmname '_p_RestoreReturnAddress';
    
    { ==================== SIGNALS AND PROCESSES ===================== }
    
    function ProcessID : Integer; asmname '_p_pid';
    
    { Extract information from the status returned by PWait }
    function StatusExited     (Status : Integer) : Boolean; attribute
      (const); asmname '_p_WIfExited';
    function StatusExitCode   (Status : Integer) : Integer; attribute
      (const); asmname '_p_WExitStatus';
    function StatusSignaled   (Status : Integer) : Boolean; attribute
      (const); asmname '_p_WIfSignaled';
    function StatusTermSignal (Status : Integer) : Integer; attribute
      (const); asmname '_p_WTermSig';
    function StatusStopped    (Status : Integer) : Boolean; attribute
      (const); asmname '_p_WIfStopped';
    function StatusStopSignal (Status : Integer) : Integer; attribute
      (const); asmname '_p_WStopSig';
    
    type
      TSignalHandler = procedure (Signal : Integer);
    
    { OldHandler and OldRestart may be null }
    function InstallSignalHandler (Signal : Integer; Handler :
      TSignalHandler;
                                   Restart, UnlessIgnored : Boolean;
                                   var OldHandler : TSignalHandler; var
      OldRestart : Boolean) : Boolean; asmname '_p_sigaction';
    
    var
      { Signal actions }
      SignalDefault : TSignalHandler; asmname '_p_SIG_DFL'; external;
      SignalIgnore  : TSignalHandler; asmname '_p_SIG_IGN'; external;
      SignalError   : TSignalHandler; asmname '_p_SIG_ERR'; external;
    
      { Signals. The constants are set to the signal numbers, and
        are 0 for signals not defined. }
      { POSIX signals }
      SigHUp    : Integer; asmname '_p_SIGHUP'; external;
      SigInt    : Integer; asmname '_p_SIGINT'; external;
      SigQuit   : Integer; asmname '_p_SIGQUIT'; external;
      SigIll    : Integer; asmname '_p_SIGILL'; external;
      SigAbrt   : Integer; asmname '_p_SIGABRT'; external;
      SigFPE    : Integer; asmname '_p_SIGFPE'; external;
      SigKill   : Integer; asmname '_p_SIGKILL'; external;
      SigSegV   : Integer; asmname '_p_SIGSEGV'; external;
      SigPipe   : Integer; asmname '_p_SIGPIPE'; external;
      SigAlrm   : Integer; asmname '_p_SIGALRM'; external;
      SigTerm   : Integer; asmname '_p_SIGTERM'; external;
      SigUsr1   : Integer; asmname '_p_SIGUSR1'; external;
      SigUsr2   : Integer; asmname '_p_SIGUSR2'; external;
      SigChld   : Integer; asmname '_p_SIGCHLD'; external;
      SigCont   : Integer; asmname '_p_SIGCONT'; external;
      SigStop   : Integer; asmname '_p_SIGSTOP'; external;
      SigTStp   : Integer; asmname '_p_SIGTSTP'; external;
      SigTTIn   : Integer; asmname '_p_SIGTTIN'; external;
      SigTTOu   : Integer; asmname '_p_SIGTTOU'; external;
    
      { Non-POSIX signals }
      SigTrap   : Integer; asmname '_p_SIGTRAP'; external;
      SigIOT    : Integer; asmname '_p_SIGIOT'; external;
      SigEMT    : Integer; asmname '_p_SIGEMT'; external;
      SigBus    : Integer; asmname '_p_SIGBUS'; external;
      SigSys    : Integer; asmname '_p_SIGSYS'; external;
      SigStkFlt : Integer; asmname '_p_SIGSTKFLT'; external;
      SigUrg    : Integer; asmname '_p_SIGURG'; external;
      SigIO     : Integer; asmname '_p_SIGIO'; external;
      SigPoll   : Integer; asmname '_p_SIGPOLL'; external;
      SigXCPU   : Integer; asmname '_p_SIGXCPU'; external;
      SigXFSz   : Integer; asmname '_p_SIGXFSZ'; external;
      SigVTAlrm : Integer; asmname '_p_SIGVTALRM'; external;
      SigProf   : Integer; asmname '_p_SIGPROF'; external;
      SigPwr    : Integer; asmname '_p_SIGPWR'; external;
      SigInfo   : Integer; asmname '_p_SIGINFO'; external;
      SigLost   : Integer; asmname '_p_SIGLOST'; external;
      SigWinCh  : Integer; asmname '_p_SIGWINCH'; external;
    
      { Signal subcodes (only used on some systems, -1 if not used) }
      IllReservedAddress        : Integer; asmname '_p_ILL_RESAD_FAULT';
      external;
      IllPriviledgedInstruction : Integer;
      asmname '_p_ILL_PRIVIN_FAULT'; external;
      IllReservedOp             : Integer; asmname '_p_ILL_RESOP_FAULT';
      external;
      FPEIntegerOverflow        : Integer; asmname '_p_FPE_INTOVF_TRAP';
      external;
      FPEIntegerDivisionByZero  : Integer; asmname '_p_FPE_INTDIV_TRAP';
      external;
      FPESubscriptRange         : Integer; asmname '_p_FPE_SUBRNG_TRAP';
      external;
      FPERealOverflow           : Integer; asmname '_p_FPE_FLTOVF_TRAP';
      external;
      FPERealDivisionByZero     : Integer; asmname '_p_FPE_FLTDIV_TRAP';
      external;
      FPERealUnderflow          : Integer; asmname '_p_FPE_FLTUND_TRAP';
      external;
      FPEDecimalOverflow        : Integer; asmname '_p_FPE_DECOVF_TRAP';
      external;
    
    { Returns a description for a signal }
    function StrSignal (Signal : Integer) : TString;
      asmname '_p_strsignal';
    
    { Sends a signal to a process. Returns True if successful. If Signal
      is 0, it doesn't send a signal, but still checks whether it would
      be possible to send a signal to the given process. }
    function Kill (PID, Signal : Integer) : Boolean; asmname '_p_kill';
    
    const
      AnyChild = - 1;
    
    { Waits for a child process with the given PID (or any child process
      if PID = AnyChild) to terminate or be stopped. Returns the PID of
      the process. WStatus will contain the status and can be evaluated
      with StatusExited etc.. If nothing happened, and Block is False,
      the function will return 0, and WStatus will be 0. If an error
      occurred (especially on single tasking systems where WaitPID is
      not possible), the function will return a negative value, and
      WStatus will be 0. }
    function WaitPID (PID : Integer; var WStatus : Integer; Block :
      Boolean) : Integer; asmname '_p_waitpid';
    
    { Sets the process group of Process (or the current one if Process
      is 0) to ProcessGroup (or its PID if ProcessGroup is 0). Returns
      True if successful. }
    function SetProcessGroup (Process, ProcessGroup : Integer) :
      Boolean; asmname '_p_setpgid';
    
    { Sets the process group of a terminal given by Terminal (as a file
      handle) to ProcessGroup. ProcessGroup must be the ID of a process
      group in the same session. Returns True if successful. }
    function SetTerminalProcessGroup (Terminal, ProcessGroup :
      Integer) : Boolean; asmname '_p_tcsetpgrp';
    
    { Returns the process group of a terminal given by Terminal (as a
      file handle), or -1 on error. }
    function GetTerminalProcessGroup (Terminal : Integer) : Integer;
      asmname '_p_tcgetpgrp';
    
    { ================= COMMAND LINE OPTION PARSING ================== }
    
    const
      EndOfOptions      = #255;
      NoOption          = #1;
      UnknownOption     = '?';
      LongOption        = #0;
      UnknownLongOption = '?';
    
    var
      FirstNonOption         : Integer; asmname '_p_first_non_option';
      external;
      HasOptionArgument      : Boolean;
      asmname '_p_has_option_argument'; external;
      OptionArgument         : TString; asmname '_p_option_argument';
      external;
      UnknownOptionCharacter : Char;
      asmname '_p_unknown_option_character'; external;
      GetOptErrorFlag        : Boolean; asmname '_p_getopt_error_flag';
      external;
    
    {
      Parses command line arguments for options and returns the next
      one.
    
      If a command line argument starts with `-', and is not exactly `-'
      or `--', then it is an option element.  The characters of this
      element (aside from the initial `-') are option characters.  If
      `GetOpt' is called repeatedly, it returns successively each of the
      option characters from each of the option elements.
    
      If `GetOpt' finds another option character, it returns that
      character, updating `FirstNonOption' and internal variables so
      that the next call to `GetOpt' can resume the scan with the
      following option character or command line argument.
    
      If there are no more option characters, `GetOpt' returns
      EndOfOptions. Then `FirstNonOption' is the index of the first
      command line argument that is not an option. (The command line
      arguments have been permuted so that those that are not options
      now come last.)
    
      OptString must be of the form `[+|-]abcd:e:f:g::h::i::'.
    
      a, b, c are options without arguments
      d, e, f are options with required arguments
      g, h, i are options with optional arguments
    
      Arguments are text following the option character in the same
      command line argument, or the text of the following command line
      argument. They are returned in OptionArgument. If an option has no
      argument, OptionArgument is empty. The variable HasOptionArgument
      tells whether an option has an argument. This is mostly useful for
      options with optional arguments, if one wants to distinguish an
      empty argument from no argument.
    
      If the first character of OptString is `+', GetOpt stops at the
      first non-option argument.
    
      If it is `-', GetOpt treats non-option arguments as options and
      return NoOption for them.
    
      Otherwise, GetOpt permutes arguments and handles all options,
      leaving all non-options at the end. However, if the environment
      variable POSIXLY_CORRECT is set, the default behaviour is to stop
      at the first non-option argument, as with `+'.
    
      The special argument `--' forces an end of option-scanning
      regardless of the first character of OptString. In the case of
      `-', only `--' can cause GetOpt to return EndOfOptions with
      FirstNonOption <= ParamCount.
    
      If an option character is seen that is not listed in OptString,
      UnknownOption is returned. The unrecognized option character is
      stored in UnknownOptionCharacter. If you set GetOptErrorFlag to
      True, an error message is printed to StdErr automatically.
    }
    function GetOpt (OptString : CString) : Char; asmname '_p_getopt';
    
    type
      OptArgType = (NoArgument, RequiredArgument, OptionalArgument);
    
      OptionType = record
        Name     : CString;
        Argument : OptArgType;
        Flag     : ^Char;      { If nil, V is returned. Otherwise, Flag^
      is }
        V        : Char        { set to V, and Ord (LongOption) is
      returned. }
      end;
    
    {
      Recognize short options, described by OptString as above, and long
      options, described by LongOptions.
    
      Long-named options begin with `--' instead of `-'. Their names may
      be
      abbreviated as long as the abbreviation is unique or is an exact
      match
      for some defined option. If they have an argument, it follows the
      option name in the same argument, separated from the option name
      by
      a `=', or else the in next argument. When GetOpt finds a
      long-named
      option, it returns LongOption if that option's `Flag' field is
      non-nil,
      and the value of the option's `V' field if the `Flag' field is
      nil.
    
      LongIndex, if not null, returns the index in LongOptions of the
      long-named option found. It is only valid when a long-named option
      has
      been found by the most recent call.
    
      If LongOnly is set, `-' as well as `--' can indicate a long
      option.
      If an option that starts with `-' (not `--') doesn't match a long
      option,
      but does match a short option, it is parsed as a short option
      instead.
      If an argument has the form `-f', where f is a valid short option,
      don't
      consider it an abbreviated form of a long option that starts with
      `f'.
      Otherwise there would be no way to give the `-f' short option. On
      the
      other hand, if there's a long option `fubar' and the argument is
      `-fu',
      do consider that an abbreviation of the long option, just like
      `--fu',
      and not `-f' with argument `u'. This distinction seems to be the
      most
      useful approach.
    }
    function GetOptLong (OptString : CString; var LongOptions : array [m
      .. n : Integer] of OptionType { can be null };
                         var LongIndex : Integer { can be null };
      LongOnly : Boolean) : Char; asmname '_p_getopt_long';
    
    { =========================== PEXECUTE =========================== }
    
    const
      PExecute_First   = 1;
      PExecute_Last    = 2;
      PExecute_One     = PExecute_First or PExecute_Last;
      PExecute_Search  = 4;
      PExecute_Verbose = 8;
    
    {
      PExecute: execute a program.
    
      Program and Arguments are the arguments to execv/execvp.
    
      Flags and PExecute_Search is non-zero if $PATH should be searched
      (It's not clear that GCC passes this flag correctly). Flags and
      PExecute_First is nonzero for the first process in chain. Flags
      and PExecute_Last is nonzero for the last process in chain.
    
      The result is the pid on systems like Unix where we fork/exec and
      on systems like MS-Windows and OS2 where we use spawn. It is up to
      the caller to wait for the child.
    
      The result is the exit code on systems like MSDOS where we spawn
      and wait for the child here.
    
      Upon failure, ErrMsg is set to the text of the error message,
      and -1 is returned. `errno' is available to the caller to use.
    
      PWait: cover function for wait.
    
      PID is the process id of the task to wait for. Status is the
      `status' argument to wait. Flags is currently unused (allows
      future enhancement without breaking upward compatibility). Pass 0
      for now.
    
      The result is the process ID of the child reaped, or -1 for
      failure.
    
      On systems that don't support waiting for a particular child, PID
      is ignored. On systems like MSDOS that don't really multitask
      PWait is just a mechanism to provide a consistent interface for
      the caller.
    }
    function PExecute (ProgramName : CString; Arguments : PCStrings; var
      ErrMsg : String; Flags : Integer) : Integer;
      asmname '_p_pexecute';
    function PWait (PID : Integer; var Status : Integer; Flags :
      Integer) : Integer; C;
    
    { ==================== TIME HANDLING ROUTINES ==================== }
    
    { Time and date routines for Extended Pascal, from time.pas }
    
    const { from types.h }
      DateLength = 11;
      TimeLength = 8;
    
    type
      UnixTimeType = LongInt; { This is hard-coded in the compiler. Do
      not change here. }
      MicroSecondTimeType = LongInt;
    
      DateString = packed array [1 .. DateLength] of Char;
      TimeString = packed array [1 .. TimeLength] of Char;
    
    var
      MonthName : array [1 .. 12] of String [9]; asmname '_p_monthname';
      external;
      MonthLength : array [1 .. 12] of Integer;
      asmname '_p_monthlength'; external;
    
    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';
    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 Sleep (Seconds : Integer); asmname '_p_sleep';
    procedure SleepMicroSeconds (MicroSeconds : Integer);
      asmname '_p_sleep_microseconds';
    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';
    
    { Get the real time. MicroSecond can be null and is ignored then. }
    function  GetUnixTime (var MicroSecond : Integer) : UnixTimeType;
      asmname '_p_get_unix_time';
    
    { Get the CPU time used. MicroSecond can be null and is ignored
      then.
      Now, GetCPUTime can measure long CPU times reliably on most
      systems
      (e.g. Solaris where it didn't work before). }
    function  GetCPUTime (var MicroSecond : Integer) : Integer;
      asmname '_p_get_cpu_time';
    
    { ==================== FILE HANDLING ROUTINES ==================== }
    
    { file routines, from files.pas }
    
    type
      FileSizeType = LongInt;
    
    { bind.c }
    
    procedure GetBinding   (protected var aFile : AnyFile; var
      aBinding : BindingType); asmname '_p_binding';
    procedure ClearBinding (var aBinding : BindingType);
      asmname '_p_clearbinding';
    
    { TFDD interface @@ Subject to change! Use with caution! }
    
    type
      TOpenMode   = (foNone, foReset, foRewrite, foAppend, foSeekRead,
      foSeekWrite, foSeekUpdate);
      TOpenProc   = procedure (var PrivateData; Mode : TOpenMode);
      TSelectFunc = function  (var PrivateData; Writing : Boolean) :
      Integer; { called before select(), must return a handle }
      TSelectProc = procedure (var PrivateData; var ReadSelect,
      WriteSelect, ExceptSelect : Boolean); { called before and after
      select() }
      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;
                          OpenProc    : TOpenProc;
                          SelectFunc  : TSelectFunc;
                          SelectProc  : TSelectProc;
                          ReadFunc    : TReadFunc;
                          WriteFunc   : TWriteFunc;
                          FlushProc   : TFlushProc;
                          CloseProc   : TCloseProc;
                          DoneProc    : TDoneProc;
                          PrivateData : Pointer);
      asmname '_p_assign_tfdd';
    
    procedure SetTFDD    (var f : AnyFile;
                          OpenProc    : TOpenProc;
                          SelectFunc  : TSelectFunc;
                          SelectProc  : TSelectProc;
                          ReadFunc    : TReadFunc;
                          WriteFunc   : TWriteFunc;
                          FlushProc   : TFlushProc;
                          CloseProc   : TCloseProc;
                          DoneProc    : TDoneProc;
                          PrivateData : Pointer); asmname '_p_set_tfdd';
    
    { Any parameter except f may be null }
    procedure GetTFDD    (var f : AnyFile;
                          var OpenProc    : TOpenProc;
                          var SelectFunc  : TSelectFunc;
                          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';
    
    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 requires some reading ahead internally (just like
      the EOF function) 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 AssignFile   (var T : AnyFile; const Name : String);
      asmname '_p_assign';
    procedure AssignBinary (var T : Text; const Name : String);
      asmname '_p_assign_binary';
    procedure AssignHandle (var T : AnyFile; Handle : Integer);
      asmname '_p_assign_handle';
    
    { BP compatible seeking routines }
    function  SeekEOF  (var f : Text) : Boolean; asmname '_p_seekeof';
    function  SeekEOLn (var f : Text) : Boolean; asmname '_p_seekeoln';
    
    { Under development }
    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';*)
    
    { 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. The somewhat confusing
      values are meant to be compatible to BP (as far as BP supports
      them). }
    const
      { Allow writing to files opened with Reset }
      FileMode_Reset_ReadWrite   = 2;
    
      { Do not allow reading from files opened with Rewrite }
      FileMode_Rewrite_WriteOnly = 4;
    
      { Do not allow reading from files opened with Extend }
      FileMode_Extend_WriteOnly  = 8;
    
    { 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
      TextFile = Text;
    
      StatFSBuffer = record
        BlockSize, BlocksTotal, BlocksFree : LongestInt;
        FilesTotal, FilesFree : Integer
      end;
    
    procedure CloseFile    (          var aFile : (*@@Any*)File);
      asmname '_p_close';
    (*@@IO critical*) procedure ChMod        (          var aFile :
      AnyFile; Mode : Integer); asmname '_p_chmod';
    (*@@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';
    
    { Get the file handle. }
    function  FileHandle   (protected var aFile : AnyFile) : Integer;
      asmname '_p_filehandle';
    
    { The following routine is meant *only* as a work-around for a
      problem under IRIX where writing reals with Write/Writeln/WriteStr
      does not work. This function will disappear after the problem has
      been solved. Width and Prec are the formatting parameters
      specified after `:'s in Write. If not wanted, NoWidth and
      NoPrecision can be passed. }
    const
      NoWidth = Low (Integer);
      NoPrecision = Low (Integer);
    function LongReal2Str (Num : LongReal; Width, Prec : Integer) :
      TString; asmname '_p_longreal2str';
    
    { 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 (see GetShellPath)
    
      ShellExecCommand:  the option to the (default) shell to execute
                         the command specified in the following argument
                         (see GetShellPath)
    
      ConfigFileMask:    a mask for the option file name as returned by
                         ConfigFileName
    
      FileNamesCaseSensitive:
                         flag to indicate whether file names are case
                         sensitive
    }
    
    const
      UnixShellEnvVar        = 'SHELL';
      UnixShellExecCommand   = '-c';
    
    {$ifdef __OS_DOS__}
    
    const
      OSDosFlag              = True;
      QuotingCharacter       = #0;
      PathSeparator          = {$ifdef __CYGWIN32__} ':' {$else} ';'
      {$endif};
      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            = UnixShellEnvVar;
      ShellExecCommand       = UnixShellExecCommand;
      ConfigFileMask         = '.*';
      FileNamesCaseSensitive = True;
    
    {$endif}
    
    const
      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;
    
    { Convert ch to lower case if FileNamesCaseSensitive is False, leave
      it unchanged otherwise. }
    function  FileNameLoCase (ch : Char) : Char;
      asmname '_p_filenamelocase';
    
    { 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 suitable 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. }
    (*@@iocritical*)function  GetTempFileName         : TString;
      asmname '_p_get_temp_file_name';
    
    { The same as GetTempFileName, but returns a CString allocated from
      the heap. }
    (*@@iocritical*)function  GetTempFileName_CString : CString;
      asmname '_p_get_temp_file_name_cstring';
    
    { Get the external name of a file }
    function  FileName (var f : AnyFile) : TString;
      asmname '_p_file_name';
    
    { Returns true if the given file name is an existing plain file }
    function  FileExists      (const aFileName : String) : Boolean;
      asmname '_p_file_exists';
    
    { Returns true if the given file name is an existing directory }
    function  DirectoryExists (const aFileName : String) : Boolean;
      asmname '_p_directory_exists';
    
    { Returns true if the given file name is an existing file, directory
      or special file (device, pipe, socket, etc.) }
    function  PathExists      (const aFileName : String) : Boolean;
      asmname '_p_path_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 aFileName already contains
      an element of DirSeparators, returns Slash2OSDirSeparator
      (aFileName) if it exists. }
    function  FSearch (const aFileName, 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 aFileName (and with
      respect to portability, it might be preferable not to do so). }
    function  FSearchExecutable (const aFileName, 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 resolved. Under Dos, the result is
      converted to lower case and a trailing ExtSeparator (except in a
      trailing DirSelf or DirParent) is removed, 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).
      Symlinks are expanded only in the directory part, not the file
      name. }
    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 aFileName a UNC filename? (Always returns False on non-Dos
      systems.) }
    function  IsUNC (const aFileName : 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, an I/O error is raised and (in case it is
      ignored) nil is returned. }
    (*@@iocritical*)function  OpenDir  (const Name : String) : DirPtr;
      asmname '_p_opendir';
    
    { 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. }
    (*@@iocritical*)procedure CloseDir (Dir : DirPtr);
      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 SubString in s that is not quoted
      at the beginning, or 0 if no such occurence exists. }
    function  FindNonQuotedStr (const SubString, 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 s 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 s : 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';
    
    type
      TPasswordEntry = record
        UserName, RealName, Password, HomeDirectory, Shell : TString;
        UID, GID : Integer
      end;
    
      PPasswordEntries = ^TPasswordEntries;
      TPasswordEntries (Count : Integer) = array [1 .. Count] of
      TPasswordEntry;
    
    { Finds a password entry by user name. Returns True if found, False
      otherwise. }
    function  GetPasswordEntryByName (const UserName : String; var
      Entry : TPasswordEntry) : Boolean;
      asmname '_p_getpasswordentrybyname';
    
    { Finds a password entry by UID. Returns True if found, False
      otherwise. }
    function  GetPasswordEntryByUID  (UID : Integer; var Entry :
      TPasswordEntry) : Boolean; asmname '_p_getpasswordentrybyuid';
    
    { Returns all password entries, or nil if none found. }
    function  GetPasswordEntries : PPasswordEntries;
      asmname '_p_getpasswordentries';
    
    { Returns the mount point (Unix) or drive (Dos) which is part of the
      given path. If the path does not contain any (i.e., is a relative
      path), an empty string is returned. Therefore, if you want to get
      the mount point or drive in any case, apply `FExpand' or
      `RealPath' to the argument. }
    function  GetMountPoint (const Path : String) = Result : TString;
      asmname '_p_GetMountPoint';
    
    { Returns the path to the shell (as the return value) and the option
      that makes it execute the command specified in the following
      argument (in `Option'). Usually these are the environment value of
      ShellEnvVar, and ShellExecCommand, but on Dos systems, the
      function will first try UnixShellEnvVar, and UnixShellExecCommand
      because ShellEnvVar will usually point to command.com, but
      UnixShellEnvVar can point to bash which is usually a better choice
      when present. If UnixShellEnvVar is not set, or the shell given
      does not exist, it will use ShellEnvVar, and ShellExecCommand.
      Option may be null (in case you want to invoke the shell
      interactively). }
    function  GetShellPath (var Option : String) : TString;
      asmname '_p_GetShellPath';
    
    { Returns the path of the running executable. NOTE: On most systems,
      this is *not* guaranteed to be the full path, but often just the
      same as `ParamStr (0)' which usually is the name given on the
      command line. Only on some systems with special support, it
      returns the full path when `ParamStr (0)' doesn't. }
    function  ExecutablePath : TString; asmname '_p_executable_path';
    
    { Returns a file name suitable for a global (system-wide) or local
      (user-specific) configuration file, depending on the Global
      parameter. The function does not guarantee that the file name
      returned exists or is readable or writable.
    
      In the following table, the base name `<base>' is given with the
      Name parameter. If it is empty, the base name is the name of the
      running program (as returned by ExecutablePath, without directory
      and extension. `<prefix>' (Unix only) stands for the value of the
      Prefix parameter (usual values include ", '/usr' and
      '/usr/local'). `<dir>' (Dos only) stands for the directory where
      the running program resides. `$foo' stands for the value of the
      environment variable `foo'.
    
             Global                    Local
      Unix:  <prefix>/etc/<base>.conf  $HOME/.<base>
    
      Dos:   $DJDIR\etc\<base>.ini     $HOME\<base>.cfg
             <dir>\<base>.ini          <dir>\<base>.cfg
    
      As you see, there are two possibilities under Dos. If the first
      file exists, it is returned. Otherwise, if the second file exists,
      that is returned. If none of them exists (but the program might
      want to create a file), if the environment variable (DJDIR or
      HOME, respectively) is set, the first file name is returned,
      otherwise the second one. This rather complicated scheme should
      give the most reasonable results for systems with or without DJGPP
      installed, and with or without already existing config files. Note
      that DJDIR is always set on systems with DJGPP installed, while
      HOME is not. However, it is easy for users to set it if they want
      their config files in a certain directory rather than with the
      executables. }
    function  ConfigFileName (const Prefix, Name : String; Global :
      Boolean) : TString; asmname '_p_config_file_name';
    
    { Returns a directory name suitable for global, machine-independent
      data. The function garantees that the name returned ends with a
      DirSeparator, but does not guarantee that it exists or is
      readable or writable.
    
      Note: If the prefix is empty, it is assumed to be '/usr'. (If you
      really want /share, you could pass '/' as the prefix, but that's
      very uncommon.)
    
      Unix: <prefix>/share/<base>/
    
      Dos:  $DJDIR\share\<base>\
            <dir>\
    
      About the symbols used above, and the two possibilities under Dos,
      see the comments for ConfigFileName. }
    function  DataDirectoryName (const Prefix, Name : String) : TString;
      asmname '_p_data_directory_name';
    
    { ==================== MATHEMATICAL ROUTINES ===================== }
    
    function  IsInfinity   (x : Extended) : Boolean; attribute (const);
      asmname '_p_isinf';
    function  IsNotANumber (x : Extended) : Boolean; attribute (const);
      asmname '_p_isnan';
    procedure SplitReal    (x : Extended; var Exponent : Integer; var
      Mantissa : Extended); asmname '_p_frexp';
    function  SinH         (x : Double)    : Double; asmname '_p_sinh';
    function  CosH         (x : Double)    : Double; asmname '_p_cosh';
    function  Arctan2      (y, x : Double) : Double;
      asmname '_p_arctan2';
    
    type
      RandomSeedType = Cardinal (32);
      RandomizeType  = ^procedure;
      SeedRandomType = ^procedure (Seed : RandomSeedType);
      RandRealType   = ^function : LongestReal;
      RandIntType    = ^function (MaxValue : LongestCard) : LongestCard;
    
    var
      RandomizePtr  : RandomizeType; asmname '_p_randomize_ptr';
      external;
      SeedRandomPtr : SeedRandomType; asmname '_p_seedrandom_ptr';
      external;
      RandRealPtr   : RandRealType; asmname '_p_randreal_ptr'; external;
      RandIntPtr    : RandIntType; asmname '_p_randint_ptr'; external;
    
    procedure SeedRandom (Seed : RandomSeedType);
      asmname '_p_seedrandom';
    
    end.
    
    

    From Borland Pascal to GNU Pascal

    This chapter is intended to be a QuickStart guide for programmers who are familiar with Borland Pascal, version 7 for Dos protected mode. Other versions don't differ too much but this one was the very last Dos version Borland has published.

    Throughout the documentation, we talk of "Borland Pascal" or "BP" for short. In most if not all cases, you can safely substitute "Turbo Pascal" if you like.

    BP Compatibility

    GNU Pascal (GPC) is compatible to version 7 of Borland Pascal (BP) to a large extent and comes with portable replacements of the Borland standard units.

    However, BP is a 16-bit compiler while GPC is a 32/64-bit compiler, so the size of the `Integer' type, for instance, is 16 bits in BP, but at least 32 bits in GPC. If a BP program has been designed with portability in mind from the ground up, it may work with GPC without any change. Programs which rely on byte order, on the internals or sizes of data types or which use unportable things like interrupts and assembler code, will need to be changed. The following section lists the possible problems with solutions.

    The GPC Run Time System (RTS) is fairly complete, and you can use all libraries written for GNU C from GNU Pascal, so there is much less need to use unportable constructs than there was in BP. (For example, BP's Turbo Vision library uses assembler to call a local procedure through a pointer. With GPC you can do this in Pascal just as with global procedures.) Please do not throw away the advantage of full portability by sticking to those workarounds.

    We have successfully ported real-world projects (with several 10000s of lines) from BP to GPC, so this is possible for you, too.

    BP Incompatibilities

    This sections lists the remaining incompatibilities of GPC to BP, and the problems you might encounter when porting BP programs from 16-bit Dos to other platforms, and gives solutions for them.

    By incompatibilites we mean problems that can arise when trying to compile a valid BP program with GPC. Of course, there are many features in GPC that BP doesn't know, but we call them extensions unless they can break valid BP programs, so they are not mentioned here. The subsequent sections of this chapter mention a number of useful extensions that you might want to know about but which will not break your BP code.

    The following differences can be "overcome" by command-line switches. As a summary:

    --borland-pascal -w --uses=System -D__BP_TYPE_SIZES__ --pack-struct
    -D__BP_RANDOM__ -D__BP_UNPORTABLE_ROUTINES__
    

    But please read the following items, and don't use these switches indiscriminately unless necessary. There are reasons why they are not GPC's defaults.