The GNU Pascal Manual

Short Contents

Table of Contents


Next: , Up: (dir)

GNU Pascal

This manual documents how to run, install and maintain the GNU Pascal Compiler (GPC), as well as its new features and incompatibilities, and how to report bugs. It corresponds to GPC 20060325 (GCC 2.8.1, 2.95.x, 3.2.x, 3.3.x or 3.4.x).

Introduction:

Installation:

Using GNU Pascal:

Development:

Licenses:

Appendix:


Next: , Previous: Top, Up: Top

Welcome to GNU Pascal ...

...

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

This version of GPC corresponds to GCC version 2.8.1, 2.95.x, 3.2.x, 3.3.x or 3.4.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, levels 0 and 1), most of Extended Pascal (ISO 10206, aiming for full compliance), is highly compatible to Borland Pascal (version 7.0), has some features for compatibility to other compilers (such as VAX Pascal, Sun Pascal, Mac Pascal, Borland Delphi and Pascal-SC).

It provides a lot of useful GNU extensions not found in other Pascal compilers, e.g. to ease the interfacing with C and other languages in a portable way, and to work with files, directories, dates and more, mostly independent of the underlying operating system.

Included units provide support for regular expressions, arithmetic with integer, rational and real numbers of unlimited size, internationalization, inter-process communication, message digests and more. Demo programs show the usage of these units and of many compiler features.

This manual 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 set types with variable bounds and discriminated ordinal schema as schema discriminants.

If you are a Borland Pascal programmer, you should probably start reading the QuickStart guide from BP to GNU Pascal, see Borland Pascal. If you are curious about the new features GPC offers, you can get an idea in the overview of GPC highlights (see Highlights), and read in more detail about them in the Programmer's Guide to GPC (see Programming) and in the alphabetical GPC Language Reference (see 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.

All trademarks used in this manual are properties of their respective owners.


Next: , Previous: Welcome, Up: Top

1 Some of GPC's most interesting features.

The GNU Pascal Compiler (GPC) is, as the name says, the Pascal compiler of the GNU family (http://www.gnu.org/software/gcc/). This means:

The compiler supports the following language standards and quasi-standards:

Some highlights:

The demo programs mentioned above are available both on the WWW and in GPC source and binary distributions.

Disadvantages:

Co-workers welcome!

Able, committed programmers are always welcome in the GNU Pascal team. If you want to be independent of companies that you have to pay in order to get a compiler with more restrictive licensing conditions that only runs on one operating system, be invited to join the development team, Acknowledgments.


Next: , Previous: Highlights, Up: Top

2 New Features of GNU Pascal.

GPC's new or changed features since the last (non alpha/beta) GPC release are listed here. Items without further description refer to new routines, variables or options.

Features implemented for compatibility to other compilers are marked with, e.g., `(B)' for BP compatibility.

A few old and obsolete features have been dropped or replaced by cleaner, more flexible or otherwise more useful ones. This might lead to minor problems with old code, but we suppose they're rare and easy to overcome. Backward-incompatible changes are marked with `(@)'.

Have fun,

The GNU Pascal Development Team


Next: , Previous: News, Up: Top

3 The GNU Pascal Frequently Asked Questions List.

This is the Frequently Asked Questions List (FAQ) for GNU Pascal. If the FAQ and the documentation do not help you, you have detected a bug in it which should be reported, Mailing List. Please really do it, so we can improve the documentation.


Next: , Up: FAQ

3.1 GNU Pascal


Next: , Up: GNU Pascal

3.1.1 What and why?

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, levels 0 and 1), most of Extended Pascal (ISO 10206, aiming for full compliance), is highly compatible to Borland Pascal (version 7.0), has some features for compatibility to other compilers (such as VAX Pascal, Sun Pascal, Mac Pascal, Borland Delphi and Pascal-SC).

It provides a lot of useful GNU extensions not found in other Pascal compilers, e.g. to ease the interfacing with C and other languages in a portable way, and to work with files, directories, dates and more, mostly independent of the underlying operating system.

Included units provide support for regular expressions, arithmetic with integer, rational and real numbers of unlimited size, internationalization, inter-process communication, message digests and more. Demo programs show the usage of these units and of many compiler features.


Next: , Previous: What and why, Up: GNU Pascal

3.1.2 What is the current version?

The current version is 20060325.

Releases are available as a source archive and precompiled binaries for several common platforms from the GPC web site, http://www.gnu-pascal.de.

For details about new features, see the section `News' on the web site. On bugs fixed recently, see the `Done' section of the To-Do list (on the same web site).

GPC uses GCC as a back-end. It supports GCC version 2.8.1, 2.95.x, 3.2.x, 3.3.x or 3.4.x. (The newest supported GCC version is usually preferable, unless it contains serious bugs in itself.)

There are no fixed time frames for new releases. Releases are made when enough interesting changes have been made and the compiler is somewhat stable.


Next: , Previous: Current version, Up: GNU Pascal

3.1.3 Is it compatible with Turbo Pascal (R)?

GPC is not a drop-in replacement for Borland's Turbo Pascal (R). Almost all BP language features are supported. Notable exceptions are the string format (as discussed below), or the `Mem' and `Port' pseudo arrays, though replacement functions for the latter on IA32 platforms exist in the `Ports' unit.

Almost all of BP's run time library is supported in GPC, either by built-in compiler features or in units with the same names as their BP counterparts.

For details about the compatibility, the few remaining incompatibilities and some useful alternatives to BP features, see the `Borland Pascal' chapter in the GPC Manual. (see Borland Pascal)


Previous: Turbo Pascal compatibility, Up: GNU Pascal

3.1.4 Which platforms are supported by GNU Pascal?

GPC uses the GCC backend, so it should run on any system that is supported by GNU CC. This includes a large variety of Unix systems, MS-DOS, OS/2 and Win32. A full list of platforms supported by GCC can be found in the file INSTALL of the GCC distribution. Not all of these have actually been tested, but it is known to run on these platforms:

ix86-gnu (GNU Hurd)
ix86-linux (Linux 2.x, ELF)
Linux/AMD64
i486-linuxaout
i486-linuxoldld
i386-freebsd1.2.0
AIX 4.2.1
AIX 4.3
DJGPP V2 (Dos)
EMX 0.9B (OS/2, Dos)
Cygwin32 beta20 and higher (MS-Windows95/98, MS-Windows NT)
mingw32 (MS-Windows95/98, MS-Windows NT)
MSYS (MS-Windows)
Mac OS/X 10.3
mips-sgi-irix5.3
mips-sgi-irix6.5
sun-sparc-sunos4.1.4
sparc-sun-solaris2.x
sun-sparc-solaris 2.5.1
sun-sparc-solaris 2.6
sun-sparc-solaris 7
sun-sparc-solaris 8
alpha-unknown-linux
alpha-dec-osf4.0b
s390-ibm-linux-gnu

OK people – send us your success stories, with canonical machine name!


Next: , Previous: GNU Pascal, Up: FAQ

3.2 Installing GPC

You find the most up-to-date installation instructions in the GPC Manual or the file `INSTALL' in source distributions, or on the GPC web site. (see Installation)

The following sections describe things you might need or want to install besides GPC itself.


Next: , Up: Installing GPC

3.2.1 What to read next

After installing GPC, please check the files in the directory /usr/local/doc/gpc:

README General Information about GPC
FAQ This FAQ :−)
NEWS Changes since the last release
BUGS How to report bugs, about the Test Suite
AUTHORS List of GPC authors
COPYING The GNU General Public License
COPYING.LIB The GNU Lesser General Public License


Next: , Previous: Documentation files, Up: Installing GPC

3.2.2 Which components do I need to compile Pascal code?

A complete Pascal compiler system should at least have:

  1. The actual compiler, GPC.
  2. An editor, assembler, linker, librarian and friends.
  3. A C library. If you have a working C compiler, you already have this.
  4. A debugger, if you want to debug your programs.

For most people, the GNU binutils and GNU debugger (`gdb') are a good choice, although some may prefer to use vendor specific tools.


Next: , Previous: Components, Up: Installing GPC

3.2.3 How do I debug my Pascal programs?

To debug your programs, (a) GNU Pascal must be able to generate executables with debug info for your platform, and (b) you must have a debugger which understands this.

The bottom line: if you can debug GCC compiled programs, you should be able to do this with GPC too.

The GNU debugger (`gdb') currently does not have a “Pascal” mode, so it is unable to display certain Pascal structures etc. When debugging, please note that the Initial Letter In Each Identifier Is In Upper Case And The Rest Are In Lower Case. If you want to display variable `foo' in the debugger, type `show Foo' or `display Foo' instead.

Although `gdb' is an excellent debugger, it's user interface is not everybody's preference. If you like to debug under X11, please refer to the comp.windows.x FAQ: “Where can I get an X-based debugger?” at:
http://www.faqs.org/faqs/x-faq/part6/section-2.html

Some useful frontends include: XXGDB, tGDB and XWPE. See:
http://www.ee.ryerson.ca:8080/~elf/xapps/Q-IV.html

Very nice, but resource consuming is the Motif based DDD:
http://sol.ibr.cs.tu-bs.de/softech/ddd/

Furthermore, RHIDE (see IDE) contains built-in debugging suport, similar to the IDE of BP.


Next: , Previous: Debugger, Up: Installing GPC

3.2.4 What additional libraries should I have?

You will need certain additional libraries when you compile some of the units. These can be found in the directory http://www.gnu-pascal.de/libs/.

Currently, there are the following libraries:

gmp
Arithmetic for integers, rationals and real numbers with arbitrary size and precision. Used by the GMP unit.
rx
Regular expression matching and substitution. Used by the RegEx unit.
ncurses
PDCurses
Screen handling. Used by the CRT unit. Depending on your system, you have the following choices:

Unix: You can compile terminal applications with ncurses and applications that run in an X11 window with PDCurses (though terminal applications can, of course, also run in an xterm under X11). ncurses is used by default. If you want to use PDCurses (a.k.a. XCurses), give the option `-DX11' when compiling CRT.

Dos with DJGPP and MS-Windows with mingw: Only PDCurses is available and will be used by default.

MS-Windows with Cygwin: PDCurses and ncurses are available. PDCurses is used by default. If you want to use ncurses, give the option `-DUSE_NCURSES' when compiling CRT.

Other systems: Please see the READMEs and installation instructions of PDCurses and ncurses to find out which one(s) can be built on your system. See the conditionals at the end of crt.inc and crtc.h (and change them if necessary) on which library is used by default.

intl
Internationalization. Used by the Intl unit. On some systems, it is part of the system library (libc).
ElectricFence
This library is not used by any GPC unit. It is a debugging tool to assist you in finding memory allocation bugs. To use it, just link it to your program, either on the command line (`-lefence') or in the source code (`{$L efence}') which you might want to put into an `{$ifdef DEBUG}' or similar since using libefence is only recommended for debugging.

The source code of the libraries is available in the main `libs' directory. Most libraries come with one or several patches which should be applied before compiling them.

Binaries for some platforms are available in the binary/platform subdirectories. If you compile the libraries for other platforms, be invited to make the binaries available to us for distribution on the web site.

There are also the following files:

terminfo-linux.tar.gz
This is a patch to enable ncurses programs to make use of the ability of Linux 2.2 and newer kernels to produce a block cursor when needed. The present patch can be installed without recompiling anything, just by copying some files into place. More details can be found in the README file included in this archive. The patch will not do any harm on older kernels. Please note that not only on Linux machines it is useful to install the patch. Installing them on any other machine will allow users who telnet in from a Linux console to profit from the block cursor capability. Besides, some Unix systems have installed older Linux terminfo entries or none at all, so it's a good thing, anyway, to give them a current version. The patch is included in the terminfo database of ncurses 5.0, so if you install ncurses 5.0 (source or binary), you don't need to get the patch separately. But you can install it on a system with an older ncurses version if you don't feel like upgrading ncurses altogether.
tsort-2.9i.zip
A little utility (extracted from util-linux-2.9i, but not Linux specific), needed for the configuration of the rx library. You need it only if you compile rx yourself (and if it's not already present on your system), not when using a rx binary.


Next: , Previous: Libraries, Up: Installing GPC

3.2.5 Contributed units

Several people have contributed units for GPC. They are usually announced on the mailing list, Mailing List. Most of them can be found in http://www.gnu-pascal.de/contrib/.


Previous: Contributed units, Up: Installing GPC

3.2.6 Can you recommend an IDE?

Users of Borland Pascal may wonder if there's a replacement for the IDE (Integrated Development Environment). Here's a few suggestions:


Next: , Previous: Installing GPC, Up: FAQ

3.3 GNU Pascal on the DJGPP (MS-DOS) platform

This chapter discusses some potential problems with GNU Pascal on MS-DOS, using DJGPP.


Next: , Up: GPC on DJGPP

3.3.1 What is DJGPP?

The following paragraph is from the site http://www.delorie.com/djgpp/:

DJGPP is a complete 32-bit C/C++ development system for Intel 80386 (and higher) PCs running DOS. It includes ports of many GNU development utilities. The development tools require a 80386 or newer computer to run, as do the programs they produce. In most cases, the programs it produces can be sold commercially without license or royalties.


Next: , Previous: What is DJGPP, Up: GPC on DJGPP

3.3.2 If you need more information

GPC/DJGPP is a DJGPP V2 application, and most of the DJGPP documentation applies for GPC too. A great source of information is the DJGPP FAQ: http://www.delorie.com/djgpp/v2faq/230b.zip

Another place to look for DJGPP documentation is the DJGPP Knowledge Base, at this URL: http://www.delorie.com/djgpp/doc/kb/


Next: , Previous: DJGPP FAQ, Up: GPC on DJGPP

3.3.3 What do I download?

As discussed in Components, other than GPC itself, you need an assembler, linker and friends, a C library and possibly a debugger. The site http://www.delorie.com/djgpp/ recommended the following files and they will help you find a mirror:

v2/djdev203.zip (C library)
v2gnu/bnu2951b.zip (assembler, ...)
v2gnu/gcc2952b.zip (gcc)
v2gnu/gdb418b.zip (debugger)
v2gnu/mak379b.zip (make)
v2gnu/txi40b.zip (texi)

This list is about 10 MB not counting GPC. You can use a binary version of GPC from the web site.


Next: , Previous: DJGPP download, Up: GPC on DJGPP

3.3.4 How do I install the compiler?

If you don't have DJGPP installed on your harddisk, create a directory for GNU Pascal (c:\gpc), and unzip the archives. Make sure you preserve the directory structure (use `pkunzip -d'). Now, add the directory where gpc.exe lives (c:\gpc\bin) to your path and set the DJGPP environment variable to point to your djgpp.env file:

     set DJGPP=c:\gpc\djgpp.env

Then, add this to your djgpp.env file:

     ---------------------------------------------------------
     [gpcpp]
     C_INCLUDE_PATH=%/>;C_INCLUDE_PATH%%DJDIR%/lang/pascal;%DJDIR%/include
     
     [gpc]
     COMPILER_PATH=%/>;COMPILER_PATH%%DJDIR%/bin
     LIBRARY_PATH=%/>;LIBRARY_PATH%%DJDIR%/lib;%DJDIR%/contrib/grx20/lib
     ---------------------------------------------------------

The GPC online documentation is in GNU info format; you need the Info reader (txi390b.zip) to read it, or use the built-in Info reader of the RHIDE or PENG IDE. To add the GPC documentation to the info directory file, edit the c:\gpc\info\dir file, and locate this section:

     ---------------------------------------------------------
     * GCC: (gcc.inf).
     The GNU C, C++, and Objective-C Compiler
     
     * GDB: (gdb.inf).
     The GNU Debugger (gdb and gdb-dpmi).
     
     ---------------------------------------------------------

To add GPC, change it to look like this:

     ---------------------------------------------------------
     * GCC: (gcc.inf).
     The GNU C, C++, and Objective-C Compiler
     
     * GPC: (gpc.inf).
     The GNU Pascal Compiler
     
     * GDB: (gdb.inf).
     The GNU Debugger (gdb and gdb-dpmi).
     
     ---------------------------------------------------------

Specific information for low-memory conditions and more can be found in the DJGPP FAQ and documentation.


Next: , Previous: Installing GPC on DJGPP, Up: GPC on DJGPP

3.3.5 I cannot read the Info documentation!

To read the Info documentation, you need the `info' program from txi390b.zip or an IDE like RHIDE or PENG.


Next: , Previous: DJGPP Info reader, Up: GPC on DJGPP

3.3.6 GPC says: no DPMI

You don't have a DPMI server installed, and DJGPP v2 requires it to run. You can either use one of the commercial DPMI servers (e.g., run `gpc' in a DOS box under MS-Windows) or download and install CWSDPMI (csdpmi3b.zip) which is a free DPMI server written for DJGPP.


Next: , Previous: DJGPP DPMI server, Up: GPC on DJGPP

3.3.7 I have troubles with assembly code

The GNU Assembler (as.exe), or gas, called by GCC accepts “AT&T” syntax which is different from “Intel” syntax. Differences are discussed in section 17.1 of the DJGPP FAQ.

A guide is available which was written by Brennan Mr. Wacko Underwood brennan@mack.rt66.com and describes how to use inline assembly programming with DJGPP, at this URL: http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html

There's also a GPC assembler tutorial at
http://www.gnu-pascal.de/contrib/misc/gpcasm.zip

Section 17.3 of the DJGPP FAQ discusses some methods to convert “Intel” syntax to “AT&T” syntax.

However, please note that assembler code is unportable, i.e. it will work on IA32 (“x86”) and compatible processors if written for them, but will not even compile for other processors. So by writing assembler code in your programs, you will limit their usefulness substantially.

If you think you “need” assembler code for speed – and you've checked that your assembler code actually runs faster than Pascal code compiled with suitable optimizations – you might want to put both Pascal and assembler versions of the critical sections in your program, and let, e.g., an `{$ifdef i386}' decide which one to use. This way, your program will at least compile on all processors.


Next: , Previous: Assembler syntax, Up: GPC on DJGPP

3.3.8 Tell me how to do DPMI, BIOS and other DOS related things.

DPMI, BIOS and other functions are no different than other system functions. Refer to the GPC Manual on how to access your system's C-library. This small example shows how to use DPMI, copying some structures and function prototypes of `<dpmi.h>':

     program DPMIDemo;
     
     { Only for DJGPP }
     
     {$X+}
     
     { `Byte' is `unsigned char' in C,
       `ShortCard' is `unsigned short' in C,
       `MedCard' is `unsigned long' in C,
       `Word' is `unsigned' in C,
       etc. (all these types are built-in). }
     
     type
       TDpmiVersionRet = record
         Major     : Byte;
         Minor     : Byte;
         Flags     : ShortCard;
         CPU       : Byte;
         Master_PIC: Byte;
         Slave_PIC : Byte;
       end;
     
     type
       TDpmiFreeMemInfo = record
         LargestAvailableFreeBlockInBytes,
         MaximumUnlockedPageAllocationInPages,
         MaximumLockedPageAllocationInPages,
         LinearAddressSpaceSizeInPages,
         TotalNumberOfUnlockedPages,
         TotalNumberOfFreePages,
         TotalNumberOfPhysicalPages,
         FreeLinearAddressSpaceInPages,
         SizeOfPagingFilePartitionInPages,
         Reserved1,
         Reserved2,
         Reserved3: MedCard;
       end;
     
     function DpmiGetVersion (var Version: TDpmiVersionRet): Integer;
              external name '__dpmi_get_version';
     
     function DpmiGetFreeMemoryInformation
              (var MemInfo: TDpmiFreeMemInfo): Integer;
              external name '__dpmi_get_free_memory_information';
     
     var
       Version: TDpmiVersionRet;
       MemInfo: TDpmiFreeMemInfo;
     
     begin
       if DpmiGetVersion (Version) = 0 then
         begin
           WriteLn ('CPU type:       ', Version.CPU, '86');
           WriteLn ('DPMI major:       ', Version.Major);
           WriteLn ('DPMI minor:       ', Version.Minor);
         end
       else
         WriteLn ('Error in DpmiGetVersion');
       if DpmiGetFreeMemoryInformation (MemInfo) = 0 then
         WriteLn ('Free DPMI memory: ',
                  MemInfo.TotalNumberOfFreePages, ' pages.')
       else
         WriteLn ('Error in DpmiGetMemoryInformation');
     end.


Previous: DJGPP specific code, Up: GPC on DJGPP

3.3.9 I got an exception when accessing an `array [1 .. 4000000] of Byte'.

Per default, the maximum stack size of a DJGPP application is 256K. If you need more, you have to adjust it with the stubedit program, i.e.:

     stubedit your_app.exe minstack=5000K

Another way is to add the following code to your program to define a minimum stack size (here: 2 MB). This value will be honored even if a user sets a lower value by using stubedit, so this method might be a little safer. (The linker name `_stklen' is essential; the Pascal identifier doesn't matter. The constant doesn't have to be used anywhere in the program. It is recommended to put this declaration in the main program file, not in any unit/module, so programs using a unit/module can set whatever limit they need.)

     {$ifdef __GO32__}
     const
       MinStackSize: Cardinal = $200000; attribute (name = '_stklen');
     {$endif}

Still, it might be a good idea to use pointers for large structures, and allocate the memory at runtime.

DJGPP has to allocate the stack in physical memory at program startup, so one might have to be careful with too large stack limits. Most other systems allocate stack pages on demand, so the only reason to set a limit at all might be to prevent a runaway recursion from eating up all memory ...

On Unix-like systems, you can set a resource limit, but you usually don't do it in normal programs, but rather in the shell settings (bash: `ulimit'; csh: `limit'; syscall: `setrlimit'(2)).


Next: , Previous: GPC on DJGPP, Up: FAQ

3.4 Strings


Next: , Up: Strings in GPC

3.4.1 What's this confusion about strings?

Turbo Pascal strings have a length byte in front. Since a byte has the range 0 .. 255, this limits a string to 255 characters. However, the Pascal string schema, as defined in section 6.4.3.3.3 of the ISO 10206 Extended Pascal standard, is a schema record:

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

The `+ 1' is a GPC extension to make it feasible to automatically add the `#0' terminator when passing or assigning them to CStrings. Thus at the expense of a little added complexity (must declare capacity, don't use `GetMem' without explicit initialization of the `Capacity' field, and the additional space requirement) you can now have very long strings.


Next: , Previous: String schema, Up: Strings in GPC

3.4.2 Overlaying strings in variant records

Q: Should the different variants in a variant record overlay in the same memory? Previous Pascals I have used have guaranteed this, and I've got low-level code that relies on this. The variants are not the same length, and they are intended not to be.

A: No, this is intentional so that the discriminants are not overwritten, and they can be properly initialized in the first place. Consider:

     record
     case Boolean of
       False: (s1: String (42));
       True:  (s2: String (99));
     end;

If the strings would overlay, in particular their discriminants would occupy the same place in memory. How should it be initialized? Either way, it would be wrong for at least one of the variants ...

So, after a discussion in the ISO Pascal newsgroup where this topic came up concerning file variables (which also require some automatic initialization and finalization), we decided to do this in GPC for all types with automatic initialization and finalization (currently files, objects and schemata, including strings, in the future this might also be Delphi compatible classes and user-defined initialized and finalized types), since the standard does not guarantee variants to overlay, anyway ...

There are two ways in GPC to get guaranteed overlaying (both non-standard, of course, since the standard does not assume anything about internal representations; both BP compatible), `absolute' declarations and variable type casts. E.g., in order to overlay a byte array `b' to a variable `v':

     var
       b: array [1 .. SizeOf (v)] of Byte absolute v;

Or you can use type-casting:

     type
       t = array [1 .. SizeOf (v)] of Byte;

then `t (v)' can be used as a byte array overlayed to `v'.


Next: , Previous: Strings in variant records, Up: Strings in GPC

3.4.3 Why does `s[0]' not contain the length?

Q: In standard Pascal you expect `s[1]' to align with the first character position of `s' and thus one character to the left is the length of `s'. Thus `s[0]' is the length of `s'. True?

A: This holds for UCSD/BP strings (which GPC does not yet implement, but that's planned). The only strings Standard Pascal knows are arrays of char without any length field.

GPC also supports Extended Pascal string schemata (see String schema), but they also don't have a length byte at “position 0”, but rather a `Length' field (which is larger than one byte).


Next: , Previous: Length byte, Up: Strings in GPC

3.4.4 Watch out when using strings as parameters

Q: Any “gotchas” with string parameters?

A: Be careful when passing string literals as parameters to routines accepting the string as a value parameter and that internally modify the value of the parameter. Inside the routine, the value parameter gets a fixed capacity – the length of the string literal that was passed to it. Any attempt to assign a longer value will not work.

This only applies if the value parameter is declared as `String'. If it is declared as a string with a given capacity (e.g., `String (255)'), it gets this capacity within the routine.


Next: , Previous: Strings as value parameters, Up: Strings in GPC

3.4.5 Support for BP compatible short strings

Q: Two different kinds of strings with the same name – `String' – does make a bit of confusion. Perhaps the oldstyle strings could be renamed `short string' ?

A: When we implement the short strings, we'll have to do such a distinction. Our current planning goes like this:

`String (n)': string schema (EP compatible)

`String [n]': short string (UCSD/BP compatible, where n must be <= 255)

`String': dependent on flags, by default undiscriminated schema, but in BP mode (or with a special switch) short string of capacity 255 (UCSD/BP compatible).

Q: So when will these short strings be available?

A: It's been planned for some years. The delay has been caused by more pressing problems.


Previous: Short strings, Up: Strings in GPC

3.4.6 What about C strings?

A C string (`char *') is an array of char, terminated with a `#0' char.

C library functions require C, not Pascal style string arguments. However, Pascal style strings are automatically converted to C style strings when passed to a routine that expects C style strings. This works only if the routine reads from the string, not if it modifies it.

E.g., this is how you could access the `system()' call in your C library (which is not necessary anymore, since `Execute' is already built-in):

     program SysCall;
     
     function System (CmdLine: CString): Integer; external name 'system';
     
     var
       Result: Integer;
     
     begin
       Result := System ('ls -l');
       WriteLn ('system() call returned: ', Result)
     end.

You could use the type `PChar' instead of `CString'. Both `CString' and `PChar' are predefined as `^Char' – though we recommend `CString' because it makes it clearer that we're talking about some kind of string rather than a single character.

A lot of library routines in Pascal for many applications exist in the GPC unit and some other units. Where available, they should be preferred (e.g. `Execute' rather than `system()', and then you won't have to worry about `CString's.)

Do not pass a C style string as a `const' or `var' argument if the C prototype says `const char *' or you will probably get a segfault.


Next: , Previous: Strings in GPC, Up: FAQ

3.5 Getting Help

Please read the GPC Manual (info files or other formats) as well as the README and BUGS files that come with GPC (usually installed in directory /usr/local/doc/gpc), plus other docs that might help (the DJGPP FAQ if you use DJGPP, etc.) before you send email to the maintainers or mailing list.

In particular, the BUGS file contains information on how to submit bug reports in the most efficient way.

The `Support' chapter of the GPC Manual tells you where to find more information about GPC and how to contact the GPC developers. (see Support)


Previous: Getting Help, Up: FAQ

3.6 Miscellaneous


Next: , Up: Miscellaneous FAQ

3.6.1 I want to contribute; where do I start?

If you want to contribute, please write to the mailing list, Mailing List.


Next: , Previous: Contributing, Up: Miscellaneous FAQ

3.6.2 Where is the GNU Pascal web site?

The GPC homepage on the web, for information and downloads, is
http://www.gnu-pascal.de.

The GPC To-Do list, listing the latest features and fixed bugs can also be found there.


Previous: GPC web site, Up: Miscellaneous FAQ

3.6.3 About this FAQ

Current Maintainer: Russ Whitaker, russ@ashlandhome.net

This is the second incarnation of the GNU Pascal FAQ list, based on the previous FAQ by J.J. van der Heijden. Comments about, suggestions for, or corrections to this FAQ list are welcome.

Please make sure to include in your mail the version number of the document to which your comments apply (you can find the version at the beginning of this FAQ list).

Many people have contributed to this FAQ, only some of them are acknowledged above. Much of the info in, and inspiration for this FAQ list was taken from the GPC mailing list traffic, so you may have (unbeknownst to you) contributed to this list.


Next: , Previous: FAQ, Up: Top

4 How to download, compile and install GNU Pascal.


Next: , Up: Installation

4.1 Where and what to download

You can download the source code of the current GNU Pascal release from

     http://www.gnu-pascal.de/current/

and binaries for some platforms from

     http://www.gnu-pascal.de/binary/

The binary archive files are named gpc-version.platform.extension – for example `gpc-2.1.alpha-unknown-linux-gnu.tar.gz' for GPC version 2.1 on an Alpha workstation running the Linux kernel with GNU C Library, or `gpc-20000616.i386-pc-msdosdjgpp' for GPC version 20000616 on an Intel IA32 compatible PC running DOS with DJGPP.

After you have downloaded the correct archive file for your platform, please read the installation notes on how to install such a binary distribution.

If you are running Dos or MS Windows, you will need additional tools – see “What else to download and where” below.

Current snapshots

GNU Pascal is subject to steady development. Alpha and beta snapshots (source only, use at your own risk) can be found at:

     http://www.gnu-pascal.de/alpha/
     http://www.gnu-pascal.de/beta/

What else to download and where

When you are using GNU Pascal on a DOS system, you will need either the DJGPP or the EMX development environment (see below). On an OS/2 system, you will need EMX. On an MS Windows 95/98/NT system you will need either the CygWin or the mingw32 ot the MSYS environment.

GNU Pascal uses the compiler back-end from the GNU Compiler Collection, GNU CC or GCC. If you want to compile GPC, you will need the source of GCC as well as the source of GPC itself. From the same place as GPC, please download GCC 2.8.1, 2.95.x, 3.2.x, 3.3.x or 3.4.x. (It is also available from any GNU mirror; see http://www.gnu.org/software/gcc/.)

Libraries

For some of GPC's units, you will need some standard libraries. In particular:

Unit Platform Library
CRT Unix/terminal ncurses >= 5.0 (1), (2)
CRT Unix/X11 PDCurses (2)
CRT Dos, MS-Windows PDCurses (3)
GMP any gmp
RegEx any rx
(debugging) Unix, MS-Windows ElectricFence (4)

Notes:

(1) ncurses version 5.0 or newer is strongly recommended because older versions contain a bug that severely affects CRT programs.

(2) You can install both ncurses and PDCurses on a Unix system, and choose at compile time whether to generate a terminal or X11 version of your program.

(3) ncurses also runs under MS-Windows with CygWin (not mingw32, however), but doesn't appear to behave much differently from PDCurses on that platform.

(4) ElectricFence is not used by any unit, but can be used for debugging memory allocation bugs by simply linking it (see the accompanying documentation).

You can find those libraries on many places on the Net. Also, many GNU/Linux distributions, DJGPP mirrors and other OS distributions already contain some of the libraries. In any case, you can find the sources of the libraries (sometimes together with patches that you should apply before building if you choose to build from the sources) and binaries for some platforms in

     http://www.gnu-pascal.de/libs/

For more information and descriptions of these libraries, see Libraries.

DJGPP

DJGPP is available from any SimTel mirror in the gnu/djgpp subdirectory; for addresses look into the DJGPP FAQ. To use GNU Pascal you need at least

We also recommend you to get:

EMX

EMX is an environment for creating 32-bit applications for DOS and OS/2. To develop EMX programs with GNU Pascal you need at least

If your DOS box has DPMI (it does if you are using MS Windows or OS/2) you will also need RSX, available from the same sites as EMX in the subdirectory rsxnt.

The GNU development tools contain the GNU C compiler which is in fact not needed to use GNU Pascal. However, the C library is needed.

CygWin

CygWin is an environment which implements a POSIX layer under MS Windows, giving it large parts of the functionality of Unix. CygWin contains development tools such as an assembler, a linker, etc. GPC needs for operation. More information about CygWin can be found at

     http://cygwin.com

mingw32

The Minimalists' GNU Win32 environment, mingw32, allows a large number of Unix programs – including GPC and GCC – to run under MS Windows 95/98/NT using native MS libraries. mingw32 ressources can be found at

     http://www.mingw.org


Next: , Previous: Download, Up: Installation

4.2 Installation instructions for a GPC binary distribution

To install a binary distribution, cd to the root directory and unpack the archive while preserving the stored directory structure. Under a Unix compatible system with GNU tar installed, the following (performed as `root') will do the job:

     # cd /
     # 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 an explicit pipe:

     # cd /
     # gzip -c -d archive.tar.gz | tar xf -

Some binary distributions are now distributed packed with `bzip2'. You can recognize them by their file name suffix .bz2 instead of .gz. For such archives, make sure you have `bunzip2' installed and then use the following command:

     # cd /
     # tar xjf archive.tar.bz2

Or:

     # cd /
     # bunzip2 -c -d archive.tar.bz2 | tar xf -

If you want to install a GPC binary distribution in another directory than it was prepared for (for example, if you do not have root access to the computer and want to install GPC somewhere under your home directory), you can do the following:

To install a ZIP archive under DOS with `PKunzip', `cd' to the appropriate directory (usually `\' for EMX, `\DJGPP' for DJGPP), then call `PKunzip' with the `-d' option:

     C:\> cd djgpp
     C:\DJGPP> pkunzip -d archive.zip

where archive.zip is the name of the distribution file.

For DJGPP you must edit your djgpp.env in the DJGPP directory to complete the installation: Please copy the entries from `[gcc]' to create a new `[gpc]' section. The result may look as follows:

     [gcc]
     COMPILER_PATH=%/>;COMPILER_PATH%%DJDIR%/bin
     LIBRARY_PATH=%/>;LIBRARY_PATH%%DJDIR%/lib
     
     [gpc]
     COMPILER_PATH=%/>;COMPILER_PATH%%DJDIR%/bin
     LIBRARY_PATH=%/>;LIBRARY_PATH%%DJDIR%/lib

If you are using the DJGPP version of GPC but do not have a DJGPP directory, please download and install DJGPP (see Download).

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.


Next: , Previous: Binary Distributions, Up: Installation

4.3 Compiling GPC

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 Binary Distributions for how to install a binary distribution.)

GPC is based on the GNU Compiler Collection, GNU CC or GCC. You will need the GCC sources to build it. It must be the same version as the one GPC is implemented with – 2.8.1, 2.95.x, 3.2.x, 3.3.x or 3.4.x as of this writing. Although you need GCC to build the GNU Pascal compiler, you don't need GCC to compile Pascal programs once GNU Pascal is installed. (However, using certain libraries will require compiling C wrappers, so it is a good idea to install the C compiler as well.)

Because GNU Pascal shares its back-end with GCC, it should run on any system supported by GCC. A full list of platforms supported by GCC can be found in the GCC installation instructions.

The GCC source can be obtained from any mirror of the GNU FTP site, ftp://ftp.gnu.org/gnu/gcc/. The “core” distribution is sufficient for GPC.

Here is the generic procedure for installing GNU Pascal on a Unix system. See Compilation Notes for extra information needed to install GPC on DOS-like platforms.

  1. Checking the prerequisites

    Make sure that GNU make is installed and that you use it in the following steps. When unsure, you can try `make --version' and/or `gmake --version'. It should tell you that it is GNU make. If you don't have it, you can obtain it from http://www.gnu.org/software/make/.

    (In the following, we will simply speak of `make' when invoking GNU make; you might need to call `gmake' instead.)

    You also need a patch program. If such a program is not installed on your system, you can get GNU patch from http://www.gnu.org/directory/patch.html.

    For extracting the example programs from the documentation to the doc/docdemos directory a non-crippled `sed' is needed. GNU sed is known to work.

    If you have downloaded a “minimal” source distribution, most derived files have to be rebuilt. This is done automatically when building GPC, but you need additional tools:

    `bash', `bzip2', GNU `sed', GNU `awk', GNU `m4', `bison' (at least version 2.1), `flex' (version 2.5.27), `autoconf' (version 2.12), `texinfo' (at least version 4.2), `help2man'.

    Make sure that these are installed. The minimal distributions are compressed with `bzip2' instead of `gzip', so substitute it in the instructions below.

    If your bison and flex programs are installed under different names, you may have to set some or all of the following environment variables before running `configure':

              FLEX=/path/to/flex
              LEX=/path/to/flex
              BISON=/path/to/bison
              YACC=/path/to/bison
              INTLBISON=/path/to/bison
         

    If you want to build the GPC WWW pages you will also need a TeX distribution (including `pdftex' and `dvips').

    If you run into trouble during the installation process, please check whether you are using outdated versions of the required utilities and upgrade if necessary.

    The GNU versions of the packages above are available from http://www.gnu.org/software/, in a subdirectory whose name is the name of the package.

  2. Unpacking the source

    From a directory of your choice (e.g. /home/fred), unpack the GCC and GNU Pascal source distributions. This will create separate subdirectories for GCC and GPC. Let us assume gcc-3.4.3 and gpc-20041218 in this example.

              % cd /home/fred
              % bzip2 -d < gcc-core-3.4.3.tar.bz2 | tar xf -
              % gzip -c -d gpc-20041218.tar.gz | tar xf -
         

    `cd' to the GPC directory and move the contents (a subdirectory p) to the subdirectory gcc of the GCC directory:

              % mv /home/fred/gpc-20041218/p /home/fred/gcc-3.4.3/gcc/
         

    Instead of moving the directory, it is now also possible to make a symbolic link (if the OS supports symlinks). This is useful if you want to build GPC with several different GCC versions:

              % ln -s /home/fred/gpc-20041218/p /home/fred/gcc-3.4.3/gcc/p
         

    It is recommended, though not required, to use a separate directory for building the compiler, rather than compiling in the source directory. In this example, let us create /home/fred/gpc-build for this purpose:

              % mkdir /home/fred/gpc-build
         

    If you use a separate directory, you do not need to write into the GCC source directory once you have patched the GCC source (see below), and can build GPC for more than one platform from the same source tree.

    In case you are re-using a directory where you have already built GCC and/or GPC 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.

  3. Configuring and building GCC

    GNU Pascal is automatically configured with GCC. Configuration of GCC is treated in depth in the GCC installation instructions. The normal procedure is as follows:

    `cd' to the GPC build directory. From there, run the `configure' script in the GCC source directory:

              % cd /home/fred/gpc-build
              % /home/fred/gcc-3.4.3/configure --enable-languages=pascal
         

    This creates all the necessary config files, links and Makefile in the GCC object directory.

    Note 1: The configuration will prompt you for patching the GCC source for GPC support, so you need write access to that directory. 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.

    Note 2: The `--enable-languages=pascal' option means that we only want to build the Pascal compiler and not, for instance, the C++ compiler.

    Note 3: The standard base directory for installing GCC and GPC is /usr/local. If you want to install files to an alternate directory dir, specify `--prefix=dir' when you run configure. For installing into a system directory such as /usr/local you will, of course, need appropriate permissions (often root). Therefore, if you want to install GPC on a system where you don't have those permissions, you must specify a prefix (e.g., `$HOME/usr').

  4. Putting other GNU tools in place

    Some environments require other GNU tools (such as the GNU assembler or linker) instead of the standard system tools for GCC to work. (See the GCC installation instructions for details.) If this is the case for your system, install the required tools in the GPC 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 (a part of GCC) and to install the GNU tools to a place where they are found by GCC but do not interfere with the standard system tools.

    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.

  5. Compiling GPC

    Once you are satisfied with the configuration as determined by configure, you can build the compiler:

              % make
         

    Notice that this procedure will build the C compiler (and maybe some other compilers) 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'

    Note: The documentation may fail to build from *.texi sources if GCC 2.95.x tries to use an older version of `makeinfo' supplied in GCC package itself. This can be prevented by supplying explicit instruction to use your system's `makeinfo':

              % make MAKEINFO=`which makeinfo`
         

    optionally followed by the rest of arguments.

  6. Completing the installation

    When everything has been compiled, you can check the installation process with:

              % make -n install
         

    To complete the installation, run the command `make install'. You need write access to the target directories (/usr/local/bin, /usr/local/lib, /usr/local/info, /usr/local/doc, and /usr/local/man in this example), so this is usually done as `root':

              % su -c "make install"
         

    If you want to install only the Pascal compiler (for example if you already have the correct version of GCC installed), `cd' to the `gcc' subdirectory of the build directory (e.g. /home/fred/gpc-build/gcc) and run `make pascal.install'. This installation process does not overwrite existing copies of libgcc.a or specs, should they exist.

    However, if you do not have the exactly matching GCC version installed, you might need some additional files (otherwise GPC will complain about missing files at runtime). You can install them by doing `make pascal.install-with-gcc' in the gcc subdirectory of the build directory.

    There is a (partial) translation of the GPC manual into Croatian available now. It is not installed by default. If you want to install it, do a `pascal.install-hr' in the `gcc' directory. This will install the manpage gpc-hr.1 and the info documentation gpc-hr.info*. Other formats like PS, PDF and HTML can be built manually (it's also easy to add appropriate make targets for them when needed).

    Also from the `gcc' subdirectory you can do some more “exotic” builds. For instance, you can build the GPC WWW pages by typing `make pascal.html' or a binary distribution by typing `make pascal.bindist'. See the Makefile in that directory for more examples.


Next: , Previous: Compiling GPC, Up: Installation

4.4 Compilation notes for specific platforms


Next: , Up: Compilation Notes

4.4.1 MS-DOS with DJGPP

The only compiler that is capable of compiling the GNU Compiler Collection (GNU CC or GCC) under MS-DOS is GCC itself. In order to compile GPC or GCC for MS-DOS with DJGPP you will therefore need either a working copy of DJGPP installed, or you will have to cross-build from a non-MS-DOS system.

Building GPC under MS-DOS with DJGPP follows the same scheme as building GPC under a Unix-like system: Place the p subdirectory in the gcc directory and follow the instructions for compiling GCC. This requires `bash' and many other tools installed, and you must be very careful at many places to circumvent the limitations of the DOS platform.

Our preferred way to build GPC for DJGPP is to cross-build it from a Unix-like platform – which is much easier. For instructions, see Cross-Compilers and Crossbuilding.


Next: , Previous: MS-DOS with DJGPP, Up: Compilation Notes

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

As of this writing, we are not aware of current versions of GCC for EMX, and EMX support in GPC has not been maintained. Please contact us if you know about recent development in EMX and are interested in continuing EMX support in GPC.


Previous: MS-DOS or OS/2 with EMX, Up: Compilation Notes

4.4.3 MS Windows 95/98/NT

There are two ports of the GNU development tools to MS Windows 95/98/NT: CygWin and mingw32.

The CygWin environment implements a POSIX layer under MS Windows, giving it large parts of the functionality of Unix. Thus, compiling GCC and GPC under the CygWin environment can be done following the instructions for compiling it under a Unix-like system (see Compiling GPC).

The Minimalists' GNU Win32 environment, mingw32, uses the native crtdll.dll library of MS Windows. It is much smaller than CygWin, but it is not self-hosting and must be crossbuilt from another system (see Crossbuilding).


Next: , Previous: Compilation Notes, Up: Installation

4.5 Building and Installing a cross-compiler

GNU Pascal can function as a cross-compiler for many machines. Information about GNU tools in a cross-configuration can be found at `ftp://ftp.cygnus.com/pub/embedded/crossgcc/'.

If you want a cross-compiler targetting Linux you may use Dan Kegel's crosstool from `http://www.kegel.com/crosstool/'

Since GNU Pascal generates assembler code, you 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. It is straightforward to install the GNU binutils to act as cross-tools – see the installation instructions of the GNU binutils for details.

You also need header files and libraries suitable for the target machine that you can install on the host machine. Please install them under prefix/platform/include/, for instance /usr/local/i386-pc-msdosdjgpp/include/ for a cross-compiler from a typical Unix-like environment to MS-DOS with DJGPP.

Configuration and compilation of the compiler can then be done using the scripts cfgpc and mkgpc which are included in the source distribution in the subdirectory p/script. Please call them with the `-h' option for instructions.


Previous: Cross-Compilers, Up: Installation

4.6 Crossbuilding a compiler

Using a cross-compiler to build GNU Pascal results in a compiler binary that runs on the cross-target platform. This is called “crossbuilding”. 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 mingw32.

To crossbuild GNU Pascal, you have to install a cross-compiler for your target first, see Cross-Compilers.

As when building a cross-compiler, configuration and compilation of the compiler can be done using the scripts cfgpc and mkgpc which are included in the source distribution in the subdirectory p/script. Please call them with the `-h' option for instructions.


Next: , Previous: Installation, Up: Top

5 Command Line Options supported by GNU Pascal.

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, except for many preprocessor options. For a complete reference and descriptions of all options, see GCC Command Options. 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 Compiler Directives).

GPC understands the same environment variables GCC does (see Environment Variables Affecting GCC). 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.

Some of the long options (e.g., `--unit-path') take an argument. This argument is separated with a `=' sign, e.g.:

     --unit-path=/home/foo/units


Next: , Up: Invoking GPC

5.1 GPC options besides those of GCC.

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

--debug-tree
(For GPC developers.) Show the internal representation of a given tree node (name or address).
--debug-gpi
(For GPC developers.) Show what is written to and read from GPI files (huge output!).
--debug-automake
(For GPC developers.) Give additional information about the actions of automake.
--debug-source
Output the source while it is being processed to standard error.
--no-debug-source
Do not output the source while it is being processed (default).
--disable-debug-info
Inhibit `-g' options (temporary work-around, this option may disappear in the future).
--progress-messages
Output source file names and line numbers while compiling.
--no-progress-messages
Do not output source file names and line numbers while compiling (default).
--progress-bar
Output number of processed lines while compiling.
--no-progress-bar
Do not output number of processed lines while compiling (default).
--automake-gpc
Set the Pascal compiler invoked by automake.
--automake-gcc
Set the C compiler invoked by automake.
--automake-g++
Set the C++ compiler invoked by automake.
--amtmpfile
(Internal switch used for automake).
--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'.
--maximum-field-alignment
Set the maximum field alignment in bits if `pack-struct' is in effect.
--ignore-packed
Ignore `packed' in the source code (default in `--borland-pascal').
--no-ignore-packed
Do not ignore `packed' in the source code (default).
--ignore-garbage-after-dot
Ignore anything after the terminating `.' (default in `--borland-pascal').
--no-ignore-garbage-after-dot
Complain about anything after the terminating `.' (default).
--extended-syntax
same as `--ignore-function-results --pointer-arithmetic --cstrings-as-strings -Wno-absolute' (same as `{$X+}').
--no-extended-syntax
Opposite of `--extended-syntax' (same as `{$X-}').
--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).
--pointer-arithmetic
Enable pointer arithmetic.
--no-pointer-arithmetic
Disable pointer arithmetic (default).
--cstrings-as-strings
Treat CStrings as strings.
--no-cstrings-as-strings
Do not treat CStrings as strings (default).
-Wabsolute
Warn about variables at absolute adresses and `absolute' variable with non-constant addresses (default).
-Wno-absolute
Do not warn about variables at absolute adresses and `absolute' variable with non-constant addresses.
--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 ISO 7185/10206 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 `--ucsd-pascal', `--borland-pascal' or `--delphi').
--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.
--double-quoted-strings
Allow strings enclosed in "\" (default).
--no-double-quoted-strings
Do not allow strings enclosed in "\" (default with dialect other than `--mac-pascal').
--longjmp-all-nonlocal-labels
Use `longjmp' for all nonlocal labels (default for Darwin/PPC).
--no-longjmp-all-nonlocal-labels
Use `longjmp' only for nonlocal labels in the main program (default except for Darwin/PPC).
--iso-goto-restrictions
Do not allow jumps into structured instructions (default).
--no-iso-goto-restrictions
Allow jumps into structured instructions (default in `--borland-pascal').
--nonlocal-exit
Allow non-local `Exit' statements (default in `--ucsd-pascal' and `--mac-pascal').
--no-nonlocal-exit
Do not allow non-local `Exit' statements (default).
--io-checking
Check I/O operations automatically (same as `{$I+}') (default).
--no-io-checking
Do not check I/O operations automatically (same as `{$I-}').
--pointer-checking-user-defined
Use user-defined procedure for validating pointers.
--no-pointer-checking-user-defined
Do not use user-defined procedure for validating pointers (default).
--pointer-checking
Validate pointers before dereferencing.
--no-pointer-checking
Do not validate pointers before dereferencing (default).
--object-checking
Check for valid objects on virtual method calls (default).
--no-object-checking
Do not check for valid objects on virtual method calls.
--range-checking
Do automatic range checks') (default).
--no-range-checking
Do not do automatic range checks (same as `{$R-}').
--range-and-object-checking
Same as `--range-checking --object-checking', same as `{$R+}'.
--no-range-and-object-checking
Same as `--no-range-checking --no-object-checking', same as `{$R-}'.
--case-value-checking
Cause a runtime error if a `case' matches no branch (default in ISO Pascal modes).
--no-case-value-checking
Do not cause a runtime error if a `case' matches no branch (default).
--stack-checking
Enable stack checking (same as `{$S+}').
--no-stack-checking
Disable stack checking (same as `{$S-} (default)').
--read-base-specifier
In read statements, allow input base specifier `n#' (default).
--no-read-base-specifier
In read statements, do not allow input base specifier `n#' (default in ISO 7185 Pascal).
--read-hex
In read statements, allow hexadecimal input with `$' (default).
--no-read-hex
In read statements, do not allow hexadecimal input with `$' (default in ISO 7185 Pascal).
--read-white-space
In read statements, require whitespace after numbers.
--no-read-white-space
In read statements, do not require whitespace after numbers (default).
--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
Optional colon-separated list of default field widths for Integer, Real, Boolean, LongInt, LongReal.
--no-field-widths
Reset the default field widths.
--pedantic
Reject everything not allowed in some dialect, e.g. redefinition of its keywords.
--no-pedantic
Don't give pedantic warnings.
--typed-address
Make the result of the address operator typed (same as `{$T+}', default).
--no-typed-address
Make the result of the address operator an untyped pointer (same as `{$T-}').
--enable-keyword
Enable a keyword, independently of dialect defaults.
--disable-keyword
Disable a keyword, independently of dialect defaults.
--implicit-result
Enable implicit `Result' for functions (default only in `--delphi').
--no-implicit-result
Disable implicit `Result' for functions.
--enable-predefined-identifier
Enable a predefined identifier, independently of dialect defaults.
--disable-predefined-identifier
Disable a predefined identifier, independently of dialect defaults.
--assertions
Enable assertion checking (default).
--no-assertions
Disable assertion checking.
--setlimit
Define the range for `set of Integer' etc..
--gpc-main
External name for the program's entry point (default: `main').
--propagate-units
Automatically re-export all imported declarations.
--no-propagate-units
Do not automatically re-export all imported declarations.
--interface-only
Compile only the interface part of a unit/module and exit (creates `.gpi' file, no `.o' file.
--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 of Pascal units.
--no-unit-destination-path
Create object and GPI files of Pascal units in the current directory (default).
--object-destination-path
Path where to create additional object files (e.g. of C files, not Pascal units).
--no-object-destination-path
Create additional object files (e.g. of C files, not Pascal units) in the current directory (default).
--disable-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.
--init-modules
Initialize the named modules in addition to those imported regularly; kind of a kludge.
--cidefine
Define a case-insensitive macro.
--csdefine
Define a case-sensitive macro.
--big-endian
Tell GPC that the system is big-endian (for those targets where it can vary).
--little-endian
Tell GPC that the system is little-endian (for those targets where it can vary).
--print-needed-options
Print the needed options.
-Wwarnings
Enable warnings (same as `{$W+}').
-Wno-warnings
Disable all warnings (same as `{$W-}').
-Widentifier-case-local
Warn about an identifier written with varying case within one program/module/unit.
-Wno-identifier-case-local
Same as `-Wno-identifier-case'.
-Widentifier-case
Warn about an identifier written with varying case.
-Wno-identifier-case
Do not warn about an identifier written with varying case (default).
-Winterface-file-name
Warn when a unit/module interface differs from the file name.
-Wno-interface-file-name
Do not warn when a unit/module interface differs from the file name (default).
--methods-always-virtual
Make all methods virtual (default in `--mac-pascal').
--no-methods-always-virtual
Do not make all methods virtual (default).
--objects-are-references
Turn objects into references (default in `--mac-pascal').
--no-objects-are-references
Do not turn objects into references (default).
--objects-require-override
Require override directive for objects (default in `--mac-pascal').
--no-objects-require-override
Do not require override directive for objects (default).
--delphi-method-shadowing
Redefining methods silently shadows old definition (default in `--delphi').
--no-delphi-method-shadowing
Do not silently shadow method definitions (default).
--borland-objects
Choose Borland object model.
--mac-objects
Choose Mac object model.
--ooe-objects
Choose OOE object model.
--gnu-objects
Reset object model to default state.
--preprocessed
Treat the input file as already preprocessed.
-nostdinc
Do not search standard system.
-remap
Remap file names when including files.
-A
Ignored.
-E
Preprocess only.
-H
Print the name of include files as they are used.
-P
Do not generate #line directives.
-Wimplicit-abstract
Warn when an object type not declared `abstract' contains an abstract method (default).
-Wno-implicit-abstract
Do not warn when an object type not `declared' abstract contains an abstract method.
-Winherited-abstract
Warn when an abstract object type inherits from a non-abstract one (default).
-Wno-inherited-abstract
Do not warn when an abstract object type inherits from a non-abstract one.
-Wobject-assignment
Warn when when assigning objects or declaring them as value parameters or function results (default).
-Wno-object-assignment
Do not warn when assigning objects or declaring them as value parameters or function results (default in `--borland-pascal').
-Wimplicit-io
Warn when `Input' or `Output' are used implicitly.
-Wno-implicit-io
Do not warn when `Input' or `Output' are used implicitly (default).
-Wfloat-equal
Warn about `=' and `<>' comparisons of real numbers.
-Wno-float-equal
Do not warn about `=' and `<>' comparisons of real numbers.
-Wtyped-const
Warn about misuse of typed constants as initialized variables (default).
-Wno-typed-const
Do not warn about misuse 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.
-Wunderscore
Warn about double/leading/trailing underscores in identifiers.
-Wno-underscore
Do not warn about double/leading/trailing underscores in identifiers.
-Wsemicolon
Warn about a semicolon after `then', `else' or `do' (default).
-Wno-semicolon
Do not warn about a semicolon after `then', `else' or `do'.
-Wlocal-external
Warn about local `external' declarations.
-Wno-local-external
Do not warn about local `external' declarations.
-Wdynamic-arrays
Warn about arrays whose size is determined at run time (including array slices).
-Wno-dynamic-arrays
Do not warn about arrays whose size is determined at run time (including array slices).
-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.
--classic-pascal-level-0
Reject conformant arrays and anything besides ISO 7185 Pascal.
--standard-pascal-level-0
Synonym for `--classic-pascal-level-0'.
--classic-pascal
Reject anything besides ISO 7185 Pascal.
--standard-pascal
Synonym for `--classic-pascal'.
--extended-pascal
Reject anything besides ISO 10206 Extended Pascal.
--object-pascal
Reject anything besides (the implemented parts of) ANSI draft Object Pascal.
--ucsd-pascal
Try to emulate UCSD 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.
--vax-pascal
Support (a few features of) VAX Pascal.
--sun-pascal
Support (a few features of) Sun Pascal.
--mac-pascal
Support (some features of) traditional Macintosh Pascal compilers.
--gnu-pascal
Undo the effect of previous dialect options, allow all features again.


Previous: GPC Command Line Options, Up: Invoking GPC

5.2 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 Cygwin, both a.out and 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 compiled units (GPI and object files) into the directory dir. The default is the current directory.
--object-destination-path=dir
Place compiled object files (e.g., from C files, but not from Pascal units) 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 Options to Request or Suppress Warnings), while `-Wall' only warns about such constructs that should be easy to avoid in programs. Therefore, we suggest using `-Wall' on most sources.

Note that some warnings (e.g., those about using uninitialized variables) are never given unless you compile with optimization (see above), because otherwise the compiler doesn't analyze the usage patterns of variables.

-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[=def]
Define the macro and conditional symbol macro as def (or as `1' if def 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.
--classic-pascal-level-0
--classic-pascal
--extended-pascal
--object-pascal
--ucsd-pascal
--borland-pascal
--delphi
--pascal-sc
--mac-pascal
GNU Pascal supports the features of several different Pascal standards and dialects. The intention is to have common language, where features off all dialects are available. As result, the defualt language is the biggest dialect, with most features. Sometimies features of different dialect conflict (in such cases we usually provide more detailed switches to choose desired behaviour). These switches turn on maximal compatiblity with given dialect. In particular they tell GPC to restrict itself to the features of the specified standard. Warnings about certain dangerous constructs which would be valid in the specified dialect (e.g., assignment to a typed constant with `--borland-pascal') are suppressed.

By default, GNU Pascal allows the redefinition of some keywords. Each of these switches causes GNU Pascal to forbid the redefinition of keywords of the specified standard.

Most ISO 7185 Pascal programs should compile properly with or without `--classic-pascal'. However, without this option, some constructs behave in non-standard way. Moreover, 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. (This option should preferably be used as a compiler directive in the unit or module which links to that strange C library, rather than be given on the command-line.)


Next: , Previous: Invoking GPC, Up: Top

6 The Programmer's Guide to GPC

This chapter is still under development.

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 Invoking GPC.


Next: , Up: Programming

6.1 Source Structures

A source file accepted by GNU Pascal may contain up to one program, zero or more ISO-style modules, and/or zero or more UCSD-style units. Units and modules can be mixed in one project.

One trivial example for a valid GPC source file follows. Note that the 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.


Next: , Up: Source Structures

6.1.1 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 uses, import.)

The declaration_part consists of label, constant, type, variable or subroutine declarations in free order. However, every identifier must be declared before it is used. The only exception are type identifiers pointing to another type identifier which may be declared below.

The statement_part consists of a sequence of statements.

As an extension, GPC supports a “declaring statement” which can be used in the statement part to declare variables (see var).


Next: , Previous: The Program, Up: Source Structures

6.1.2 Label Declaration

A label declaration has the following look:

     label
       label_name, ..., label;

A label declaration part starts with the reserved word label, which contains a list of labels.

See also

label, goto


Next: , Previous: Label Declaration, Up: Source Structures

6.1.3 Constant Declaration

A constant declaration has the following look:

     const
       constant_identifier = constant_expression;
       ...
       constant_identifier = constant_expression;

A constant declaration part starts with the reserved word const. It declares a constant_identifier which is defined by constant_expression. This expression has to be evaluatable during compilation time, i.e. it can include numbers, parentheses, predefined operators, sets and type casts (the last, however, is a Borland extension). In ISO 7185 Pascal, constant_expression must be a constant or a set. All Pascal Dialects but ISO-Pascal allow the use of these intrinsic functions in constant_expression:

Abs, Round, Trunc, Chr, Ord, Length, Pred, Succ, SizeOf, Odd.

In Borland Pascal, in the constant declaration part variables can be declared as well, which are given an initial value. These variables are called “typed constants”. It is good style to avoid this use, especially since Extended Pascal and GNU Pascal allow to initialize a variable in variable declaration part or give a type a preset value on declaration.

     const
       FiveFoo      = 5;
       StringFoo    = 'string constant';
       AlphabetSize = Ord ('Z') - Ord ('A') + 1;
     
     type
       PInteger     = ^Integer;     { Define a pointer to an Integer }
     
     const
       { Constant which holds a pointer to an Integer at address 1234 }
       AddressFoo   = PInteger (1234);

See also

Subroutine Parameter List Declaration


Next: , Previous: Constant Declaration, Up: Source Structures

6.1.4 Type Declaration

A type declaration looks like this:

     type
       type_identifier = type_definition;
       ...
       type_identifier = type_definition;

or, with preset content:

     type
       type_identifier = type_definition value constant_expression;
       ...
       type_identifier = type_definition value constant_expression;

A type declaration part begins with the reserved word type. It declares a type_identifier which is defined by type_definition. A type definition either can be an array, a record, a schema, a set, an object, a subrange, an enumerated type, a pointer to another type_identifier or simply another type_identifier which is to alias. If a schema type is to be declared, type_identifier is followed by a discriminant enclosed in parentheses:

     type_identifier (discriminant) = schema_type_definition;

If value is specified, followed by a constant satisfying the type definition, every variable of this type is initialized with constant_expression, unless it is initialized by value itself. The reserved word value can be replaced by `=', however value is not allowed in ISO-Pascal and Borland Pascal, and the replacement by `=' is not allowed in Extended Pascal.

Type declaration example

     type
       { This side is the }     { That side is the }
       { type declaration }     { type definition  }
     
       Arrayfoo            = array [0 .. 9] of Integer;  { array definition }
       Recordfoo           = record                      { record definition }
                               Bar: Integer;
                             end;
     
            { schema def with discriminants ``x, y: Integer'' }
       SchemaFoo (x, y: Integer) = array [x .. y] of Integer;
       CharSetFoo          = set of Char;              { Def of a set }
       ObjectFoo           = object                    { Def of an object }
                               procedure DoAction;
                               constructor Init;
                               destructor Done;
                             end;
       SubrangeFoo         = -123..456;                { subrange def }
     
       EnumeratedFoo       = (Pope,John,the,Second);   { enum type def }
            { Def of a pointer to another type identifier }
       PInteger            = ^arrayfoo;
            { Def of an alias name for another type identifier }
       IdentityFoo         = Integer;
            { Def of an integer which was initialized by 123 }
       InitializedFoo      = Integer value 123;

See also

Type Definition, Data Types, Variable Declaration


Next: , Previous: Type Declaration, Up: Source Structures

6.1.5 Variable Declaration

A variable declaration looks like this:

     var
       var_identifier: type_identifier;
       ...
       var_identifier: type_identifier;

or

     var
       var_identifier: type_definition;
       ...
       var_identifier: type_definition;

and with initializing value:

     var
       var_identifier: type_identifier value constant_expression;
       ...
       var_identifier: type_identifier value constant_expression;

or

     var
       var_identifier: type_definition value constant_expression;
       ...
       var_identifier: type_definition value constant_expression;

A variable declaration part begins with the reserved word var. It declares a var_identifier whose type either can be specified by a type identifier, or by a type definion which either can be an array, a record, a set, a subrange, an enumerated type or a pointer to an type identifier. If value is specified followed by a constant expression satisfying the specified type, the variable declared is initialized with constant_expression. The reserved word value can be replaced by `=', however value is not allowed in ISO-Pascal and Borland Pascal, and the replacement by `=' is not allowed in Extended Pascal.

See also

Type Definition, Type Declaration, Data Types, The Declaring Statement, Subroutine Parameter List Declaration


Next: , Previous: Variable Declaration, Up: Source Structures

6.1.6 Subroutine Declaration


Next: , Up: Subroutine Declaration
6.1.6.1 The Procedure

     procedure procedure_identifier;
     declaration_part
     begin
       statement_part
     end;

or with a parameter list:

     procedure procedure_identifier (parameter_list);
     declaration_part
     begin
       statement_part
     end;

A procedure is quite like a sub-program: The declaration_part consists of label, constant, type, variable or subroutine declarations in free order. The statement_part consists of a sequence of statements. If parameter_list is specified, parameters can be passed to the procedure and can be used in statement_part. A recursive procedure call is allowed.

See also

The Function, Subroutine Parameter List Declaration


Next: , Previous: The Procedure, Up: Subroutine Declaration
6.1.6.2 The Function

     function function_identifier: function_result_type;
     declaration_part
     begin
       statement_part
     end;

or with a parameter list:

     function function_identifier (parameter_list): result_type;
     declaration_part
     begin
       statement_part
     end;

A function is a subroutine which has a return value of type function_result_type. It is structured like the program: the declaration_part consists of label, constant, type, variable or subroutine declarations in free order. The statement_part consists of a sequence of statements. If parameter_list is specified, parameters can be passed to the function and can be used in statement_part. The result is set via an assignment:

     function_identifier := expression

Recursive function calls are allowed. Concerning the result type, ISO 7185 Pascal and Borland Pascal only allow the intrinsic types, subranges, enumerated types and pointer types to be returned. In Extended Pascal, function_result_type can be every assignable type. Of course, there are no type restrictions in GNU Pascal as well. If extended syntax is switched on, functions can be called like procedures via procedure call statement.

See also

The Procedure, Subroutine Parameter List Declaration, Data Types


Next: , Previous: The Function, Up: Subroutine Declaration
6.1.6.3 The Operator

GNU Pascal allows to define operators which can be used the infix style in expressions. For a more detailed description, see Operators


Previous: The Operator, Up: Subroutine Declaration
6.1.6.4 Subroutine Parameter List Declaration

     parameter; ...; parameter

Each parameter can start with a prefix (see below) describing how the parameters are passed, followed by a comma seperated list of one or more parameter_identifiers and an optional parameter_type.

     procedure DoIt (var x, y, z: OneType; a, b: AnotherType; var q);

To understand parameter passing, first some definitions.

actual parameter
the parameter passed in to the routine.
formal parameter
the parameter as used inside the procedure.
by value
the value of the actual parameter is copied on to the stack.
by reference
the address of the actual parameter is copied on to the stack.
L-value
(left hand of a `:=' statement) something that can be assigned to (not a constant, or const or protected variable or other immutable item).
R-value
(right hand of a `:=' statement) anything you can get the value of (could be a constant, an expression, a variable (whether const or protected or not) or just about anything.
addressable
something you can get the address of (not a field of a packed structure or a variable with `attribute (register)' (GPC extension)).
aliasing
accessing memory via two different names (e.g. a global variable passed by reference to a procedure can be accessed either as the global variable or the formal paramater). Generally this is very bad practice.

Technical note: Parameters are not always passed on the stack, they may also be passed in registers, especially on RISC machines.

The prefix defines how a variable is passed on the stack and how you can access the formal_parameter inside the procedure. The prefix can be one of:

nothing
          procedure DoIt (x: SomeType);
     

Technical: The actual parameter is passed by value or reference, but if passed by reference, it is then copied to a local copy on the stack. Aliasing has no effect on x.

What it means: you can modify `x' inside the routine, but your changes will not affect the actual parameter (and vice versa). The actual parameter can be a constant or other immutable object, or a protected or const variable.

protected
          procedure DoIt (protected x: SomeType);
     

Technical: The actual parameter is passed by value or reference, but if passed by reference, it is then copied to a local copy on the stack. Aliasing has no effect on x. protected is a Extended Pascal extension.

What it means: if you modify the actual parameter, this will not affect `x' inside the routine. The actual parameter can be a constant or other immutable object, or a protected or const variable. You are forbidden from modifying x inside the routine.

var
          procedure DoIt (var x: SomeType);
     

Technical: The actual parameter is passed by reference. Aliasing will definitely change `x'.

What it means: modifications to `x' inside the routine will change the actual parameter passed in. The actual parameter must be an addressable L-value (ie, it must be something you can take the address of and assign to).

A parameter of this kind is called variable parameter and internally corresponds to an L-value pointer (to the specified type identifier if any). This declaration is necessary if the parameter is to be modified within the routine and to hold its value still after return.

const
          procedure DoIt (const x: SomeType);
     

Technical: The actual parameter is passed by value or reference. The compiler will make a copy of the actual parameter to have something it can address if the actual parameter is not addressable. You are forbidden from modifying `x' inside the routine, and therefore you cannot modify the actual parameter. Aliasing may or may not change `x'. const is a Borland Pascal extension.

What it means: You can pass any R-value. You cannot modify `x' inside the routine. If you change the actual parameter while inside the routine, `x' will have an undefined value.

protected var
          procedure DoIt (protected var x: SomeType);
     

Technical: The actual parameter is passed by reference. The compiler will never make a copy of the actual parameter. You are forbidden from modifying `x' inside the routine, and therefore you cannot modify the actual parameter. Aliasing will definitely change `x'.

What it means: You can pass anything addressable. You cannot modify `x' inside the routine. If you change the actual parameter while inside the routine, `x' will change as well.

In GPC, the protected var mode guarantees that the parameter is always passed by reference, making it the correct choice for calling C routines with `const' pointer parameters.

If you omit the formal parameter type specification, then any type may be passed to that parameter. Generally this is a bad idea, but occasionally it can be useful, especially for low level code.

As an Extended Pascal extension, you can also declare procedural parameters directly:

     procedure parameter_identifier

or:

     function parameter_identifier: parameter_identifier_result_type

Example for parameter lists:

     program ParameterDemo;
     
     procedure Foo (var Bar; var Baz: Integer; const Fred: Integer);
     
       procedure Glork1 (function Foo: Integer; procedure Bar (Baz: Integer));
       begin
         Bar (Foo)
       end;
     
     begin
       Baz := Integer (Bar) + Fred
     end;
     
     var
       a, b, c: Integer;
     
     begin
       Foo (a, b, c)
     end.

See also

Data Types, var, const, protected


Next: , Previous: Subroutine Declaration, Up: Source Structures

6.1.7 Statements


Next: , Up: Statements
6.1.7.1 Assignment

The way an assignment looks like:

     L-value := expression;

This statement assigns any valid expression to L-value. Make sure that the result of expression is compatible with L-value, otherwise an compilation error is reported. The `:=' is called assignment operator. As long as L-value and expression are type compatible, they are assignment compatible for any definable type as well.


Next: , Previous: Assignment, Up: Statements
6.1.7.2 begin end Compound Statement

It looks like that:

     begin
       statement;
       statement;
       ...
       statement
     end

This statement joins several statements together into one compound statement which is treated as a single statement by the compiler. The finishing semicolon before `end' can be left out.


Next: , Previous: begin end Compound Statement, Up: Statements
6.1.7.3 if Statement

This statement has the following look:

     if boolean_expression then
       statement

or with an alternative statement:

     if boolean_expression then
       statement1
     else
       statement2

The `if' ... `then' statement consists of a boolean expression and a statement, which is conditionally executed if the evaluation of boolean_expression yields true.

If `if' ... `then' ... `else' is concerned, statement1 is executed depending on boolean_expression being true, otherwise statement2 is executed alternatively. Note: the statement before else must not finish with a semicolon.


Next: , Previous: if Statement, Up: Statements
6.1.7.4 case Statement

     case expression of
       selector: statement;
       ...
       selector: statement;
     end

or, with alternative statement sequence:

     case ordinal_expression of
       selector: statement;
       ...
       selector: statement;
     otherwise                   { ``else'' instead of ``otherwise'' allowed }
       statement;
       ...
       statement;
     end

or, as part of the invariant record type definition:

     type
       foo = record
         field_declarations
       case bar: variant_type of
         selector: (field_declarations);
         selector: (field_declarations);
         ...
       end;

or, without a variant selector field,

     type
       foo = record
         field_declarations
       case variant_type of
         selector: (field_declarations);
         selector: (field_declarations);
         ...
       end;

The case statement compares the value of ordinal_expression to each selector, which can be a constant, a subrange, or a list of them separated by commas, being compatible with the result of ordinal_expression. Note: duplicate selectors or range crossing is not allowed unless {$borland-pascal} is specified. In case of equality the corresponding statement is executed. If otherwise is specified and no appropriate selector matched the expression, the series of statements following otherwise is executed. As a synonym for otherwise, else can be used. The semicolon before otherwise is optional.

@@ ???? The expression must match one of the selectors in order to continue, unless an alternative statement series is specified.

For case in a variant record type definition, see Record Types.

See also

if Statement


Next: , Previous: case Statement, Up: Statements
6.1.7.5 for Statement

For ordinal index variables:

     for ordinal_variable := initial_value to final_value do
       statement

or

     for ordinal_variable := initial_value downto final_value do
       statement

For sets:

     for set_element_type_variable in some_set do
       statement

For pointer index variables:

     for pointer_variable := initial_address to final_address do
       statement

or

     for pointer_variable := initial_address downto final_address do
       statement

The for statement is a control statement where an index variable assumes every value of a certain range and for every value the index variable assumes statement is executed. The range can be specified by two bounds (which must be of the same type as the index variable, i.e. ordinal or pointers) or by a set.

For ordinal index variables:

For pointer index variables:

Since gpc provides a flat memory modell, all addresses are linear, so they can be compared. Still, such loops should be used (if at all) only for iterating through successive elements of an array.

For sets:

Please note: A modification of the index variable may result in unpredictable action.

See also

Set Types, Pointer Arithmetics, repeat Statement, for Statement


Next: , Previous: for Statement, Up: Statements
6.1.7.6 while Statement

The while loop has the following form

     while boolean_expression do
       statement

The while statement declares a loop which is executed while boolean_expression is true. Since the terminating condition is checked before execution of the loop body, statement may never be executed.

See also

repeat Statement, for Statement


Next: , Previous: while Statement, Up: Statements
6.1.7.7 repeat Statement

     repeat
       statement;
       ...
       statement;
     until boolean_expression

The repeat ... until statement declares a loop which is repeated until boolean_expression is true. Since the terminating condition is checked after execution of the loop body, the statement sequence is executed at least once.

See also

while Statement, for Statement


Next: , Previous: repeat Statement, Up: Statements
6.1.7.8 asm Inline

@@ ????

     asm (StatementList: String);

The asm inline statement is a GNU Pascal extension. It requires its parameter to be AT&T-noted assembler statements, and therefore it is not compatible with that one of Borland Pascal. statementlist is a string containing asm statements separated by semicolons.


Next: , Previous: asm Inline, Up: Statements
6.1.7.9 with Statement


Next: , Previous: with Statement, Up: Statements
6.1.7.10 goto Statement

@@ ???? This statement looks like this:

     goto label

(Under construction.)


Next: , Previous: goto Statement, Up: Statements
6.1.7.11 Procedure Call

     subroutine_name;

This statement calls the subroutine subroutine_name which can either be a procedure or, if GNU extended syntax is turned on, a function. In this case, the result is ignored.


Next: , Previous: Procedure Call, Up: Statements
6.1.7.12 The Declaring Statement

This statement allows to declare a variable within a statement part. It looks like this:

     var
       var_identifier: type_identifier;

or

     var
       var_identifier: type_definition;

and with initializing value:

     var
       var_identifier: type_identifier value expression;

or

     var
       var_identifier: type_definition value expression;

Unlike in declaration parts, the initializing expression does not have to be a constant expression. Note that every declaring statement has to start with var. The name space of the variable extends from its declaration to the end of the current matching statement sequence (which can be a statement part (of the program, a function, a procedure or an operator) or, within that part, a begin end compound statement, a repeat loop, or the else branch of a case statement). This statement is a GNU Pascal extension.

See also

Type Definition, Data Types


Previous: The Declaring Statement, Up: Statements
6.1.7.13 Loop Control Statements

These are

     Continue;

and

     Break;

These simple statements must not occur outside a loop, i.e. a `for', `while' or `repeat' statement. `Continue' transfers control to the beginning of the loop right by its call, `Break' exits the current loop turn and continues loop execution.


Previous: Statements, Up: Source Structures

6.1.8 Import Part and Module/Unit Concept


Next: , Up: Modules and Units
6.1.8.1 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 result 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. Please 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 the following example. They do not have an export part, do not have a separate module-block, do not use import/export features.

Instead, you have to emulate the exporting/importing yourself using `attribute' and `external name'.

     module DemoMod3;
     
     type
       FooType = Integer;
     
     var
       Foo: FooType;
     
     procedure SetFoo (f: FooType); attribute (name = 'SetFoo');
     begin
       Foo := f
     end;
     
     function GetFoo: FooType; attribute (name = 'GetFoo');
     begin
       GetFoo := Foo;
     end;
     
     end.
     program ModDemo3 (Output);
     
     {$L demomod3.pas}  { explicitly link module }
     
     { Manually do the "import" from DemoMod3 }
     type
       FooType = Integer;
     
     procedure SetFoo (f: FooType); external name 'SetFoo';
     function  GetFoo: FooType;     external name 'GetFoo';
     
     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.


Previous: Modules, Up: Modules and Units
6.1.8.2 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 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 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 results 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 to begin do, to end do.

Note that GPC does not yet check whether all interface declarations are resolved in the same unit. The implementation of 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. However, relying on a GPC bug (that will eventually be fixed) is not a good idea, so this is not recommended. Instead, declare such routines as `external'.

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.


Next: , Previous: Source Structures, Up: Programming

6.2 Data Types


Next: , Up: Data Types

6.2.1 Type Definition

As described in Type Declaration, a type declaration part looks like this:

     type
        type_identifier = type_definition;
        ...
        type_identifier = type_definition;

where the left side is the type declaration and the right one the type definition side. GNU Pascal offers various possibilities to implement highly specialized and problem-specific data types.


Next: , Previous: Type Definition, Up: Data Types

6.2.2 Ordinal Types

An ordinal type is one that can be mapped to a range of whole numbers. It includes integer types, character types, enumerated types and subrange types of them.

A character type is represented by the intrinsic type `Char' which can hold elements of the operating system's character set (usually ASCII). Conversion between character types and integer types is possible with the intrinsic functions Ord and Chr.

An enumerated type defines a range of elements which are referred to by identifiers. Conversion from enumerated types to integer types is possible with the intrinsic function Ord. Conversion from integer to ordinal types is only possible by type-casting or using the extended form of `Succ'.

     var
       Foo: Char;       { foo can hold a character }
       Num: '0' .. '9'; { Can hold decimal digits, is a subrange type of Char }
       Day: (Monday, Tuesday, Wednesday, Thursday,
             Friday, Saturday, Sunday);  { Can hold weekdays }

See also

Ord, Chr, Type Casts


Next: , Previous: Ordinal Types, Up: Data Types

6.2.3 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 Pascal 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: Subrange Types.


Next: , Up: Integer Types
6.2.3.1 The CPU'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 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 Cardinal, Word).

These natural integer types should be your first choice for best performance. For instance on an IA32 CPU operations with `Integer' usually work faster than operations with shorter integer types like `ShortInt' or `ByteInt' (see below).


Next: , Previous: Natural Integer Types, Up: Integer Types
6.2.3.2 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 types (plus one Boolean type) are guaranteed to be compatible to the respective types of GNU C as listed below (whereas `Integer', `Cardinal' and `Word' themselves are not guaranteed to be compatible to any given C type). The sizes given, however, are not guaranteed. They are just typical values currently used on some platforms, but they may be actually shorter or longer on any given platform.

signed unsigned also unsigned GNU C equivalent size in bits (example)
ByteInt ByteCard Byte [un]signed char 8
ShortInt ShortCard ShortWord [unsigned] short int 16
CInteger CCardinal CWord [unsigned] int 32
MedInt MedCard MedWord [unsigned] long int 32
LongInt LongCard LongWord [unsigned] long long int 64
SizeType size_t 32
PtrDiffType ptrdiff_t 32
PtrInt PtrCard PtrWord 32
CBoolean _Bool, bool 8

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


Next: , Previous: Main Branch Integer Types, Up: Integer Types
6.2.3.3 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 type attributes (see attribute). The type

     Integer attribute (Size = 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 attribute (Size = 32)', not just `Integer' which might be bigger. The same works with unsigned integer types such as `Cardinal' and `Word' and with Boolean types.

This way, you can't get a higher precision than that of `LongestInt' or `LongestCard' (see Main Branch Integer Types). If you need higher precision, you can look at the `GMP' unit (see GMP) which provides integer types with arbitrary precision, but their usage is different from normal integer types.


Next: , Previous: Integer Types with Specified Size, Up: Integer Types
6.2.3.4 Integer Types and Compatibility

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 IA32 platform.

On the other hand, to increase compatibility to Borland Pascal and Delphi, GPC provides the alias name `Comp' for `LongInt' (64 bits on IA32) and `SmallInt' for `ShortInt' (16 bits on IA32). Note that BP treats `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.


Previous: Integer Types and Compatibility, Up: Integer Types
6.2.3.5 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.

ByteInt
signed 8-bit integer type, `-128..128',
compatible to `signed char' in GNU C.
Byte
unsigned 8-bit integer type, `0..255',
compatible to `unsigned char' in GNU C.
ShortInt
signed 16-bit integer type, `-32768..32767',
compatible to `short int' in GNU C.
ShortWord
unsigned 16-bit integer type, `0..65535',
compatible to `unsigned short int' in GNU C.
Integer
signed 32-bit integer type, `-2147483648..2147483647',
compatible to `int' in GNU C.
Word
unsigned 32-bit integer type, `0..4294967295',
compatible to `unsigned int' in GNU C.
MedInt
signed 32-bit integer type, `-2147483648..2147483647',
compatible to `long int' in GNU C.
MedWord
unsigned 32-bit integer type, `0..4294967295',
compatible to `unsigned long int' in GNU C.
LongInt
signed 64-bit integer type, `-9223372036854775808..9223372036854775807',
compatible to `long long int' in GNU C.
LongWord
unsigned 64-bit integer type, `0..18446744073709551615',
compatible to `unsigned long long int' in GNU C.
LongestInt
signed 64-bit integer type, `-9223372036854775808..9223372036854775807'.
LongestWord
unsigned 64-bit integer type, `0..18446744073709551615'.
Comp
signed 64-bit integer type, `-9223372036854775808..9223372036854775807'.
SmallInt
signed 16-bit integer type, `-32768..32767'.
SizeType
integer type (usually unsigned) to represent the size of objects in memory
PtrDiffType
signed integer type to represent the difference between two positions in memory
PtrInt
signed integer type of the same size as a pointer
PtrWord
unsigned integer type of the same size as a pointer

To specify the number of bits definitely, use type attributes, attribute.

     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: Subrange Types.


Next: , Previous: Integer Types, Up: Data Types

6.2.4 Built-in Real (Floating Point) Types

GPC has three built-in floating point types to represent real numbers. Each of them is available under two names (for compatibility to other compilers and languages).

For most purposes, you will always use `Real' which is the only one of them that is part of Standard and Extended Pascal. If memory constraints apply, you might want to choose `ShortReal' for larger arrays. On the other hand, if high precision is needed, you can use `LongReal'. When interfacing with libraries written in other languages such as C, you will need the equivalents for their real types.

Note that not all machines support longer floating point types, so `LongReal' is the same as `Real' on these machines. Also, some machines may support a longer type, but not do all arithmetic operations (e.g. the `Sin' function, Sin) in a precision higher than that of `Real'. If you need higher precision, you can look at the `GMP' unit (see GMP) which provides rational and real numbers with arbitrary precision, but their usage is different from normal real types.

The following real types are guaranteed to be compatible to the real types of GNU C. The sizes given, however, are not guaranteed. They are just typical values used on any IEEE compatible floating point hardware, but they may be different on some machines.

type name alternative name GNU C equivalent size in bits (typically)
ShortReal Single float 32
Real Double double 64
LongReal Extended long double 80


Next: , Previous: Real Types, Up: Data Types

6.2.5 Strings Types

There are several ways to use strings in GNU Pascal. One of them is the use of the intrinsic string type `String' which is a predefined schema type. The schema discriminant of this type holds the maximal length, which is of type Integer, so values up to MaxInt can be specified. For `String', an assignment is defined. There are many built-in functions and procedures for comfortable strings handling.

@@ ???? String procedures and functions.

Another way to use strings is to use arrays of type `Char'. For these, an intrinsic assignment is defined as well. Besides, `String' and `Char' are assignment compatible. The preferred way, however, is `String' because of the numerous possibilities for string handling.


Next: , Previous: String Types, Up: Data Types

6.2.6 Character Types

Character types are a special case of ordinal types.

See also

Ordinal Types, Chr, Ord, Pred, Succ.


Next: , Previous: Character Types, Up: Data Types

6.2.7 Enumerated Types

     type
       enum_type_identifier = (identifier, ..., identifier);

An enumerated type is a a special case of ordinal types and defines a range of elements which are referred to by identifiers. Enumerated types are ordered by occurence in the identifier list. So, they can be used as index types in an array definition, and it is possible to define subranges of them. Since they are ordered, they can be compared to one another. The intrinsic function Ord applied to name_identifier returns the number of occurence in the identifier list (beginning with zero), Pred and Succ return the predecessor and successor of name_identifier. `Boolean' is a special case of an enumerated type.

See also

Ordinal Types, Array Types, Subrange Types, Ord, Boolean, Char, Pred, Succ.


Next: , Previous: Enumerated Types, Up: Data Types

6.2.8 File Types

Files are used to store data permanently, normally on hard drives or floppies. There are tree types of files available: text files, typed and untyped files.

Text files are used to store text in them, where typed files are used to store many entries of the same type in them, e.g. addresses. Text files and typed files are accessible by `Read' and `Write' operations and do not need the parameter `BlockSize' in `Reset' or `Rewrite'. On the other hand, untyped files are used to store any type of information in them but you need to use `BlockWrite' or `BlockRead' to store or retrieve data out of this file.

     var
       F1: Text;   { a textfile }
       F2: file of Real;   { a typed filed used to store real values in it }
       F3: File;   { an untyped file }

See also

File Routines, Write, Read, BlockRead, BlockWrite, Reset, Rewrite


Next: , Previous: File Types, Up: Data Types

6.2.9 Boolean (Intrinsic)

The intrinsic Boolean represents boolean values, i.e. it can only assume true and false (which are predefined constants). This type corresponds to the enumerated type

     type
       Boolean = (False, True);

Since it is declared this way, it follows:

     Ord (False) = 0
     Ord (True) = 1
     False < True

There are four intrinsic logical operators. The logical and, or and not. In Borland Pascal and GNU Pascal, there is a logical “exclusive or” xor.

See also

Enumerated Types, and, or, not, xor


Next: , Previous: Boolean (Intrinsic), Up: Data Types

6.2.10 Pointer (Intrinsic)

The intrinsic Pointer Type is a so-called unspecified or typeless pointer (i.e. a pointer which does not point to any type but holds simply a memory address).

See also

Pointer Types, nil


Next: , Previous: Pointer (Intrinsic), Up: Data Types

6.2.11 Type Definition Possibilities


Next: , Up: Type Definition Possibilities
6.2.11.1 Subrange Types

GNU Pascal supports Standard Pascal's subrange types:

     program SubrangeDemo;
     type
       MonthInt = 1 .. 12;
       Capital = 'A' .. 'Z';
       ControlChar = ^A .. ^Z;  { `^A' = `Chr (1)' is a BP extension }
     begin
     end.

Also possible: Subranges of enumerated types:

     program EnumSubrangeDemo;
     type
       { This is an enumerated type. }
       Days = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
     
       { This is a subrange of `Days'. }
       Working = Mon .. Fri;
     
     begin
     end.

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 IA32 CPU.

For the case you want to save storage at the expense of speed, GPC provides a `packed' variant of these as an extension:

     program PackedSubrangeDemo;
     type
       MonthInt = packed 1 .. 12;
     begin
     end.

A variable of this type occupies the shortest possible (i.e., addressable) space in memory – one byte on an IA32 compatible CPU.

See also: packed.


Next: , Previous: Subrange Types, Up: Type Definition Possibilities
6.2.11.2 Array Types

     type
       array_type_identifier = array [index_type] of element_type

or

     type
       array_type_identifier = array [index_type, ..., index_type] of element_type

The reserved word array defines an array type. index_type has to be an ordinal type, subrange type or an enumerated type, where several index types, separated by commas, are allowed. element_type is an arbitrary type. An element of an array is accessed by array_type_variable [index_number]. The upper and lower index bounds can be determined by the intrinsic functions High and Low.

     type
       IntArray = array [1 .. 20] of Integer;
       Foo      = array [(Mo, Tu, We, Th, Fr, Sa, Su)] of Char;
       Bar      = array [0 .. 9, 'a' .. 'z', (Qux, Glork1, Fred)] of Real;
       Baz1     = array [1 .. 10] of IntArray;
       { equal (but declared differently): }
       Baz2     = array [1 .. 10, 1 .. 20] of Integer;

See also

High, Low


Next: , Previous: Array Types, Up: Type Definition Possibilities
6.2.11.3 Record Types

     type
       record_type_identifier = record
         field_identifier: type_definition;
         ...
         field_identifier: type_definition;
       end;

or, with a variant part,

     type
       record_type_identifier = record
         field_identifier: type_definition;
         ...
         field_identifier: type_definition;
       case bar: variant_type of
         selector: (field_declarations);
         selector: (field_declarations);
         ...
       end;

or, without a variant selector field,

     type
       record_type_identifier = record
         field_identifier: type_definition;
         ...
         field_identifier: type_definition;
       case variant_type of
         selector: (field_declarations);
         selector: (field_declarations);
         ...
       end;

The reserved word record defines a structure of fields. Records can be `packed' to save memory usage at the expense of speed.

The reserved word `record' and record types are defined in ISO 7185 Pascal. According to ISO Pascal, the variant type must be an identifier. GNU Pascal, like UCSD and Borland Pascal, also allows a subrange here.

A record field is accessed by record_type_variable . field_identifier

See also: packed, case Statement.


Next: , Previous: Record Types, Up: Type Definition Possibilities
6.2.11.4 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:

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

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

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


Next: , Previous: Variant Records, Up: Type Definition Possibilities
6.2.11.5 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:

     program Schema1Demo;
     type
       PositiveInteger = 1 .. MaxInt;
       RealArray (n: Integer) = array [1 .. n] of Real;
       Matrix (n, m: PositiveInteger) = array [1 .. n, 1 .. m] of Integer;
     
     var
       Foo: RealArray (42);
     
     begin
       WriteLn (Foo.n)  { yields 42 }
     end.

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:

     program Schema2Demo;
     type
       RealArray (n: Integer) = array [1 .. n] of Real;
       RealArrayPtr = ^RealArray;
     var
       Bar: RealArrayPtr;
     begin
     end.

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:

     program Schema3Demo;
     type
       RealArray (n: Integer) = array [1 .. n] of Real;
       RealArrayPtr = ^RealArray;
     var
       Bar: RealArrayPtr;
       i: Integer;
     begin
       Bar := New (RealArrayPtr, 137);
       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 SchemaWithDemo;
     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 SchemaExoticDemo;
     
     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: 0 .. Capacity;
         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.


Next: , Previous: Schema Types, Up: Type Definition Possibilities
6.2.11.6 Set Types

     set_type_identifier = set of set_element_type;

set_type_identifier is a set of elements from set_element_type which is either an ordinal type, an enumerated type or a subrange type. Set element representatives are joined together into a set by brackets:

     [set_element, ..., set_element]

`[]' indicates the empty set, which is compatible with all set types. Note: Borland Pascal restricts the maximal set size (i.e. the range of the set element type) to 256, GNU Pascal has no such restriction. The number of elements a set variable is holding can be determined by the intrinsic set function Card (which is a GNU Pascal extension, in Extended Pascal and Borland Pascal you can use SizeOf instead but note the element type size in bytes, then) to the set. There are four intrinsic binary set operations: the union `+', the intersection `*' and the difference `-'. The symmetric difference `><' is an Extended Pascal extension.

See also

Card, SizeOf


Next: , Previous: Set Types, Up: Type Definition Possibilities
6.2.11.7 Pointer Types

     pointer_type_identifier = ^type_identifier;

A pointer of the type pointer_type_identifier holds the address at which data of the type type_identifier is situated. Unlike other identifier declarations, where all identifiers in definition part have to be declared before, in a pointer type declaration type_identifier may be declared after pointer_type_identifier. The data pointed to is accessed by `pointer_type_variable^'. To mark an unassigned pointer, the `nil' constant (which stands for “not in list”) has to be assigned to it, which is compatible with all pointer types.

     type
       ItselfFoo = ^ItselfFoo;  { possible but mostly senseless }
     
       PInt      = ^Integer;    { Pointer to an Integer }
     
       PNode     = ^TNode;      { Linked list }
       TNode     = record
         Key     : Integer;
         NextNode: PNode;
       end;
     
     var
       Foo, Bar: PInt;
     
     begin
       Foo := Bar;  { Modify address which foo is holding }
       Foo^ := 5;   { Access data foo is pointing to }
     end.

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

     program ProcPtrDemo (Output);
     
     type
       ProcPtr = ^procedure (i: 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.

See also: Pointer (Intrinsic).


Next: , Previous: Pointer Types, Up: Type Definition Possibilities
6.2.11.8 Procedural and Functional Types

For procedures without a parameter list:

     procedure_type_identifier = procedure name_identifier;

or functions:

     function_type_identifier =
            function name_identifier: function_result_type;

For procedures with a parameter list:

     procedure_type_identifier =
            procedure name_identifier (parameter_list);

or functions:

     function_type_identifier =
            function name_identifier (parameter_list): function_result_type;

Procedural types can be used as procedures or functions respectively, but also a value can be assigned to them. Procedural types are a Borland Pascal extension. In Borland Pascal, function_result_type can only be one of these types: ordinal types, real types, pointer types, the intrinsic `String' type. In GNU Pascal every function result type for procedural types is allowed.

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.

See also: The Procedure, The Function, Subroutine Parameter List Declaration, Procedure Call.


Next: , Previous: Procedural Types, Up: Type Definition Possibilities
6.2.11.9 Object Types

Object types are used to encapsulate data and methods. Furthermore, they implement a mechanism for inheritance.

See also

OOP


Next: , Previous: Object Types, Up: Type Definition Possibilities
6.2.11.10 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.)


Previous: Type Initializers, Up: Type Definition Possibilities
6.2.11.11 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 AccessRestricted (p: UnrestrictedRecord): RestrictedRecord;
     var URes: UnrestrictedRecord;
     begin
       { The parameter is treated as unrestricted, even though the actual
         parameter may be restricted }
       URes.a := p.a;
       { It is allowed to assign a function result }
       AccessRestricted := URes;
     end;
     
     begin
       r1.a := 354;
     
       { Assigning a restricted function result to a restricted variable }
       { @@ Verify if this should really be allowed????? }
       r2 := AccessRestricted (r1);
     
       { Passing a restricted value to unrestricted formal parameter is ok }
       r2 := AccessRestricted (r2);
     
       {$ifdef BUG}
       { *** The following statements are not allowed *** }
       k := r2.a;      { field access (reading) }
       r2.a := 100;    { field access (writing) }
       r1 := r2;       { assignment source is restricted }
       r2 := r1;       { assignment target is restricted }
       r1 := AccessRestricted (r2); { assigning a restricted function
                                      result to an unrestricted object }
       i  := 16#ffff;  { assignment target is restricted }
       k  := i + 2;    { arithmetic with restricted value }
       {$endif}
     end.


Previous: Type Definition Possibilities, Up: Data Types

6.2.12 Machine-dependencies in Types


Next: , Up: Machine-dependencies in Types
6.2.12.1 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 CPU. The most common forms are:

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 CPU 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 CPU 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 CPU's endianness. These routines are described in the RTS reference (see Run Time System), under `endianness'. The demo program endiandemo.pas contains an example on how to use these routines.


Previous: Endianness, Up: Machine-dependencies in Types
6.2.12.2 Alignment

(Under construction.) @@ ????


Next: , Previous: Data Types, Up: Programming

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


Next: , Up: Operators

6.3.1 Built-in Operators

The following table lists all built-in GNU Pascal operators, ordered by precedence: `<' etc. have the lowest precedence, `not' etc. the highest. As usual, the precedence of operators can be superseded with parentheses.

In an assignment statement, `:=' has lower precedence than all operators. (This is rather obvious from the syntax of assignment statements, and is merely noted for programmers familiar with C where `=' is an operator.)

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


Previous: Built-in Operators, Up: Operators

6.3.2 User-defined Operators

GNU Pascal allows the (re-)definition of binary operators according to the Pascal-SC (PXSC) syntax. 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 = (1, 2, 3);
     
     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 result 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.


Next: , Previous: Operators, Up: Programming

6.4 Procedure And Function Parameters


Next: , Up: Parameters

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


Next: , Previous: Protected Parameters, Up: Parameters

6.4.2 The Standard way to pass arrays of variable size

@@ (Under construction.)

A feature of Standard Pascal level 1.


Previous: Conformant Arrays, Up: Parameters

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


Next: , Previous: Pointer Arithmetics, Up: Programming

6.5 Accessing parts of strings (and other arrays)

GPC allows the access of parts (“slices”) of strings as defined in Extended Pascal. For example:

     program StringSliceDemo;
     
     const
       HelloWorld = 'Hello, world!';
     
     begin
       WriteLn (HelloWorld[8 .. 12])  { yields `world' }
     end.

As an extension, it also allows write access to a string slice:

     program SliceWriteDemo;
     
     var
       s: String (42) = 'Hello, world!';
     
     begin
       s[8 .. 12] := 'folks';
       WriteLn (s)  { yields `Hello, folks!' }
     end.

As a further extension, GPC allows slice access also to non-string arrays. However, the usefulness of this feature is rather limited because of Pascal's strict type checking rules: If you have, e.g., an `array [1 .. 10] of Integer' and take a slice `[1 .. 5]' of it, it will not be compatible to another `array [1 .. 5] of Integer' because distinct array types are not compatible in Pascal, even if they look the same.

However, array slice access can be used in connection with conformant or open array parameters. See the program arrayslicedemo.pas (in the demos directory) for an example.


Next: , Previous: Parameters, Up: Programming

6.6 Pointer Arithmetics

GPC allows to increment, decrement, compare, and subtract pointers or to use them in `for' loops just like the C language.

GPC implements the address operator @ (a Borland Pascal extension).

     program PointerArithmeticDemo;
     var
       a: array [1 .. 7] of Char;
       p, q: ^Char;
       i: Integer;
     
     {$X+}  { We need extended syntax for pointer arithmetic }
     
     begin
       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;
     
       p := @a[7];
       q := @a[3];
       i := q - p;    { yields 4 }
     end.

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.


Next: , Previous: String Slice Access, Up: Programming

6.7 Type Casts

In some cases, especially in low-level situations, Pascal's strong typing can be an obstacle. To temporarily circumvent this, GPC defines explicit “type casts” in a Borland Pascal compatible way.

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. Both the value's type and the destination type must be ordinal or pointer types. The ordinal value (extended to pointers to mean the address) is preserved in the cast.

An example:

     program TypeCastDemo;
     
     var
       Ch: Char;
       i: Integer;
     
     begin
       i := Integer (Ch)
     end.

Another, more complicated, example:

     program TypeCst2Demo;
     
     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 }
     
     begin
       Foo1 := CharPtr (Bar);
       Foo2 := CharPtr (Succ (Bar))
     end.

However, because of risks involved with type casts, explained below, and because type-casts are non-standard, 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];

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

Variable type casts

It is also possible to temporarily change the type of a variable (more generally, any “lvalue”, i.e. something whose address can be taken), without converting its contents in any way. This is called variable type casting.

The syntax is the same as for value type casting. 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:

There are cases where a type-cast could be either a value or a variable cast. This is when both types are ordinal or pointer, and of the same size, and the value is an lvalue. Fortunately, in those cases, the results of both forms are the same, since the same ordinal values (or pointer addresses) are represented by the same bit patterns (when of the same size). Therefore, it doesn't matter which form of type-casting is actually used in these cases.

When dealing with objects (see OOP), it is sometimes necessary to cast a polymorphic pointer to an object into a pointer to a more specialized (derived) object (after checking the actual type). However, the `as' operator is a safer approach, so type-casts should be used there only for backward-compatibility (e.g., to BP).

See also: absolute, Alignment, Endianness, OOP, Ord, Chr, Round, Trunc.


Next: , Previous: Type Casts, Up: Programming

6.8 Object-Oriented Programming

GNU Pascal allows multiple object models. The oldest one 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 now we have also partial support of ISO draft (plus the Borland Delphi Object Extensions which are quite similar to the ISO draft). Moreover most of traditional Mac Pascal object model is covered.

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) = s: 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
       z := c;
       inherited bar (z)  { or: FooParent.Bar (z) }
     end;

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)


Next: , Previous: OOP, Up: Programming

6.9 Compiler Directives And The Preprocessor

GPC, like UCSD Pascal 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 of these directives are case-insensitive (but some of them have case-sensitive arguments). Directives are local and can be changed 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 either without special options or 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 the dialect, e.g., with `{$ifopt borland-pascal}'.

In general, almost every GPC specific command line option (see GPC Command Line Options) can be turned into a compiler directive (exceptions are those options that contain directory names, such as `--unit-path', because they refer to the installation on a particular system, and therefore should be set system-wide, rather than in a source file):

     --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-]range-checking  $R+ $R- like in Borland Pascal:
                                    enable/disable range 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 resuls, operator
                                    definitions, `PChar', pointer
                                    arithmetic, ...)
     
     --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
                                    (the name is converted to lower case)
     
     {$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 the preprocessor directives in C style, e.g. `#include', but this is deprecated because of possible confusion 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.


Next: , Previous: Compiler Directives, Up: Programming

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


Next: , Up: Library Routines

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


Next: , Previous: File Routines, Up: Library Routines

6.10.2 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, on most platforms), or the available memory, whichever is smaller).

When trying to write programs portable to other EP compilers, it is however safe 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.


Next: , Previous: String Operations, Up: Library Routines

6.10.3 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 argument #', Counter, ' is `',
                  ParamStr (Counter), '''')
     end.


Next: , Previous: Accessing Command Line Arguments, Up: Library Routines

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

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 freed later by another FreeMem call:

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


Next: , Previous: Memory Management Routines, Up: Library Routines

6.10.5 Operations for Integer and Ordinal Types


Next: , Previous: Operations for Integer and Ordinal Types, Up: Library Routines

6.10.6 Complex Number Operations

@@ A lot of details missing here

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

     program ComplexOperationsDemo (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.


Next: , Previous: Complex Number Operations, Up: Library Routines

6.10.7 Set Operations

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

In the following description, S1 and S2 are variables of set type, s is of the base type of the set.

S1 := S2
Assign a set to a set variable.
S1 + S2
Union of sets.
S1 - S2
Difference between two sets.
S1 * S2
Intersection of two sets.
S1 >< S2
Symmetric difference
S1 = S2
Comparison between two sets. Returns boolean result. True if S1 has the same elements as S2.
S1 <> S2
Comparison between two sets. Returns boolean result. True if S1 does not have the same elements as S2.
S1 < S2
S2 > S1
Comparison between two sets. Returns boolean result. True if S1 is a strict subset of S2.
S1 <= S2
S2 >= S1
Comparison between two sets. Returns boolean result. True if S1 is a subset of (or equal to) S2.
s in S1
Set membership test between an element s and a set. Returns boolean result. True if s is an element of S1.

The following example demonstrates some set operations. The results of the operations are given in the comments.

     program SetOpDemo;
     
     type
       TCharSet = set of Char;
     
     var
       S1, S2, S3: TCharSet;
       Result: Boolean;
     
     begin
       S1 := ['a', 'b', 'c'];
       S2 := ['c', 'd', 'e'];
       S3 := S1 + S2;       { S3 = ['a', 'b', 'c', 'd', 'e'] }
       S3 := S1 * S2;       { S3 = ['c'] }
       S3 := S1 - S2;       { S3 = ['a', 'b'] }
       S3 := S1 >< S2;      { S3 = ['a', 'b', 'd', 'e'] }
     
       S1 := ['c', 'd', 'e'];
       Result := S1 = S2;   { False }
       Result := S1 < S2;   { False }
       Result := S1 <= S2;  { True }
     
       S1 := ['c', 'd'];
       Result := S1 <> S2;  { True }
       Result := S2 > S1;   { True }
       Result := S2 >= S1   { True }
     end.


Previous: Set Operations, Up: Library Routines

6.10.8 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 TimeStamp.


Next: , Previous: Library Routines, Up: Programming

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


Next: , Up: Other Languages

6.11.1 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 a 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
       MyFoo: CInteger; external name 'foo';
     
     procedure Bar; external name 'bar';
     
     begin
       MyFoo := 42;
       Bar
     end.

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

     unit CallCUnit;
     
     interface
     
     var
       MyFoo: CInteger; external name 'foo';
     
     procedure Bar; external name 'bar';
     
     implementation
     
     {$L callc.c}  { Or: `callc.o' if you don't have the source }
     
     end.
     program CallCUDemo;
     
     uses CallCUnit;
     
     begin
       MyFoo := 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 often convenient, there is no must to give the C function `bar' the name `Bar' in Pascal; you can name it as you like (e.g., the variable `MyFoo' has a C name of `foo' in the example above).

If you omit the `name', the default is the Pascal identifier, converted to lower-case. So, in this example, the `name' could be omitted for `Bar', but not for `MyFoo'.

It is important that data types of both languages are mapped correctly onto each other. C's `int', for instance, translates to GPC's `CInteger', and C's `unsigned long' to `MedCard'. For a complete list of integer types with their C counterparts, see 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 be 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 `{$gpc-main="GPCmain"}'.


Previous: Importing Libraries from Other Languages, Up: Other Languages

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


Next: , Previous: Other Languages, Up: Programming

6.12 Notes for Debugging


Next: , Previous: Notes for Debugging, Up: Programming

6.13 How to use I18N in own programs

This chapter discusses shortly how to use the Internationalization (I18N) features of GNU Pascal.

Prerequisite

You need to have gettext installed. Try to compile demos/gettextdemo.pas. Furthermore, you should download a tool named `pas2po' from http://www.gnu-pascal.org/contrib/eike/.

The source

We would like to translate the messages provided with this simple example different languages (here: German) without touching the source for each language:

     program Hello1;
     
     begin
       WriteLn ('Hello, World!');
       WriteLn ('The answer of the questions is: ', 42)
     end.

Preparing the source

To do so, we must prepare the source to use gettext:

     program Hello2;
     
     uses GPC, Intl;
     
     var s: TString;
     
     begin
       Discard (BindTextDomain ('hello2', '/usr/share/locale/'));
       Discard (TextDomain ('hello2'));
       WriteLn (GetText ('Hello, World!'));
       s := FormatString (GetText ('The answer of the questions is %s'), 42);
       WriteLn (s)
     end.

`BindTextDomain' sets the path to find our message catalogs in the system. This path is system dependent. `TextDomain' tells the program to use this catalog. `GetText' looks up the given string in the catalog and returns a translated string within the current locale settings. `FormatString' replaces some format specifiers with the following argument. `%s' is the first following argument. After this step is done, we do not need to touch the sourcefile any longer. The output of this program is as follows:

     Hello, World!
     The answer of the questions is 42

Getting the translatable strings

There are lots of strings in the above example, but only those surrounded with `GetText' should be translated. We use `pas2po hello2.pas -o hello2.po' to extract the messages. The output is:

     # This file was created by pas2po with 'hello2.pas'.
     # Please change this file manually.
     # SOME DESCRIPTIVE TITLE.
     # Copyright (C) YEAR Free Software Foundation, Inc.
     # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
     #
     #, fuzzy
     msgid ""
     msgstr ""
     "Project-Id-Version: PACKAGE VERSION\n"
     "POT-Creation-Date: 2003-04-27 20:48+0200\n"
     "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
     "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     "Language-Team: LANGUAGE <LL@li.org>\n"
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=CHARSET\n"
     "Content-Transfer-Encoding: 8bit\n"
     
     #hello2.pas:10
     msgid "Hello, World!"
     msgstr ""
     
     #hello2.pas:11
     msgid "The answer of the questions is %s"
     msgstr ""

Now we translate the message ids into German language, and set some needful informations at their appropriate places. The following steps must be repeated for each language we would like to support:

     # This file was created by pas2po with 'hello2.pas'.
     # Copyright (C) 2003 Free Software Foundation, Inc.
     # Eike Lange  <eike@g-n-u.de>, 2003.
     msgid ""
     msgstr ""
     "Project-Id-Version: Hello2 1.0\n"
     "POT-Creation-Date: 2003-04-27 12:00+0200\n"
     "PO-Revision-Date: 2003-04-27 12:06+0200\n"
     "Last-Translator: Eike Lange <eike@g-n-u.de>\n"
     "Language-Team: de <de@li.org>\n"
     "MIME-Version: 1.0\n"
     "Content-Type: text/plain; charset=ISO-8859-1\n"
     "Content-Transfer-Encoding: 8bit\n"
     
     #hello2.pas:10
     msgid "Hello, World!"
     msgstr "Hallo, Welt!"
     
     #hello2.pas:11
     msgid "The answer of the questions is %s"
     msgstr "'%s' lautet die Antwort auf die Frage."

Please note that we swapped text and numeric arguments and added some single quotes arround the first argument. We compile the message catalog with `msgfmt -vv hello2.po -o hello2.mo' and install the file hello2.mo at /usr/share/locale/de/LC_MESSAGES/ With a german locale setting, the output should be as follows:

     Hallo, Welt!
     '42' lautet die Antwort auf die Frage.

System dependent notes:

The topmost path where message catalogs reside is system dependent:

for DJGPP:
`GetEnv ('$DJDIR') + '/share/locale''
for Mac OS X:
/usr/share/locale or /sw/share/locale
for Linux, *BSD:
/usr/share/locale or /usr/local/share/locale

See also

Gettext, FormatString, Intl.


Next: , Previous: I18N, Up: Programming

6.14 Pascal declarations for GPC's Run Time System

Below is a Pascal source of the declarations in GPC's Run Time System (RTS). 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.)

     { This file was generated automatically by make-gpc-pas.
       DO NOT CHANGE THIS FILE MANUALLY! }
     
     { Pascal declarations of the GPC Run Time System 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 linker names, 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 be
       declared as `const' in Pascal. However, Extended Pascal's
       `protected var' can be used since this guarantees passing by
       reference.
     
       Copyright (C) 1998-2006 Free Software Foundation, Inc.
     
       Authors: Jukka Virtanen <jtv@hut.fi>
                Peter Gerwinski <peter@gerwinski.de>
                Frank Heckenbach <frank@pascal.gnu.de>
                J.J. v.der Heijden <j.j.vanderheijden@student.utwente.nl>
                Nicola Girardi <nicola@g-n-u.de>
                Prof. Abimbola A. Olowofoyeku <African_Chief@bigfoot.com>
                Emil Jerabek <jerabek@math.cas.cz>
                Maurice Lombardi <Maurice.Lombardi@ujf-grenoble.fr>
                Toby Ewing <ewing@iastate.edu>
                Mirsad Todorovac <mtodorov_69@yahoo.com>
     
       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,I-}
     {$if __GPC_RELEASE__ <> 20060325}
     {$error
     Trying to compile gpc.pas with a non-matching GPC version is likely
     to cause problems.
     
     In case you are building the RTS separately from GPC, make sure you
     install a current GPC version previously. If you are building GPC
     now and this message appears, something is wrong -- if you are
     overriding the GCC_FOR_TARGET or GPC_FOR_TARGET make variables, this
     might be the problem. If you are cross-building GPC, build and
     install a current GPC cross-compiler first, sorry. If that's not the
     case, please report it as a bug.
     
     If you are not building GPC or the RTS currently, you might have
     installed things in the wrong place, so the compiler and RTS
     versions do not match.}
     {$endif}
     
     { Command-line options must not change the layout of RTS types
       declared here. }
     {$no-pack-struct, maximum-field-alignment 0}
     
     module GPC;
     
     export
       GPC = all;
       GPC_CP = (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, FileMode, Pos);
       GPC_Delphi = (MaxLongInt, Int64, InitProc, EConvertError,
                     ExitCode, ErrorAddr, FileMode, Pos, SetString,
       StringOfChar,
                     TextFile, AssignFile, CloseFile);
     
     type
       GPC_FDR = AnyFile;
     
     { Pascal declarations of the GPC Run Time System routines that are
       implemented in C, from rtsc.pas }
     
     const
       { Maximum size of a variable }
       MaxVarSize = MaxInt div 8;
     
     { If set, characters >= #$80 are assumed to be letters even if the
       locale routines don't say so. This is a kludge because some
       systems don't have correct non-English locale tables. }
     var
       FakeHighLetters: Boolean; attribute (name = '_p_FakeHighLetters');
       external;
     
     type
       PCStrings = ^TCStrings;
       TCStrings = array [0 .. MaxVarSize div SizeOf (CString) - 1] of
       CString;
     
       Int64 = Integer attribute (Size = 64);
       UnixTimeType = LongInt;  { This is hard-coded in the compiler. Do
       not change here. }
       MicroSecondTimeType = LongInt;
       FileSizeType = LongInt;
       SignedSizeType = Integer attribute (Size = BitSizeOf (SizeType));
       TSignalHandler = procedure (Signal: CInteger);
     
       StatFSBuffer = record
         BlockSize, BlocksTotal, BlocksFree: LongInt;
         FilesTotal, FilesFree: CInteger
       end;
     
       InternalSelectType = record
         Handle: CInteger;
         Read, Write, Exception: Boolean
       end;
     
       PString = ^String;
     
       { `Max' so the range of the array does not become invalid for
         Count = 0 }
       PPStrings = ^TPStrings;
       TPStrings (Count: Cardinal) = array [1 .. Max (Count, 1)] of
       PString;
     
       GlobBuffer = record
         Result: PPStrings;
         Internal1: Pointer;
         Internal2: PCStrings;
         Internal3: CInteger
       end;
     
     { Mathematical routines }
     
     function  SinH (x: Real): Real; attribute (const); external
       name '_p_SinH';
     function  CosH (x: Real): Real; attribute (const); external
       name '_p_CosH';
     function  ArcTan2 (y: Real; x: Real): Real; attribute (const);
       external name '_p_ArcTan2';
     function  IsInfinity (x: LongReal): Boolean; attribute (const);
       external name '_p_IsInfinity';
     function  IsNotANumber (x: LongReal): Boolean; attribute (const);
       external name '_p_IsNotANumber';
     procedure SplitReal (x: LongReal; var Exponent: CInteger; var
       Mantissa: LongReal); external name '_p_SplitReal';
     
     { Character routines }
     
     { Convert a character to lower case, according to the current
       locale. }
     function  LoCase (ch: Char): Char; attribute (const); external
       name '_p_LoCase';
     function  IsUpCase (ch: Char): Boolean; attribute (const); external
       name '_p_IsUpCase';
     function  IsLoCase (ch: Char): Boolean; attribute (const); external
       name '_p_IsLoCase';
     function  IsAlpha (ch: Char): Boolean; attribute (const); external
       name '_p_IsAlpha';
     function  IsAlphaNum (ch: Char): Boolean; attribute (const);
       external name '_p_IsAlphaNum';
     function  IsAlphaNumUnderscore (ch: Char): Boolean; attribute
       (const); external name '_p_IsAlphaNumUnderscore';
     function  IsSpace (ch: Char): Boolean; attribute (const); external
       name '_p_IsSpace';
     function  IsPrintable (ch: Char): Boolean; attribute (const);
       external name '_p_IsPrintable';
     
     { Time routines }
     
     { Sleep for a given number of seconds. }
     procedure Sleep (Seconds: CInteger); external name '_p_Sleep';
     
     { Sleep for a given number of microseconds. }
     procedure SleepMicroSeconds (MicroSeconds: CInteger); external
       name '_p_SleepMicroSeconds';
     
     { Set an alarm timer. }
     function  Alarm (Seconds: CInteger): CInteger; external
       name '_p_Alarm';
     
     { Convert a Unix time value to broken-down local time.
       All parameters except Time may be Null. }
     procedure UnixTimeToTime (Time: UnixTimeType; var Year: CInteger;
       var Month: CInteger; var Day: CInteger; var Hour: CInteger; var
       Minute: CInteger; var Second: CInteger;
                                     var TimeZone: CInteger; var DST:
       Boolean; var TZName1: CString; var TZName2: CString); external
       name '_p_UnixTimeToTime';
     
     { Convert broken-down local time to a Unix time value. }
     function  TimeToUnixTime (Year: CInteger; Month: CInteger; Day:
       CInteger; Hour: CInteger; Minute: CInteger; Second: CInteger):
       UnixTimeType; external name '_p_TimeToUnixTime';
     
     { Get the real time. MicroSecond can be Null and is ignored then. }
     function  GetUnixTime (var MicroSecond: CInteger): UnixTimeType;
       external name '_p_GetUnixTime';
     
     { Get the CPU time used. MicroSecond can be Null and is ignored
       then. }
     function  GetCPUTime (var MicroSecond: CInteger): CInteger; external
       name '_p_GetCPUTime';
     
     { Signal and process routines }
     
     { Extract information from the status returned by PWait }
     function  StatusExited (Status: CInteger): Boolean; attribute
       (const); external name '_p_StatusExited';
     function  StatusExitCode (Status: CInteger): CInteger; attribute
       (const); external name '_p_StatusExitCode';
     function  StatusSignaled (Status: CInteger): Boolean; attribute
       (const); external name '_p_StatusSignaled';
     function  StatusTermSignal (Status: CInteger): CInteger; attribute
       (const); external name '_p_StatusTermSignal';
     function  StatusStopped (Status: CInteger): Boolean; attribute
       (const); external name '_p_StatusStopped';
     function  StatusStopSignal (Status: CInteger): CInteger; attribute
       (const); external name '_p_StatusStopSignal';
     
     { Install a signal handler and optionally return the previous
       handler. OldHandler and OldRestart may be Null. }
     function  InstallSignalHandler (Signal: CInteger; Handler:
       TSignalHandler; Restart: Boolean; UnlessIgnored: Boolean;
       var OldHandler: TSignalHandler; var OldRestart: Boolean): Boolean;
       external name '_p_InstallSignalHandler';
     
     { Block or unblock a signal. }
     procedure BlockSignal (Signal: CInteger; Block: Boolean); external
       name '_p_BlockSignal';
     
     { Test whether a signal is blocked. }
     function  SignalBlocked (Signal: CInteger): Boolean; external
       name '_p_SignalBlocked';
     
     { 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: CInteger; Signal: CInteger): Boolean; external
       name '_p_Kill';
     
     { Constant for WaitPID }
     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: CInteger; var WStatus: CInteger; Block:
       Boolean): CInteger; external name '_p_WaitPID';
     
     { Returns the process ID. }
     function  ProcessID: CInteger; external name '_p_ProcessID';
     
     { Returns the process group. }
     function  ProcessGroup: CInteger; external name '_p_ProcessGroup';
     
     { Returns the real or effective user ID of the process. }
     function  UserID (Effective: Boolean): CInteger; external
       name '_p_UserID';
     
     { Tries to change the real and/or effective user ID. }
     function  SetUserID (Real: CInteger; Effective: CInteger): Boolean;
       external name '_p_SetUserID';
     
     { Returns the real or effective group ID of the process. }
     function  GroupID (Effective: Boolean): CInteger; external
       name '_p_GroupID';
     
     { Tries to change the real and/or effective group ID. }
     function  SetGroupID (Real: CInteger; Effective: CInteger): Boolean;
       external name '_p_SetGroupID';
     
     { Low-level file routines. Mostly for internal use. }
     
     { Get information about a file system. }
     function  StatFS (Path: CString; var Buf: StatFSBuffer): Boolean;
       external name '_p_StatFS';
     function  CStringOpenDir (DirName: CString): Pointer; external
       name '_p_CStringOpenDir';
     function  CStringReadDir (Dir: Pointer): CString; external
       name '_p_CStringReadDir';
     procedure CStringCloseDir (Dir: Pointer); external
       name '_p_CStringCloseDir';
     
     { Returns the value of the symlink FileName in a CString allocated
       from the heap. Returns nil if it is no symlink or the function
       is not supported. }
     function  ReadLink (FileName: CString): CString; external
       name '_p_ReadLink';
     
     { Returns a pointer to a *static* buffer! }
     function  CStringRealPath (Path: CString): CString; external
       name '_p_CStringRealPath';
     
     { File mode constants that are ORed for BindingType.Mode, ChMod,
       CStringChMod and Stat. The values below are valid for all OSs
       (as far as supported). If the OS uses different values, they're
       converted internally. }
     const
       fm_SetUID           = 8#4000;
       fm_SetGID           = 8#2000;
       fm_Sticky           = 8#1000;
       fm_UserReadable     = 8#400;
       fm_UserWritable     = 8#200;
       fm_UserExecutable   = 8#100;
       fm_GroupReadable    = 8#40;
       fm_GroupWritable    = 8#20;
       fm_GroupExecutable  = 8#10;
       fm_OthersReadable   = 8#4;
       fm_OthersWritable   = 8#2;
       fm_OthersExecutable = 8#1;
     
     { Constants for Access and OpenHandle }
     const
       MODE_EXEC     = 1 shl 0;
       MODE_WRITE    = 1 shl 1;
       MODE_READ     = 1 shl 2;
       MODE_FILE     = 1 shl 3;
       MODE_CREATE   = 1 shl 4;
       MODE_EXCL     = 1 shl 5;
       MODE_TRUNCATE = 1 shl 6;
       MODE_APPEND   = 1 shl 7;
       MODE_BINARY   = 1 shl 8;
     
     { Check if a file name is accessible. }
     function  Access (FileName: CString; Request: CInteger): CInteger;
       external name '_p_Access';
     
     { Get information about a file. Any argument except FileName can
       be Null. }
     function  Stat (FileName: CString; var Size: FileSizeType;
       var ATime: UnixTimeType; var MTime: UnixTimeType; var CTime:
       UnixTimeType;
       var User: CInteger; var Group: CInteger; var Mode: CInteger; var
       Device: CInteger; var INode: CInteger; var Links: CInteger;
       var SymLink: Boolean; var Dir: Boolean; var Special: Boolean):
       CInteger; external name '_p_Stat';
     function  OpenHandle (FileName: CString; Mode: CInteger): CInteger;
       external name '_p_OpenHandle';
     function  ReadHandle (Handle: CInteger; Buffer: Pointer; Size:
       SizeType): SignedSizeType; external name '_p_ReadHandle';
     function  WriteHandle (Handle: CInteger; Buffer: Pointer; Size:
       SizeType): SignedSizeType; external name '_p_WriteHandle';
     function  CloseHandle (Handle: CInteger): CInteger; external
       name '_p_CloseHandle';
     procedure FlushHandle (Handle: CInteger); external
       name '_p_FlushHandle';
     function  DupHandle (Src: CInteger; Dest: CInteger): CInteger;
       external name '_p_DupHandle';
     function  SetFileMode (Handle: CInteger; Mode: CInteger; On:
       Boolean): CInteger; attribute (ignorable); external
       name '_p_SetFileMode';
     function  CStringRename (OldName: CString; NewName: CString):
       CInteger; external name '_p_CStringRename';
     function  CStringUnlink (FileName: CString): CInteger; external
       name '_p_CStringUnlink';
     function  CStringChDir (FileName: CString): CInteger; external
       name '_p_CStringChDir';
     function  CStringMkDir (FileName: CString): CInteger; external
       name '_p_CStringMkDir';
     function  CStringRmDir (FileName: CString): CInteger; external
       name '_p_CStringRmDir';
     function  UMask (Mask: CInteger): CInteger; attribute (ignorable);
       external name '_p_UMask';
     function  CStringChMod (FileName: CString; Mode: CInteger):
       CInteger; external name '_p_CStringChMod';
     function  CStringChOwn (FileName: CString; Owner: CInteger; Group:
       CInteger): CInteger; external name '_p_CStringChOwn';
     function  CStringUTime (FileName: CString; AccessTime: UnixTimeType;
       ModificationTime: UnixTimeType): CInteger; external
       name '_p_CStringUTime';
     
     { Constants for SeekHandle }
     const
       SeekAbsolute = 0;
       SeekRelative = 1;
       SeekFileEnd  = 2;
     
     { Seek to a position on a file handle. }
     function  SeekHandle (Handle: CInteger; Offset: FileSizeType;
       Whence: CInteger): FileSizeType; external name '_p_SeekHandle';
     function  TruncateHandle (Handle: CInteger; Size: FileSizeType):
       CInteger; external name '_p_TruncateHandle';
     function  LockHandle (Handle: CInteger; WriteLock: Boolean; Block:
       Boolean): Boolean; external name '_p_LockHandle';
     function  UnlockHandle (Handle: CInteger): Boolean; external
       name '_p_UnlockHandle';
     function  SelectHandle (Count: CInteger; var Events:
       InternalSelectType; MicroSeconds: MicroSecondTimeType): CInteger;
       external name '_p_SelectHandle';
     
     { Constants for MMapHandle and MemoryMap }
     const
       mm_Readable   = 1;
       mm_Writable   = 2;
       mm_Executable = 4;
     
     { Try to map (a part of) a file to memory. }
     function  MMapHandle (Start: Pointer; Length: SizeType; Access:
       CInteger; Shared: Boolean; Handle: CInteger; Offset:
       FileSizeType): Pointer; external name '_p_MMapHandle';
     
     { Unmap a previous memory mapping. }
     function  MUnMapHandle (Start: Pointer; Length: SizeType): CInteger;
       external name '_p_MUnMapHandle';
     
     { Returns the file name of the terminal device that is open on
       Handle. Returns nil if (and only if) Handle is not open or not
       connected to a terminal. If NeedName is False, it doesn't bother
       to search for the real name and just returns DefaultName if it
       is a terminal and nil otherwise. DefaultName is also returned if
       NeedName is True, Handle is connected to a terminal, but the
       system does not provide information about the real file name. }
     function  GetTerminalNameHandle (Handle: CInteger; NeedName:
       Boolean; DefaultName: CString): CString; external
       name '_p_GetTerminalNameHandle';
     
     { System routines }
     
     { 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: CInteger; ProcessGroup:
       CInteger): Boolean; external name '_p_SetProcessGroup';
     
     { 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 (Handle: CInteger; ProcessGroup:
       CInteger): Boolean; external name '_p_SetTerminalProcessGroup';
     
     { Returns the process group of a terminal given by Terminal (as a
       file handle), or -1 on error. }
     function  GetTerminalProcessGroup (Handle: CInteger): CInteger;
       external name '_p_GetTerminalProcessGroup';
     
     { Set the standard input's signal generation, if it is a terminal. }
     procedure SetInputSignals (Signals: Boolean); external
       name '_p_SetInputSignals';
     
     { Get the standard input's signal generation, if it is a terminal. }
     function  GetInputSignals: Boolean; external
       name '_p_GetInputSignals';
     
     { Internal routines }
     
     { Returns system information if available. Fields not available will
       be set to nil. }
     procedure CStringSystemInfo (var SysName: CString; var NodeName:
       CString; var Release: CString; var Version: CString; var Machine:
       CString; var DomainName: CString); external
       name '_p_CStringSystemInfo';
     
     { Returns the path of the running executable *if possible*. }
     function  CStringExecutablePath (Buffer: CString): CString; external
       name '_p_CStringExecutablePath';
     
     { Sets ErrNo to the value of `errno' and returns the description
       for this error. May return nil if not supported! ErrNo may be
       Null (then only the description is returned). }
     function  CStringStrError (var ErrNo: CInteger): CString; external
       name '_p_CStringStrError';
     
     { Mathematical routines, from math.pas }
     
     function Ln1Plus  (x: Real) = y: Real; attribute (const, name
       = '_p_Ln1Plus'); external;
     
     { String handling routines (lower level), from string1.pas }
     
     { 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
       MaxLongInt = High (LongInt);
     
       TStringSize = 2048;
       SpaceCharacters = [' ', #9];
       NewLine = "\n";  { the separator of lines within a string }
       LineBreak = {$if defined (__OS_DOS__) and not defined (__CYGWIN__)
       and not defined (__MSYS__)}
                   "\r\n"
                   {$else}
                   "\n"
                   {$endif};  { the separator of lines within a file }
     
     type
       TString    = String (TStringSize);
       TStringBuf = packed array [0 .. TStringSize] of Char;
       CharSet    = set of Char;
       Str64      = String (64);
       TInteger2StringBase = Cardinal(2) .. Cardinal(36);
       TInteger2StringWidth = 0 .. High (TString);
     
     var
       NumericBaseDigits: array [0 .. 35] of Char; attribute (const, name
       = '_p_NumericBaseDigits'); external;
       NumericBaseDigitsUpper: array [0 .. 35] of Char; attribute (const,
       name = '_p_NumericBaseDigitsUpper'); external;
     
       CParamCount: Integer; attribute (name = '_p_CParamCount');
       external;
       CParameters: PCStrings; attribute (name = '_p_CParameters');
       external;
     
     function  MemCmp      (const s1, s2; Size: SizeType): CInteger;
       external name 'memcmp';
     function  MemComp     (const s1, s2; Size: SizeType): CInteger;
       external name 'memcmp';
     function  MemCompCase (const s1, s2; Size: SizeType): Boolean;
       attribute (name = '_p_MemCompCase'); external;
     
     procedure UpCaseString    (var s: String); attribute (name
       = '_p_UpCaseString'); external;
     procedure LoCaseString    (var s: String); attribute (name
       = '_p_LoCaseString'); external;
     function  UpCaseStr       (const s: String) = Result: TString;
       attribute (name = '_p_UpCaseStr'); external;
     function  LoCaseStr       (const s: String) = Result: TString;
       attribute (name = '_p_LoCaseStr'); external;
     
     function  StrEqualCase    (const s1, s2: String): Boolean; attribute
       (name = '_p_StrEqualCase'); external;
     
     function  Pos             (const SubString, s: String): Integer;
       attribute (name = '_p_Pos'); external;
     function  PosChar         (const ch: Char; const s: String):
       Integer; attribute (name = '_p_PosChar'); external;
     function  LastPos         (const SubString, s: String): Integer;
       attribute (name = '_p_LastPos'); external;
     function  PosCase         (const SubString, s: String): Integer;
       attribute (name = '_p_PosCase'); external;
     function  LastPosCase     (const SubString, s: String): Integer;
       attribute (name = '_p_LastPosCase'); external;
     function  CharPos         (const Chars: CharSet; const s: String):
       Integer; attribute (name = '_p_CharPos'); external;
     function  LastCharPos     (const Chars: CharSet; const s: String):
       Integer; attribute (name = '_p_LastCharPos'); external;
     
     function  PosFrom         (const SubString, s: String; From:
       Integer): Integer; attribute (name = '_p_PosFrom'); external;
     function  LastPosTill     (const SubString, s: String; Till:
       Integer): Integer; attribute (name = '_p_LastPosTill'); external;
     function  PosFromCase     (const SubString, s: String; From:
       Integer): Integer; attribute (name = '_p_PosFromCase'); external;
     function  LastPosTillCase (const SubString, s: String; Till:
       Integer): Integer; attribute (name = '_p_LastPosTillCase');
       external;
     function  CharPosFrom     (const Chars: CharSet; const s: String;
       From: Integer): Integer; attribute (name = '_p_CharPosFrom');
       external;
     function  LastCharPosTill (const Chars: CharSet; const s: String;
       Till: Integer): Integer; attribute (name = '_p_LastCharPosTill');
       external;
     
     function  IsPrefix        (const Prefix, s: String): Boolean;
       attribute (name = '_p_IsPrefix'); external;
     function  IsSuffix        (const Suffix, s: String): Boolean;
       attribute (name = '_p_IsSuffix'); external;
     function  IsPrefixCase    (const Prefix, s: String): Boolean;
       attribute (name = '_p_IsPrefixCase'); external;
     function  IsSuffixCase    (const Suffix, s: String): Boolean;
       attribute (name = '_p_IsSuffixCase'); external;
     
     function  CStringLength      (Src: CString): SizeType; attribute
       (inline, name = '_p_CStringLength'); external;
     function  CStringEnd         (Src: CString): CString; attribute
       (inline, name = '_p_CStringEnd'); external;
     function  CStringNew         (Src: CString): CString; attribute
       (name = '_p_CStringNew'); external;
     function  CStringComp        (s1, s2: CString): Integer; attribute
       (name = '_p_CStringComp'); external;
     function  CStringCaseComp    (s1, s2: CString): Integer; attribute
       (name = '_p_CStringCaseComp'); external;
     function  CStringLComp       (s1, s2: CString; MaxLen: SizeType):
       Integer; attribute (name = '_p_CStringLComp'); external;
     function  CStringLCaseComp   (s1, s2: CString; MaxLen: SizeType):
       Integer; attribute (name = '_p_CStringLCaseComp'); external;
     function  CStringCopy        (Dest, Source: CString): CString;
       attribute (ignorable, name = '_p_CStringCopy'); external;
     function  CStringCopyEnd     (Dest, Source: CString): CString;
       attribute (ignorable, name = '_p_CStringCopyEnd'); external;
     function  CStringLCopy       (Dest, Source: CString; MaxLen:
       SizeType): CString; attribute (ignorable, name
       = '_p_CStringLCopy'); external;
     function  CStringMove        (Dest, Source: CString; Count:
       SizeType): CString; attribute (ignorable, name
       = '_p_CStringMove'); external;
     function  CStringCat         (Dest, Source: CString): CString;
       attribute (ignorable, name = '_p_CStringCat'); external;
     function  CStringLCat        (Dest, Source: CString; MaxLen:
       SizeType): CString; attribute (ignorable, name
       = '_p_CStringLCat'); external;
     function  CStringChPos       (Src: CString; ch: Char): CString;
       attribute (inline, name = '_p_CStringChPos'); external;
     function  CStringLastChPos   (Src: CString; ch: Char): CString;
       attribute (inline, name = '_p_CStringLastChPos'); external;
     function  CStringPos         (s, SubString: CString): CString;
       attribute (name = '_p_CStringPos'); external;
     function  CStringLastPos     (s, SubString: CString): CString;
       attribute (name = '_p_CStringLastPos'); external;
     function  CStringCasePos     (s, SubString: CString): CString;
       attribute (name = '_p_CStringCasePos'); external;
     function  CStringLastCasePos (s, SubString: CString): CString;
       attribute (name = '_p_CStringLastCasePos'); external;
     function  CStringUpCase      (s: CString): CString; attribute (name
       = '_p_CStringUpCase'); external;
     function  CStringLoCase      (s: CString): CString; attribute (name
       = '_p_CStringLoCase'); external;
     function  CStringIsEmpty     (s: CString): Boolean; attribute (name
       = '_p_CStringIsEmpty'); external;
     function  NewCString         (const Source: String): CString;
       attribute (name = '_p_NewCString'); external;
     function  CStringCopyString  (Dest: CString; const Source: String):
       CString; attribute (name = '_p_CStringCopyString'); external;
     procedure CopyCString        (Source: CString; var Dest: String);
       attribute (name = '_p_CopyCString'); external;
     
     function  NewString       (const s: String) = Result: PString;
       attribute (name = '_p_NewString'); external;
     procedure DisposeString   (p: PString); external name '_p_Dispose';
     
     procedure SetString       (var s: String; Buffer: PChar; Count:
       Integer); attribute (name = '_p_SetString'); external;
     function  StringOfChar    (ch: Char; Count: Integer) = s: TString;
       attribute (name = '_p_StringOfChar'); external;
     
     procedure TrimLeft        (var s: String); attribute (name
       = '_p_TrimLeft'); external;
     procedure TrimRight       (var s: String); attribute (name
       = '_p_TrimRight'); external;
     procedure TrimBoth        (var s: String); attribute (name
       = '_p_TrimBoth'); external;
     function  TrimLeftStr     (const s: String) = Result: TString;
       attribute (name = '_p_TrimLeftStr'); external;
     function  TrimRightStr    (const s: String) = Result: TString;
       attribute (name = '_p_TrimRightStr'); external;
     function  TrimBothStr     (const s: String) = Result: TString;
       attribute (name = '_p_TrimBothStr'); external;
     function  LTrim           (const s: String) = Result: TString;
       external name '_p_TrimLeftStr';
     
     function  GetStringCapacity (const s: String): Integer; attribute
       (name = '_p_GetStringCapacity'); external;
     
     { A shortcut for a common use of WriteStr as a function }
     function  Integer2String (i: Integer) = s: Str64; attribute (name
       = '_p_Integer2String'); external;
     
     { Convert integer n to string in base Base. }
     function  Integer2StringBase (n: LongestInt; Base:
       TInteger2StringBase): TString; attribute (name
       = '_p_Integer2StringBase'); external;
     
     { Convert integer n to string in base Base, with sign, optionally in
       uppercase representation and with printed base, padded with
       leading zeroes between `[<Sign>]<Base>#' and the actual digits to
       specified Width. }
     function  Integer2StringBaseExt (n: LongestInt; Base:
       TInteger2StringBase; Width: TInteger2StringWidth; Upper: Boolean;
       PrintBase: Boolean): TString; attribute (name
       = '_p_Integer2StringBaseExt'); external;
     
     { String handling routines (higher level), from string2.pas }
     
     type
       PChars0 = ^TChars0;
       TChars0 = array [0 .. MaxVarSize div SizeOf (Char) - 1] of Char;
     
       PPChars0 = ^TPChars0;
       TPChars0 = array [0 .. MaxVarSize div SizeOf (PChars0) - 1] of
       PChars0;
     
       PChars = ^TChars;
       TChars = packed array [1 .. MaxVarSize div SizeOf (Char)] of Char;
     
       { 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; attribute (name = '_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; attribute (name
       = '_p_GetEnv'); external;
     function  CStringGetEnv (EnvVar: CString): CString; attribute (name
       = '_p_CStringGetEnv'); external;
     
     { 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); attribute (name
       = '_p_SetEnv'); external;
     
     { Un-sets an environment variable with the name given in VarName. }
     procedure UnSetEnv (const VarName: String); attribute (name
       = '_p_UnSetEnv'); external;
     
     { Returns @Environment^.CStrings, converted to PCStrings, to be
       passed to libc routines like execve which expect an environment. }
     function  GetCEnvironment: PCStrings; attribute (name
       = '_p_GetCEnvironment'); external;
     
     type
       FormatStringTransformType = ^function (const Format: String):
       TString;
     
     var
       FormatStringTransformPtr: FormatStringTransformType; attribute
       (name = '_p_FormatStringTransformPtr'); external;
     
     { Runtime error and signal handling routines, from error.pas }
     
     const
       EAssert = 306;
       EAssertString = 307;
       EOpen = 405;
       EMMap = 408;
       ERead = 413;
       EWrite = 414;
       EWriteReadOnly = 422;
       ENonExistentFile = 436;
       EOpenRead = 442;
       EOpenWrite = 443;
       EOpenUpdate = 444;
       EReading = 464;
       EWriting = 466;
       ECannotWriteAll = 467;
       ECannotFork = 600;
       ECannotSpawn = 601;
       EProgramNotFound = 602;
       EProgramNotExecutable = 603;
       EPipe = 604;
       EPrinterRead = 610;
       EIOCtl = 630;
       EConvertError = 875;
       ELibraryFunction = 952;
       EExitReturned = 953;
     
       RuntimeErrorExitValue = 42;
     
     var
       { Error number (after runtime error) or exit status (after Halt)
         or 0 (during program run and after succesful termination). }
       ExitCode: Integer; attribute (name = '_p_ExitCode'); external;
     
       { Contains the address of the code where a runtime occurred, nil
         if no runtime error occurred. }
       ErrorAddr: Pointer; attribute (name = '_p_ErrorAddr'); external;
     
       { Error message }
       ErrorMessageString: TString; attribute (name
       = '_p_ErrorMessageString'); external;
     
       { String parameter to some error messages, *not* the text of the
         error message (the latter can be obtained with
         GetErrorMessage). }
       InOutResString: PString; attribute (name = '_p_InOutResString');
       external;
     
       { Optional libc error string to some error messages. }
       InOutResCErrorString: PString; attribute (name
       = '_p_InOutResCErrorString'); external;
     
       RTSErrorFD: Integer; attribute (name = '_p_ErrorFD'); external;
       RTSErrorFileName: PString; attribute (name = '_p_ErrorFileName');
       external;
     
     function  GetErrorMessage                 (n: Integer): CString;
       attribute (name = '_p_GetErrorMessage'); external;
     procedure RuntimeError                    (n: Integer); attribute
       (noreturn, name = '_p_RuntimeError'); external;
     procedure RuntimeErrorErrNo               (n: Integer); attribute
       (noreturn, name = '_p_RuntimeErrorErrNo'); external;
     procedure RuntimeErrorInteger             (n: Integer; i: MedInt);
       attribute (noreturn, name = '_p_RuntimeErrorInteger'); external;
     procedure RuntimeErrorCString             (n: Integer; s: CString);
       attribute (noreturn, name = '_p_RuntimeErrorCString'); external;
     procedure InternalError                   (n: Integer); attribute
       (noreturn, name = '_p_InternalError'); external;
     procedure InternalErrorInteger            (n: Integer; i: MedInt);
       attribute (noreturn, name = '_p_InternalErrorInteger'); external;
     procedure InternalErrorCString            (n: Integer; s: CString);
       attribute (noreturn, name = '_p_InternalErrorCString'); external;
     procedure RuntimeWarning                  (Message: CString);
       attribute (name = '_p_RuntimeWarning'); external;
     procedure RuntimeWarningInteger           (Message: CString; i:
       MedInt); attribute (name = '_p_RuntimeWarningInteger'); external;
     procedure RuntimeWarningCString           (Message: CString; s:
       CString); attribute (name = '_p_RuntimeWarningCString'); external;
     
     procedure IOError                         (n: Integer; ErrNoFlag:
       Boolean); attribute (iocritical, name = '_p_IOError'); external;
     procedure IOErrorInteger                  (n: Integer; i: MedInt;
       ErrNoFlag: Boolean); attribute (iocritical, name
       = '_p_IOErrorInteger'); external;
     procedure IOErrorCString                  (n: Integer; s: CString;
       ErrNoFlag: Boolean); attribute (iocritical, name
       = '_p_IOErrorCString'); external;
     
     function  GetIOErrorMessage = Res: TString; attribute (name
       = '_p_GetIOErrorMessage'); external;
     procedure CheckInOutRes; attribute (name = '_p_CheckInOutRes');
       external;
     
     { 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); attribute (name = '_p_RegisterRestoreTerminal');
       external;
     
     { 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; attribute (name
       = '_p_UnregisterRestoreTerminal'); external;
     
     { 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); attribute
       (name = '_p_RestoreTerminal'); external;
     
     procedure AtExit (procedure Proc); attribute (name = '_p_AtExit');
       external;
     
     function  ReturnAddr2Hex (p: Pointer) = s: TString; attribute (name
       = '_p_ReturnAddr2Hex'); external;
     
     { This function is used to write error messages etc. It does not use
       the Pascal I/O system here because it is usually called at the
       very end of a program after the Pascal I/O system has been shut
       down. }
     function  WriteErrorMessage (const s: String; StdErrFlag: Boolean):
       Boolean; attribute (name = '_p_WriteErrorMessage'); external;
     
     procedure SetReturnAddress (Address: Pointer); attribute (name
       = '_p_SetReturnAddress'); external;
     procedure RestoreReturnAddress; attribute (name
       = '_p_RestoreReturnAddress'); external;
     
     { Returns a description for a signal }
     function  StrSignal (Signal: Integer) = Res: TString; attribute
       (name = '_p_StrSignal'); external;
     
     { Installs some signal handlers that cause runtime errors on certain
       signals. This procedure runs only once, and returns immediately
       when called again (so you can't use it to set the signals again if
       you changed them meanwhile). @@Does not work on all systems (since
       the handler might have too little stack space). }
     procedure InstallDefaultSignalHandlers; attribute (name
       = '_p_InstallDefaultSignalHandlers'); external;
     
     var
       { Signal actions }
       SignalDefault: TSignalHandler; attribute (const); external
       name '_p_SIG_DFL';
       SignalIgnore : TSignalHandler; attribute (const); external
       name '_p_SIG_IGN';
       SignalError  : TSignalHandler; attribute (const); external
       name '_p_SIG_ERR';
     
       { Signals. The constants are set to the signal numbers, and
         are 0 for signals not defined. }
       { POSIX signals }
       SigHUp   : Integer; attribute (const); external name '_p_SIGHUP';
       SigInt   : Integer; attribute (const); external name '_p_SIGINT';
       SigQuit  : Integer; attribute (const); external name '_p_SIGQUIT';
       SigIll   : Integer; attribute (const); external name '_p_SIGILL';
       SigAbrt  : Integer; attribute (const); external name '_p_SIGABRT';
       SigFPE   : Integer; attribute (const); external name '_p_SIGFPE';
       SigKill  : Integer; attribute (const); external name '_p_SIGKILL';
       SigSegV  : Integer; attribute (const); external name '_p_SIGSEGV';
       SigPipe  : Integer; attribute (const); external name '_p_SIGPIPE';
       SigAlrm  : Integer; attribute (const); external name '_p_SIGALRM';
       SigTerm  : Integer; attribute (const); external name '_p_SIGTERM';
       SigUsr1  : Integer; attribute (const); external name '_p_SIGUSR1';
       SigUsr2  : Integer; attribute (const); external name '_p_SIGUSR2';
       SigChld  : Integer; attribute (const); external name '_p_SIGCHLD';
       SigCont  : Integer; attribute (const); external name '_p_SIGCONT';
       SigStop  : Integer; attribute (const); external name '_p_SIGSTOP';
       SigTStp  : Integer; attribute (const); external name '_p_SIGTSTP';
       SigTTIn  : Integer; attribute (const); external name '_p_SIGTTIN';
       SigTTOu  : Integer; attribute (const); external name '_p_SIGTTOU';
     
       { Non-POSIX signals }
       SigTrap  : Integer; attribute (const); external name '_p_SIGTRAP';
       SigIOT   : Integer; attribute (const); external name '_p_SIGIOT';
       SigEMT   : Integer; attribute (const); external name '_p_SIGEMT';
       SigBus   : Integer; attribute (const); external name '_p_SIGBUS';
       SigSys   : Integer; attribute (const); external name '_p_SIGSYS';
       SigStkFlt: Integer; attribute (const); external
       name '_p_SIGSTKFLT';
       SigUrg   : Integer; attribute (const); external name '_p_SIGURG';
       SigIO    : Integer; attribute (const); external name '_p_SIGIO';
       SigPoll  : Integer; attribute (const); external name '_p_SIGPOLL';
       SigXCPU  : Integer; attribute (const); external name '_p_SIGXCPU';
       SigXFSz  : Integer; attribute (const); external name '_p_SIGXFSZ';
       SigVTAlrm: Integer; attribute (const); external
       name '_p_SIGVTALRM';
       SigProf  : Integer; attribute (const); external name '_p_SIGPROF';
       SigPwr   : Integer; attribute (const); external name '_p_SIGPWR';
       SigInfo  : Integer; attribute (const); external name '_p_SIGINFO';
       SigLost  : Integer; attribute (const); external name '_p_SIGLOST';
       SigWinCh : Integer; attribute (const); external
       name '_p_SIGWINCH';
     
       { Signal subcodes (only used on some systems, -1 if not used) }
       FPEIntegerOverflow      : Integer; attribute (const); external
       name '_p_FPE_INTOVF_TRAP';
       FPEIntegerDivisionByZero: Integer; attribute (const); external
       name '_p_FPE_INTDIV_TRAP';
       FPESubscriptRange       : Integer; attribute (const); external
       name '_p_FPE_SUBRNG_TRAP';
       FPERealOverflow         : Integer; attribute (const); external
       name '_p_FPE_FLTOVF_TRAP';
       FPERealDivisionByZero   : Integer; attribute (const); external
       name '_p_FPE_FLTDIV_TRAP';
       FPERealUnderflow        : Integer; attribute (const); external
       name '_p_FPE_FLTUND_TRAP';
       FPEDecimalOverflow      : Integer; attribute (const); external
       name '_p_FPE_DECOVF_TRAP';
     
     { Routines called implicitly by the compiler. }
     procedure GPC_Assert (Condition: Boolean; const Message: String);
       attribute (name = '_p_Assert'); external;
     function  ObjectTypeIs (Left, Right: PObjectType): Boolean;
       attribute (const, name = '_p_ObjectTypeIs'); external;
     procedure ObjectTypeAsError; attribute (noreturn, name
       = '_p_ObjectTypeAsError'); external;
     procedure DisposeNilError; attribute (noreturn, name
       = '_p_DisposeNilError'); external;
     procedure CaseNoMatchError; attribute (noreturn, name
       = '_p_CaseNoMatchError'); external;
     procedure DiscriminantsMismatchError; attribute (noreturn, name
       = '_p_DiscriminantsMismatchError'); external;
     procedure NilPointerError; attribute (noreturn, name
       = '_p_NilPointerError'); external;
     procedure InvalidPointerError (p: Pointer); attribute (noreturn,
       name = '_p_InvalidPointerError'); external;
     procedure InvalidObjectError; attribute (noreturn, name
       = '_p_InvalidObjectError'); external;
     procedure RangeCheckError; attribute (noreturn, name
       = '_p_RangeCheckError'); external;
     procedure IORangeCheckError; attribute (name
       = '_p_IORangeCheckError'); external;
     procedure SubrangeError; attribute (noreturn, name
       = '_p_SubrangeError'); external;
     procedure ModRangeError; attribute (noreturn, name
       = '_p_ModRangeError'); external;
     
     { Pointer checking with `--pointer-checking-user-defined' }
     
     procedure DefaultValidatePointer (p: Pointer); attribute (name
       = '_p_DefaultValidatePointer'); external;
     
     type
       ValidatePointerType = ^procedure (p: Pointer);
     
     var
       ValidatePointerPtr: ValidatePointerType; attribute (name
       = '_p_ValidatePointerPtr'); external;
     
     { Time and date routines, from time.pas }
     
     const
       InvalidYear = -MaxInt;
     
     var
       { DayOfWeekName is a constant and therefore does not respect the
         locale. Therefore, it's recommended to use FormatTime instead. }
       DayOfWeekName: array [0 .. 6] of String [9]; attribute (const,
       name = '_p_DayOfWeekName'); external;
     
       { MonthName is a constant and therefore does not respect the
         locale. Therefore, it's recommended to use FormatTime instead. }
       MonthName: array [1 .. 12] of String [9]; attribute (const, name
       = '_p_MonthName'); external;
     
     function  GetDayOfWeek (Day, Month, Year: Integer): Integer;
       attribute (name = '_p_GetDayOfWeek'); external;
     function  GetDayOfYear (Day, Month, Year: Integer): Integer;
       attribute (name = '_p_GetDayOfYear'); external;
     function  GetSundayWeekOfYear (Day, Month, Year: Integer): Integer;
       attribute (name = '_p_GetSundayWeekOfYear'); external;
     function  GetMondayWeekOfYear (Day, Month, Year: Integer): Integer;
       attribute (name = '_p_GetMondayWeekOfYear'); external;
     procedure GetISOWeekOfYear (Day, Month, Year: Integer; var ISOWeek,
       ISOWeekYear: Integer); attribute (name = '_p_GetISOWeekOfYear');
       external;
     procedure UnixTimeToTimeStamp (UnixTime: UnixTimeType; var
       aTimeStamp: TimeStamp); attribute (name
       = '_p_UnixTimeToTimeStamp'); external;
     function  TimeStampToUnixTime (protected var aTimeStamp: TimeStamp):
       UnixTimeType; attribute (name = '_p_TimeStampToUnixTime');
       external;
     function  GetMicroSecondTime: MicroSecondTimeType; attribute (name
       = '_p_GetMicroSecondTime'); external;
     
     { Is the year a leap year? }
     function  IsLeapYear (Year: Integer): Boolean; attribute (name
       = '_p_IsLeapYear'); external;
     
     { Returns the length of the month, taking leap years into account. }
     function  MonthLength (Month, Year: Integer): Integer; attribute
       (name = '_p_MonthLength'); external;
     
     { Formats a TimeStamp value according to a Format string. The format
       string can contain date/time items consisting of `%', followed by
       the specifiers listed below. All characters outside of these items
       are copied to the result unmodified. The specifiers correspond to
       those of the C function strftime(), including POSIX.2 and glibc
       extensions and some more extensions. The extensions are also
       available on systems whose strftime() doesn't support them.
     
       The following modifiers may appear after the `%':
     
       `_'  The item is left padded with spaces to the given or default
            width.
     
       `-'  The item is not padded at all.
     
       `0'  The item is left padded with zeros to the given or default
            width.
     
       `/'  The item is right trimmed if it is longer than the given
            width.
     
       `^'  The item is converted to upper case.
     
       `~'  The item is converted to lower case.
     
       After zero or more of these flags, an optional width may be
       specified for padding and trimming. It must be given as a decimal
       number (not starting with `0' since `0' has a meaning of its own,
       see above).
     
       Afterwards, the following optional modifiers may follow. Their
       meaning is locale-dependent, and many systems and locales just
       ignore them.
     
       `E'  Use the locale's alternate representation for date and time.
            In a Japanese locale, for example, `%Ex' might yield a date
            format based on the Japanese Emperors' reigns.
     
       `O'  Use the locale's alternate numeric symbols for numbers. This
            modifier applies only to numeric format specifiers.
     
       Finally, exactly one of the following specifiers must appear. The
       padding rules listed here are the defaults that can be overriden
       with the modifiers listed above.
     
       `a'  The abbreviated weekday name according to the current locale.
     
       `A'  The full weekday name according to the current locale.
     
       `b'  The abbreviated month name according to the current locale.
     
       `B'  The full month name according to the current locale.
     
       `c'  The preferred date and time representation for the current
            locale.
     
       `C'  The century of the year. This is equivalent to the greatest
            integer not greater than the year divided by 100.
     
       `d'  The day of the month as a decimal number (`01' .. `31').
     
       `D'  The date using the format `%m/%d/%y'. NOTE: Don't use this
            format if it can be avoided. Things like this caused Y2K
            bugs!
     
       `e'  The day of the month like with `%d', but padded with blanks
            (` 1' .. `31').
     
       `F'  The date using the format `%Y-%m-%d'. This is the form
            specified in the ISO 8601 standard and is the preferred form
            for all uses.
     
       `g'  The year corresponding to the ISO week number, but without
            the century (`00' .. `99'). This has the same format and
            value as `y', except that if the ISO week number (see `V')
            belongs to the previous or next year, that year is used
            instead. NOTE: Don't use this format if it can be avoided.
            Things like this caused Y2K bugs!
     
       `G'  The year corresponding to the ISO week number. This has the
            same format and value as `Y', except that if the ISO week
            number (see `V') belongs to the previous or next year, that
            year is used instead.
     
       `h'  The abbreviated month name according to the current locale.
            This is the same as `b'.
     
       `H'  The hour as a decimal number, using a 24-hour clock
            (`00' .. `23').
     
       `I'  The hour as a decimal number, using a 12-hour clock
            (`01' .. `12').
     
       `j'  The day of the year as a decimal number (`001' .. `366').
     
       `k'  The hour as a decimal number, using a 24-hour clock like `H',
            but padded with blanks (` 0' .. `23').
     
       `l'  The hour as a decimal number, using a 12-hour clock like `I',
            but padded with blanks (` 1' .. `12').
     
       `m'  The month as a decimal number (`01' .. `12').
     
       `M'  The minute as a decimal number (`00' .. `59').
     
       `n'  A single newline character.
     
       `p'  Either `AM' or `PM', according to the given time value; or
            the corresponding strings for the current locale. Noon is
            treated as `PM' and midnight as `AM'.
     
       `P'  Either `am' or `pm', according to the given time value; or
            the corresponding strings for the current locale, printed in
            lowercase characters. Noon is treated as `pm' and midnight as
            `am'.
     
       `Q'  The fractional part of the second. This format has special
            effects on the modifiers. The width, if given, determines the
            number of digits to output. Therefore, no actual clipping or
            trimming is done. However, if padding with spaces is
            specified, any trailing (i.e., right!) zeros are converted to
            spaces, and if "no padding" is specified, they are removed.
            The default is "padding with zeros", i.e. trailing zeros are
            left unchanged. The digits are cut when necessary without
            rounding (otherwise, the value would not be consistent with
            the seconds given by `S' and `s'). Note that GPC's TimeStamp
            currently provides for microsecond resolution, so there are
            at most 6 valid digits (which is also the default width), any
            further digits will be 0 (but if TimeStamp will ever change,
            this format will be adjusted). However, the actual resolution
            provided by the operating system via GetTimeStamp etc. may be
            far lower (e.g., ~1/18s under Dos).
     
       `r'  The complete time using the AM/PM format of the current
            locale.
     
       `R'  The hour and minute in decimal numbers using the format
            `%H:%M'.
     
       `s'  Unix time, i.e. the number of seconds since the epoch, i.e.,
            since 1970-01-01 00:00:00 UTC. Leap seconds are not counted
            unless leap second support is available.
     
       `S'  The seconds as a decimal number (`00' .. `60').
     
       `t'  A single tab character.
     
       `T'  The time using decimal numbers using the format `%H:%M:%S'.
     
       `u'  The day of the week as a decimal number (`1' .. `7'), Monday
            being `1'.
     
       `U'  The week number of the current year as a decimal number
            (`00' .. `53'), starting with the first Sunday as the first
            day of the first week. Days preceding the first Sunday in the
            year are considered to be in week `00'.
     
       `V'  The ISO 8601:1988 week number as a decimal number
            (`01' .. `53'). ISO weeks start with Monday and end with
            Sunday. Week `01' of a year is the first week which has the
            majority of its days in that year; this is equivalent to the
            week containing the year's first Thursday, and it is also
            equivalent to the week containing January 4. Week `01' of a
            year can contain days from the previous year. The week before
            week `01' of a year is the last week (`52' or `53') of the
            previous year even if it contains days from the new year.
     
       `w'  The day of the week as a decimal number (`0' .. `6'), Sunday
            being `0'.
     
       `W'  The week number of the current year as a decimal number
            (`00' .. `53'), starting with the first Monday as the first
            day of the first week. All days preceding the first Monday in
            the year are considered to be in week `00'.
     
       `x'  The preferred date representation for the current locale, but
            without the time.
     
       `X'  The preferred time representation for the current locale, but
            with no date.
     
       `y'  The year without a century as a decimal number
            (`00' .. `99'). This is equivalent to the year modulo 100.
            NOTE: Don't use this format if it can be avoided. Things like
            this caused Y2K bugs!
     
       `Y'  The year as a decimal number, using the Gregorian calendar.
            Years before the year `1' are numbered `0', `-1', and so on.
     
       `z'  RFC 822/ISO 8601:1988 style numeric time zone (e.g., `-0600'
            or `+0100'), or nothing if no time zone is determinable.
     
       `Z'  The time zone abbreviation (empty if the time zone can't be
            determined).
     
       `%'  (i.e., an item `%%') A literal `%' character. }
     function  FormatTime (const Time: TimeStamp; const Format: String) =
       Res: TString; attribute (name = '_p_FormatTime'); external;
     
     { Pseudo random number generator, from random.pas }
     
     type
       RandomSeedType = Cardinal attribute (Size = 32);
       RandomizeType  = ^procedure;
       SeedRandomType = ^procedure (Seed: RandomSeedType);
       RandRealType   = ^function: LongestReal;
       RandIntType    = ^function (MaxValue: LongestCard): LongestCard;
     
     procedure SeedRandom (Seed: RandomSeedType); attribute (name
       = '_p_SeedRandom'); external;
     
     var
       RandomizePtr : RandomizeType; attribute (name
       = '_p_RandomizePtr'); external;
       SeedRandomPtr: SeedRandomType; attribute (name
       = '_p_SeedRandomPtr'); external;
       RandRealPtr  : RandRealType; attribute (name = '_p_RandRealPtr');
       external;
       RandIntPtr   : RandIntType; attribute (name = '_p_RandIntPtr');
       external;
     
     { File name routines, from fname.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
     
       MaskNoStdDir:      a file name mask that matches all names except
                          the standard directories DirSelf and DirParent
     
       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 it 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__}
     
     {$if defined (__CYGWIN__) or defined(__MSYS__)}
       {$define __POSIX_WIN32__}
     {$endif}
     
     const
       OSDosFlag              = True;
       QuotingCharacter       = #0;
       PathSeparator          = {$ifdef __POSIX_WIN32__} ':' {$else} ';'
       {$endif};
       DirSeparator           = '\';
       DirSeparators          = [':', '\', '/'];
       ExtSeparator           = '.';
       DirRoot                = '\';
       DirSelf                = '.';
       DirParent              = '..';
       MaskNoStdDir           = '{*,.[^.]*,..?*}';
       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              = '..';
       MaskNoStdDir           = '{*,.[^.]*,..?*}';
       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;
     
     { Convert ch to lower case if FileNamesCaseSensitive is False, leave
       it unchanged otherwise. }
     function  FileNameLoCase (ch: Char): Char; attribute (name
       = '_p_FileNameLoCase'); external;
     
     { Change a file name to use the OS dependent directory separator }
     function  Slash2OSDirSeparator (const s: String) = Result: TString;
       attribute (name = '_p_Slash2OSDirSeparator'); external;
     
     { Change a file name to use '/' as directory separator }
     function  OSDirSeparator2Slash (const s: String) = Result: TString;
       attribute (name = '_p_OSDirSeparator2Slash'); external;
     
     { Like Slash2OSDirSeparator for CStrings. *Note*: overwrites the
       CString }
     function  Slash2OSDirSeparator_CString (s: CString): CString;
       attribute (ignorable, name = '_p_Slash2OSDirSeparator_CString');
       external;
     
     { Like OSDirSeparator2Slash for CStrings. *Note*: overwrites the
       CString }
     function  OSDirSeparator2Slash_CString (s: CString): CString;
       attribute (ignorable, name = '_p_OSDirSeparator2Slash_CString');
       external;
     
     { 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) = Result: TString;
       attribute (name = '_p_AddDirSeparator'); external;
     
     { Like AddDirSeparator, but also if the directory does not exist }
     function  ForceAddDirSeparator (const s: String) = Result: TString;
       attribute (name = '_p_ForceAddDirSeparator'); external;
     
     { 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) = Result: TString;
       attribute (name = '_p_RemoveDirSeparator'); external;
     
     { Returns the current directory using OS dependent directory
       separators }
     function  GetCurrentDirectory: TString; attribute (name
       = '_p_GetCurrentDirectory'); external;
     
     { 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; attribute (name
       = '_p_GetTempDirectory'); external;
     
     { Returns a non-existing file name in the directory given. If the
       directory doesn't exist or the Directory name is empty, an I/O
       error is raised, and GetTempFileNameInDirectory returns the empty
       string. }
     function  GetTempFileNameInDirectory (const Directory: String) =
       Result: TString; attribute (iocritical, name
       = '_p_GetTempFileNameInDirectory'); external;
     
     { Returns a non-existing file name in GetTempDirectory. If no temp
       directory is found, i.e. GetTempDirectory returns the empty
       string, an I/O error is raised, and GetTempFileName returns the
       empty string as well. }
     function  GetTempFileName: TString; attribute (iocritical, name
       = '_p_GetTempFileName'); external;
     
     { The same as GetTempFileName, but returns a CString allocated from
       the heap. }
     function  GetTempFileName_CString: CString; attribute (iocritical,
       name = '_p_GetTempFileName_CString'); external;
     
     { Returns True if the given file name is an existing plain file }
     function  FileExists      (const aFileName: String): Boolean;
       attribute (name = '_p_FileExists'); external;
     
     { Returns True if the given file name is an existing directory }
     function  DirectoryExists (const aFileName: String): Boolean;
       attribute (name = '_p_DirectoryExists'); external;
     
     { 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;
       attribute (name = '_p_PathExists'); external;
     
     { 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;
       attribute (name = '_p_FSearch'); external;
     
     { Like FSearch, but only find executable files. Under Dos, if not
       found, the function tries appending '.com', '.exe', '.bat' and
       `.cmd' (the last one only if $COMSPEC points to a `cmd.exe'), 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) =
       Result: TString; attribute (name = '_p_FSearchExecutable');
       external;
     
     { 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; attribute
       (name = '_p_ExpandEnvironment'); external;
     
     { 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; attribute
       (name = '_p_FExpand'); external;
     
     { 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; attribute
       (name = '_p_FExpandQuoted'); external;
     
     { 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) = Result: TString; attribute (name = '_p_RelativePath');
       external;
     
     { Is aFileName a UNC filename? (Always returns False on non-Dos
       systems.) }
     function  IsUNC (const aFileName: String): Boolean; attribute (name
       = '_p_IsUNC'); external;
     
     { Splits a file name into directory, name and extension. Each of
       Dir, BaseName and Ext may be Null. }
     procedure FSplit (const Path: String; var Dir, BaseName, Ext:
       String); attribute (name = '_p_FSplit'); external;
     
     { 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) = Dir: TString;
       attribute (name = '_p_DirFromPath'); external;
     function  NameFromPath    (const Path: String) = BaseName: TString;
       attribute (name = '_p_NameFromPath'); external;
     function  ExtFromPath     (const Path: String) = Ext: TString;
       attribute (name = '_p_ExtFromPath'); external;
     function  NameExtFromPath (const Path: String): TString; attribute
       (name = '_p_NameExtFromPath'); external;
     
     { 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. }
     function  OpenDir  (const DirName: String) = Res: DirPtr; attribute
       (iocritical, name = '_p_OpenDir'); external;
     
     { 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; attribute (name
       = '_p_ReadDir'); external;
     
     { Closes a directory opened with OpenDir. }
     procedure CloseDir (Dir: DirPtr); attribute (name = '_p_CloseDir');
       external;
     
     { 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; attribute (name = '_p_FindNonQuotedChar');
       external;
     
     { 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; attribute (name = '_p_FindNonQuotedStr');
       external;
     
     { Does a string contain non-quoted wildcard characters? }
     function  HasWildCards (const s: String): Boolean; attribute (name
       = '_p_HasWildCards'); external;
     
     { Does a string contain non-quoted wildcard characters, braces or
       spaces? }
     function  HasWildCardsOrBraces (const s: String): Boolean; attribute
       (name = '_p_HasWildCardsOrBraces'); external;
     
     { Insert QuotingCharacter into s before any special characters }
     function  QuoteFileName (const s: String; const SpecialCharacters:
       CharSet) = Result: TString; attribute (name = '_p_QuoteFileName');
       external;
     
     { Remove QuotingCharacter from s }
     function  UnQuoteFileName (const s: String) = Result: TString;
       attribute (name = '_p_UnQuoteFileName'); external;
     
     { Splits s at non-quoted spaces and expands non-quoted braces like
       bash does. The result and its entries should be disposed after
       usage, e.g. with DisposePPStrings. }
     function  BraceExpand (const s: String) = Result: PPStrings;
       attribute (name = '_p_BraceExpand'); external;
     
     { Dispose of a PPStrings array as well as the strings it contains.
       If you want to keep the strings (by assigning them to other string
       pointers), you should instead free the PPStrings array with
       `Dispose'. }
     procedure DisposePPStrings (Strings: PPStrings); attribute (name
       = '_p_DisposePPStrings'); external;
     
     { Tests if a file name matches a shell wildcard pattern (?, *, []) }
     function  FileNameMatch (const Pattern, FileName: String): Boolean;
       attribute (name = '_p_FileNameMatch'); external;
     
     { FileNameMatch with BraceExpand }
     function  MultiFileNameMatch (const Pattern, FileName: String):
       Boolean; attribute (name = '_p_MultiFileNameMatch'); external;
     
     { 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); attribute (name
       = '_p_GlobInit'); external;
     procedure Glob        (var Buf: GlobBuffer; const Pattern: String);
       attribute (name = '_p_Glob'); external;
     procedure GlobOn      (var Buf: GlobBuffer; const Pattern: String);
       attribute (name = '_p_GlobOn'); external;
     procedure MultiGlob   (var Buf: GlobBuffer; const Pattern: String);
       attribute (name = '_p_MultiGlob'); external;
     procedure MultiGlobOn (var Buf: GlobBuffer; const Pattern: String);
       attribute (name = '_p_MultiGlobOn'); external;
     procedure GlobFree    (var Buf: GlobBuffer); attribute (name
       = '_p_GlobFree'); external;
     
     type
       TPasswordEntry = record
         UserName, RealName, Password, HomeDirectory, Shell: PString;
         UID, GID: Integer
       end;
     
       PPasswordEntries = ^TPasswordEntries;
       TPasswordEntries (Count: Integer) = array [1 .. Max (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) = Res: Boolean; attribute (name
       = '_p_GetPasswordEntryByName'); external;
     
     { Finds a password entry by UID. Returns True if found, False
       otherwise. }
     function  GetPasswordEntryByUID (UID: Integer; var Entry:
       TPasswordEntry) = Res: Boolean; attribute (name
       = '_p_GetPasswordEntryByUID'); external;
     
     { Returns all password entries, or nil if none found. }
     function  GetPasswordEntries = Res: PPasswordEntries; attribute
       (name = '_p_GetPasswordEntries'); external;
     
     { Dispose of a TPasswordEntry. }
     procedure DisposePasswordEntry (Entry: TPasswordEntry); attribute
       (name = '_p_DisposePasswordEntry'); external;
     
     { Dispose of a PPasswordEntries. }
     procedure DisposePasswordEntries (Entries: PPasswordEntries);
       attribute (name = '_p_DisposePasswordEntries'); external;
     
     { 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;
       attribute (name = '_p_GetMountPoint'); external;
     
     type
       TSystemInfo = record
         OSName,
         OSRelease,
         OSVersion,
         MachineType,
         HostName,
         DomainName: TString
       end;
     
     { Returns system information if available. Fields not available will
       be empty. }
     function  SystemInfo = Res: TSystemInfo; attribute (name
       = '_p_SystemInfo'); external;
     
     { Returns the path to the shell (as the result) 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) = Res: TString;
       attribute (name = '_p_GetShellPath'); external;
     
     { 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; attribute (name
       = '_p_ExecutablePath'); external;
     
     { 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
       BaseName 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>
     
       DJGPP:  $DJDIR\etc\<base>.ini     $HOME\<base>.cfg
               <dir>\<base>.ini          <dir>\<base>.cfg
     
       Other   $HOME\<base>.ini          $HOME\<base>.cfg
         Dos:  <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, BaseName: String; Global:
       Boolean): TString; attribute (name = '_p_ConfigFileName');
       external;
     
     { 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>/
     
       DJGPP:  $DJDIR\share\<base>\
               <dir>\
     
       Other   $HOME\<base>\
         Dos:  <dir>\
     
       About the symbols used above, and the two possibilities under Dos,
       see the comments for ConfigFileName. }
     function  DataDirectoryName (const Prefix, BaseName: String):
       TString; attribute (name = '_p_DataDirectoryName'); external;
     
     { 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. }
     function  Execute (const CmdLine: String): Integer; attribute
       (iocritical, name = '_p_Execute'); external;
     function  ExecuteNoTerminal (const CmdLine: String): Integer;
       attribute (iocritical, name = '_p_ExecuteNoTerminal'); external;
     
     { File handling routines, from files.pas }
     
     type
       TextFile = Text;
       TOpenMode = (fo_None, fo_Reset, fo_Rewrite, fo_Append,
       fo_SeekRead, fo_SeekWrite, fo_SeekUpdate);
       PAnyFile = ^AnyFile;
     
       TOpenProc   = procedure (var PrivateData; Mode: TOpenMode);
       TSelectFunc = function  (var PrivateData; Writing: Boolean):
       Integer;  { called before SelectHandle, must return a file handle
       }
       TSelectProc = procedure (var PrivateData; var ReadSelect,
       WriteSelect, ExceptSelect: Boolean);  { called before and after
       SelectHandle }
       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;
     
     { Flags that can be `or'ed into FileMode. The default value of
       FileMode is FileMode_Reset_ReadWrite. The somewhat confusing
       numeric values are meant to be compatible to BP (as far as
       BP supports them). }
     const
       { Allow writing to binary 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;
     
       { Allow writing to text files opened with Reset }
       FileMode_Text_Reset_ReadWrite = $100;
     
     var
       FileMode: Integer; attribute (name = '_p_FileMode'); external;
     
     { Get the external name of a file }
     function  FileName (protected var f: GPC_FDR): TString; attribute
       (name = '_p_FileName'); external;
     
     procedure IOErrorFile (n: Integer; protected var f: GPC_FDR;
       ErrNoFlag: Boolean); attribute (iocritical, name
       = '_p_IOErrorFile'); external;
     
     procedure GetBinding (protected var f: GPC_FDR; var b: BindingType);
       attribute (name = '_p_GetBinding'); external;
     procedure ClearBinding (var b: BindingType); attribute (name
       = '_p_ClearBinding'); external;
     
     { TFDD interface @@ Subject to change! Use with caution! }
     procedure AssignTFDD (var f: GPC_FDR;
                           aOpenProc:    TOpenProc;
                           aSelectFunc:  TSelectFunc;
                           aSelectProc:  TSelectProc;
                           aReadFunc:    TReadFunc;
                           aWriteFunc:   TWriteFunc;
                           aFlushProc:   TFlushProc;
                           aCloseProc:   TCloseProc;
                           aDoneProc:    TDoneProc;
                           aPrivateData: Pointer); attribute (name
       = '_p_AssignTFDD'); external;
     
     procedure SetTFDD    (var f: GPC_FDR;
                           aOpenProc:    TOpenProc;
                           aSelectFunc:  TSelectFunc;
                           aSelectProc:  TSelectProc;
                           aReadFunc:    TReadFunc;
                           aWriteFunc:   TWriteFunc;
                           aFlushProc:   TFlushProc;
                           aCloseProc:   TCloseProc;
                           aDoneProc:    TDoneProc;
                           aPrivateData: Pointer); attribute (name
       = '_p_SetTFDD'); external;
     
     { Any parameter except f may be Null }
     procedure GetTFDD    (var f: GPC_FDR;