Compile procedures and functions into the current object (.OBJ) file


      SET PROCEDURE TO [<idProgramFile>[.<ext>]]


TO <idProgramFile> is the name of the procedure file to compile into the current object file. It can optionally include a path and/or drive designator.

<ext> is the optional extension of the procedure. If not specified, .prg is assumed.

SET PROCEDURE TO with no argument is ignored.


SET PROCEDURE directs the compiler to compile all procedures and user- defined functions declared within the specified procedure file into the current object (.OBJ) file.

SET PROCEDURE is a compatibility command and not recommended. It has been superseded by other facilities more appropriate to the compiled environment (e.g., the compiler script (.clp)) file.

See the Clipper “Compiler” chapter in the Programming and Utilities Guide for a full discussion of program architecture and configuration.





Declare a list of procedure or user-defined function names to the linker


       EXTERNAL <idProcedure list>


<idProcedure list> is the list of procedures, user-defined functions, or format procedures to add to the list of routines that will be linked into the current executable (.EXE) file.


EXTERNAL is a declaration statement that specifies uncoded references to the linker. Like all other declaration statements, an EXTERNAL statement must be specified before any executable statements in either the program file, or a procedure or user-defined function definition.

During the compilation of Harbour source code, all explicit references to procedures and user-defined functions are made to the linker. In some instances, there may be no references made to procedure or user-defined function names until runtime. EXTERNAL resolves this by forcing the named procedures or user-defined functions to be linked even if they are not explicitly referenced in the source file. This is important in several instances:

. Procedures, user-defined functions, or formats referenced with macro expressions or variables

. Procedures and user-defined functions used in REPORT and LABEL FORMs and not referenced in the source code . User-defined functions used in index keys and not referenced in the source code

. ACHOICE(), DBEDIT(), or MEMOEDIT() user functions

To group common EXTERNAL declarations together, place them in a header file and then include (#include) the header file into each program (.prg) file that might indirectly use them.

EXTERNAL is a compatibility statement and therefore not recommended. It is superseded by the REQUEST statement that defines a list of module identifiers to the linker.


       .  These examples are equivalent header files consisting of
          common EXTERNAL references for REPORT FORMs:


#include, REQUEST

FT Toolkit Overview

NANFOR.LIB Working Group G. Scott [71620,1521]
Overview UCLA
Version 2.1 October, 1992




This is a standard for establishing and maintaining NANFOR.LIB, a public-domain, user-supported library of functions designed to interface with Computer Associates CA-Clipper, version 5.01a, and later. You are encouraged to read it over and forward comments to Glenn Scott, CIS ID [71620,1521].

1.1 History

In October and November of 1990, a discussion on the evolution of third-party products, vendors, and marketing took place on the CompuServe Information Service’s Nantucket Forum (NANFORUM). During this discussion, a forum subscriber named Alexander Santic suggested the idea of a user-supported Clipper function library, available to all on the CompuServe Information Service (CIS). A number of subscribers, including several Clipper third party developers, and some Nantucket employees, expressed their support. This standard was a first step toward organizing such an endeavor.

Release 1.0 of the toolkit was made available in April, 1991 and had nearly 150 functions. By the time version 2.0 was released in August, 1991, the 1.0 library had been downloaded nearly 700 times by CompuServe users. By October of 1992, release 2.0 had been downloaded over 2100 times. The source code had been downloaded nearly 1500 times. In addition, release 2.0 was placed on the massive Internet archive site called SIMTEL20 where it was downloaded by CA- Clipper users worldwide. Over the course of the year that release 2.0 was available, seven patches were issued, each one gathering nearly 1000 downloads.

Computer Associates International, Inc. acquired Nantucket in the summer of 1992 and subsequently renamed NANFORUM to simply CLIPPER. In addition, the Clipper product itself was renamed to CA-CLIPPER. Despite the name changes, forum members decided to keep the toolkit’s name as “The Nanforum Toolkit,” partly for nostalgia. References to NANFORUM in this RFC have been replaced with CLIPPER.

1.2 Trademarks

CA-Clipper is a registered trademark of Computer Associates International, Inc. Computer Associates will be referred to as CA throughout this document.

1.3 Relationship to CA and third party

NANFOR.LIB is a project independent of any third party developer or CA. There is no official “sanction” or “seal of approval” from CA of any kind. In addition, NANFOR.LIB routines will be accepted and included without regard for whether or not routines performing a similar function are included in a commercial third party or CA product.

It is desired that NANFOR.LIB not compete with third party products but rather fill in the holes in CA-Clipper’s standard library. However, there will be some overlap into commercial third-party library functions, so it would be best if this is never taken into consideration when deciding on including a particular function.

Developers submitting NANFOR.LIB routines can and will be corporate developers, third party developers, independent consultant / programmers, hobbyists, and other CA-Clipper people. Perhaps even CA employees will contribute. No one is excluded or included due to any particular affiliation.

CA employees submitting functions are doing so as individuals, and are not making a policy of involving CA in the project, nor are they committing CA to supporting the public domain library.

1.4 CA-Clipper version supported

NANFOR.LIB functions, no matter what language they are written in, will be designed to work with CA-Clipper version 5.01a and later. Many of the functions, particularly those that use the EXTEND system, will be compatible with the Summer 1987 version of CA-Clipper. However, ensuring Summer 87 compatibility will be the responsibility of the user. If a user wants a function to work with Summer 87, she will have to modify the code herself if necessary. In many cases, this is a trivial task.

1.5 Queries from new users

Queries from new users interested in finding NANFOR.LIB should be handled in a uniform and courteous way. A short text file will be created that will briefly explain NANFOR.LIB, who the current people maintaining it are, and how to get a hold of it. This text message can be sent in response to any query. TAPCIS users will find this method very easy to implement.


2.1 Public Domain

NANFOR.LIB, its source code, and documentation will be public-domain software. It is not for “sale”, and shall not be sold. No fee or contribution of any kind will be required for anyone wanting a copy, other than what they would normally pay to download it from CompuServe. Users will be encouraged to submit functions via CompuServe.

2.2 Official repository

It is possible that copies of NANFOR.LIB will be downloaded and distributed elsewhere. This is encouraged, but the only copy of NANFOR.LIB and all associated documentation that will be maintained by volunteers is in an appropriate library on the CIS CLIPPER Forum.

2.2.1 Contents

The deliverables that make up the official posting on CompuServe shall be: NFLIB.ZIP

This will contain the files NANFOR.LIB (library), and NANFOR.NG (Norton Guide). NFSRC.ZIP

This will contain all the library source code, makefile, and other source-code related materials. NFINQ.TXT

This is a short text file used as a response to new user queries (see paragraph 1.5) NFRFC.ZIP

This contains an ASCII format, as well as a WordPerfect 5.1 format copy of NANFOR.RFC named NFRFC.TXT (ASCII) and NFRFC.WP5 (WordPerfect 5.1). NFHDRS.ZIP

This contains templates of the file and documentation header blocks, including a sample, for prospective authors (FTHDR.PRG, FTHDR.ASM, FTHDR.SAM) PATx.ZIP

These are patch files (see paragraph 4.5.1).


3.1 “Best Function”

It is possible that more than one developer will submit a function or package of functions that perform substantially the same services. In that event, the referees will choose one to be included based on power, functionality, flexibility, and ease of use. Due to the cooperative, non-commercial nature of the library, no one’s feelings should be hurt by excluding duplicate functions.

In addition, it is possible that two substantially similar functions or packages will benefit from merging them together to provide new functionality. This will be the prerogative of the referees (see paragraph 6.3), in close consultation with the authors.

3.2 Public Domain

Each author submitting source code must include as part of that code a statement that this is an original work and that he or she is placing the code into the public domain. The librarian (see paragraph 6.1) and referees should make a reasonable effort to be sure no copyrighted source code, such as that supplied with some third party libraries, makes it into NANFOR.LIB. However, under no circumstances will the librarian, referees, or any other party other than the submitter be responsible for copyrighted code making it into the library accidentally.

3.3 Source code

Full source code must be provided by the author for every routine to be included in NANFOR.LIB. No routine, no matter what language, will be put into the library on the basis of submitted object code.

3.4 Proper submission

Due to the volume of submissions expected, librarians and referees may not have the time to fix inconsistencies in documentation format, function naming, and other requirements. Therefore, the librarian shall expect source code to arrive in proper format before proceeding further with it.

3.5 Quality and perceived usefulness

In a cooperative effort like this, it is very difficult to enforce some standard of quality and/or usefulness. For example, a package of functions to handle the military’s “Zulu time” may be very useful to some, and unnecessary to others.

The Nanforum Toolkit will by its very nature be a hodgepodge of routines, some of very high quality, some not so high. It is up to the users to improve it. It will be complete in some areas and vastly inadequate in others. It is up to the users to fill in the holes.

We shall err on the side of including “questionable” functions, provided they seem to work. Debates on the quality of the library’s source code shall be encouraged and will take place in the proper message section of the CompuServe CLIPPER forum.


4.1 Selection procedure

Source code will be submitted to the librarian, the documenter (see paragraph 6.2), or one of the referees. Code will be added if it has been reviewed, and approved by at least one, but preferably two, referees.

Code not meeting the documentation or source code formatting standards will generally be returned to the author with instructions.

Referees will test the submitted code. When the referees have finished evaluating a submission, they will report their approval or disapproval to the librarian, with comments.

Every effort should be made to make sure that the C and ASM functions are reviewed by referees with suitable C and ASM experience.

4.2 Update interval

As new functions are submitted, they will added to the library, and the documentation updated. Because this is a volunteer project, and because of the complexity involved in coordinating testing, documentation, and delivery, there will be no fixed interval for updates.

4.3 Version control

NANFOR.LIB will use a numeric version number as follows:

The major version will be numeric, starting from 1. This will change with each quarterly update. The minor version will change with each bug fix. This will start with zero and continue until the next major update, at which point it will revert to zero again.

Typical version numbers might be 1.1, 2.12, 15.2, etc.

The .LIB file, and all associated files, will carry a date stamp corresponding to the day it is released on the CLIPPER forum. The file time stamps shall correspond to the version number (i.e., 1:03am is version 1.3).

4.4 Announcing updates

As the library and its associated documentation are updated, simple announcements will be posted on the CLIPPER forum. This is the only place where an update shall be announced. An update will be announced after it has been successfully uploaded to the appropriate library on CompuServe.

4.5 Bug reports and fixes

The librarian will correlate and verify all bug reports, with the help of the referees. If the referees believe a bug to be serious, they will fix it and the librarian will release a maintenance upgrade immediately. If they consider it a minor bug, they will fix it but wait for the next scheduled upgrade to release it. In this case, a bug fix may be released as a “Patch.”

4.5.1 Patches

A “patch” is simply an ASCII text file containing instructions for editing the source code to a misbehaving function or group of functions. Patches may appear in the CIS library before a maintenance release or quarterly upgrade. A patch file will have a name of the form


where <n> is a number starting from 1. Patches will be numbered sequentially. Patches will be deleted every time a new version of NANFOR.LIB goes on-line.

A patch zipfile may optionally contain .OBJ files to be replaced in user libraries via a LIB utility.

4.6 Technical Support

Technical support will work just as any technical subject on the CompuServe CLIPPER forum works. Users will post questions and suggestions to a particular message area or thread, and anyone who knows the answer should respond. No one is obliged to answer, but it is considered good form to respond with something, even if one doesn’t know the answer.

Support will include help on recompiling the routines or modifying the source.

4.7 Linker Compatibility

In order to assist users of CA-Clipper third party linkers (such as WarpLink or Blinker), NANFOR.LIB may need to broken up into root and overlay sections. How this will be done will be determined when splitting becomes necessary.

The librarian is not responsible for testing every possible linker for NANFOR.LIB compatibility. It is hoped that linker users will submit appropriate link scripts or other documentation for posting in the appropriate section on the CLIPPER forum.

4.8 Splitting NANFOR.LIB by functional category

It is possible that at some future date, it will make sense to split NANFOR.LIB into separate functional areas (e.g., video routines vs. date routines, etc). This RFC will be modified accordingly should that need arise.


The goal of this standard is not to force anyone to rewrite his code for this library, but to create some consistency among the functions so that they may more easily maintained and understood by all CA-Clipper developers, both novice and advanced.

However, it is extremely important that anyone submitting code attach the proper headers and documentation and fill them out correctly. This will make it much easier for code to be added to the library.

5.1 Required sections for each function
5.1.1 Header (author name/etc, version ctrl info)

Figure 1 shows a header that must be included at the top of every piece of source code submitted to the library. This header will work with both CA-Clipper and C code. For ASM code, substitute each asterisk (“*”) with a semicolon (“;”) and delete the slashes (“/”).

 * File......:
 * Author....:
 * CIS ID....: x, x
 * Date......: $Date$
 * Revision..: $Revision$
 * Log file..: $Logfile$
 * Modification history:
 * ---------------------
 * $Log$
Figure 1 - Standard function header.

Note that the date, revision, logfile, and modification history fields will be maintained by the librarian and should not be edited or adjusted by code authors.

The “File” field shall contain the source file name. This is often independent of the individual function name. For example, a function named ft_screen() would be included in SCREEN.PRG. As a rule, source files (.PRG, .C, .ASM) should not have the “FT” prefix.

The “Author” field should have the author’s full name, and CIS number. A CIS number is important, as this will make bug fixing and other correspondence easier.

5.1.2 Public domain disclaimer

Authors shall simply state “This is an original work by [Author’s name] and is hereby placed in the public domain.”

5.1.3 Documentation block
/* $DOC$
 * $END$

Figure 2 – Standard Documentation Header

The documentation block must be carefully formatted as it is used by the documenter to produce the Norton Guide documentation for the library.

The keywords enclosed in dollar-signs delimit sections of the documentation header analogous to those in the CA-Clipper 5.0 documentation. Documentation should be written in the same style and flavor as the CA material, if possible. Refer to the CA-Clipper documentation for more detail and numerous examples.

The documentation will appear on comment lines between the keywords. Examples are optional. Do not put documentation on the same line as the comment keyword.

Note that the $DOC$ and $END$ keywords serve as delimiters. Do not place any text between $DOC$ and $FUNCNAME$, or any documentation after the $END$ keyword, unless that documentation belongs in the source code file and not in the resultant Norton Guide file.

The $FUNCNAME$ keyword should be followed by the function name, with parentheses, and no arguments or syntax, such as:


Note the indent for readability. Parentheses shall be added after the function name as shown above.

The $ONELINER$ keyword should be followed by a simple statement expressing what the function does, phrased in the form of a command, e.g.:

          Sum the values in an array

The length of the entire $ONELINER$ shall not exceed 60 characters (this is a Norton Guide limitation).

The $SYNTAX$ keyword should be followed by a CA- standard syntax specifier, such as:

         ft_screen( <nTop> [,<nBottom>] ) -> NIL

All parameters have proper prefixes (see paragraph 5.4), and are enclosed in <angle brackets>. Optional parameters are enclosed in [square brackets] as well. An arrow should follow, pointing to the return value. If there is no return value, it should be NIL. Any others should be preceded with the proper prefix (see the CA- Clipper documentation).

The $SEEALSO$ field provides a way to generate cross-references in the Norton Guide help documentation. Use it to point the user to other related functions in the forum toolkit. For example, if ft_func1() is also related to ft_func2() and ft_func3(), the field would look like this:

ft_func2() ft_func3()

Note that fields are separated by spaces and the parentheses are included.

The $INCLUDE$ area allows you to specify what files are included by this function (this will be used to organize the on-line help file, and possibly the master makefile). An example would be


Other documentation fields should be self- explanatory. Review the appendix for a sample. All fields are required and must be filled in. Examples should not be considered optional.

5.1.4 Sample header and documentation block

Refer to the Appendix for a sample header and documentation block.

5.1.5 Test driver

A test driver is an optional section of C or CA- Clipper code that will only be compiled under certain circumstances. Developers are encouraged to include a short “test section” in front of their code.

The test driver shall be surrounded by the following pre-processor directives, and placed at the top of the source file:

#ifdef FT_TEST
     [test code]

The test driver is currently optional, but authors submitting Clipper code should seriously consider adding it. It is a good way to include short demos within a piece of source code, yet pay no penalty because it is only compiled if needed. It will be invoked when a #define is created that says “#define FT_TEST.” This is a way for submitters to include short test routines with their functions and yet keep it all in one source file. This will be useful to end users.

This test driver may become required in a future version of the RFC.

5.1.6 Code

The source code shall be formatted as described in paragraph 5.4.

5.2 Function names

All NANFOR.LIB functions start with one of two prefixes. If the function is to be called by user programs, then it will begin with the prefix

FT_       ("F", "T", underscore)

Note that “FT” is a mnemonic for “Forum Toolkit.” If the function is “internal” to a module, then it will be prefixed by an underscore:

_FT ( Underscore, "F", "T" )

with no trailing underscore. Examples:

FT_CURDIR() "external"
_ftAlloc() "internal"
5.3 Librarian’s authority to change function names

Some functions will be submitted that either (1) bear a similar name to another function in the library, or (2) bear an inappropriate name. For example, a function called FT_PRINT that writes a character to the screen could be said to be named inappropriately, as a name like FT_PRINT implies some relationship to a printer. The librarian shall have the responsibility to rename submitted functions for clarity and uniqueness.

5.3.1 Changing a function name after it has been released

Once the library is released with a particular function included, then a function name should generally be frozen and not renamed. To do so would probably cause difficulties with users who had used the previous name and are not tracking the changes to the library.

5.4 Source code formatting
5.4.1 Clipper

Clipper code shall be formatted in accordance with CA’s currently defined publishing standard. Although there will surely be some debate over whether this is a good idea, in general, the goal is to provide something consistent that all CA- Clipper developers will recognize.

Minor deviations will be permitted.

The CA standard usually means uppercase keywords, and manifest constants, and lower case everything else.

In addition, identifiers shall be preceded with the proper metasymbol:

 n Numeric
 c Character or string
 a Array
 l Logical, or boolean
 d Date
 m Memo
 o Object
 b Code block
 h Handle
 x Ambiguous type

Refer to the CA-Clipper documentation for samples of CA’s code publishing format.

5.4.2 C

C source code shall be formatted in a generally accepted way, such as Kernighan and Ritchie’s style used in the book _The C Programming Language_.” The use of CA’s EXTEND.H is encouraged.

5.4.3 ASM

No particular formatting conventions are required for assembly language source code, since assembly code formatting is fairly standard. Lowercase code is preferred. Be sure to include the proper documentation header information, as described above.

Do not place ASM code in DGROUP. See paragraph 5.11.

5.5 Organization into .PRGs

Since many different people will be submitting routines, it is probably best if all routines that belong together are housed in the same .PRG. If there is some reason to split the .PRG, the referees and the librarian will handle that as part of library organization.

5.6 Header files

Including a “.ch” or “.h” or “.inc” file with each function would get unwieldy. For the purpose of NANFOR.LIB, all #defines, #ifdefs, #commands, #translates, etc that belong to a particular source file shall be included at the top of that source file. Since few submissions will split over multiple source files, there will usually be no need to #include a header in more than one place.

If a “ch” file will make the end user’s job of supplying parameters and other information to NANFOR.LIB functions easier, then it shall be submitted as a separate entity. The referees will decide on whether to include these directives in a master NANFOR.CH file.

5.7 Clipper 5.0 Lexical Scoping

NANFOR.LIB routines that are written in CA-Clipper will make use of CA-Clipper 5.0’s lexical scoping features to insulate themselves from the rest of the user’s application.

For example, all “privates” shall generally be declared “local.”

If a package of Clipper functions is added to the library, then the lower-level, support functions will be declared STATIC as necessary.

5.8 Use of Publics

Authors shall not use PUBLIC variables in NANFOR.LIB functions, due to the potential interference with an end-user’s application or vice versa.

If a global is required for a particular function or package of functions, that global shall be accessed through a function call interface defined by the author (.e.g, “ft_setglobal()”, “ft_getglobal()”, and so on). Globals such as these shall be declared static in the .PRG that needs them.

5.9 Use of Macros (“&” operator)

The use of macros in NANFOR.LIB functions will be, for the most part, unnecessary. Since this is a CA-Clipper 5.0 library, the new 5.0 codeblock construct should be used instead. Anyone having trouble figuring out how to convert a macro to a codeblock should post suitable questions on the CLIPPER forum on CompuServe.

5.10 Use of Static Functions

Any CA-Clipper 5.0 function that is only needed within the scope of one source file shall be declared STATIC. This applies mostly to NANFOR.LIB “internals” (names with an “_ft” prefix) that user programs need not access.

5.11 Use of DGROUP in ASM Functions

Use of DGROUP in assembly language functions shall be avoided, in accordance with CA’s recommendations. Assembly functions written for NANFOR.LIB shall use a segment named _NanFor, as in the following example:

Public FT_ChDir
Extrn _ftDir:Far
Segment _NanFor Word Public "CODE"
 Assume CS:_NanFor
Proc FT_ChDir Far
 Endp FT_ChDir
 Ends _NanFor
5.12 Use of "Internals"

Use of CA-Clipper “internals” by code authors is allowed. However, should any code make use of an internal, i.e., a function or variable that is not part of the published CA-Clipper API, then that internal shall be clearly marked in the documentation (under “DESCRIPTION”) and in the actual code, everywhere the internal is used.

5.13 Procedures for compiling functions
5.13.1 Clipper

Clipper functions will be compiled under the current release of CA-Clipper 5.0, with the following compiler options:

/n /w /l /r

Note that neither line numbers nor debugging information will find its way into NANFOR.LIB, to keep the code size down. End users may recompile NANFOR.LIB with these options enabled if they want to view NANFOR.LIB source in the debugger.

5.13.2 ASM

Assembly functions must compile successfully under any MSDOS assembler capable of producing the proper .OBJ file. However, care should be taken not to use any macros or special syntax particular to one vendor’s assembler, because that would make it difficult for end users to recompile the source. The preferred assembler is MASM, followed by TASM.

5.13.3 C

C functions must compile successfully under any C compiler capable of interfacing to CA-Clipper. Obviously, Microsoft C, version 5.1, is the preferred development environment. Care should be taken, when writing C code, not to use any special compiler features particular to one vendor’s C compiler, because that would make it difficult for end users to recompile the source.

5.14 Functions requiring other libraries

It is very easy to write functions in C that call the compiler’s standard C library functions. However, NANFOR.LIB can make no assumptions about the end user’s ability to link in the standard library or any other library. Therefore, no function will be added to NANFOR.LIB that requires any other third party or compiler manufacturer’s library.


6.1 Librarian

The librarian will be the person who rebuilds the library from the sources and uploads the resulting deliverables to the proper CLIPPER forum library on CompuServe. The librarian generally does *not* test code or edit source code to repair formatting errors.

6.2 Documenter

The documenter is responsible for maintaining the Norton and guides and keeping it in sync with each new release.

6.3 Referees

Referees are volunteers who read source code, clean it up, compile it, look for problems like potentially problematic C code, decide on which function is best, consolidate common functions, etc. They make sure the header and documentation blocks are present. There is no election or term for refereedom. One simply performs the task as long as one can and bows out when necessary.

6.4 Transitions

Not everyone will be able to stay around forever to keep working on this project. Therefore, it is the responsibility of each referee, documenter, or librarian to announce as far in advance as possible his or her intention to leave, in order to give everyone a chance to come up with a suitable replacement. Don’t let it die!


Current contributors, directly and indirectly, to this document include:

Don Caton [71067,1350]
Bill Christison [72247,3642]
Robert DiFalco [71610,1705]
Paul Ferrara [76702,556]
David Husnian [76064,1535]
Ted Means [73067,3332]
Alexander Santic [71327,2436]
Glenn Scott [71620,1521]
Keith Wire [73760,2427]
Craig Yellick [76247,541]
James Zack [75410,1567]


  • In Harbour library file name of NanForum Toolkit is hbnf.a
  • Maybe some functions :
    • obsoleted,
    • used some low-level hardware access or some OS specific features,
    • so not included in hbnf library.


 Include a file into the current source file

     #include "<headerFileSpec>"


     <headerFileSpec> specifies the name of another source file to
     include in the current source file.  As indicated in the syntax, the
     name must be enclosed in double quotation marks.

     <headerFileSpec> may contain an explicit path and file name as well as a
     file extension.  If, however, no path is specified, the preprocessor
     searches the following places:

     .  Source file directory

     .  Directories supplied with the /I option

     .  Directories specified in the INCLUDE environment variable

     #include directives may be nested up to 15 levels deep--that is, a file
     that has been included may contain #include directives, up to 15 levels.


     #include inserts the contents of the specified file in place of the
     #include directive in the source file.  By convention, the file inserted
     is referred to as a header file.  Header files should contain only
     preprocessor directives and external declarations.  By convention
     Clipper header files have a .ch extension.

     When deciding where to locate your header files, you have two basic
     choices.  You can place them in the source file directory where they are
     local to the current system; or, you can make them globally available by
     placing them in the directory specified in the INCLUDE environment
     variable.  A list of one or more directories can be specified.

     Header files overcome the one major drawback of defining constants or
     inline functions--the #define directive only affects the file in which
     it is contained.  This means that every program which needs access to
     these statements must have a list of directives at the top.  The
     solution to this problem is to place #define statements in a separate
     file and use the #include directive to tell the preprocessor to include
     that file before compiling.

     For example, suppose the file "" contains a list of #define
     directives assigning key values to constants.  Instead of including
     these directives at the top of each program file (.prg) requiring access
     to them, you can simply place the following line at the top of each
     program file:

     #include ""

     This causes the preprocessor to look for and place all the
     directives contained within it at the top of this program.

     Another advantage of using the #include directive is that all the
     #define statements are contained in one file.  If any modifications to
     these statements are necessary, only the #include file need be altered;
     the program itself remains untouched.

     Note that the scope of definitions within an included header file is the
     current program file unless the header file is included on the compiler
     command line with the /U option.  In this case, the scope is all the
     program files compiled in the current invocation of the compiler.


     .  Supplied header files: Clipper provides a number of header
        files containing manifest constants for common operations.  Refer to
        \CLIP53\INCLUDE for more information.

     . standard header file: is the standard
        header file provided with Clipper.  Its default location is
        \CLIP53\INCLUDE. contains the definitions of all Clipper
        commands and the standard functions specified as pseudofunctions.  It
        is strongly recommended that no changes be made to  If
        changes are desired, it is advisable to copy to a new name,
        make the changes, and compile with /U.

        This header file differs somewhat from a header file you might
        #include in that everything defined in, with #define,
        #translate, or #command, has a scope of the entire compile rather
        than the current source file.


     .  This example uses #include to insert, a file of
        common keyboard definitions, into a key exception handler called by
        an interface function:

        #include ""

        FUNCTION GetEvent()
           LOCAL nKey, nResult
           nKey = INKEY(0)
           DO CASE
           CASE nKey = K_F10
              nResult := DoMenu("Browse")
           CASE nKey = K_ESC
              nResult := DoQuit()
              . <statements>
           CASE nKey = K_CTRL_RIGHT
              nResult := DoNextRec()
           RETURN nResult

See Also: #command #define

C5 Directives

#command        Specify a user-defined command or translation directive
#define         Define a manifest constant or pseudofunction
#error          Generate a compiler error and display a message
#ifdef          Compile a section of code if an identifier is defined
#ifndef         Compile a section of code if an identifier is undefined
#include        Include a file into the current source file
#stdout         Send literal text to the standard output device
#translate      Specify a user-defined command or translation directive
#undef          Remove a #define macro definition 
#xcommand       Specify a user-defined command or translation directive
#xtranslate     Specify a user-defined command or translation directive

Quick Start to Migration

Chapter I – Text to text conversion

In Clipper world, “migration” means “convert a DOS based Clipper program to Windows”. This is a dream of every Clipper – DOS programmer.

 Before all, we need clarify some terms:

May be found multiple ways for convert a DOS based Clipper program to Windows. In general, DOS programs are runs in “text” mode and Windows program runs in “Graphic” mode; and this is what meant by term “migration”.

Converting a text mode program to directly GUI (Graphical User Interface) is a painful job. First, we need to find a Compiler with GUI support, or a GUI library usable with a specific compiler. If we have more than one opportunity ( yes, it is so ) we need make a choice between them.

For make a right selection we need learn, understand specialties of each option and differences between them.

Believe me, this is an endless way 😦

Instead, let’s begin with simpler thing: convert a DOS text mode program to Windows text mode program.

Question: Without GUI, what meaning will be to migrate from DOS to Windows?

Answer: Good question and like all good question, answer isn’t easy.

First, modern OSs moves away day to day from DOS conditions; memory problems, screen problems, codepage problems, etc… By the time, building / running 16 bit executable becomes more difficult day to day.

Whereas Harbour already is a 32 / 64 bit compiler.

Second, all DOS Compilers for Clipper are commercial and registration required products; furthermore they are almost out of sold for this days; what compiler you could use?

And third, Harbour is best free compiler and the best way to use a free GUI tool for xBase language.

So, beginning with using Harbour in text mode is the best start point, I think.

First step is downloading and install HMG or Harbour. If you didn’t past this step yet please refer previous articles in this section or “Links” page of this blog.

The easiest way for using Harbour compiler is calling hbmk2, the wonderful project maker for Harbour compiler.

Depending your installation, hbmk2 may be in different locations; such as C:\Harbour\bin or c:\hmg\harbour\bin or anything else.

Hereafter I will assume that your hbmk2 is in C:\hmg\Harbour\bin. If your installation is different, please modify above examples.

Second step is assign an empty folder (directory) for work / test affairs; say C:\test.

And the third step is copying your Clipper program(s) to this folder.

But don’t rush; we have some precautions:

– Better way is starting with a single-program project; if you haven’t written a new one. Don’t uses for now projects have multiple program file.

 – Your program may have some “national” characters and these characters may be differently shown between DOS and Windows. If so, you may want fix manually these differences via a Windows based text editor. Or use a program if you have one. Harbour has a clever tool (HB_OEMTOANSI() function) is usable for this purpose.

 – In Clipper it’s possible a program file without module (procedure / function) definition. If you have such file(s), enclose your code with PROCEDURE — RETURN statement pair.

– Every Harbour project must have one and only one MAIN module (procedure / function). The first procedure / function in your single program file will be considered as MAIN module of your project. (In HMG, name of this module must be “main” also).

– Almost all Clipper commands, statement, functions, pseudo functions, manifest constants etc are usable almost in the same ways with Clipper. May be exist some very few and very rare differences, and of course solving methods for its.

For compile process we will use command box (DOS / console window) of Windows. You can open a console window, with the menu Start -> Run -> cmd or selecting it in the “Command Prompt” from the Start Menu \ All Programs.

 – “Command / console window” size may not appropriate for easy use. You may

      – use a MODE ( DOS ) command :

         MODE CON LINES=54 COLS=148


   – adding a SetMode() statement at the beginning of MAIN module of your project. For example:

       SetMode( 25,  80 )  // 25 line 80 column same as standard 
                           // DOS screen ( but not full screen ! )
       SetMode( 48, 128 )  // 48 line 128 column, may be more readable

Now, we are ready to begin: Enter this command in console window :

 C:\hmg\harbour\bin hbmk2 <mainPrgName>

You don’t need any SET command (such as PATH etc) before this command; hbmk2 will find all necessary paths / files.

For running executable after compile, add a -run switch to the command line :

 C:\hmg\harbour\bin hbmk2 <mainPrgName> -run

Of course, you need supply name of your main .prg file in place of <mainPrgName>.

Note that you don’t need a separate “linking” step; hbmk2 will do everything for you.

You may use this

 C:\hmg\harbour\bin hbmk2 <mainPrgName>

command via a batch ( .bat ) command file (such as “build.bat”) too. In this way you can apply compiling process without console window; run .bat file by double click in the Windows Explorer. In this case you may need add a PAUSE command at end of .bat file.

That’s all.

You know, a program file may contains more than one module (procedure / function). So you may develop your project by adding new modules to your single program file.

In this step you don’t need trying extra features, extensions of Harbour. Before that adventure your primary need is to convert existing project Clipper to Harbour.

When you reach a level of multiple-program file project:

– Basic rules are the same: the first module in the your program file is MAIN module of your project.

If your .prg files contains:

  SET PROCEDURE TO <procedure_File_Name>

 and / or

   #include <procedure_File_Name>

 you may or may not continue using these statement.

 – The shortest way for compiling a multiple-file project is use a .hbp ( Harbour Projet ) file. This is a text file and its simplest form is a file contains list of your .prg files. For example:


and the compile command is the same :

  C:\hmg\harbour\bin hbmk2 <mainProjectFileName>

In this case you don’t need to use SET PROC… and #include … statement and this is the better way.

Because hbmk2 applies “incremental” compiling, that is compiles only modified files.

Under normal circumstances, any module in any program file is callable in anywhere in the project. If you have some modules that exclusive to this program file, you may use STATIC keyword at the beginning of PROCEDURE / FUNCTION statement. For example:


With this syntax you will prevent calling this module outside of this .prg file and the possibility of using this module name into other .prg files.

Example :

Take “A typical Harbour Program” in the “Harbour Sample” page.

As seen at .pdf file by given link, this sample program borrowed from official reference guide of a Clipper compiler. That is, in fact this is a Clipper program and it will may compile with Harbour and run without any modification.

Let’s try.

– Copy and paste this sample and save in your PC with a name say “typical.prg”.

– Comment out the line for now.

 #include "Database.prg" // Contains generic database functions

– Call hbmk2:

 C:\hmg\harbour\bin hbmk2 typical -run

 Note: While working / playing on programs, you may encounter some error messages like:

  Error F0029  Can't open #include file xxx
  Error E0002  Redefinition of procedure or function xxx
  Error: Referenced, missing, but unknown function(s): xxx
  undefined reference to HB_FUN_xxx

 Please don’t panic !

    “Error” is salt and pepper of programming play ! 😉

 The worst situation isn’t getting error, but is unable to stay !

   The “HB_FUN_xxx” may be seen weird at first meet. The “HB_FUN_” is a prefix given by system ( compiler ) to your function; so you need search erroneous point into tour program files without this prefix.

Now, let’s continue to our “typical” program:

If you compile the program with commented out #include … line, possibly it will work, by opening main menu:


But what’s that?

When selected a menu item (except “Quit”) we can’t see other than an empty screen!

Again, don’t panic!

This situation too is not very rare !

If you use vertical scroll bar of command / console window, you will notice that your screen is considerably much longer than seen !

To avoid this conflict, ( as stated above ) we need use a SetMode() function call at top of our Main() procedure ( but AFTER LOCAL statement ! ) :

  SetMode( 24, 79 )

 And now everything is OK.


In fact, not really everything, we have a few “fine adjustment”.

Cut and paste the section after “// Database.prg” to a separate “Database.prg” file, un-comment the “#include …” line and then re-compile.

In this case we have a “multiple prg” project. As stated earlier, better way is using a .hbp file instead of “#include …” statements.

Now comment out ( or delete now ) the #include line.

Build a new text file with name “typical.hbp” and with this content :


And recall hbmk2 without any modification :

C:\hmg\harbour\bin hbmk2 typical -run

That’s all !

Congratulations !

Now you have a multiple-prg project  !

PutFile() with 5th parameter

Beware : This article posted on  February 2, 2013 and than with HMG 3.1.3 release on 23 May 2013 added 5th and 6th parameters to that function by our genius Dr. Soto …

Look at changelog of HMG.


PutFile() is a HMG function that :

Opens ‘Save As’ System Dialog And Returns The Saved File name


PutFile ( acFilter , cTitle , cIniFolder , lNoChangeDir ) –> cSavedFileName

Although its name is “Put”, this function doesn’t “put” anything to anywhere; that is don’t write anything to disk. It only return a file name ( or empty string if user not selected / typed anything). File that name returned by PutFile() may exist or not. This is only difference between PutFile() and GetFile(); the second return only name of an existing file.

Therefore PutFile() function doesn’t check overwrite status. This is totally responsibility of programmer and if not care, PutFile() become a dangerous tool. The “Default File Name” and network environments will increase the risk. Of course no problem for intentionally overwrite.

As a result, PutFile() open a “Save As…” dialog box and returns a file name to save, selected / typed by user.

As above syntax indicated, this function has four parameters.

Whereas sometime required a bit more info : default file name.

When program suggest a default file name, in addition to select / type a new file name, user may feel more comfortable by only confirm (verbatim or after typing something) suggested file name.

This is a bit modified version of PutFile() (with a small test program); since accept default file name as 5th parameter, name is PutFile5P()

Note : This work is superseded by adding two parameters to official PutFile() function at HMG 3.1.4 2013/06/16.

Happy HMG’ing 😀




  HMG Common Dialog Functions 
  PutFile5P() Test prg.

#include ""
  LOCAL nTask
     AT 0,0 ;
     WIDTH 400 ;
     HEIGHT 400 ;
     TITLE 'PutFile with Default File Name' ;
        POPUP 'Common &Dialog Functions'
           ITEM 'PutFile5P()'ACTION MsgInfo( Putfile5P( ;                       
                { {'Text Files','*.txt'} },; // 1° acFilter ;
                   'Save Text',;             // 2° cTitle 
                   'C:\',;                   // 3° cIniFolder 
                   ,;                        // 4° lNoChangeDir 
                  "New_Text.TXT" ) )         // 5° cDefaultFileName
       END POPUP
FUNCTION Putfile5P ( aFilter, title, cIniFolder, nochangedir, cDeFilName )
   LOCAL c:='' , n

   IF aFilter == Nil
      aFilter := {}

   IF HB_ISNIL( cDeFilName )
      cDeFilName := ''

   FOR n := 1 TO Len ( aFilter )
       c += aFilter [n] [1] + chr(0) + aFilter [n] [2] + chr(0)

RETURN C_PutFile5P ( c, title, cIniFolder, nochangedir, cDeFilName )
#define HB_OS_WIN_USED
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include "hbapi.h"
#include "hbapiitm.h"



 char buffer[512];


 if ( hb_parl(4) )
 flags = flags | OFN_NOCHANGEDIR ;

 if( strlen( hb_parc( 5 ) ) != 0 )
 strcpy( buffer, hb_parc( 5 ) );
 strcpy( buffer, "" );

 memset( (void*) &ofn, 0, sizeof( OPENFILENAME ) );
 ofn.lStructSize = sizeof(ofn);
 ofn.hwndOwner = GetActiveWindow() ;
 ofn.lpstrFilter = hb_parc(1) ;
 ofn.lpstrFile = buffer;
 ofn.nMaxFile = 512;
 ofn.lpstrInitialDir = hb_parc(3);
 ofn.lpstrTitle = hb_parc(2) ;
 ofn.Flags = flags;

 if( GetSaveFileName( &ofn ) )
 hb_retc( ofn.lpstrFile );
 hb_retc( "" );
#pragma ENDDUMP

Hash Basics


In general, a Hash Table, or Hash Array, or Associative array, or shortly Hash is an array- like data structure, to store some data with an associated key for each; so, ‘atom’ of a hash is a pair of a ‘key’ with a ‘value’. A hash system needs to perform at least three operations:

–      add a new pair,

–      access to value via key

–      the search and delete operations on a key pair

In Harbour, a hash is simply a special array, or more precisely a “keyed” array with special syntax with a set of functions.


The “=>” operator can be used to indicate literally the relation between <key> <value> pair: <key> => <value>

 We can define and initialize a hash by this “literal” way :

 hDigits_1 := { 1 => 1, 2  => 2, 3  => 3, 4  => 4 }

 or by a special function call:

 hDigits_1 := HB_HASH( 1, 1, 2, 2, 3, 3, 4, 4 )

 Using “add” method may be another way :

hDigits_1 := { => } // Build an empty hash
hDigits_1[ 1] := 1

hDigits_1[ 2] := 2

hDigits_1[ 3] := 3

hDigits_1[ 4] := 4

In this method while evaluating each of above assignments, if given key exits in hash, will be replaced its value; else add a new pair to the hash.

In addition, data can be added to a hash by extended “+=” operator:

   hCountries := { 'Argentina' => "Buenos Aires" }
   hCountries += { 'Brasil'    => "Brasilia" }
   hCountries += { 'Chile'     => "Santiago" }
   hCountries += { 'Mexico'    => "Mexico City" }

Hashs may add ( concatenate ) each other by extended “+” sign :

   hFruits := { "fruits" => { "apple", "chery", "apricot" } }
   hDays   := { "days"   => { "sunday", "monday" } } 
   hDoris := hFruits + hDays

Note:  This “+” and “+=” operators depends xHB lib and needs to xHB lib and

Typing :

<key> part of a hash may be any legal scalar type : C, D, L, N; and <value> part may be in addition scalar types, any complex type ( array or hash ).

Correction : This definition is wrong ! The correct is :

<key> entry key; can be of type: number, date, datetime, string, pointer.

Corrected at : 2015.12.08; thanks to Marek.

hDigits_2 := {  1  => “One”,  2  => “Two”,  3  => “Three”,  4  => “Four” }

hDigits_3 := { "1" => "One", "2" => "Two", "3" => "Three", "4" => "Four" }
hDigits_4 := { "1" => "One",  2  => "Two",  3  => "Three", "4" => "Four" }
hDigits_5 := {  1  => "One",  1  => "Two",  3  => "Three",  4  => "Four"

All of these examples are legal. As a result, a pair record of a hash may be:

–      Numeric key, numeric value ( hDigits_1 )

–      Numeric key, character value ( hDigits_2 )

–      Character key, character value ( hDigits_3 )

–      Mixed type key ( hDigits_4 )

Duplicate keys (as seen in hDigits_5) is permitted to assign, but not give a result such as double keyed values: LEN( hDigits_5 ) is 3, not 4; because first pair replaced by second due to has same key.

Consider a table-like data for customers records with two character fields: Customer ID and customer name:

Cust_ID Cust_Name
CC001 Pierce Firth
CC002 Stellan Taylor
CC003 Chris Cherry
CC004 Amanda Baranski

We can build a hash with this data :

  hCustomers := { "CC001" => "Pierce Firth",;
 "CC002" => "Stellan Taylor",;
 "CC003" => "Chris Cherry",;
 "CC004" => "Amanda Baranski" }

and list it:

   ? "Listing a hash :"
   h1Record := NIL
   FOR EACH h1Record IN hCustomers
      ? cLMarj, h1Record:__ENUMKEY(), h1Record:__ENUMVALUE()

 Accessing a specific record is easy :

 hCustomers[ "CC003" ] // Chris Cherry
Hash Basics

#include ""
#define NTrim( n ) LTRIM( STR( n ) )

 cLMarj := SPACE( 3 )


 hDigits_1 := { => } // Build an empty hash

 hDigits_1[ 1 ] := 1
 hDigits_1[ 2 ] := 2
 hDigits_1[ 3 ] := 3
 hDigits_1[ 4 ] := 4

 ListHash( hDigits_1, "Digits_1" )

 hDigits_2 := HB_HASH( 1, 1, 2, 2, 3, 3, 4, 4 )

 ListHash( hDigits_2, "Digits_2" )

 hDigits_3 := { 1 => 1,;
 2 => 2,;
 3 => 3,;
 4 => 4 }
 ListHash( hDigits_3, "Digits_3" )

 hDigits_4 := { 1 => "One",;
 2 => "Two",;
 3 => "Three",;
 4 => "Four" }
ListHash( hDigits_4, "Digits_4" )

 hDigits_5 := { "1" => "One",;
 "2" => "Two",;
 "3" => "Three",;
 "4" => "Four" }
 ListHash( hDigits_5, "Digits_5" )

 hDigits_6 := { "1" => "One",;
 2 => "Two",;
 3 => "Three",;
 "4" => "Four" }
 ListHash( hDigits_6, "Digits_6" )

 hDigits_7 := { 1 => "One",;
 1 => "Two",; // This line replace to previous due to same key 
 3 => "Three",;
 4 => "Four" }
 ListHash( hDigits_7, "Digits_7" )

 * WAIT "EOF digits"

 hCustomers := { "CC001" => "Pierce Firth",;
 "CC002" => "Stellan Taylor",;
 "CC003" => "Chris Cherry",;
 "CC004" => "Amanda Baranski" }
 ListHash( hCustomers, "A hash defined and initialized literally" )
 ? "Hash value with a specific key (CC003) :", hCustomers[ "CC003" ] // Chris Cherry
 cKey := "CC003" 
 ? "Locating a specific record in an hash by key (", cKey, ":"
 c1Data := hCustomers[ cKey ]
 ? cLMarj, c1Data

 hCountries := { 'Argentina' => "Buenos Aires" }
 hCountries += { 'Brasil' => "Brasilia" }
 hCountries += { 'Chile' => "Santiago" }
 hCountries += { 'Mexico' => "Mexico City" }

 ListHash( hCountries, "A hash defined and initialized by adding with '+=' operator:" )

 hFruits := { "fruits" => { "apple", "chery", "apricot" } }
 hDays := { "days" => { "sunday", "monday" } } 

 hDoris := hFruits + hDays

 ListHash( hDoris, "A hash defined and initialized by concataned two hash with '+' operator:" )

 @ MAXROW(), 0
 WAIT "EOF HashBasics.prg"

RETURN // HashBasics.Main()
PROCEDURE ListHash( hHash, cComment )

 LOCAL x1Pair := NIL

 cComment := IF( HB_ISNIL( cComment ), '', cComment )

 ? cComment, "-- Type :", VALTYPE( hHash ), "size:", NTrim ( LEN( hHash ) ) 
 FOR EACH x1Pair IN hHash
    nIndex := x1Pair:__ENUMINDEX()
    x1Key := x1Pair:__ENUMKEY()
    x1Value := x1Pair:__ENUMVALUE()
    ? cLMarj, NTrim( nIndex ) 
*   ?? '', VALTYPE( x1Pair )
    ?? '', x1Key, "=>"
*   ?? '', VALTYPE( x1Key ) 
*   ?? VALTYPE( x1Value ) 
    IF HB_ISARRAY( x1Value ) 
       AEVAL( x1Value, { | x1 | QQOUT( '', x1 ) } )
       ?? '', x1Value

RETURN // ListHash()


Uniform Arrays


If a multi-dimension array

–          have a fixed number elements in each dimension and

–          each column contains the same type of information for each row in array

called “uniform”.

This structure is similar to a table structure.

Built-in functions DBSTRUCT() and DIRECTORY() produces uniform arrays.

Array produced by DBSTRUCT() will have field count  in size and the structure of an array is:

Field Name  C
Field Type  C
Field Width N
Field Dec   N

And DIRECTORY() function produces an array with elements as file count and with this structure:

File Name        C
File Size        N
File Date        D
File Time        C
File Attributes  C

Building, maintaining and using those arrays is simple as possible.

Let’s look at a sample .prg:

#include ""
#include ""
  ? "Uniform arrays :" 
  ? " Directory file list :"
  ? " Table structure list :"
  IF MakUseTable()
     ? "Couldn't USE or Make th table." 
  @ MAXROW(), 0
  WAIT "EOF UF_Arrays.prg"
RETURN // UF_Arrays.Main

  LOCAL aFList := DIRECTORY( "C:\Harbour\*.*" )
  LOCAL a1File
  FOR EACH a1File IN aFList 
     ? SPACE( 4 ),;
       PAD( a1File[ F_NAME ], 13 ),; /* File name */ 
       TRAN( a1File[ F_SIZE ], "999,999,999" ),; /* File size */
       a1File[ F_DATE ],; /* File date */
       a1File[ F_TIME ],; /* File time */
       a1File[ F_ATTR ] /* File attribute */
RETURN // FileList()
FUNCTION MakUseTable() 
  LOCAL lRetval, aStru 
  IF FILE( cTablName ) 
     USE (cTablName)
     aStru := { { "CUST_ID",    "C",  5, 0 },;
                { "CUST_NAME",  "C", 10, 0 },;
                { "CUST_SNAM",  "C", 10, 0 },;
                { "CUST_FDAT",  "D",  8, 0 },;
                { "CUST_ACTV",  "L",  1, 0 },;
                { "CUST_BLNCE", "N", 11, 2 } }
    * 5-th parameter of DBCREATE() is alias - 
    * if not given then WA is open without alias 
    *                              ^^^^^^^^^^^^^ 
    DBCREATE( cTablName, aStru, , .F., "CUSTOMER" ) 
 lRetval := ( ALIAS() == "CUSTOMER" )
RETURN lRetval // MakUseTable()
   LOCAL nTotal := 1
   IF SELECT() > 0
      aStructur := DBSTRUCT()
      ? SPACE( 4 ), "No: Field Name Type Width Dec"
      ? SPACE( 4 ), "--- ---------- ---- ----- ---"
      AEVAL( aStructur, { | aF1, nFNo | ;
             QOUT( SPACE( 4 ),; // Left Marj 
                   PADL( nFNo, 3 ),; // Field No
                   PADR( aF1[ DBS_NAME ], 11 ),; // Field Name
                   PADC( aF1[ DBS_TYPE ], 4 ),; // Field Type
                   PADL( aF1[ DBS_LEN ], 4 ),; // Field Len
                   PADL( aF1[ DBS_DEC ], 3 )),; // Field Dec 
             nTotal += aF1[ 3 ] } )
      ? SPACE( 4 ), "--- ---------- ---- ----- ---"
      ? SPACE( 4 ), "** Total ** ", TRAN( nTotal, "9,999" )
      ? "Current work area is empty"
RETURN // DispStru()

What a preprocessor is ?

What a preprocessor is, how will operate, and what benefits it will offer ?

Let’s Look at Clipper 5.0’s preprocessor