SELCOPY
SELCOPY is a non-structured, interpreted procedural language from Compute (Bridgend) Ltd - first shipped in 1971 as an IBM mainframe SELect-and-COPY utility and still generally available and serviced more than fifty years later
Created by Compute (Bridgend) Ltd (CBL), Bridgend, Wales
SELCOPY is one of the quietest survivors in programming-language history. It was born in 1971 as a utility with a job-shop name - SELect and COPY - written in IBM mainframe assembler by a small Welsh software house, Compute (Bridgend) Ltd. Its purpose was mundane: read a file, look at some bytes, decide whether to keep the record, and write it somewhere else. Over the following five decades that utility accreted an arithmetic system, declared variables, subroutines, dynamic allocation, database access, directory traversal and regular expressions, until what had been a set of control cards was, unmistakably, a programming language - the vendor’s own reference manual now describes it as “a high level, interpreted language” that is, “like Assembler, C and COBOL, a non-structured, procedural programming language.”
It is also, unusually for anything covered in this encyclopedia, still on sale and still on a published service schedule. The CBL Product Suite reached Release 3.60 on 11 September 2024, and CBL’s news page was still announcing published service packages for it into 2026. SELCOPY is frequently catalogued as a historical or dormant language, which is a fair description of its visibility and an inaccurate one of its status.
History and Origins
Compute (Bridgend) Ltd has been developing for the IBM mainframe since 1970, from an address in Bridgend, South Wales that has appeared unchanged on the cover of its manuals for decades. The BAL - Basic Assembler Language - version of SELCOPY was first made generally available in 1971, targeting the IBM OS and DOS operating system families that would become z/OS, z/VSE and z/VM CMS.
The original design decision that shaped everything after it was operating-system independence. As the manual puts it, “All mainframe SELCOPY code is independent of Operating System. The same program will work under all varieties of MVS, VSE, TSO and CMS.” In an era when a shop’s utility library was typically fragmented across incompatible operating systems, a single control-statement dialect that ran under all of them was a real productivity argument - and one that made the language sticky, because programs written for it kept working through decades of platform migration.
Numbering of the BAL line ran into single-digit major releases; the manual records a mainframe release 9.8P in March 1999, which is largely a Year 2000 release: it introduced the SELCNAM options file, licence range options, four-digit year handling for VM and VSE directory input, and OPT Y2/Y4 support. The BAL line was then renumbered to 2.00 in May 2001 to align it with the portable version’s numbering.
The C++ rewrite
By the early 1990s, CBL’s customers were no longer purely mainframe shops. Development of a SELCOPY written in C++ began in 1994, explicitly for portability across the IBM mainframe, the AS/400 and the various PC and Unix platforms. Crucially, the new implementation was not a new language: “Its specification was based on that of SELCOPY written in BAL and so, with only a few exceptions, supports the same syntax.”
The first C++ release shipped in 1996 for PC-DOS and MS-DOS, and then spread outward with each point release: HP-UX and OS/2 in 2.02 (June 1998); AS/400 and the Windows 95/98/ME/NT/2000 family in 2.04 (May 1999). By the time the 2.0x manual was written, the supported grid ran to OS/390, z/OS, VM/ESA, z/VM, VSE/ESA, OS/400, AIX, Solaris on SPARC, Tru64 on Alpha, HP-UX on PA-RISC and Windows on x86.
The final twist came in 2011. The C++ version had by then accumulated facilities the assembler version never had, and rather than back-port them, CBL compiled the C++ interpreter for the mainframe and shipped it as a second executable, SLC, alongside the original SELCOPY module. Both remain in the product suite: SELCOPY is still the default interpreter for legacy programs, and SLC is where new syntax lands. Two independent implementations of the same language, one in assembler and one in C++, running side by side on the same z/OS system, is a rare arrangement.
Design Philosophy
SELCOPY’s design goal is stated plainly in the user manual: “Its intention is to insulate users whenever possible from the rigorous rules and tedious tasks found in data processing, thereby gaining productivity.” Three principles follow from that.
Nothing is compiled. The SELCOPY or SLC executable takes the program as control input, parses it into internal structures and executes it. There is no build step, no load module to manage, and no reason not to write a five-line program to answer a one-off question.
Legibility over expressiveness. The reference states that the language “is designed to be practical and easy to understand so that inexperienced programmers may deduce the function of a SELCOPY application without in-depth analysis.” Keywords are English verbs - READ, WRITE, PRINT, IF, THEN, CHANGE, EOJ - and they may be abbreviated to a documented minimum prefix or spelled in any mix of case.
Forgiving syntax. “Flexibility of syntax has been given special attention. As a result, there are numerous methods of saying the same thing.” Blanks, commas and equals signs are all interchangeable as delimiters; <>, ^< and ¬= all mean not equal; hexadecimal digits may be written in either case. This is deliberate tolerance for control cards typed by people whose main job was not programming.
The cost of that philosophy is the one the manual is honest about: SELCOPY is non-structured. A program is a flat sequence of statements with labels, and control flow may jump to any of them. There are no block-structured loops in the ALGOL sense.
Key Features
The implied loop
The single most characteristic feature of SELCOPY is that the main loop is invisible. A READ statement establishes a prime input; after the last statement executes, selection processing loops back to the first selectable statement automatically, exactly as if GOTO GET had been coded. Processing ends when the prime input hits end of file, when STOPAFT thresholds are satisfied, or when the program executes EOJ. If no READ exists there is no prime input, and the program simply runs once, top to bottom.
This is why the shortest useful SELCOPY programs are one line long. The record loop, the open, the close and the end-of-job reporting are all supplied by the interpreter.
Positional data with a work area
Every execution has a base storage buffer - the work area - into which records are read and out of which they are written. Data is addressed by position within that buffer: POS 31,33 is the three-byte field running from position 31 to position 33. On top of that, DECLARE provides named variables with data types (CHAR, VARCHAR, CHARV, CHARZ, BIN, DEC, FLOAT and DOUBLE), while packed decimal, zoned decimal, binary, floating-point and date representations are selected on individual field definitions through TYPE= and STYLE=. EQU provides symbol substitution during control-statement analysis, so that record layouts can be named rather than hard-coded.
The type system is thoroughly EBCDIC-and-COBOL-shaped: packed decimal and zoned decimal are first-class, conversion operations (CVCF, CVBx, CVxB, CVDATE) move between any representation and any other, and the FORMAT string uses picture-clause style symbols (zz,zz9, s,sss,ss9.999) for edited output.
A worked example
The following illustrates the shape of a typical program - declarations, an implied loop over the prime input, a positional test, and end-of-file reporting:
* Copy department 42 records and report the count.
EQU IREC 1 * Name the work area origin.
DECLARE TOTAL BIN INI=0 * Binary counter.
READ INDD INTO IREC * Prime input - drives the loop.
IF POS IREC+30, IREC+32 = 'D42' * Three-byte department code.
THEN WRITE OUTDD FROM IREC * Copy the record out.
THEN TOTAL = TOTAL + 1
IF EOF INDD * After the last record...
THEN PRINT 'Records copied: ' TOTAL
THEN EOJ
Comments begin at an unquoted asterisk; ! separates statements on one line; a trailing backslash continues a statement onto the next record. Two further comment forms exist that no other language has felt the need for: *> puts the comment text next to the statement’s selection-identifier number in the diagnostic summary block of the output listing, and *< swallows everything after it including statement separators.
Files as a uniform abstraction
READ and WRITE hide a striking amount of variety behind one syntax. The same two verbs handle sequential data sets, PDS and PDSE members, VSAM KSDS/ESDS/RRDS/LDS, z/OS Unix HFS and ZFS files, Windows and Unix files, stdin/stdout streams, directory listings (DIR and DIRDATA), z/OS system lists (READ LIST="LSG" for SMS storage groups), and database tables via TABLE= or a full SQL= statement. Dynamic allocation via DSN= means mainframe files need no JCL DD statement at all.
Diagnostics as a first-class output
Every run produces a SELCOPY list: the control statements as parsed, each with a selection identifier number, any error messages with an asterisk pointing at the offending token, printed output, and a closing summary block giving per-statement execution counts and per-file record counts. On z/OS and z/VM the listing is written in RECFM=VBA with ASA carriage control. For a language whose programs are often written once and thrown away, this built-in accounting of what actually happened is a large part of the appeal.
Evolution
The 3.x releases show a language still absorbing ideas from outside its own world:
| Release | Notable additions |
|---|---|
| 3.20 (announced October 2013) | CHANGE operation; multiple field specifications on WRITE and MOD; Windows clipboard and keystroke I/O |
| 3.30 (March 2015) | Regular expressions as search strings on IF/AND/OR and CHANGE; variable-length character types on DECLARE; MATCHLEN; CASEI |
| 3.40 (announced November 2017) | Full-screen debugging through the SELCOPYi debug utility; build date in the listing footer; additional SORTDIR orderings |
| 3.50 (GA 24 February 2021) | Native 64-bit build for x86-64 Linux; PTR and MATCHLEN on CHANGE; predefined regex classes :h, :i, :n |
| 3.60 (GA 11 September 2024) | Suite renamed CBL Product Suite; SELCOPYi renamed FileKit |
Regular expressions arriving in a 1971 language in the 2010s, and 64-bit Linux support arriving in 2021, are a good summary of how CBL develops the product. The company says so directly: “SELCOPY development and support on various operating platforms has primarily been, and continues to be, driven by user requests,” and releases are made “only for operating systems on which SELCOPY programs are actively being developed.” SELCOPY for OS/2, the manual notes without ceremony, “is no longer developed.”
Current Relevance
SELCOPY today is a commercial product, not a community one. There is no public repository, no package manager, no Docker image and no free-tier interpreter; the interpreter is licensed, and older builds carry expiry dates that appear in the listing footer. That is why the language is close to invisible in the places programming languages are usually counted, and why it is often listed as dormant.
The vendor’s own record says otherwise. Release 3.60 went generally available on 11 September 2024; the z/OS service package X2025176 was published on 24 June 2025; Release 3.40 reached end of support on 6 October 2025, which is a statement that customers were still running it. CBL’s supported-operating-systems page still lists z/OS, z/VM and z/VSE for the current 3.60 suite, with Linux (Intel) and Windows served by SELCOPY 3.50; AIX and Solaris are listed only at the much older SELCOPY 2.08 level, and iSeries appears in that page’s section heading without a current release level of its own. Knowledge of the language circulated well beyond CBL, too: independent mainframe training providers have offered dedicated one-day SELCOPY courses, and the product is listed in third-party mainframe software directories, though CBL’s own site remains the only authoritative description of it.
Why It Matters
SELCOPY is a case study in how a utility becomes a language, and how long that language can then live.
It began at the same historical moment as the IBM utility programs it competes with - IEBGENER, IEBCOPY, IDCAMS - and took the opposite path. Those utilities stayed utilities: fixed function, parameterised by control cards. SELCOPY kept adding the things its users asked for until the control cards had variables, arithmetic, conditionals, subroutines, labels and an I/O model general enough to reach a DB2 table. What it did not add is equally instructive: no block structure, no modules, no type inference, no attempt to modernise the surface syntax. Backward compatibility with programs written in the 1970s was worth more to its customers than any of that, and CBL’s decision in 2011 to keep both the assembler and the C++ interpreters in the same product rather than force a migration is the clearest possible statement of that priority.
For the history of computing it is also a reminder of how much of the world’s data processing has always been done by languages nobody writes conference papers about. SELCOPY predates C, Prolog and Smalltalk. It is roughly contemporary with Pascal. It has no standards committee, no ISO number and no Wikipedia-scale literature - and it has been continuously developed, sold and serviced by the same company for more than fifty years, which is a claim very few programming languages of any fame can make.
Timeline
Notable Uses & Legacy
Production z/OS batch job steps
The vendor's own documentation lists data modification and verification steps inside production z/OS batch jobs as the primary application of SELCOPY. A SELCOPY step is invoked from JCL like any other utility, with its control statements supplied in SYSIN, and is presented as an alternative to z/OS utilities such as IEBGENER and IEBCOPY
Ad-hoc data repair and troubleshooting
Because a SELCOPY program is interpreted with no compile step, CBL documents "quick, execute once only jobs to trouble shoot and fix data" as a core use case. Update-in-place (the UPD statement, added in release 2.05 in October 1999) lets a record be patched in situ rather than copied through a new file
Scripting glue for CLIST, REXX and shell
SELCOPY is documented as being driven from a CLIST or REXX procedure on the mainframe and from Unix shell scripts, Windows VBScript or batch files elsewhere, to interrogate and reformat data - the role sed, grep and awk play on Unix, but over mainframe record formats
Database and VSAM data movement
READ and WRITE operations accept TABLE and SQL operands, so the same program can move data between flat files and database tables (the mainframe BAL version additionally documents ADABAS and IMS/DL1 processing). VSAM KSDS, ESDS, RRDS and LDS data sets are handled natively; on Windows, VSAM support is provided through Micro Focus file-handling libraries
FileKit (formerly SELCOPY/i)
The interactive, multi-windowed 3270 environment bundled with a SELCOPY licence includes a full-screen SELCOPY debugger that steps through control statements, sets breakpoints and monitors variable values - an unusually modern debugging story for a language of this vintage. It was renamed FileKit in the 3.60 release of September 2024
Third-party mainframe training
SELCOPY has been taught outside the vendor: independent mainframe training providers have offered a one-day "SELCOPY Utility" course aimed at application programmers, systems and operations analysts with at least six months of JCL and TSO/ISPF experience, covering syntax, file types, branching, data conversion and subroutines