Differences between Clipper 5.x and Xbase++ Foundation
The most important aspect when porting a Clipper program to Xbase++ is given by the fact that the first routine of an Xbase++ application must be called MAIN. Without a MAIN procedure, the linker cannot determine the entry point in the program and the executable file cannot be loaded.
Program code located outside a FUNCTION or PROCEDURE declaration is automatically associated with the MAIN procedure by the Xbase++ compiler. Because of this, there can be only one PRG file with program code located outside FUNCTION or PROCEDURE declarations. Otherwise the MAIN procedure appears to be declared multiple times and an executable file is not created.
The second point to keep in mind is that Xbase++ programs always run in multiple threads. The thread executing implemented program code has the highest priority. It receives CPU access on preference by the operating system. This is why permanently polling DO WHILE loops should be avoided. For example:
DO WHILE Inkey() <> 0
<program code>
ENDDO
Querying the keyboard in this way leads to permanent polling since there is no wait state in the loop. This is allowed under DOS but contradicts the architecture of a pre-emptive operating system. The above loop must be coded with Xbase++ as follows:
DO WHILE Inkey(0.1) <> 0
<program code>
ENDDO
Now, the loop has a wait state of 1/10th of a second. This is sufficient to guarantee that all threads of a program will be executed. A Clipper program should be searched for DO WHILE loops which do a permanent polling and provide no wait state. Some functions accept a parameter to achieve a wait state. Another possibility for this is the Sleep() function.
The following table gives an overview of the commands that can lead to incompatibilities when a Clipper program is compiled using Xbase++.
Clipper | Xbase++ |
---|---|
CALL | Not available |
COPY..TO..SDF | Xbase++ uses SDF as file extension for a structure extended SDF file |
DIR | Not available |
LABEL FORM | Not available |
REPORT FORM | Not available |
SET FORMAT | Not available |
SET FUNCTION | Not available |
SET TYPEAHEAD TO 0 | Not allowed (min 10, max unlimited) |
KEYBOARD Chr(0) | Chr(0) is ignored |
RESTORE FROM | Existing MEM files cannot be read |
RUN | Starts a new command shell |
FRM file | The FRM file format is not supported |
LBL file | The LBL file format is not supported |
MEM file | The MEM file format is not supported |
When using commands to import or export data the features of a corresponding Xbase++ DatabaseEngine (DBE) must be taken into consideration. DBEs are loaded implicitly when commands are used. This applies to commands like COPY TO ... SDF or APPEND FROM ... SDF. The import or export file, respectively, is maintained by a DatabaseEngine which is loaded into memory if it is not found. In the case of the SDF format this is the SDF Datebase Engine. It creates a structure-extended file with the extension 'SDF'. For this reason, the following code is not allowed:
USE Customer
COPY TO Customer.sdf SDF
In this case, the Xbase++ SDFDBE implicitly creates the structure-extended file 'Customer.sdf'. It has the same name as the target file. As a result, a runtime error is raised. At this point, it is recommended to all Clipper programmers to read the specifications of the "Xbase++ DatabaseEngines"in the Xbase++ documentation. The Xbase++ DBEs differ in many aspects from Clipper's RDDs.
Xbase++ differs from Clipper in that keyboard entries are registered in the event queue. The command SET TYPEAHEAD TO 0 in Xbase++ causes all events in the event queue to be deleted. The number of events in the event queue cannot be set to 0, since this would lead to a system halt. The minimum number of events that can be stored in the event queue is ten.
The KEYBOARD command is translated to a keyboard event that is added to the event queue. The character Chr(0) is an invalid event and is ignored. This can lead to problems in Clipper programs which use Chr(0) for setting the return code of the Lastkey() function to a defined value. If this is the case, another character must be used for this purpose, e.g. Chr(255). An alternative is also given by the preprocessor:
#xtranslate KEYBOARD( Chr(0) ) => KEYBOARD Chr(255)
#xtranslate KEYBOARD Chr(0) => KEYBOARD Chr(255)
#xtranslate Lastkey() == 0 => Lastkey() == 255
#xtranslate Lastkey() = 0 => Lastkey() == 255
The MEM file format is not supported by Xbase++. This means existing MEM files cannot be read. In Xbase++, XPF files replace MEM files. Objects, arrays and code blocks can be stored using this file format as well as character, date, numeric and logical data types. This opens a completely new dimension for communicating between workstations on a network. Using the XPF file format, code blocks can be exchanged between two workstations.
Clipper | Xbase++ |
---|---|
AEval() | Fifth parameter determines whether array elements are passed by reference to the code block |
CurDir() | Returns or changes the current directory |
Not available | CurDrive() returns or changes the current drive |
File() | Includes second parameter "D", "H", "S" |
FkLabel() | Not available |
FkMax() | Not available |
NoSnow() | Not available |
ReadKey() | Not available |
SetBlink() | Only available in full screen mode (VIO mode) |
SetColor() | Intensity attribute is supported for background color |
Word() | Not available |
In Xbase++, the function AEval() accepts a fifth parameter that is a logical value. This specifies whether array elements are passed by reference or by value to the code block. The following line creates an array and fills the 10 elements with their corresponding indexes:
aArray := AEval( Array(10), {|x,i| x:=i },,, .T.)
The functions CurDir() and File() have expanded functionality in Xbase++ (compared to Clipper). The additional function CurDrive() is also included in Xbase++. The current directory and drive can be changed using CurDir() and CurDrive() without using the command RUN. Since RUN operates differently under Xbase++ by starting another command shell, the Clipper technique will not change the directory in the application under Xbase++. The function File() accepts a file type as a second parameter. An example of the enhanced file function is shown in the following code that checks for the existence of a directory:
cDir := Space(64)
@ 10, 10 GET cDir
READ
IF ! File( Trim(cDir), "D")
Alert( "Invalid directory")
ELSE
CurDir( cDir )
ENDIF
The GetDoSetKey() function programmed in GETSYS.PRG calls GetPostValidate() prior to evaluating a SetKey() code block. By this, Xbase++ guarantees that no invalid data is written to database fields.
Reserved keywords
Xbase++ has more reserved keywords than Clipper. Using an Xbase++ reserved keyword as an identifier for variables, functions etc., causes the Xbase++ compiler to assert an error. A list of all reserved keywords is found in the online help in the section "Language elements of Xbase++".
Clipper | Xbase++ |
---|---|
oGet:assign | oGet:_assign() |
oGet:end | oGet:_end() |
oGet:badDate | oGet:badDate() |
oGet:minus | oGet:minus() |
oGet:picture | When not indicated, default picture |
oGet:subScript | Always NIL |
Not available | oGet:posInBuffer() |
Clipper | Xbase++ |
---|---|
oTbrowse:end() | oTBrowse:_end() |
oTBrowse:rowPos:=<n> | Does not synchronize with the data source but only moves the TBrowse cursor |
oTBrowse:nTop:=<n> | :configure() must be subsequently executed |
oTBrowse:nLeft:=<n> | :configure() must be subsequently executed |
oTBrowse:nBottom:=<n> | :configure() must be subsequently executed |
oTBrowse:nRight:=<n> | :configure() must be subsequently executed |
Not available | oTBrowse:firstScrCol() |
Not available | oTBrowse:viewArea() |
Clipper | Xbase++ |
---|---|
EVAL( oTBrowse:skipBlock, nSkip, oTBrowse ) | |
EVAL( oTBrowse:goTopBlock, oTBrowse ) | |
EVAL( oTBrowse:goBottomBlock, oTBrowse ) |
A leading underscore is added to the names of the :assign() and :end() methods of the Get and TBrowse classes in Xbase++. This is done because the previous identifiers are reserved keywords. No changes need to be made in Clipper programs, since the Xbase++ preprocessor makes this change.
Clipper requires the instance variable oGet:subScript to obtain correct references to array elements used as variables in the @...GET command. Xbase++ uses the reference operator @ instead, since single array elements can be passed by reference. For this reason, oGet:subScript is obsolete and always contains NIL. To achieve in Xbase++ the same behavior as in Clipper, an appropriate value must be assigned to oGet:subScript. For example:
LOCAL aArray := {.t., .f.}
CLS
SET CURSOR ON
@ 10, 10 GET aArray[1] PICTURE "Y" SEND subScript := {1}
@ 11, 10 GET aArray[2] PICTURE "Y" SEND subScript := {2}
READ
There is an essential difference between the TBrowse class in Xbase++ and Clipper. Assignments to the instance variable :rowPos do not automatically synchronize the record pointer in the data source. If the TBrowse cursor is repositioned by changing :rowPos, the record pointer of the data source must be explicitly moved. Also, the TBrowse object is passed as a parameter to the code blocks :skipBlock, :goTopBlock and :goBottomBlock.
In addition, methods have been added to the Get class and the TBrowse class which are required for supporting mouse control.
Functions and commands
Clipper | Xbase++ |
---|---|
DbSetDriver() | DbeSetDefault() |
RddList() | DbeList() |
RddSetDefault() | DbeSetDefault() |
Command | Clipper | Xbase++ |
---|---|---|
SET EXCLUSIVE | Default value is ON | Default value is OFF |
SET EXACT | Is not considered with SEEK / DbSeek() | Is considered with SEEK / DbSeek() |
CREATE INDEX | Sorting order of characters depends on NTX???.OBJ modules that must be linked | Sorting order of characters depends on SET COLLATION and SET LEXICAL |
COMMIT at end of program | Is implicitly executed | Is not implicitly executed |
Column | Clipper | Xbase++ |
---|---|---|
FIELD_LEN | The field length is 3 | The field length is 5 |
FIELD_DEC | Used when field length > 999 | Not Used |
|
RDD versus DBE
The database function DbSetDriver() and all the Rdd...() functions of Clipper are not available in Xbase++. This is because Xbase++ does not support the proprietary concept of a monolithic RDD (Replaceable Database Driver). Instead of the RDD approach, the concept of database engines is used in Xbase++ and offers much more flexibility in data and file management. Because of this difference, Xbase++ offers the Dbe...() functions instead of the Rdd...() functions in Clipper.
SET EXCLUSIVE
SET EXCLUSIVE is set OFF by default in Xbase++. This means that by default, databases are opened in SHARED mode for multi-user (network) operation in Xbase++. If a Clipper application not designed for multi-user access is recompiled under Xbase++, the command SET EXCLUSIVE ON needs to be inserted in the startup routine before any databases are opened.
SET EXACT
When SEEK and DbSeek() are used to search for character values in a database, Xbase++ uses the toggle SET EXACT to determine whether blank spaces at the end of character strings should be ignored in comparing character values.
CREATE INDEX
Xbase++ supports collation tables. A collation table assigns weighing factors to single characters. This allows the sorting order of characters to be user-defined. A collation table is used for string comparison as well as for index creation. The collation table is extremely important when creating index files to be accessed from both Xbase++ and Clipper. In this case, Xbase++ must use the same collation table as Clipper. In Clipper, the sorting order of characters is defined at link time by a nation module, and cannot be changed at runtime.
Clipper includes various NTX???.OBJ files that must be linked to the EXE in order to define the country-specific sorting of characters. To achieve the same sorting order with Xbase++, the corresponding collation table must be activated using the SET COLLATION TO command. The following table lists all language specific differences between Clipper and Xbase++.
Language | Clipper module | Xbase++ command |
---|---|---|
American | not available | SET COLLATION TO AMERICAN |
British | not available | SET COLLATION TO BRITISH |
Danish | NTXDAN.OBJ | SET COLLATION TO DANISH |
Dutch | NTXDUT.OBJ | SET COLLATION TO DUTCH |
Finnish | NTXFIN.OBJ | SET COLLATION TO FINNISH |
French | NTXFRE.OBJ | SET COLLATION TO FRENCH |
German | NTXGER.OBJ | SET COLLATION TO GERMAN |
Greek 437 | NTXGR437.OBJ | SET COLLATION TO GREEK437 |
Greek 851 | NTXGR851.OBJ | SET COLLATION TO GREEK851 |
Icelandic 850 | NTXIC850.OBJ | SET COLLATION TO ICELANDIC850 |
Icelandic 861 | NTXIC861.OBJ | SET COLLATION TO ICELANDIC861 |
Italian | NTXITA.OBJ | SET COLLATION TO ITALIAN |
Norwegian | NTXNOR.OBJ | SET COLLATION TO NORWEGIAN |
Portuguese | NTXPOR.OBJ | SET COLLATION TO PORTUGUESE |
Spanish | NTXSPA.OBJ | SET COLLATION TO SPANISH |
Swedish | NTXSWE.OBJ | SET COLLATION TO SWEDISH |
System | not available | SET COLLATION TO SYSTEM |
ASCII | SET COLLATION TO ASCII |
The default for SET COLLATION TO is defined in DBESYS.PRG. It depends on the country specific version of Xbase++. If index files are to be accessed from Xbase++ as well as from Clipper, you must include the following lines in your code:
#ifdef __XPP__
SET COLLATION TO <your country>
#endif
Accessing index files from Xbase++ and Clipper at the same time requires both using the same sorting order for characters. When a Clipper program uses a different sorting order than an Xbase++ program, index files will get corrupted sooner or later.
CREATE FROM
The format of a structure-extended DBF file is different in Xbase++. The length of the field FIELD_LEN is 5, not 3 as in Clipper. This allows the maximum possible field length to be entered directly. It is no longer necessary to use the decimal place field to enter field lengths longer than 999 characters.
Memo Files
The maximum number of characters that can be stored in a memo field is not limited to 64 KB under Xbase++. If memo fields are accessed in a multi-user environment from Clipper and Xbase++, the 64 KB limitation must be implemented in Xbase++.
COMMIT at program's end
When a Clipper program ends, it commits all pending record updates to databases still open (the COMMIT command is implicitly executed). This is not the case with Xbase++. Instead, Clipper's behaviour is programmed in the file APPEXIT.PRG which contains the implicit EXIT PROCEDURE AppExit(). This procedure is called when a program terminates and can be changed to meet a programmer's needs.
RETURN and QUIT
An optional numeric parameter can be specified for QUIT. It is passed to the ErrorLevel() function before an application terminates. The same can be achieved if the function Main() returns a numeric value with the RETURN statement.
Constant | Clipper | Xbase++ |
---|---|---|
_SET_DEBUG | Supported | Not supported |
_SET_SCROLLBREAK | Supported | Not supported |
_SET_CHARSET | Not available | Available |
_SET_COLLATION | Not available | Available |
_SET_LEXICAL | Not available | Available |
_SET_TIME | Not available | Available |
Topic | Clipper | Xbase++ |
---|---|---|
PROCDDURE Main | Must be the first procedure of the application | |
APPSYS.PRG | Not available | Has implicit INIT procedure |
DBESYS.PRG | Not available | Has implicit INIT procedure |
ERRORSYS.PRG | Has implicit INIT procedure | Has implicit INIT procedure |
RDDSYS.PRG | Has implicit INIT procedure | Not available |
APPEXIT.PRG | Has implicit EXIT procedure | Not available |
PICTURE function @E | Numbers are displayed in the country specific format of the operating system | |
Transform(1.23,"@N") | Decimal point and thousands separator are configurable | |
Time() | Separators between HH:MM:SS are configurable | |
SetLocale() | Not available | Configures country specific settings |
The configuration settings of the operating system are used to determine the default separators used in formatting numeric and date values as well as the return value of the function Time(). Thus, the PICTURE formatting with @E is obsolete and is ignored by Xbase++. However, numerous country specific settings can be configured with the function SetLocale().
If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.