Here is an example of handling your own constraints to illustrate why it is more convenient to use the packaged routines, where applicable, and also to demonstrate how you might write your own extended routine should you need one. It is a little contrived, since the PAR library already provides the most-common combinations.
Here we obtain from parameter NAME an integer that is not exactly divisible by 3, set the dynamic default to 1, and interpret null to mean set the value to 3. See SUN/104 for details of the MSG_ calls.
LOGICAL NOTOK INTEGER VALUE : : : * Set the dynamic default. CALL PAR_DEF0I( 'NAME', 1, STATUS ) * Start a new error context. CALL ERR_MARK * Loop to obtain the value of the parameter. * ========================================== * Initialise NOTOK to start off the loop and indicate that a * satisfactory value has yet to be obtained. NOTOK = .TRUE. 100 CONTINUE * The loop will keep going as long as a suitable value has not be read * and there is no error. IF ( .NOT. NOTOK .OR. ( STATUS .NE. SAI__OK ) ) GOTO 120 * Get a value from the parameter. CALL PAR_GET0I( 'NAME', VALUE, STATUS ) * Check for an error before using the value. IF ( STATUS .EQ. SAI__OK ) THEN * Test the value against the constraints. Here it is just to see * if the value is divisible by 3. You can replace this expression * with more complicated constraints. NOTOK = MOD( VALUE, 3 ) .EQ. 0 * The value is not within the constraints, so report as an error, * including full information using tokens. You would substitute a * routine name for fac_xxxxx. IF ( NOTOK ) THEN STATUS = SAI__ERROR CALL MSG_SETC( 'PARAM, 'NAME' ) CALL MSG_SETI( 'VALUE', VALUE ) CALL ERR_REP( 'fac_xxxxx_OUTR', : '^VALUE is not permitted for ^PARAM. Please give '/ : /'an integer not exactly divisible by 3.', STATUS ) * The error is flushed so the user can see it immediately. CALL ERR_FLUSH( STATUS ) * Cancel the parameter to enable a retry to get a value satisfying * the constraint. CALL PAR_CANCL( 'NAME', STATUS ) END IF * Use the default value following an error. ELSE * Annul a null error to prevent an error report about null appearing. * Create a message informing the user of what has happened. IF ( STATUS .EQ. PAR__NULL ) THEN CALL ERR_ANNUL( STATUS ) * If MSG verbose output is requested, inform the user what has happened. * You would substitute a routine name for fac_xxxxx. CALL MSG_SETC( 'PARAM', 'NAME' ) CALL MSG_OUTIF( MSG__VERB, 'fac_xxxxx_DEFA', : 'A value of 3 has been adopted '/ : /'for parameter ^PARAM.', STATUS ) END IF * Set the returned value to the special case. VALUE = 3 * Terminate the loop. NOTOK = .FALSE. END IF * Go to the head of the loop. GOTO 100 * Come here when the loop has been exited. This includes when * an error status was returned by the PAR_GET0I routine. 120 CONTINUE * Release the new error context. CALL ERR_RLSE
To set another constraint you have to modify the logical expression for variable NOTOK, and revise the ERR_REP error report, possibly with more tokens. Suppose variables VMIN and VMAX define a range of permitted values, which is inclusive when VMAX is the larger of the two and exclusive when VMAX is less than VMIN. The constraint expression could modified to the following.
* Check that the value is within the specified include or exclude * range, and not divisible by 3. IF ( VMIN .GT. VMAX ) THEN NOTOK = ( ( VALUE .LT. VMIN ) .AND. ( VALUE .GT. VMAX ) ) : .OR. ( MOD( VALUE, 3 ) .EQ. 0 ) ELSE NOTOK = ( VALUE .LT. VMIN ) .OR. ( VALUE .GT. VMAX ) .OR. : ( MOD( VALUE, 3 ) .NE. 0 ) END IF
and the error report would look something like this
* The value is not within the constraints, so report as an error, * including full information using tokens. IF ( NOTOK ) THEN STATUS = PAR__ERROR CALL MSG_SETC( 'PARAM', 'NAME' ) CALL MSG_SETI( 'VALUE', VALUE ) CALL MSG_SETI( 'MIN', VMIN ) CALL MSG_SETI( 'MAX', VMAX ) IF ( VMIN .GT. VMAX ) THEN CALL MSG_SETC( 'XCLD', 'outside' ) ELSE CALL MSG_SETC( 'XCLD', 'in' ) END IF CALL ERR_REP( 'fac_xxxxx_OUTR', : '^VALUE is not permitted for ^PARAM. Please give '/ : /'an integer ^XCLD the range ^MIN to ^MAX, and not '/ : /'exactly divisible by 3.', STATUS )
In practice you would probably define a logical variable outside the loop
to indicate whether the range was inclusive or exclusive.
Having looked `behind the scenes', we can now look at what the PAR_ extended routines offer.
PAR Interface to the ADAM Parameter System