subroutine

The subroutine keyword is used to define a named subroutine

Syntax

subroutine subroutine_name {
   # Statements
}

Details

Overview

A subroutine is a named section of code that can be executed multiple times on demand from anywhere in the script. When called (via the gosub statement), execution of the script jumps to the start of the specified subroutine. When the end of the code in the subroutine body is reached or a return statement is encountered (whichever comes first), execution resumes at the statement following the most recent gosub statement that was executed.

The code in the body of a subroutine statement is never executed unless the subroutine is explicitly called using gosub. If a subroutine is encountered during normal linear execution of the script then the code in it will be ignored.

Subroutines in USE do not return any values, but any variables that are set within the subroutine can be accessed from anywhere in the script and as such they should be used for returning values as needed.

Subroutine Arguments

When invoked via the gosub statement, arguments can be passed to the subroutine. These arguments are read-only but may be copied to normal variables if required.

Arguments are accessed using the same syntax as is used for variables as follows:

${SUBARG.COUNT} contains the number of arguments that were passed to the subroutine

${SUBARG_N} is the value of any given argument, where N is the number of the argument starting at 1

Every time a subroutine is called, any number of arguments may be passed to it. These arguments are local to the subroutine and will be destroyed when the subroutine returns. However, copying an argument to a standard variable will preserve the original value as follows:

subroutine example {
    if (${SUBARG.COUNT} == 0) {
        var return_value = "NULL"
    } else {
        var return_value = ${SUBARG_1}
    }
}

After the subroutine above has been executed the return_value variable will retain the value it was set to.

It is not permitted to nest subroutine statements. If used within the body of a subroutine statement, a subroutine statement will cause the script to terminate with an error.

Example

The following demonstrates using a subroutine to detect when another subroutine has been provided with an incorrect number of arguments:

if (${ARGC} == 0) {
    print This script requires a yyyyMMdd parameter
    terminate with error
} 

# Ensure the parameter is an 8 digit number
gosub check_date(${ARG_1})
#
# (script to make use of the argument goes here)
#
terminate

# ----
#     This subroutine checks that its argument
#     is an 8 digit decimal number
# ----
subroutine check_date {
    # Ensure this subroutine was called with one argument
    gosub check_subargs("check_date", ${SUBARG.COUNT}, 1)

    # Validate the format
    match date "^([0-9]{8})$" ${SUBARG_1}
    if (${date.STATUS} != MATCH) {
        print Error: the provided argument is not in yyyyMMdd format
        terminate with error
    }
}

# ----
#     This subroutine generates an error message for
#     other subroutines if they do not have the correct
#     number of arguments
#
#     It is provided as a useful method for detecting internal
#     script errors whereby a subroutine is called with the
#     wrong number of arguments
#
#     Parameters:
#        1: The name of the calling subroutine
#        2: The number of arguments provided
#        3: The minimum number of arguments permitted
#        4: OPTIONAL: The maximum number of arguments permitted
# ----
subroutine check_subargs {
    # A check specific to this subroutine as it can't sanely call itself
    if ( (${SUBARG.COUNT} < 3) || (${SUBARG.COUNT} > 4) ) {
        print Error: check_subargs() requires 3 or 4 arguments but got ${SUBARG.COUNT}
        terminate with error
    }

    # A generic check
    var SCS_arg_count = ${SUBARG_2}
    var SCS_min_args = ${SUBARG_3}
    if (${SUBARG.COUNT} == 3) {
       var SCS_max_args = ${SUBARG_3}
    } else {
       var SCS_max_args = ${SUBARG_4}
    }

    if ( (${SCS_arg_count} < ${SCS_min_args}) || (${SCS_arg_count} > ${SCS_max_args}) ) {
        if (${SCS_min_args} == ${SCS_max_args}) {
            print Error in script: the ${SUBARG_1}() subroutine requires ${SCS_min_args} arguments but was given ${SCS_arg_count}
        } else {
            print Error in script: the ${SUBARG_1}() subroutine requires from ${SCS_min_args} to ${SCS_max_args} arguments but was given ${SCS_arg_count}
        }
        terminate with error
    }
}

Last updated