5 QMERGE - Version Selection

5.1 What Does it Do?

QMERGE is a small tool which tackles a common problem - how to keep control of programs which exist in a number of different versions. Some common examples are programs which run on a variety of different machines, and require slight changes to the source code for each one. For example, changes may be necessary because of different file naming conventions, word length, or different ways of accessing the system.

QMERGE allows the user to keep all the code variants within the master version of the source code. It comments and un-comments sections of code depending on the settings of user-defined logical flags. Unlike a macro pre-processor or conditional compilation tool, QMERGE does not require that you deviate in any way from standard Fortran, or that you pre-process code before submitting it to a compiler - the master version is legal Fortran and can be compiled directly. QMERGE is needed only when you create a version for porting to a different machine.

The operation of QMERGE can be understood by reference to a simple example, such as that in the following table. This program fragment consists of one section which is activated if the the user defined condition named LINUX is TRUE, and another which is activated if LINUX is FALSE, and at least one of the conditions MAC, VMS and WINDOWS is TRUE (the commas between them may be read as 'OR'). Inside the LINUX section is a nested !-IF construct containing sections which may be activated depending on the values of the DEMO and DEBUG conditions. The condition names are not case sensitive, and may be up to 32 characters long. They are defined simply by using them.

Version 1 of the program fragment is consistent with the condition LINUX being FALSE, and one of MAC, VMS or WINDOWS being TRUE . The values of DEMO and DEBUG are irrelevant in this case. Version 2 could be obtained by passing version 1 through QMERGE and specifying LINUX as TRUE, DEMO as FALSE, and DEBUG as TRUE (the '-' in front of DEBUG may be read as 'NOT'). In fact, the result does not depend on which lines are commented out in version 1, but only on values of the conditions. It is quite possible to convert version 2 back to version 1 (by running QMERGE with LINUX set to FALSE and MAC set to TRUE).

Version 1

Version 2


!-IF LINUX
!-      PRINT *,'LINUX'
!-IF DEMO
!-      PRINT *
!-      PRINT *,'Demo'
!-ELSEIF -DEBUG
!-      PRINT *
!-      PRINT *,'Debug off'
!-ELSE
!-      PRINT *
!-      PRINT *,'Debug on'
!-ENDIF
!-      X = Y
!-      A = B
!-ELSEIF MAC,VMS,WINDOWS
      PRINT *,'Default'
!-ENDIF

!-IF LINUX
      PRINT *,'LINUX'
!-IF DEMO
!-      PRINT *
!-      PRINT *,'Demo'
!-ELSEIF -DEBUG
!-      PRINT *
!-      PRINT *,'Debug off'
!-ELSE
      PRINT *
      PRINT *,'Debug on'
!-ENDIF
      X = Y
      A = B
!-ELSEIF MAC,VMS,WINDOWS
!-      PRINT *,'Default'
!-ENDIF

5.2 The QMERGE Command Line

To start a run, simply type qmerge followed by the name of the file(s) you wish to process. You can use wild-cards to specify more than one file. For example

      qmerge a*.for b*.for

processes the contents of all files in the current directory which fit either wildcard. QMERGE conbines the files to a single output file. Whenever it finds a !-IF or !-ELSEIF condition, QMERGE prompts the user for "Yes or No" decision, unless the status of the condition is already known, because of a previous prompt, or because it was specified in a condition string.

Condition strings are used to reduce or eliminate prompting by pre-defining conditions to be true (or false). They consist of a list of condition names separated by "/" (or "," in Windows). Condition strings can be specified on the command line, using the SELECT= keyword. For example

      qmerge a*.for b*.for SELECT=LINUX,-DEMO

or on Linux/Mac

      qmerge a*.f b*.f select=LINUX/-DEMO

specifies that "LINUX" is true, and "DEMO" is false (the "-" sign before "DEMO" signifies that the condition is false.) Condition Strings are discussed in more detail below.

Under Windows, .for is assumed if no extension is specified (b* is treated as b*.for). The default file name is *.for. Thus, if you don't specify any files, all .for files in the current directory are processed. The separator in the condition string may be either '/' or ','.

On Linux or Mac, the extension must be specified, and there is no default file name. The separator in the condition string must be '/'.

The operation of QMERGE may be modified by command line switches. Currently the following switches are available:

FIG=

specifies the configuration file name. If you don't specify a file name in this way, QMERGE assumes that the configuration file is called qmerge.fig. In either case, the search rules defined in section 1.4 are followed. If the configuration file exists, QMERGE reads it before reading the input files. The configuration file may contain source code directives to set further conditions (see Section 5.4). Nothing from the configuration file is copied to the output file.

If a '?' is appended (e.g. FIG=QMERGE.FIG? or FIG=?), QMERGE lists the contents of the active configuration file to the screen, with a pause after each screen full.

TO=

specifies the name of the file to which the QMERGE output is sent. The default file name is qmerge.out QMERGE sorts file names into alphabetical order before processing, and inserts header records in the output file so that the modified version of each input file can be identified.

HEAD=

specifies the four characters to be used to identify the header records which are placed before each file in qmerge.out. The header record contains the 4 specified characters followed by the name of the following file. A utility called QSPLIT which splits up merged files produced by QMERGE or SPAG is supplied. The default header record identifier is **==.

PREFIX=

specifies up to four characters which are used at the start of lines within the source code to identify QMERGE directives and lines which are not active in the current version. The default is the two character string "!-". The character string must identify the rest of the line as a comment, so the first character is normally "!".

For example

      qmerge a*.ftn select== head=c##== prefix=!!

5.3 Specifying Conditions

Normally, QMERGE determines the value of conditions by prompting the user as the need arises. For example:

      Is LINUX true? (Y or N) ==>

However, it is also possible to specify the value of some or all conditions externally to reduce or eliminate the need for prompts. This is done by setting up 'condition strings' which are passed to QMERGE via the command line, embeded in the source code, or in the QMERGE configuration files. A condition string consists of a series of condition names separated by '/' or ',' characters. The conditions specified in the condition string are taken to be TRUE, unless the condition name is preceded by a '-' in which case the condition is FALSE. For example,

      qmerge *.f select=linux/debug/-demo

specifies that LINUX and DEBUG are TRUE, but DEMO is FALSE. All other conditions are undefined, and if necessary, QMERGE will prompt for a value.

To suppress prompting, so that QMERGE can be run non-interactively, it is necessary to specify all conditions, or include '#NOPROMPT' in the list of conditions. This has the effect of implicitly answering with a 'N' whenever a prompt would otherwise appear. For example

      qmerge select=LINUX/#NOPROMPT

specifies that LINUX is TRUE and that everything else is FALSE.

If you include the word '#SHORT' in the list of conditions, then any lines which begin with the characters !- are not copied to the output file. That includes QMERGE directives, and source lines which are not active in the current version. Thus if the condition string contains

      qmerge select=MAC/#SHORT/#NOPROMPT

the output file for the example in section 5.1 would be reduced to a single line

      PRINT *,'Default'

Other special condtions include #NOSELECT, which suppresses the selection mechanism to that QMERGE simply combines the files without changing them, and #PREFIXxy which changes the QMERGE source code prefix from !- to xy.

5.4 Source Code Directives

Conditions may also be specified within the source code itself, or within a configuration file which is read at the start of every run. This is done using the !-SELECT directive. For example

      !-SELECT -DEBUG,-DEMO
      !-IF VMS
      !-SELECT VT100,ASCII,GKS,ORACLE
      !-ELSEIF IBM370
      !-SELECT IBM3270,EBCDIC,GDDM,DB2
      !-ELSE
      !-SELECT WYSE,ASCII,XWINDOWS,DBASE
      !-ENDIF

activates different flags depending on the values of VMS and IBM370.

!-DEFAULT is a variant of the !-SELECT directive. Conditions specified after !-DEFAULT take effect only if the specified condition is undefined. So, for example, if you have

      !-SELECT DEBUG
      !-DEFAULT -DEBUG,-DEMO

then DEBUG is true, because the specification in the !-DEFAULT directive does not override that in the !-SELECT. DEMO will be false (assuming it has not previously been set).

Note that !-SELECT will over-ride conditions passed from the command line, while !-DEFAULT will not.

A useful directive is !-ONEOF. This has the effect of specifying that exactly one of the following conditions must be true, and that all others are false. If in doubt, QMERGE will ask the user to specify which is true. For example, if QMERGE reads:

      !-ONEOF SUN,HP,IBM,DEC

then QMERGE evaluates the conditions SUN, HP, IBM and DEC. If one is true, then the others are set false. Otherwise QMERGE issues a prompt:

      Which of the following is TRUE?

      1 - SUN
      2 - HP
      3 - IBM
      4 - DEC

      Please enter number ==>

A sample configuration file containing examples of all these source code directives is available in the plusFORT installation directory.