How to change definitions or commands in a system .ch file

I Love Xbase++ (ILX)
The portal for Xbase++ developers worldwide

Pat France

New member
Staff member
I am here to help you!
Aug 9, 2022
22
3
3
Customer Identifier
E114627
Sometimes it is necessary to make changes to a command or definition which is defined in a system include (.ch) file, for example, for adapting behavior to conform to a certain Clipper version. As an example, we'll apply a modification to the GET system so that the ReadVar() function also returns the index of the read variable of a @..GET if the variable references an array element. This achieves compatibility with Clipper 5.2.

The @..GET command and other aspects of the GET system are defined in the get.ch include file. This is a system file that is installed with Xbase++. Consequently, changes that are made in this file will be lost if an update is installed or if Xbase++ needs to be reinstalled.

As a general rule, making changes to system (header) files is discouraged! Instead, changes should be applied in a dedicated file located in the project.

The definition of the @..GET command in get.ch looks like this:
Xbase++:
// Intermediate pseudo functions
#xtrans __gName(<var>)                    =>  <"var">
#xtrans __gName(<var>\[<i,...>])          =>  <"var">
#xtrans __gName(<var>\[<i>]\[<j>])        =>  <"var">

#command  @ <nRow>, <nCol> GET <Var> ;
                      [PICTURE <cPict>] ;
                        [VALID <lValid>] ;
                         [WHEN <lWhen>] ;
                         [SEND <message>] ;
      =>  aadd( getList, ;
            ( Get():new( <nRow>, <nCol>, __gBlock(<Var>), __gName(<Var>), ;
                        <cPict>, NIL, <{lValid}>, <{lWhen}>) ):display() ) ;
       [; Atail( getList ):<message>]

This command definition basically uses the parameters specified in the @..GET command for instantiating a Get object and adding it to the Get list. Note the __gName() pseudo function which is used in conjunction with the read variable <var>. This pseudo function derives the variable from the variable used in the @..GET command, and is what needs to be changed for allowing ReadVar() to return an array index. To achieve this, the definition of the changed pseudo functions need to be defined in a local header (.ch) file. Because the pseudo function is used in the definition of the @..GET command which is also defined in the original get.ch file, the @..GET command must be redefined in the local .ch file, too.

In order to change a definition in a system header (.ch) file, copy the original definition to a local .ch file and apply the changes there. If the changed definition is used in #command or #translate directives in the original .ch file, these must also be copied. Afterwards, the local .ch file must be included in all source (.prg) files which should use the changed definition.

In the above example, the __gName() pseudo function must be changed to include the array index in the variable name. The resulting local header file might look like this:

Xbase++:
//////////////////////////////////////////////////////////////////////
//
// myget.ch
//
// Changes the @..GET command so that ReadVar() returns array indices
// for Clipper 5.2-compatibility
//////////////////////////////////////////////////////////////////////
// myget.ch is not included
#ifndef  _MYGET_CH

#xtrans __gName(<var>\[<i,...>])   =>  <(var)>+"["+\[<i>]+"]"      // Original: <"var">
#xtrans __gName(<var>\[<i>]\[<j>]) =>  <(var)>+"["+\[<i>,<j>]+"]"  // Original: <"var">

#command  @ <nRow>, <nCol> GET <Var> ;
                      [PICTURE <cPict>] ;
                        [VALID <lValid>] ;
                         [WHEN <lWhen>] ;
                         [SEND <message>] ;
      =>  AAdd( getList, ;
            ( Get():new( <nRow>, <nCol>, __gBlock(<Var>), __gName(<Var>), ;
                      <cPict>, NIL, <{lValid}>, <{lWhen}>) ):display() ) ;
       [; Atail( getList ):<message>]

// myget.ch is included
#define  _MYGET_CH
#endif

In order to use these changes in your source code, the local header file must be included in the .prg(s) instead of or in addition to the original .ch file.

Xbase++:
#include "myget.ch" // Changes @..GETs so that ReadVar() returns array indices

PROCEDURE Main()
 LOCAL a := {123,456}

  @ 5,2 SAY "Element 1:" GET a[1]
  READ
  WAIT
RETURN

If the original .ch file needs to be included along with a modified local header file, the local .ch file should be included last. This ensures that changed definitions "overwrite" the original ones. If #define values were changed, the #undef preprocessor directive can be used to avoid "redefinition or duplicate definition of #define" warnings.

Note: get.ch is automatically included by the compiler which is why it does not need to be included in the example above.
 
Last edited by a moderator: