INIT PROCEDURE

INIT PROCEDURE

Declare an initialization procedure

Syntax

       INIT PROCEDURE <idProcedure> [(<idParam list>)]
          [FIELD <idField list> [IN <idAlias>]]
          [LOCAL <identifier> [[:= <initializer>]]]
          [MEMVAR <identifer list>]
          .
          . <executable statements>
          .
          [RETURN]

Arguments

INIT PROCEDURE declares a procedure that will be executed at program startup.

<idProcedure> is the name of the initialization procedure to declare. Initialization procedure names can be any length, but only the first 10 characters are significant. Names may not begin with an underscore but can contain any combination of characters, numbers, or underscores.

<idParam list> is the declaration of one or more parameter variables. Variables specified in this list are declared local.

FIELD declares a list of identifiers to use as field names whenever encountered. If the IN clause is specified, referring to the declared name includes an implicit reference to the specified alias.

LOCAL declares and, optionally, initializes a list of variables or arrays whose visibility and lifetime is the current procedure.

MEMVAR declares a list of identifiers to use as private or public memory variables or arrays whenever encountered.

RETURN passes control to the next initialization procedure or the first executable routine in the program, if no other initialization procedures are pending.

Description

The INIT PROCEDURE statement declares a procedure that will be executed at program startup. INIT procedures are called prior to the first executable statement in a Clipper application, and are useful for performing common initialization tasks such as reading configuration settings, or opening a communications port.

INIT PROCEDUREs are executed implicitly by Clipper at program startup. The visibility of initialization procedures is restricted to the system; therefore, it is not possible to call an INIT PROCEDURE from a procedure or user-defined function. Each INIT PROCEDURE receives a copy of the DOS command line arguments used to invoke the application.

Control passes from one INIT PROCEDURE to the next until all procedures in the initialization list have been called. Control then passes to the first executable statement in the program.

The ANNOUNCE statement declares a module identifier for a source (.prg) file. Once declared, INIT PROCEDUREs are referenced by this module identifier. An application may use any number of initialization procedures by explicitly REQUESTing their module identifiers.

If an error is raised during system initialization, the system returns to DOS, and pending initialization procedures are not called.

Examples

       .  The following example uses both INIT and EXIT PROCEDUREs to
       save and restore the context of the operating system. You can have
       your program, "Myfile.prg", REQUEST SaveDos:

       ANNOUNCE SaveDos
       #define DOS_SCREEN    1
       #define DOS_ROW       2
       #define DOS_COL       3
       #define DOS_CURSOR    4
       #define DOS_COUNT     4
       STATIC saSaveDos[ SD_COUNT ]
       INIT PROCEDURE dosSave()
          SAVE SCREEN TO saSaveDos[ DOS_SCREEN ]
          saSaveDos[ DOS_ROW ]    := ROW()
          saSaveDos[ DOS_COL ]    := COL()
          saSaveDos[ DOS_CURSOR ] := SETCURSOR()
          RETURN
       EXIT PROCEDURE dosRestore()
          RESTORE SCREEN FROM saSaveDos[ DOS_SCREEN ]
          SETPOS   ( saSaveDos[ DOS_ROW ], saSaveDos[ DOS_COL ] )
          SETCURSOR( saSaveDos[ DOS_CURSOR ] )
          RETURN

Seealso

ANNOUNCE, REQUEST, EXIT PROCEDURE

EXTERNAL

EXTERNAL*

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

Syntax

       EXTERNAL <idProcedure list>

Arguments

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

Description

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.

Examples

       .  These examples are equivalent header files consisting of
          common EXTERNAL references for REPORT FORMs:
       // Externals.ch
       EXTERNAL HARDCR
       EXTERNAL TONE
       EXTERNAL MEMOTRAN
       EXTERNAL STRTRAN
       // Externals.ch
       EXTERNAL HARDCR, TONE, MEMOTRAN, STRTRAN

Seealso

#include, REQUEST

EXIT PROCEDURE

EXIT PROCEDURE

Declare an exit procedure

Syntax

       EXIT PROCEDURE <idProcedure>
              [FIELD <idField list> [IN <idAlias>]]
              [LOCAL <identifier> [[:= <initializer>]]]
              [MEMVAR <identifer list>]
              .
              . <executable statements>
              .
              [RETURN]

Arguments

EXIT PROCEDURE declares a procedure that will be executed on program termination.

<idProcedure> is the name of the exit procedure to declare. Exit procedure names can be any length, but only the first 10 characters are significant. Names may not begin with an underscore but can contain any combination of characters, numbers, or underscores.

FIELD declares a list of identifiers to use as field names whenever encountered. If the IN clause is specified, referring to the declared name includes an implicit reference to the specified alias.

LOCAL declares and optionally initializes a list of variables or arrays whose visibility and lifetime is the current procedure.

MEMVAR declares a list of identifiers to use as private or public memory variables or arrays whenever encountered.

RETURN passes control to the next exit procedure or to the operating system, if no other exit procedures are pending.

Description

The EXIT PROCEDURE statement declares a procedure that will be executed upon program termination. EXIT procedures are called after the last executable statement in application has completed. EXIT PROCEDUREs can be used to perform common housekeeping tasks such as saving configuration settings to a file, closing a log file, or concluding a communications session.

The visibility of exit procedures is restricted to the system; therefore, it is not possible to call an EXIT PROCEDURE from a procedure or user-defined function. Exit procedures do not receive parameters.

Once the last executable statement has completed, control passes from one EXIT PROCEDURE to the next until all procedures in the exit list have been called. Control then passes to the operating system.

The ANNOUNCE statement declares a module identifier for a source (.prg) file. Once declared, EXIT PROCEDUREs are referenced with this module identifier. An application may use any number of exit procedures by explicitly REQUESTing their module identifiers.

The EXIT PROCEDUREs requested for an application are collectively referred to as the exit list. There is no mandatory execution order of procedures in the exit list; however, if an EXIT PROCEDURE is declared in the same source (.prg) file as the application’s primary routine (root), it is guaranteed to be the first exit procedure called.

Termination of a given application can be attributed to any of the following:

       . RETURNing from the primary (root) routine 

       . the QUIT command 

       . issuing a BREAK without an enclosing BEGIN SEQUENCE...END 

       . unrecoverable error

    Execution of an EXIT PROCEDURE cannot be guaranteed when the system encounters an unrecoverable error. If         an error is raised during an exit procedure, the system returns to DOS. Pending exit procedures are not called.

Examples

       .  This example illustrates construction of a simple timing 
       mechanism using INIT and EXIT PROCEDUREs: 
       // prints the amount of time required to read, 
       // sort,  and display a list of file names. 
       ANNOUNCE MySystem 
       STATIC nStart 
       PROCEDURE Main()       AEVAL( ASORT( DIRECTORY( "*.*" ) ), ; 
               { | aFileInfo | QOUT( aFileInfo[ 1 ] ) } ) 
       RETURN 
       INIT PROCEDURE MyInit() 
          nStart := SECONDS() 
       RETURN 
       EXIT PROCEDURE MyExit() 
          ? 
          ? "Elapsed Time: " 
          ?? SECONDS() - nStart 
       RETURN

See Also

ANNOUNCE, REQUEST, INIT PROCEDURE

ANNOUNCE

ANNOUNCE

Declare a module identifier

Syntax

     ANNOUNCE <idModule>

Arguments

<idModule> is a module identifier name.

Description

ANNOUNCE is a declaration statement that defines a module identifier. A linker may use this identifier later to satisfy pending module REQUESTs. ANNOUNCE and REQUEST provide a mechanism for managing application modules (.prg files).

Specify ANNOUNCE statements prior to any executable statements in a program file. A source (.prg) file can only have one module identifier; all subsequent ANNOUNCE declarations produce a compiler warning and will be ignored.

Module identifiers must be unique and should not duplicate the name of any procedures or user-defined functions in a source (.prg) file.

Examples.

// This example illustrates the ANNOUNCE declaration:

        ANNOUNCE CustomInit
        INIT PROCEDURE MyInit

           ? "Hypothetical Industries, Inc."

           RETURN

        /* 
        The above program module, CustomInit, should be compiled with the /N
        option.  Subsequently, the program is addressed in the source code of
        another program module through use of the REQUEST statement */

        REQUEST CustomInit

        which causes the module CustomInit to be linked into the resultant
        executable (.EXE) file.


Seealso 


REQUEST

hb_Translate()

HB_TRANSLATE()

Translate a string from one code page to the other

Syntax

      HB_TRANSLATE( <cSrcText>, [<cPageFrom>], [<cPageTo>] ) --> cDstText

Arguments

<cSrcText> Is the source string to translate.

<cPageFrom> Is the optional character code page ID of the source string. If not specified, the default code page is used.

<cPageTo> Is the optional character code page ID of the destination string. If not specified, the default code page is used.

Returns

HB_TRANSLATE() return destination string converted from the source string.

Description

HB_TRANSLATE() try to convert a source string from one code page into the other. If a code page ID is not recognized, or not linked in, the default code page is used. HB_TRANSLATE() is used usually to convert between the Dos and the Windows code pages of the same language.

NOTE: If the source code page and target code page does not have the same number of characters, a translation can not be done and the destination string is a copy of the source string.

NOTE: You must REQUEST every code page module you intend to use. For example: to use the Russian RU866 code page you must add the following to your program: REQUEST HB_CODEPAGE_RU866

Examples

      REQUEST HB_CODEPAGE_DE
      REQUEST HB_CODEPAGE_DEWIN
      PROCEDURE Main()
         LOCAL cTxt := "A" + Chr( 142 ) + "BC"
         ? "German CP-850 text:", cTxt
         ? "German Windows-1252 text:", hb_Translate( cTxt, "DE", "DEWIN" )
         RETURN

Compliance

This function is a Harbour Extension.

Platforms

All

Files

Libraty are rtl, codepage

Seealso

HB_LANGSELECT(), HB_CDPSELECT(), NATIONMSG(), REQUEST

hb_langSelect()

HB_LANGSELECT()

Select a specific nation message module

Syntax

      HB_LANGSELECT( [ <cNewLang> ][, <cCodepage> ] ) --> cOldLang

Arguments

<cNewLang> The optional ID of the country language module. Possible values for <cNewLang> are below as defined in the Lang library, sorted by language. <cCodepage> Optional codepage ID into which the language module strings are automatically converted by Harbour.

      Language              <cNewLang>
      --------------------- ----------------------------------
      Basque                eu
      Belorussian           be
      Bulgarian             bg
      Catalan               ca
      Chinese Simplified    zh_sim
      Chinese Traditional   zh_tra
      Croatian              hr
      Czech                 cs
      Dutch                 nl
      Esperanto             eo
      French                fr
      Galician              gl
      German                de
      Greek                 el
      Hebrew                he
      Hungarian             hu
      Icelandic             is
      Indonesian            id
      Italian               it
      Korean                ko
      Lithuanian            lt
      Polish                pl
      Portuguese            pt
      Romanian              ro
      Russian               ru
      Serbian (cyrillic)    sr_cyr
      Serbian (latin)       sr_lat
      Slovak                sk
      Slovenian             sl
      Spanish               es
      Swedish               sv
      Turkish               tr
      Ukrainian             uk

Returns

<cOldLang> The old language indentifier

Description

This function set a default language module for date/month names, internal warnigs, NatMsg messages and internal errors. When a Lang ID is selected all messages will be output with the current language selected until another one is selected or the program ends. The default language is English (cLang == “EN”).

NOTE: You must REQUEST every language module you intend to use. For example: to use the Russian RU866 language you must add the following to your program: REQUEST HB_LANG_RU866

Examples

      REQUEST HB_LANG_PT
      REQUEST HB_LANG_RO
      REQUEST HB_LANG_ES
      PROCEDURE Main()
         HB_LANGSELECT( "pt" )       // Default language is now Portuguese
         ? CDOW( Date() )            // Segunda-feira
         ? "Old language id selected is ", HB_LANGSELECT()   // PT
         HB_LANGSELECT( "ro" )       // Default language is now Romanian
         ? CMONTH( Date() )          // Mai
         ? "Old language id selected is ", HB_LANGSELECT()   // RO
         HB_LANGSELECT( "es" )       // Default language is now Spanish
         ? CMONTH( Date() )          // Mayo
         ? CDOW( Date() )            // Lunes
         RETURN

Tests

      See tests/langapi.prg, tests/langmsg.prg

Compliance

Harbour

Platforms

All

Files

Libraty are rtl, lang

Seealso

HB_LANGNAME(), HB_CDPSELECT(), NATIONMSG(), REQUEST

hb_langMessage()

HB_LANGMESSAGE()

Returns international strings messages and errors

Syntax

      HB_LANGMESSAGE( <nMsg> ) --> cMessage

Arguments

<nMsg> is the message number to get.

Returns

HB_LANGMESSAGE() return the text associated with the code <nMsg>.

Description

HB_LANGMESSAGE() is similar to NATIONMSG() but give access to the whole list of language messages: Day and month names, generic error messages, internal errors, and others…

Use the header file hblang.ch for a list of base values for <nMsg>.

Examples

      #include "hblang.ch"
      REQUEST HB_LANG_ES
      PROCEDURE Main()
         // English: Monday
         ? "English:", HB_LANGMESSAGE( HB_LANG_ITEM_BASE_DAY + 1 )
          "ES" )
         // Spanish: Lunes
         ? "Spanish:", HB_LANGMESSAGE( HB_LANG_ITEM_BASE_DAY + 1 )
         RETURN

Compliance

Harbour

Platforms

All

Files

Library are rtl, lang Header is hblang.ch

Seealso

HB_LANGSELECT(), NATIONMSG(), REQUEST

hb_cdpSelect()

HB_CDPSELECT()

Select the active code page by language ID

Syntax

      HB_CDPSELECT( [<cNewLang>] ) --> cOldLang

Arguments

<cNewLang> The optional ID of the country language module. Possible values for <cNewLang> are below as defined in the Codepage library, sorted by language.

      Language              Codepage       <cNewLang>
      --------------------- -------------- ----------------------
      Bulgarian             866            BG866
      Bulgarian             ISO-8859-5     BGISO
      Bulgarian             MIK            BGMIK
      Bulgarian             Windows-1251   BGWIN
      Croatian              437            HR437
      Croatian              852            HR852
      Croatian              Windows-1250   HR1250
      Czech                 852            CS852
      Czech                 ISO-8859-2     CSISO
      Czech                 KAM            CSKAM
      Czech                 Windoes-1250   CSWIN
      English               437            EN
      French                850            FR
      German                850            DE
      German                ISO-8859-1     DEWIN
      Greek                 737            EL
      Greek                 Windows-1253   ELWIN
      Hungarian (ntxhu852)  852            HU852
      Hungarian (sixhu852)  852            HU852S
      Hungarian (ntxhu852)  ISO-8859-2     HUISO
      Hungarian (sixhu852)  ISO-8859-2     HUISOS
      Hungarian (ntxhu852)  Windows-1250   HUWIN
      Hungarian (sixhu852)  Windows-1250   HUWINS
      Italian               437            IT437
      Italian               850            IT850
      Italian               ISO-8859-1b    ITISB
      Italian               ISO-8859-1     ITISO
      Lithuanian            Windows-1257   LT
      Polish                852            PL852
      Polish                ISO-8859-2     PLISO
      Polish                Mazowia        PLMAZ
      Polish                Windows-1250   PLWIN
      Portuguese            850            PT850
      Portuguese            ISO-8859-1     PTISO
      Russian               866            RU866
      Russian               KOI-8          RUKOI8
      Russian               Windows-1251   RU1251
      Serbian               Windows-1251   SRWIN
      Slovak                852            SK852
      Slovak                ISO-8859-2     SKISO
      Slovak                Kamenicky      SKKAM
      Slovak                Windows-1250   SKWIN
      Slovenian             437            SL437
      Slovenian             852            SL852
      Slovenian             ISO-8859-2     SLISO
      Slovenian             Windows-1250   SLWIN
      Spanish               850            ES
      Spanish               ISO-8859-1     ESWIN
      Spanish Modern        ISO-8859-1     ESMWIN
      Swedish               850            SV850
      Swedish (Clipper)     437            SVCLIP
      Swedish               ISO-8859-1     SVWIN
      Turkish               857            TR857
      Turkish               Windows-1254   TRWIN
      Ukrainian             866            UA866
      Ukrainian             KOI-8U         UAKOI8
      Ukrainian             Windows-1251   UA1251

Returns

<cOldLang> The old language indentifier

Description

HB_CDPSELECT() set the active code page use by Harbour for sorting and comparing strings. The default code page use ASCII order (cLang == “EN”).

NOTE: You must REQUEST every code page module you intend to use. For example: to use the Russian RU866 code page you must add the following to your program: REQUEST HB_CODEPAGE_RU866

Examples

      REQUEST HB_CODEPAGE_HU852
      PROCEDURE Main()
         LOCAL cTxt := Chr( 71 ) + " > " + Chr( 144 ) + " is"
         ? hb_cdpSelect()                 // EN
         ? cTxt, Chr( 71 ) > Chr( 144 )   // G > É is .F.
         ? hb_cdpSelect( "HU852" )        // EN
         ? cTxt, Chr( 71 ) > Chr( 144 )   // G > É is .T.
         ? hb_cdpSelect( "EN" )           // HU852
         ? cTxt, Chr( 71 ) > Chr( 144 )   // G > É is .F.
         RETURN

Compliance

This function is a Harbour Extension.

Platforms

All

Files

Libraty are rtl, codepage

Seealso

HB_LANGNAME(), HB_LANGSELECT(), HB_TRANSLATE(), NATIONMSG(), REQUEST

C5DG-8 DBPX Driver

Clipper 5.x – Drivers Guide

Chapter 8

DBPX Driver Installation and Usage

DBPX is the Paradox 3.5 compatible RDD for Clipper. It connects to the low-level database management subsystem in the Clipper architecture. When you use the DBPX RDD, you add a number or features, including the ability to:

. Create access to and modify Paradox tables, records, and fields

. Create, select, and activate secondary indexes on Paradox tables

. Create and modify Paradox table structures, including primary index fields

. Use explicit record and file locks with concurrent execution of other Clipper applications

. Import Paradox tables directly into Clipper arrays

In This Chapter

This chapter explains how to install DBPX and how to use it in your applications. The following major topics are discussed:

. Overview of the DBPX RDD

. Installing DBPX Driver Files

. Linking the DBPX Driver

. Using the DBPX Driver

Overview of the DBPX RDD

The DBPX driver lets you create and maintain (.db), (.px), (.x??), and (.y??) files with features different from those supplied with the original DBFNTX driver and compatible with files created under Paradox 3.5. The new features are supplied in the form of several syntactical additions to database and indexing commands and functions. Specifically you can:

. Create tables that recognize the standard Clipper data types as well as Currency ($) and Short (S) numbers between -32,767 to +32,767

. Create equally efficient keyed and unkeyed tables

. Create, select, and activate secondary indexes on Paradox tables

The DBPX driver provides simple, seamless access to the Paradox database system. The Clipper application programmer who intends to access Paradox tables with the “VIA” clause need only include the RDD header file at compile time and make the appropriate libraries available at link time.

Paradox stores data in tables (known to Xbase developers as data files (.db)’s), consisting of fields and records. Unlike Xbase databases, a Paradox database refers to a group of files that are related to each other in some way, rather than to one file.

Also, Paradox employs the concept of companion files, known as objects, that are related to the table. Some examples of object files are report forms, indexes, and data entry forms. A table and its accompanying objects are referred to as a family.

It is easy to identify objects belonging to a particular family since they all have the same base filename and are distinguished by their extensions as shown in the table below.

Paradox File Descriptions
——————–  —————————————————
Extension         Object

.DB                       Table

.PX          Primary Index 
.X?? or Y??  Secondary Index
.F or F??    Data Entry Forms
.R or R??    Report Formats
.G or G??    Graph Specifications
.SET         Image Settings
.VAL         Field Validity Specifications
------------ ------------------------------------------------------------

The DBPX driver only deals with the table and index files (.db, .px, .x?? and y??) so only these files are discussed here.

Though Paradox tables are limited to 8 character filenames, each table can contain an unlimited number of records in files up to 256M in size. Paradox records in nonkeyed tables can be up to 4000 bytes each while keyed tables have a 1350 byte limitation. Each record can contain up to 255 fields of up to 255 characters each.

There are some field naming restrictions you must observe. Field names may:

. Although the Paradox file structure allows fields to be up to 25 characters long, since Clipper symbols can only be 10 characters, DBPX truncates the field name to 10 characters.

. The Paradox file structure allows embedded spaces in field names. Since this is illegal in Clipper, the DBPX driver converts spaces into underscores (_).

. Not be duplicated in the same table.

Also, most Paradox data types directly match data types in standard Xbase data files, with these differences:

. Paradox tables support both the Numeric (N) data type as well as a more specific Currency ($) data type. Both the N and $ data types can have 15 significant digits. Numeric types that exceed this length are rounded and stored as scientific notation. Also, DBPX supports the Short (S) data type to represent numbers between -32,767 and +32,767.

. The Alphanumeric field type allows all ASCII characters except embedded nulls (ASCII 0). The Alphanumeric type is identical to the Character (C) data type in Xbase. Paradox limits this field type to 255 characters.

. Paradox also supports a Date (D) field type, stored as a long integer. It can contain any value between January 1, 100 A.D. and December 31, 9999.

Installing DBPX Driver Files

The DBPX RDD is supplied as the file, DBPX.LIB:

The Clipper installation program installs this driver in the \CLIPPER5\LIB subdirectory on the drive that you specify, so you need not install the driver manually.

Linking the DBPX Database Driver

To link the DBPX driver, you must specify DBPX.LIB to the linker along with your application object (.OBJ) modules.

1. To link with .RTLink using positional syntax:

C>RTLINK <appObjectList> ,,,DBPX

2. To link with .RTLink using freeformat syntax:

C>RTLINK FI <appObjectList> LIB DBPX

Note: These link commands all assume the LIB, OBJ, and PLL environment variables are set to the standard locations. They also assume that the Clipper programs were compiled without the /R option.

Using the DBPX Database Driver

To use Paradox files in a Clipper program:

1. Place REQUEST DBPX at the top of each program file (.prg) that opens a database file using the DBPX driver.

2. Specify the VIA “DBPX” clause if you open the database file with the USE command.

-OR-

3. Specify “DBPX” for the <cDriver> argument if you open the database file with the DBUSEAREA() function.

-OR-

4. Use RDDSETDEFAULT( “DBPX” ) to set the default driver to DBPX.

Except in the case of REQUEST, the RDD name must be a literal character string or a variable. In all cases it is important that the driver name be spelled correctly using uppercase letters.

The following program fragments illustrate:

REQUEST DBPX 
. 
. 
. 
USE Customers INDEX Name, Address NEW VIA "DBPX"
-OR-
REQUEST DBPX RDDSETDEFAULT( "DBPX" )
.
. 
. 
. 
USE Customers INDEX Name, Address NEW

Index Management 

The greatest variation from the standard Xbase database design in Paradox tables is index management. As in other systems, Paradox indexes are an efficient method of dynamically sorting or locating specific data within a table without forcing a search of all data in that table. Paradox tables take two forms: unkeyed and keyed.

An unkeyed table has no fields in its structure that have been identified as specific index keys. Therefore, records are maintained in natural order. New records are added to the end of an existing table, and the unique identity for each record is a record number.

Unlike Xbase data files, unkeyed tables are not more efficient in design or faster to traverse than keyed tables. This is because Paradox tables are built as linked lists rather than fixed-length, sequential tables. Therefore, it is actually less efficient to SKIP through a unkeyed table than it is through a keyed table.

A keyed table, on the other hand, can be lightning fast as long as the data you seek is part of the key. Otherwise, just as in an unkeyed table, you are forced to do a sequential search through the table’s data fields.

Paradox tables support two types of keys or indexes.

. Primary

. Secondary

Primary Indexes

Primary indexes are directly tied to keyed tables because a primary index indicates the table is keyed. Simply, it is impossible to have a keyed table without a primary index. If you remove the primary index from a keyed table it becomes an unkeyed table.

When you identify one or more of the table’s fields as a key field (by placing an asterisk (*) at the end of the field name) during table creation/restructuring, these fields are used to create a primary index. (Note that all key fields must be together as the first fields in a table). This invisibly rebuilds the table’s structure, though in operation it only seems to change or create the key index.

Once you identify this primary key, the table is automatically maintained in the key field order and all new records are checked to make sure that no duplicate keys are added to the table. This type of index is called a unique key index. You may have only one primary key per table, but this key can be a composite of many fields in the table. You may only modify by restructuring the table.

If it is necessary to change a primary key and restructure a table, all data in the table will still be bound to the unique key restriction. This is important if you change the primary key by adding a new field to it and there is already data in the table where this new composite key would have duplicates.

DBPX handles this situation by generating a runtime error and removing every record that violates this unique key and moving it to another table named KEYVIOL.db which has the identical structure of the offending table.

The KEYVIOL.db is automatically generated whenever this situation occurs. If there is already a KEYVIOL table, it is overwritten. Because of this you should always check for the existence of a KEYVIOL.db table immediately after any type of table restructuring.

Secondary Indexes

Secondary indexes are more like common Xbase-type indexes because they can be generated or modified on the fly without having any effect on the data or table structure and aren’t restricted to unique key data.

Unlike Xbase indexes, secondary indexes can only contain a single field as their key. As mentioned earlier, primary indexes are automatically maintained so that they are always up to date. Secondary indexes are created in two different types.

. Incremental (for keyed tables)

. Independent (for unkeyed tables)

Independent indexes are created only for unkeyed tables and are not dynamically maintained in any way. Because of this they can only be considered accurate at the time of their creation. If data changes inside the table that affects the index, the index must be completely regenerated before it can be considered useful again.

Alternately, incremental indexes are created only for keyed tables and are automatically maintained similarly to primary indexes except that instead of a complete rebuild at every change, only the portion of the index affected is updated. Incremental indexes are preferable when you are handling large tables since they take considerably less time and energy to keep accurate.

Temporary Indexes

ALL, NEXT, RECORD, and REST are all supported in the scoping expressions. The syntax of these keywords is identical to that used in Clipper. Note that you can only use one scope keyword at a time. If more than one of these keywords is encountered in a scoping expression, then the last keyword in the expression is the option used.

The ALL keyword (default) specifies that all records in the table should be included in the operation, starting at the first record.

NEXT processes the specified number of records, starting with the current record. For example, NEXT 5 would process the current record and the four records following it.

The RECORD keyword identifies a specific record to process. The desired record number should follow the keyword RECORD. To process record number 3, you would include “RECORD 3” in the expression.

The REST keyword causes processing to begin with the current record, instead of starting at the beginning of the table.

Sorting

In the event that you want to reorder a table based on field data but don’t need or want to have an index attached to it, you have the option of sorting the table based on the current index. This entails a simple copy from a keyed table to an unkeyed table using the table sort function.

Passwords and Security

Although the Paradox DBMS cannot be considered a data dictionary system, it does have some special characteristics that make it more suitable to networks than the standard Xbase tables. One of these features is the level of security available.

There are two methods to make sure that your data is secure: master passwords and auxiliary passwords. As the owner of a table, you can limit access by attaching a master password to it. Auxiliary passwords can also be identified to establish access to the table and its family.

Once any type of password is identified for a table, its is encrypted. This protects it not only from unauthorized Paradox users but also from anyone trying to dissect it at the DOS file level. The encryption method used by Paradox is literally unbreakable and if you (or your users) forget a table password, there is no way to recover that information.

Auxiliary passwords allow access control at the table and field levels. Access to tables can be restricted to:

. ReadOnly: No changes to the table can be made

. Update: Changes to nonkey fields are allowed, no records can be added or deleted

. Entry: Same as update except that new records can be added

. InsertDelete: Same as Entry except that records can be inserted and deleted

. All: Full access including restructuring and table deletion

Access to the fields can be identified as:

. None: This field data cannot be displayed to the user

. ReadOnly: User can see the field value, but cannot change it

. All: Full access

With DBPX, you may perform basic database operations on Paradox tables without code changes.

Note that because Paradox tables can have primary indexes which are actually part of the table structure specification, when you open a Paradox table, its associated primary index (if applicable) is also opened and activated. The only exception to this rule is if you indicate that you want a secondary index to be activated at the time you open the table. If no primary index is available and no secondary index is specified, the table is opened in natural sequence order.

You can have up to twenty-four Paradox tables open simultaneously. These may be separate tables or the same table repeatedly or any variation in between. This might be important if you want to have more than one secondary index active for a single table, allowing you to move from one work area to another with the only change being the index order of the data in the table. Be careful with this type of multiviewed approach, however, since you will be eating up memory for each work area, despite the fact that they refer to the same table.

Sharing Data in Networks

The DBPX driver supports the native Clipper single-lock locking scheme. Therefore, in a shared environment, your application and Paradox will not see each other’s record locks. This may result in some concurrency corruption and errors.

In a shared environment, DBPX performs no record buffering; immediately writing all changes to disk.

Concurrency is an issue whenever your application is running either on a network or in some other shared environment. One example of a non- network shared environment is when your application is called from another program (like Paradox, Quatro Pro, etc.) that also has access to the Paradox tables. Even if you don’t have any plans to use your program on a network, you should design it to be smart enough not to become a problem if faced with this type of shared example.

Also be aware that many networks have different rights and privilege restrictions and you should know what they are and how to handle them.

Using (.px) and (.ntx) Files Concurrently

You can use both (.px), as well as (.x), (.y) and (.ntx) files concurrently in a Clipper program like this:

REQUEST DBPX
// (.ntx) file using default DBFNTX driver
USE File1 INDEX File1 NEW
// (.idx) files using DBPX driver
USE File2 VIA "DBPX" INDEX File2 NEW

Note, however, that you cannot use (.px) and (.ntx) files in the same work area. For example, the following does not work:

USE File1 VIA "DBFNTX" INDEX File1.ntx, File2.px

Summary

In this chapter, you were given an overview of the features and benefits of the DBPX RDD. You also learned how to link this driver and how to use it in your applications.

C5DG-6 DBFNDX Driver

Clipper 5.x – Drivers Guide

Chapter 6

DBFNDX Driver Installation and Usage

DBFNDX is the dBASE III PLUS compatible RDD for Clipper. The DBFNDX driver uses the Clipper driver architecture to access dBASE III PLUS compatible index files within a Clipper program.

In This Chapter

This chapter explains how to install DBFNDX and how to use it in your applications. The following major topics are discussed:

. Overview of the DBFNDX RDD

. Installing DBFNDX Driver Files

. Linking the DBFNDX Driver

. Using the DBFNDX Driver

. Compatibility with dBASE III PLUS

Overview of the DBFNDX RDD

The DBFNDX database driver allows creation, access, and updating of dBASE III and dBASE III PLUS compatible index (.ndx) files. Index files (.ndx) created with Clipper are exactly the same as those created by dBASE III PLUS. All operations that can be performed on standard Clipper index (.ntx) files can be performed on (.ndx) files using the DBFNDX database driver.

In a network environment, the DBFNDX driver supports the Clipper file and record locking scheme. The multiuser behavior is the same as the default DBFNTX driver. This means that the DBFNDX database driver supports concurrent access to (.ndx) files between Clipper applications only. Concurrent access to (.ndx) files between dBASE III PLUS and Clipper programs is not supported.

Important! Updating database (.dbf) and index (.ndx) files shared between dBASE III PLUS and Clipper programs may corrupt the (.dbf) and any of its associated (.ndx) files.

Installing DBFNDX Driver Files

The DBFNDX database driver is supplied as the file, DBFNDX.LIB.

The Clipper installation program installs this driver in the \CLIPPER5\LIB subdirectory on the drive that you specify, so you need not install the driver manually.

Linking the DBFNDX Database Driver

To link the DBFNDX database driver into an application program, you must specify DBFNDX.LIB to the linker in addition to your application object files (.OBJ).

1. To link with .RTLink using positional syntax:

C>RTLINK <appObjectList> ,,, DBFNDX

2. To link with .RTLink using freeformat syntax:

C>RTLINK FI <appObjectList> LIB DBFNDX

Note: These link commands all assume the LIB, OBJ, and PLL environment variables are set to the standard locations. They also assume that the Clipper programs were compiled without the /R option.

Using the DBFNDX Database Driver

To use (.ndx) files in a Clipper program:

1. Place a REQUEST DBFNDX at the beginning of your application or at the top of the first program file (.prg) that opens a database file using the DBFNDX driver.

2. Specify the VIA “DBFNDX” clause if you open the database file with the USE command.

-OR-

3. Specify “DBFNDX” for the <cDriver> argument if you open the database file with the DBUSEAREA() function.

-OR-

4. Use RDDSETDEFAULT(“DBFNDX”) to set the default driver to DBFNDX.

Except in the case of REQUEST, the RDD name must be a literal character string or a variable. In all cases it is important that the driver name be spelled correctly.

The following program fragments illustrate:

REQUEST DBFNDX 
. 
. 
. 
USE Customers INDEX Name, Address NEW VIA "DBFNDX"

-OR-

REQUEST DBFNDX RDDSETDEFAULT( "DBFNDX" ) 
.
.
. 
USE Customers INDEX Name, Address NEW

Using (.ntx) and (.ndx) Files Concurrently

You can use (.ndx) and (.ntx) files concurrently in a Clipper program like this:

REQUEST DBFNDX

// (.ntx) file using default DBFNTX driver USE File1 INDEX File1 NEW

// (.ndx) files using DBFNDX driver USE File2 VIA “DBFNDX” INDEX File2 NEW

Note, however, that you cannot use (.ndx) and (.ntx) files in the same work area. For example, the following does not work:

USE File1 VIA "DBFNDX" INDEX File1.ntx, File2.ndx

Compatibility with dBASE III PLUS

When accessing dBASE III PLUS (.ndx) files, there are several compatibility issues of which you must be aware. These issues are discussed below.

Supported Data Types

The DBFNDX database driver supports the following data types for key expressions:

. Character

. Numeric

. Date

This is consistent with dBASE III PLUS.

The DBFNDX database driver does not support indexing with logical key expressions as does the default DBFNTX database driver. This is actually a dBASE III PLUS limitation and is not supported by the DBFNDX driver in order to enforce compatibility with dBASE III PLUS.

To work around this limitation, index logical values by converting them to character values like this:

INDEX ON IIF(<lExp>, "T", "F") TO <logicalIndex>

Supported Key Expressions

When you create (.ndx) files using the DBFNDX driver, you must use only Clipper or user-defined functions compatible with dBASE III PLUS. Use of the other functions will render the (.ndx) file unreadable in dBASE III PLUS.

FIND vs SEEK

In Clipper, you can use the FIND command only to locate keys in indexes where the index key expression is character type. This differs from dBASE III PLUS where FIND supports character and numeric key values.

Note: In Clipper programs, always use the SEEK command or the DBSEEK() function to search an index for a key value.

The DBFNDX driver lets you recover from a data type error raised during a FIND or SEEK. However, since Error:canDefault, Error:canRetry, or Error:canSubstitute are set to false (.F.), you should use BEGIN SEQUENCE…END to handle a SEEK or FIND data type error. Within the error block for the current operation, issue a BREAK() using the error object the DBFNDX database driver generates, like this:

bOld := ERRORBLOCK({|oError| BREAK(oError)})
.
.
 .
BEGIN SEQUENCE
SEEK xVar
RECOVER USING oError
// Recovery code
END
.
.
 .
ERRORBLOCK(bOld)

There is an extensive discussion of the effective use of the Clipper error system in the Error Handling Strategies chapter of the Programming and Utilities guide.

Sharing Data on a Network

As mentioned above, the DBFNDX driver does not support dBASE III PLUS file and record locking schemes. Instead, the DBFNDX driver supports the DBFNTX file and record locking scheme. This means that if the same database and index files are open in Clipper and dBASE III PLUS, Clipper program locks are not visible to dBASE III PLUS and vice versa.

Warning! Database integrity is not guaranteed and index corruption will occur if Clipper and dBASE III PLUS programs attempt to write to a database or index file at the same time. For this reason, concurrent use of the same database (.dbf) and index (.ndx) files by dBASE III PLUS and Clipper programs is strongly discouraged and not supported.

Compatibility with dBASE IV

Specific compatibility with dBASE IV is provided through the DBFMDX driver. It includes (.dbf), (.mdx), and (.dbt) file format compatibility and is described in detail in the previous chapter.

Summary

In this chapter, you were given an overview of the features and benefits of the DBFNDX RDD. You learned how to link this driver and how to use it in your applications, and were given an overview of the compatibility issues.