Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 2

Advanced Data Manipulation with Files, Strings, and Intrinsic Functions

Recommended resources

Welcome back. In our previous lesson, we conducted a rapid review of COBOL's structure and its DATA DIVISION, re-establishing the foundation of how data is defined. Now, we shift our focus from defining data to actively manipulating it within the PROCEDURE DIVISION.

This lesson addresses three critical areas of COBOL programming that are hallmarks of a senior developer's skill set and frequent topics in technical interviews. We will cover:

  1. Advanced file handling, focusing on robust error checking using the FILE STATUS clause.
  2. Powerful string manipulation with the STRING, UNSTRING, and INSPECT verbs.
  3. The use of intrinsic functions to write cleaner, more modern, and efficient code.

Mastery of these concepts is essential for building resilient batch programs and services that can gracefully handle the imperfect data and unexpected I/O conditions common in production environments.

Building Robust I/O with Advanced File Handling

In any production system, assuming every READ or WRITE operation will succeed is a recipe for failure. A senior developer is expected to write code that anticipates and correctly handles I/O errors. COBOL provides several mechanisms for this, but the most comprehensive is the FILE STATUS clause.

When you declare a file in the FILE-CONTROL paragraph of your ENVIRONMENT DIVISION, you can associate it with a two-byte data item. After every I/O operation on that file, COBOL updates this field with a status code.

Here's an example of the declaration:

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT INPUT-FILE ASSIGN TO INFILE
           FILE STATUS IS WS-INFILE-STATUS.
       ...
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-INFILE-STATUS      PIC XX.
           88 INFILE-OK          VALUE '00'.
           88 INFILE-EOF         VALUE '10'.

The FILE STATUS key is your program's window into the outcome of an I/O request. A value of '00' indicates success. '10' indicates an end-of-file condition on a sequential read. Any other value signals a warning or an error that your program must handle.

IBM's documentation provides a concise overview of the different error handling techniques available in COBOL.

Handling errors in input and output operations - IBM

This document from IBM outlines the primary methods for intercepting and managing I/O errors in COBOL.

Read the initial overview to see the list of available techniques. Then, examine the two flowcharts that illustrate the logical flow after an I/O error for VSAM and QSAM files. These diagrams show how your error-handling logic (like checking the file status key) fits into the overall process.

As the documentation highlights, you have several tools at your disposal:

  • AT END: Used in a READ statement for sequential files. This is the standard way to detect the end of a file and exit a read loop.
  • INVALID KEY: Used with indexed (KSDS) or relative (RRDS) files for operations like READ, WRITE, REWRITE, and DELETE. This phrase is triggered by key-related errors, such as:
    • Attempting to WRITE a record with a key that already exists.
    • Attempting to READ or DELETE a record with a key that does not exist.
    • Sequence errors when loading an indexed file.
  • FILE STATUS checking: This is the most versatile method. By checking the value of your file status variable after each I/O verb, you can diagnose a wide range of issues. For example:
    • '23': Record not found for a KSDS file (often handled by INVALID KEY but also reported here).
    • '35': File not found (a DD statement might be missing in the JCL).
    • '39': A mismatch between the file definition (FD) and the actual file attributes (e.g., wrong RECORD CONTAINS length).
    • '9x': Serious VSAM or system-level errors.

In an interview, being able to discuss specific file status codes and how you would code routines to handle them demonstrates a deep understanding of building resilient applications.


Powerful String Manipulation: STRING, UNSTRING, and INSPECT

Raw data rarely arrives in the exact format you need. COBOL provides three powerful verbs for parsing, concatenating, and transforming string data.

Concatenating with STRING

The STRING verb is used to combine multiple data items into a single destination field. It is far more flexible than simple MOVE statements, allowing you to specify delimiters and stop concatenation based on specific conditions.

A common use case is building a delimited record (like a CSV line) or formatting a line for a report. The WITH POINTER clause is crucial for managing the current position within the destination field, preventing overwrites.

This diagram illustrates the `STRING` verb in action. Several source fields (ID-1, ID-2, ID-4, ID-5) are concatenated into a single target field (ID-7). A delimiter (ID-3, an asterisk) is placed between each field. The pointer (ID-8), which tracks the next available position in the target, starts at 1 and ends at 16 after the operation.

Parsing with UNSTRING

The UNSTRING verb is the inverse of STRING. It deconstructs a single string into multiple destination fields based on one or more delimiters. This is invaluable for parsing data from external sources, such as comma-separated values or space-delimited fields.

UNSTRING offers fine-grained control with clauses like:

  • DELIMITED BY: Specifies the character(s) that separate the fields.
  • INTO: The list of receiving fields.
  • COUNT IN: Stores the number of characters moved into a receiving field.
  • TALLYING IN: Stores the total number of receiving fields that were populated.
This diagram shows the `UNSTRING` verb parsing a source string (`ID-SEND`). It uses asterisks and question marks as delimiters (`DEL-ID`). The data is distributed into four receiving fields (ID-R1 to ID-R4). The diagram also shows fields that capture the delimiter found (ID-D1, ID-D2, ID-D3) and the count of characters moved (ID-C1, ID-C3, ID-C4).

Analyzing with INSPECT

While STRING and UNSTRING move data, INSPECT analyzes data in place. It can be used to count occurrences of specific characters or to replace them.

Common uses for INSPECT include:

  • Data Validation: Using TALLYING to count non-numeric or invalid characters in a field before a calculation.
    INSPECT WS-INPUT-FIELD TALLYING WS-NON-NUMERIC-COUNT
       FOR ALL CHARACTERS BEFORE INITIAL '0'.
    
  • Data Cleansing: Using REPLACING to change leading spaces to zeros or to convert lowercase letters to uppercase.
    INSPECT WS-PRODUCT-CODE REPLACING LEADING ' ' BY '0'.
    
  • Pre-processing for UNSTRING: Counting delimiters in a source string to ensure it has the expected number of fields before attempting to parse it.

These three verbs are the core toolkit for handling the complex data formatting and re-formatting tasks that are ubiquitous in batch processing.


Leveraging Intrinsic Functions

Modern COBOL standards have introduced a rich library of intrinsic functions that can significantly simplify code, improve readability, and reduce the need to write complex, error-prone procedural logic. As a senior developer, you are expected to know and use these functions where appropriate.

Here are a few essential functions grouped by purpose:

Date and Time Functions

  • FUNCTION CURRENT-DATE: Returns a 21-character string containing the system date, time, and timezone offset. You typically move this to a group item to parse its components.
  • FUNCTION DATE-OF-INTEGER(integer-date): Converts an integer date (days since Dec 31, 1600) to YYYYMMDD format.
  • FUNCTION INTEGER-OF-DATE(yyyymmdd-date): The inverse, converting a YYYYMMDD date to an integer for calculations.

String and Character Functions

  • FUNCTION TRIM(source-string): Returns the source string with trailing spaces removed. Extremely useful for cleaning up data.
  • FUNCTION LENGTH(data-item): Returns the length in bytes of a data item. Useful for dynamically handling variable-length fields.
  • FUNCTION UPPER-CASE(string) and FUNCTION LOWER-CASE(string): Convert a string's case, which is useful for case-insensitive comparisons.

Numeric and Conversion Functions

  • FUNCTION NUMVAL(string): Converts an alphanumeric string containing a number into a numeric value. It handles leading/trailing signs and spaces.
  • FUNCTION NUMVAL-C(string): Similar to NUMVAL, but also handles currency symbols, commas, and decimal points. Indispensable when working with formatted report data.
    MOVE FUNCTION NUMVAL-C("$1,234.56CR") TO WS-AMOUNT.
    *> WS-AMOUNT would now hold -1234.56
    
  • FUNCTION SQRT(number): Calculates the square root.

Using these functions not only makes your code more concise but also signals that your knowledge of COBOL is current.


Conclusion

In this lesson, we have moved beyond data definition to data manipulation, a critical step in building functional and robust programs. You should now be comfortable with:

  • Robust I/O Handling: The central role of the FILE STATUS clause in trapping and diagnosing file errors, supplemented by AT END and INVALID KEY for specific conditions.
  • String Manipulation Verbs: The distinct purposes of STRING (to build), UNSTRING (to parse), and INSPECT (to analyze and transform) strings.
  • Intrinsic Functions: How to use key built-in functions to simplify common tasks related to dates, strings, and numeric conversions, leading to more modern and maintainable code.

These skills form the core of procedural logic in COBOL. In our next lesson, we will build upon this by exploring how to structure that logic into reusable modules. We will dive into advanced subprogram patterns, analyzing the trade-offs between static and dynamic CALL statements and the different methods of passing data between programs.