Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

z/OS REXX Standard Library

libzostd (Library for z/OS STanDard utilities, or z/OS REXX Standard Library) is a collection of REXX utility libraries that provide a foundation for cross-environment development on z/OS mainframes. The functions and wrappers included in these libraries can be used for environment detection, dataset operations, job monitoring, unified argument parsing, output logging, and more.

The purpose of this library, at its core, is to simplify REXX development on z/OS mainframes through standardization and interoperability. The code components provided with this repository can be used by z/OS programmers of varying skill levels in order to easily plan, develop, and deploy different types of programs or scripts. These libraries have been built to operate identically across the TSO/E, ISPF, MVS, and UNIX System Services (USS/OMVS) environments and to be highly portable.

This collection of libraries may also be referred to as rexx-libzostd in order to distinguish itself against other libraries with similar names.


Table of Contents


Components

File Name: PDS Member Name: Purpose:
lib/global_vars.rexx GLBLVARS Shared constants, return codes, limits, and character sets
lib/zoscore.rexx ZOSCORE Foundation library: environment, datasets, jobs, utilities, logging
lib/zosargp.rexx ZOSARGP Standardized POSIX-style argument parsing for TSO, ISPF, MVS, and USS environments
libzostd.rexx LIBZOSTD All three combined in one file (the main static library artifact)
samples/template.rexx TEMPLATE Complete working program template and usage demo

Dependency order: global_vars.rexx -> zoscore.rexx -> zosargp.rexx (each library depends on the one before it).


Repository Structure

libzostd/
├── libzostd.rexx          Main static library file, all components combined;
│
├── lib/
│   ├── global_vars.rexx   Shared constant variables definitions for libraries;
│   ├── zoscore.rexx       Foundational base REXX library for z/OS; 
│   └── zosargp.rexx       Argument parsing REXX library for z/OS;
│
├── samples/
│   └── template.rexx      Consumer sample template and executable demo;
│
└── scripts/               Repository helper scripts;
    └── copy-lib2pds.sh    Upload library members to a z/OS PDS via USS;

Quick Start

The fastest way to start developing a new z/OS REXX program that utilizes this library is to copy samples/template.rexx and modify the variables PROGRAM_NAME, PROGRAM_DESC, and the argparse_addoption calls in the main: function. Everything else (global vars, all library subroutines) is already prepared for use. After this, the core logic and code can be built or integrated around the rest of the template.

Developing without the template sample

If you only need the static library artifact (e.g. to drop into a PDS or to implement into an existing REXX program), use the library code file named libzostd.rexx which contains all three components in one file.

Note: The difference between the template.rexx and libzostd.rexx library files is that the template.rexx already includes a main function as well as the necessary structuring for running the program to completion (for demo purposes).


Documentation

Static Inclusion Pattern

The code libraries provided in this repository are considered to be static, mainly because mainframe REXX has no standardized 'include' or 'import' mechanism as you would typically find with other programming languages. The terminology associated with the process of physically adding code libraries directly into a codebase or source code is known as static inclusion - this is referenced throughout the relevant documentation within this repository.

Global variable assignments must appear before the first subroutine call, at the top of the program. Library subroutines must appear after your exit statement so they are never executed as inline code, only via function calls (call). With regard to using this library, the best practice is to build a main: function underneath the global variable definitions which can be used for isolating the core program logic.

Example: The layout for statically including the code into a program or script is always:

/* REXX */
/* --- 1. Global variable assignments (from global_vars.rexx) --- */
GLOBAL.RC_SUCCESS = 0
...etc...
PROGRAM_NAME = 'MYPROG'

/* --- 2. Your main program --- */
main:
  call argparse_init
  ...your logic...
  exit GLOBAL.RC_SUCCESS

/* --- 3. Library subroutines (from zoscore + zosargp) --- */
environment_getaddress: procedure expose GLOBAL.
  ...etc...

Global Variables

The global variables definition file defines all shared constants under a single stem named GLOBAL. located before any function declarations. This is used to define standard (and/or customized) globally-scoped variables that can be referenced throughout the rest of the program or script.

Standard Return Codes

Constant Value Meaning
GLOBAL.RC_SUCCESS 0 Operation succeeded
GLOBAL.RC_NOTFOUND 16 Resource not found
GLOBAL.RC_ERROR 8 General error
GLOBAL.RC_INVALIDINPUT 12 Bad input / validation failure
GLOBAL.RC_TIMEOUT 4 Timeout elapsed

Security Limits

Constant Value Purpose
GLOBAL.LIMITS_MAX_DATASET_NAME_LEN 44 Maximum MVS dataset name length
GLOBAL.LIMITS_MAX_USERID_LEN 8 Maximum TSO user ID length
GLOBAL.LIMITS_MAX_STRING_LEN 255 Maximum safe string length
GLOBAL.LIMITS_MAX_COMMAND_OUTPUT_LINES 1000 Output trap line limit
GLOBAL.LIMITS_MAX_LOOP_ITERATIONS 10000 Infinite-loop guard

Timing Constants

Constant Value
GLOBAL.LIMITS_DEFAULT_SLEEP_SECS 5
GLOBAL.LIMITS_DEFAULT_WAIT_TIME 60
GLOBAL.LIMITS_SLEEP_INTERVAL 10
GLOBAL.LIMITS_MAX_SLEEP_SECS 3600
GLOBAL.LIMITS_MAX_WAIT_TIME 86400

Character Sets

Constant Purpose
GLOBAL.CHARS_SAFE_DATASET Valid dataset name characters
GLOBAL.CHARS_SAFE_USERID Valid user ID characters
GLOBAL.CHARS_SAFE_DEBUG Valid debug flag characters
GLOBAL.CHARS_UPPERCASE / LOWERCASE Full alpha ranges (for translate())

SAFE_DATASET_CHARS, SAFE_USERID_CHARS, SAFE_DEBUG_CHARS, and SAFE_OPT_CHARS are provided as plain variable aliases for backwards compatibility.

Program Mode Flags

DEBUG and VERBOSE are initialized to 0. Statically override them in your program or script after including global_vars.rexx, or enable them via flags using the zosargp.rexx library:

EXAMPLE: Statically enable or disable DEBUG and VERBOSE constants within a script or program:

DEBUG   = 1   /* statically enable constant debug output */
VERBOSE = 1   /* statically enable constant verbose output */

z/OS Core Library

The z/OS core library (libzoscore, zoscore) is a foundational base library that exposes several functions and wrappers used for performing common operations in a uniform way. All functions within this library use a procedure expose GLOBAL. statement for securing variable scope through isolation. A debug_flag parameter (optional on most functions) accepts 'DEBUG', '1', or 1 to enable per-function trace output.

Function Reference

Environment Detection

environment_getaddress(debug_flag)

  • Detect the current REXX execution environment. Returns one of:
Value Environment
SH USS / OMVS / UNIX System Services
TSO TSO interactive session
ISPEXEC ISPF dialog environment
MVS MVS batch
ERROR Could not determine

EXAMPLE:

env = environment_getaddress('')
if env = 'SH' then call log_info 'Running in USS', use_verbose

environment_currentlocation(debug_flag)

  • Returns the current working directory (USS) or dataset/member context (TSO/MVS). Returns 'ERROR' on failure.

environment_onlyin_posix(environment, debug_flag)

  • This guard clause logs an error and returns GLOBAL.RC_ERROR if environment is not 'SH' or 'OMVS'. Use at the top of USS-only scripts or to handle USS-only operation logic.

environment_onlyin_mvs(environment, debug_flag)

  • This guard clause returns GLOBAL.RC_ERROR if environment is not TSO/ISPF/MVS. Essentially, this is the opposite (or TSO/E equivalent) of environment_onlyin_posix().

Dataset Operations

dataset_validateinput(dataset_name, debug_flag)

  • Full data set validation: empty check, numeric check, length limit, dangerous character check, character set validation, and qualifier structure. Returns GLOBAL.RC_SUCCESS or GLOBAL.RC_ERROR.

dataset_validateformat(dataset_name)

  • Validates qualifier structure (no leading/trailing dots, no consecutive dots, max 22 qualifiers). Called internally by dataset_validateinput.

dataset_validatequalifier(qualifier)

  • Validates a single qualifier: 1–8 chars, starts with alpha or national (@#$). Called internally by dataset_validateformat.

dataset_parsetype(dataset_name, debug_flag)

  • Best-effort classification based on naming patterns. Returns one of:
    • PDS_MEMBER
    • PDS
    • VSAM
    • SEQUENTIAL
    • UNKNOWN

dataset_ismember(dataset_name)

  • Returns 1 if the name includes a (MEMBER) reference, 0 otherwise.

dataset_extractmember(dataset_name, debug_flag)

  • Returns the member name from a DATASET(MEMBER) reference, or '' if there is no member portion.

dataset_extractname(dataset_name, debug_flag)

  • Returns the dataset name without the (MEMBER) portion. Returns the original name unchanged if there is no member reference.

dataset_normalizename(dataset_name)

  • Adds surrounding single quotes if not already present ('HLQ.DS').

dataset_testexistence(dataset_name, debug_flag)

  • Wraps SYSDSN() with full error handling for both plain datasets and member references.
Return Meaning
0 Not found
1 Found
2 Invalid input
3 Invalid dataset name (SYSDSN)
4 Dataset unavailable
5 Unexpected SYSDSN result
6 SYSDSN function failed
if dataset_testexistence('SYS1.PARMLIB(IEASYS00)') = 1 then
  call log_info 'IEASYS00 found', use_verbose

Job Management

job_waitforcompletion(job_name, max_wait, debug_flag)

  • Polls the JES output queue at GLOBAL.LIMITS_SLEEP_INTERVAL-second intervals until the job appears on the output queue or max_wait seconds elapse. Returns 1 (completed) or 0 (timeout/error).
if job_waitforcompletion('MYJOB01', 120, '') = 1 then
  call log_info 'MYJOB01 completed', use_verbose
else
  call log_error 'Timeout waiting for MYJOB01'

job_checkstatus(job_name, debug_flag)

  • Single-pass check via the TSO STATUS command. Returns 1 if the job is on the output queue, 0 otherwise.

General Utilities

validate_flag(flag)

  • Normalizes any flag argument to 1 (on), 0 (off), or -1 (invalid input). Accepts 1, '1', 'VERBOSE', 'DEBUG', 'verbose', 'debug', 'dbg'. Nearly every other function calls this before acting on a flag parameter.

safe_userid()

  • Validated wrapper around USERID(). Returns the current user ID or '' on error. Validates length and character set before returning.

prompt_confirm(message, force_flag, debug_flag)

  • Prompts the user to type CONFIRM, YES, or Y before a destructive operation. Returns 1 (confirmed) or 0 (declined/cancelled). force_flag = 'Y' or 1 bypasses the prompt for non-interactive use.
if prompt_confirm('Delete all output datasets?', use_force, '') = 1 then
  call do_delete

sleep(sleep_seconds, debug_flag)

  • Cross-platform sleep using TIME('S') that works in TSO, USS, and MVS batch. This can be used in situations where the REXX environment is missing a native/adapted sleep routine. Handles midnight time rollover. Enforces GLOBAL.LIMITS_MAX_SLEEP_SECS.

Output Logging

All log functions validate and truncate messages to GLOBAL.LIMITS_MAX_STRING_LEN.

log_error(message)

  • Prints ERROR: message unconditionally.

log_warning(message)

  • Prints WARNING: message unconditionally.

log_info(message, verbose_flag)

  • Prints INFO: message only when verbose_flag is on.

log_verbose(message, verbose_flag)

  • Prints raw message only when verbose_flag is on.

log_debug(message, debug_flag)

  • Prints _> DEBUG: message only when debug_flag is on.

z/OS Argument Parse Library

The z/OS argument parsing library (libzosargp, zosargp) is a simple argument parsing library implementation for REXX programs, with the primary goal being to standardize argument parsing across different z/OS environments. This implementation supports both TSO-style (OPTION=value) and POSIX-style (--option=value or -o=value) argument syntax parsing, so that programs and scripts can parse arguments easily from within both UNIX (via the $PATH variable) and TSO/E (via the SYSEXEC concatenation) environments.

  • Requires global_vars.rexx and zoscore.rexx libraries.

Note: A common and historical pattern with REXX mainframe development is that nearly every program/script one may encounter will potentially implement a different form or style of argument parsing (input handling), which leads to an overall inconsistency across projects built with the language. This library aims to prevent inconsistency by providing mainframe developers with a portable and practical library for managing input parameters, similar to other well-known programming languages such as Python, Java, Golang, C, etc.

Function Reference

argparse_init

  • Initializes all internal state. Must be called before any other argparse_* function. Automatically registers -h / --help. Returns GLOBAL.RC_SUCCESS.

argparse_addoption(short, long, type, default, help, required)

  • Registers one option. Both short and long may be provided; at least one is required.
Parameter Description
short Single character ('f') or ''
long Name string 1–20 chars ('file') or ''
type 'FLAG', 'STRING', or 'INTEGER'
default Default value (empty string for FLAGS)
help Description shown in --help output
required 'Y' or 'N'
  • Returns GLOBAL.RC_SUCCESS on success, GLOBAL.RC_ERROR or GLOBAL.RC_INVALIDINPUT on failure. Maximum 19 user-defined options (slot 20 is reserved for --help).

argparse_parse(args)

  • Parses a space-delimited argument string. Handles both --long=value and SHORT=value formats. Returns the number of parse errors (0 = success).

argparse_getvalue(name)

  • Returns the value of an option (by short or long name), or '' if not found. For FLAG types, returns 'Y' if provided, default ('') otherwise.

argparse_isprovided(name)

  • Returns 1 if the option was explicitly provided in the argument string, 0 if it was not (even if a default exists).

argparse_geterrors

  • Prints all accumulated parse errors with hints. Returns the error count.

argparse_showhelp

  • Prints usage, option table, and examples in both TSO and USS syntax. Requires PROGRAM_NAME and optionally PROGRAM_DESC to be set.

argparse_checkrequired (internal)

  • Called automatically by argparse_parse. Reports errors for any option marked required = 'Y' that was not provided.

argparse_cleanup

  • Drops all internal argparse state. Call at end of program or before a second argparse_init call in the same exec.

EXAMPLE: Below is a sample reference that displays the required call sequence of the zosargp.rexx library:

call argparse_init

rc = argparse_addoption('f', 'file',    'STRING',  '',    'Input file',  'Y')
rc = argparse_addoption('v', 'verbose', 'FLAG',    '',    'Verbose',     'N')
rc = argparse_addoption('c', 'count',  'INTEGER', '10',  'Record count','N')

parse arg input_args
error_count = argparse_parse(input_args)

if error_count > 0 then do
  call argparse_geterrors
  exit GLOBAL.RC_ERROR
end

filename   = argparse_getvalue('file')
is_verbose = argparse_isprovided('verbose')

call argparse_cleanup

Supply-Option Syntax Reference

The zosargp.rexx argument parsing library accepts several syntax variations when supplying command line arguments to programs: TSO-style, POSIX-style, or a hybrid approach. The table below describes the basic syntax options for providing arguments to a program using this library, and is also available for reference within the zosargp.rexx help menu function (e.g. providing the -h, --help, or help argument to a program will also display a version of the table data as seen below, for user reference).

Environment Format
TSO / ISPF / MVS OPTION=value or O=value
USS / OMVS / POSIX --option=value or -o=value
FLAG (any) --verbose or VERBOSE (no =value needed)

Debugging

This library has dedicated a large portion of code specifically towards output logging and debugging features. Although the REXX programming langauge's trace routine already provides exceptionally robust debugging capabilities, every function and wrapper in the library also accepts an optional debug_flag parameter to enable verbose debugging output. Pass 'DEBUG' or 1 to enable per-function or program-wide debug logging:

env = environment_getaddress('DEBUG')
rc  = dataset_testexistence('SYS1.PARMLIB', 'DEBUG')

Note: log_debug output is prefixed with a stylized _> DEBUG: tag and can be grepped or filtered from normal program output in UNIX environments. Combining this with REXX's built-in TRACE I provides very precise execution tracing.


Security Model

TLDR

The security methodology associated with this style of REXX programming is based on the core concept that all potentially unsafe operations should be handled or prevented by the limitations and guardrails set within the library by default. The developer should have to either build their code around the existing limitations, or explicitly modify library source code to behave otherwise.

  • If a programmer is developing code that utilizes this library according to the proper implementation and usage guidelines (as outlined throughout this documentation), then the path of least resistance should lead to safer code - secure patterns should be the default, and bypassing guardrails will require deliberate, explicit modification.

Note: Unlike other programming languages that already provide several standard libraries/modules and wrappers for handling these types of common situations, the REXX programming language implementations on mainframe operating systems can sometimes be very barebones/limited in terms of libraries, and some environments may often include nothing more than a REXX interpreter or compiler. As a byproduct of these circumstances, most REXX mainframe development requires more upfront labor to create secure routines for performing what would otherwise already be included in a standard library with other programming languages. Put more simply, when a developer is re-inventing the wheel every time a new tool/program needs to be created, the margin for errors or bugs greatly increases.

Security Philosophy

The security philosophy regarding this REXX library is that by providing security checks and strong debugging capabilities directly within the libraries themselves (that would otherwise need to be manually written every time a program or script is being built), there is less burden on the developer to physically and mentally plan security components such as validations, input sanitization, and consistency maintenance upfront - allowing for more focus on core program logic and results.

By following this philosophy, the libraries generally attempt to provide safer functions by default and will require the developer to make explicit changes to security components as necessary, which would ideally cause the developer to be more aware of the changes to safeguards that they are making or draw specific attention to areas of the libraries that have been modified.

Technical Security Integrations

  • Every input-accepting function validates length and character set before use (see GLOBAL.CHARS_SAFE_* and GLOBAL.LIMITS_MAX_*).

  • Destructive operations can/should be routed through prompt_confirm() unless explicitly bypassed with the force flag.

  • argparse_validateinput rejects command strings containing known command injection patterns (e.g. $(, which is unsafe when passed to ADDRESS SYSTEM or bpxwunix() functions) and excessive special characters.

  • All log functions truncate messages at GLOBAL.LIMITS_MAX_STRING_LEN to prevent potential runaway output.


PDS Member Library Names

When loading individual files into an MVS PDS, the equivalent 8-character member names are:

File PDS Member
libzostd.rexx LIBZOSTD
lib/global_vars.rexx GLBLVARS
lib/zoscore.rexx ZOSCORE
lib/zosargp.rexx ZOSARGP

Use scripts/copy-lib2pds.sh to copy the library files into a PDS and automatically set member names. Run ./copy-lib2pds.sh --help for full usage, or ./copy-lib2pds.sh -n TARGET_DS for a dry run.


License

This repository is currently provided under the Apache License 2.0, see the License or the license header in each library file.

Not an officially supported IBM product; open-source, and provided as-is with no warranty.

About

libzostd is a collection of REXX utility libraries that provide a foundation for cross-environment development on z/OS mainframes.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages