An open API service indexing awesome lists of open source software.

https://github.com/lsyueh/get-the-picture

為現代 .NET 應用程式提供 COBOL Copybook 支援
https://github.com/lsyueh/get-the-picture

cobol cobol-conversion cobol-copybook cobol-pic csharp csharp-library data-exchange data-export deserialization endian endianness endianswap isam parser serialization

Last synced: 4 months ago
JSON representation

為現代 .NET 應用程式提供 COBOL Copybook 支援

Awesome Lists containing this project

README

          

# Get The Picture

[![CI](https://github.com/LsYueh/Get-The-Picture/actions/workflows/dotnet.yml/badge.svg?branch=main)](https://github.com/LsYueh/Get-The-Picture/actions/workflows/dotnet.yml)
[![License](https://img.shields.io/github/license/LsYueh/Get-The-Picture)](/LICENSE)
[![.NET SDK 8.0](https://img.shields.io/badge/.NET-8.0-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
[![GitHub release](https://img.shields.io/github/v/release/LsYueh/Get-The-Picture)](https://github.com/LsYueh/Get-The-Picture/releases)

Modern .NET library for working with COBOL Copybook–based data
用於處理以 COBOL Copybook 為基礎資料的現代 .NET 類別庫

> **讀懂你 COBOL 的明白**

## 開發需求
- **.NET 8.0** 或更新版本
- **C# 12** 或相容版本(.NET 8 預設)

## 輸入格式需求
- COBOL Copybook (`.cpy`) 純文字檔案
- ASCII / CP950 編碼



# 專案目的
> 透過簡單的文字 `X` 與數字 `9 / S9`,我們建構出長達百年的金融體系。


TL;DR

COBOL 的 `PICTURE` 子句,以極少的符號,精確地描述出資料的**型態、長度、符號位、顯示格式與儲存語意**。
這套設計方式歷經數十年的實務驗證,支撐了銀行、保險、政府與大型企業的核心系統,至今仍在持續運作。


然而,在現代語言(例如C#、Java、TypeScript、Rust)中,這些語意往往被**隱含、分散或遺失**:

* `string` 與 `number` 無法完整表達 **定長、補零、符號位置、顯示與儲存差異**
* 解析邏輯常以 ad-hoc 的 `TryParse`、正則或硬編碼規則存在
* PIC 與現代型別之間缺乏**可驗證、可測試、可組合**的轉換模型


本專案的目的,是將 `COBOL PICTURE` 子句視為一種 **明確的資料規格(Data Specification)**,並:

### 將 PIC 語意轉換為可映射的現代資料模型

* 明確區分 **顯示格式(DISPLAY)** 與 **實際數值語意**
* 將 `9 / S9 / V / X / A` 等元素拆解為結構化資訊
* 建立可對應至現代語言型別(`int / long / decimal / string` 等)的判斷依據

### 建立可組合、可擴充的 Decode / Encode 流程

* 以 **Fluent / Builder 風格**描述解析上下文
* 將「字串 → 型別」與「型別 → 字串」視為對等的一階公民
* 讓轉換過程可被單元測試、驗證與重構

### 降低 COBOL 與現代系統整合的心智與實作成本

* 避免重複撰寫易出錯的解析邏輯
* 提供一致、可預期的行為邊界(精度、符號)
* 作為資料轉換、系統汰換、或雙軌運行的一部分

### 保留歷史系統的「語意」,而不只是資料

⚠️ 本專案不試圖「現代化」COBOL語言,而是**尊重並保存其資料設計哲學**,使其能被現代語言理解、驗證與安全地使用。


## 適用情境

* 核心系統資料轉出
* COBOL 與現代服務的資料交換層
* 舊系統重構或漸進式汰換
* 對 PIC 規格進行靜態分析或測試驗證



# COBOL Copybook
`Copybook` 是 COBOL 中用來定義資料結構的重用檔案,透過 COPY 指令引入,常用於描述檔案格式、資料欄位配置與記憶體布局。在大型主機與金融系統中,Copybook 是資料交換與系統整合的核心。

Copybook 通常包含:
- 欄位階層(Level Number)
- 資料型別與長度(PIC 子句)
- 儲存格式(如 DISPLAY、COMP、COMP-3)

由於 Copybook 直接對應到位元與位元組配置,它不僅是程式碼的一部分,更是系統間共用的資料規格說明書。


## Copybook Wrapper

Copybook Wrapper 是一個 Raw Buffer 層級的存取工具。提供**欄位級別抽象存取**,不需要傳統的 DTO(`Data Transfer Object`,資料傳輸物件)或序列化/反序列化過程。

![work flow](docs/get-the-picture/wrapper-work-flow.png)

Wrapper vs Serialization(序列化)

| 功能 | Wrapper | Serialization |
| ---------- | ------------------------------- | --------------- |
| Raw ↔ 物件 | 不需要 DTO,直接欄位級存取 | Yes, 一次性 DTO |
| 欄位抽象化 | Yes,靠 `CbAddress` + indexer/屬性 | No / 需要 mapping |
| Memory 複製 | 幾乎零複製,Span 直接操作 Raw | 全部複製 |
| 動態欄位讀寫 | 內建 indexer 或強型別屬性 | 一般不方便 |
| 物件圖 / 狀態管理 | No,Raw 是唯一來源 | Yes |


### 使用方式
資料物件需**繼承**核心物件 `CbWrapper`,根據 Copybook 定義,透過 `CbAddress` 設定每個欄位的起始位置、長度及格式。
- 可透過 indexer 或 **強型別屬性**存取欄位
- 支援即時驗證 Raw Buffer 長度是否符合欄位配置


程式碼範例:櫃買中心 T30 漲跌幅度資料

```csharp
const string s = "11011 00106600000096950000087300020251219000000 0台泥一永 000000000000000000000 0 ";

byte[] raw = cp950.GetBytes(s);

var T30 = new T30_t(raw);

Console.WriteLine(T30.StockNo); // "11011"
Console.WriteLine(T30.StockName); // "台泥一永"
Console.WriteLine(T30.LastMthDate); // "2025-12-19"
```


T30_t

```csharp
public class T30_t(byte[] raw) : CbWrapper(raw)
{
// ----------------------------
// Copybook Address Map
// ----------------------------

protected override Dictionary AddressMap { get; } = new Dictionary
{
["STOCK-NO"] = new CbAddress( 1, 6, "X(6)"),
["BULL-PRICE"] = new CbAddress( 7, 9, "9(5)V9(4)"),
["LDC-PRICE"] = new CbAddress(16, 9, "9(5)V9(4)"),
["BEAR-PRICE"] = new CbAddress(25, 9, "9(5)V9(4)"),
["LAST-MTH-DATE"] = new CbAddress(34, 8, "9(8)", PicSemantic.GregorianDate), // 用語意方式轉換
["SETTYPE"] = new CbAddress(42, 1, "X(01)"),
["MARK-W"] = new CbAddress(43, 1, "X(01)"),
["MARK-P"] = new CbAddress(44, 1, "X(01)"),
["MARK-L"] = new CbAddress(45, 1, "X(01)"),
["IND-CODE"] = new CbAddress(46, 2, "X(02)"),
["IND-SUB-CODE"] = new CbAddress(48, 2, "X(02)"),
["MARK-M"] = new CbAddress(50, 1, "X(01)"),
["STOCK-NAME"] = new CbAddress(51,16, "X(16)"),
// MARK-W
["MATCH-INTERVAL"] = new CbAddress(67, 3, "9(03)"),
["ORDER-LIMIT"] = new CbAddress(70, 6, "9(06)"),
["ORDERS-LIMIT"] = new CbAddress(76, 6, "9(06)"),
["PREPAY-RATE"] = new CbAddress(82, 3, "9(03)"),
["MARK-S"] = new CbAddress(85, 1, "X(01)"),
["STK-MARK"] = new CbAddress(86, 1, "X(01)"),
["MARK-F"] = new CbAddress(87, 1, "X(01)"),
["MARK-DAY-TRADE"]= new CbAddress(88, 1, "X(01)"),
["STK-CTGCD"] = new CbAddress(89, 1, "X(01)"),
["FILLER"] = new CbAddress(90,11, "X(11)"),
};

// ----------------------------
// 強型別屬性
// ----------------------------

public string StockNo
{
get => this["STOCK-NO"].Get();
set => this["STOCK-NO"].Set(value);
}

public decimal BullPrice
{
get => this["BULL-PRICE"].Get();
set => this["BULL-PRICE"].Set(value);
}

public decimal LdcPrice
{
get => this["LDC-PRICE"].Get();
set => this["LDC-PRICE"].Set(value);
}

public decimal BearPrice
{
get => this["BEAR-PRICE"].Get();
set => this["BEAR-PRICE"].Set(value);
}

public DateOnly LastMthDate
{
get => this["LAST-MTH-DATE"].Get();
set => this["LAST-MTH-DATE"].Set(value);
}

// (略...)
}
```


📖 更多關於 [Copybook Compiler](docs/get-the-picture/copybook/compiler.md) ...
📖 更多關於 [Copybook Resolver](docs/get-the-picture/copybook/resolver.md) ...
📖 更多關於 Sub-Class Generator : [Forge](docs/forge/forge.md) ...



# COBOL Coding Sheet (Reference Format)

![punched card](/docs/source/punched-card.webp)

COBOL 程式有一套固定的欄位規則,尤其在 `固定格式(Fixed Format)` 下很重要。主要分為 `Sequence Area`, `Indicator Area`, `Area A`, `Area B` 等區域。


```cobol
|...+.*..1....+....2....+....3....+....4....+....5....+....6....+....7..
01 ORDER-RECORD.
05 ORDER-ID PIC 9(6).
05 ORDER-DATE PIC 9(8).
05 ORDER-AMOUNT PIC S9(7)V99 COMP-3.
```


| 位置 (Column) | 說明 |
| ----------- | ------------------------------------------------------------------ |
| 1–6 | **Sequence Number**(序號欄,可選):用於列印或版本控制。 |
| 7 | **Indicator Area**(指示欄):
- `*`:註解
- `/`:換頁
- `-`:延續上一行 |
| 8–11 | **Area A**:段落名稱、Section 名稱、DIVISION 關鍵字等。 |
| 12–72 | **Area B**:語句、指令、變數宣告、程式碼本體。 |
| 73–80 | **Identification Area**(識別欄,可選):通常用於序號或其他控制用途。 |

> 現代 COBOL `(Free Format) ` 已經不限制欄位,但固定格式仍常用於舊系統。


ℹ️ "Elementary Data Item" and "Group Item"

| 面向 | Elementary Data Item | Group Item |
| --------------------- | ----------------------- | ---------------------- |
| 定義角色 | **最小資料單位(leaf)** | **結構性容器(composite)** |
| 是否可包含子項目 | ❌ 不可 | ✅ 可 |
| 是否有 `PIC` 子句 | ✅ **必須有** | ❌ **不可有** |
| 是否直接描述資料型態 | ✅ 是(數值、字元、COMP、COMP-3…) | ❌ 否(由子項目間接決定) |
| 是否可直接被 MOVE / COMPUTE | ✅ 可 | ⚠️ 可(視情況,為整段記憶體移動) |
| 記憶體佔用 | 由 `PIC` 決定 | 為所有子項目記憶體的總和 |
| 可否有 `OCCURS` | ✅ 可 | ✅ 可 |
| 可否有 `REDEFINES` | ✅ 可 | ✅ 可 |
| 可否有 `VALUE` | ✅ 可 | ❌(標準上 group 不定義 VALUE) |
| 是否為樹的葉節點 | ✅ 是 | ❌ 否 |
| COBOL 規格名稱 | *Elementary data item* | *Group item* |


📖 更多關於 [Elementary Data Item](docs/get-the-picture/cobol/ElementaryDataItem.md) ...



# COBOL DATA DIVISION (Data description entry)

用於描述程式中所有資料的結構、型態與儲存方式。

**Format 1**
```

[REDEFINES ]
[PICTURE ]
[USAGE ]
[OCCURS TIMES]
[VALUE ].
```


**Format 2**
```
66 RENAMES THRU .
```


**Format 3**
```
88 VALUE [THRU ].
```


## 📋 Format 支援狀態

| Format | 語法用途 | 支援狀態 | 說明 |
| -------- | ------------------------------- | ----- | --------------------------------------------- |
| Format 1 | 一般資料項目(Group / Elementary Item) | ✅ 支援 | 用於描述資料結構、型別、PIC、USAGE、OCCURS 等,是目前解析與生成的核心格式。 |
| Format 2 | `66 RENAMES` | ⚠️ 有限支援 | 屬於語意別名(Alias)的定義,不影響實際的資料儲存結構;相關別名可由 Wrapper 於應用層自行進行二次定義。 |
| Format 3 | `88 LEVEL` 條件名稱 | ❌ 未支援 | 為條件常數定義(Condition Name),本身不佔用任何實體儲存空間。
當與 OCCURS 子句混合使用時,條件判斷的呼叫與對應關係在實作上較為複雜,易影響可讀性與使用一致性,建議直接呼叫 Wrapper 內的屬性來處理。 |



# Level Numbers

COBOL 使用 `Level Number`(層級號) 來描述資料結構,主要有:

| Level | 用途 | 說明 |
| ----------- | -------------- | ------------------- |
| **01** | 主結構 | 定義檔案或記錄的頂層結構 |
| **02 … 49** | 子結構 | 01 之下的子群組或欄位,形成巢狀結構 |
| **66** | RENAMES | 將已有欄位重新命名或形成別名區段 |
| **77** | 單一變數 | 不屬於群組,獨立使用 |
| **88** | Condition Name | 定義邏輯條件(True/False) |

> ⚠️ Level number 越小層級越高,01 是最外層。

📖 更多關於特殊層級 ...

Level 66 — [RENAMES](docs/get-the-picture/cobol-level-numbers/lv66.md)
Level 77 — [Standalone Variable (單一變數)](docs/get-the-picture/cobol-level-numbers/lv77.md)
Level 88 — [Condition Name](docs/get-the-picture/cobol-level-numbers/lv88.md)



# REDEFINES 子句

## 與 `66 RENAMES` 的差異
| | RENAMES | REDEFINES |
| ---------- | --------------- | --------------- |
| 影響 storage | ❌ | ✅ |
| 改變 offset | ❌ | ✅(對齊另一個) |
| 本體是 | 邏輯群組 | **GroupItem** |
| 最終表現 | View / Property | View / Property |


## 支援說明

在 IBM 提供的 [REDEFINES clause](https://www.ibm.com/docs/en/cobol-linux-x86/1.2.0?topic=entry-redefines-clause) 文件中,整理出幾種 `REDEFINES` 可能的使用與法規則:

CASE 1:Group REDEFINES Elementary Data Item

```cobol
05 A PICTURE X(6).
05 B REDEFINES A.
10 B-1 PICTURE X(2).
10 B-2 PICTURE 9(4).
05 C PICTURE 99V99.

```

CASE 2:01-level + GLOBAL

```cobol
01 A1 PICTURE X(6).
01 B1 REDEFINES A1 GLOBAL PICTURE X(4).
```

CASE 3:多個 REDEFINES 指向同一 target

```cobol
05 A PICTURE 9999.
05 B REDEFINES A PICTURE 9V999.
05 C REDEFINES A PICTURE 99V99.
```

CASE 4:REDEFINES 鏈

```cobol
05 A PICTURE 9999.
05 B REDEFINES A PICTURE 9V999.
05 C REDEFINES B PICTURE 99V99.
```

### 📋 支援狀態總覽

| Case | 用法說明 | 支援狀態 | 說明 |
|------|----------|----------|------|
| CASE 1 | Group REDEFINES Elementary Data Item | ✅ 支援 | 最常見且結構單純的用法。Group 僅作為 Elementary Item 的另一種結構化視角,不引入額外 storage。 |
| CASE 2 | 01-level REDEFINES + GLOBAL | ❌ 不支援 | 涉及 01-level overlay 與 GLOBAL 可視範圍,在高階語言中難以安全對應。 |
| CASE 3 | 多個 REDEFINES 指向同一 target | ⚠️ 有限支援 | 會形成多重 storage alias,容易造成資料覆寫與語意不明確。 |
| CASE 4 | REDEFINES 鏈(REDEFINES 已 REDEFINES 的 item) | ⚠️ 有限支援 | 需解析並正規化多層 alias 關係,實作與維護成本過高。 |


再根據這篇 [Redefined data items and OCCURS clauses](https://www.ibm.com/docs/en/cobol-linux-x86/1.2.0?topic=changes-redefined-data-items-occurs-clauses) 的說明,裡面提到:

> According to Standard `COBOL 2002`, the data item being redefined cannot contain an OCCURS clause.

所以本專案亦不支援過於複雜的 REDEFINES 運作行為。



# PICTURE 子句

![PICTURE clause](docs/get-the-picture/cobol-picture/picture-clause.png)

支援的 ***character-string*** (`Symbols`) 語法

| Alphabetic | Alphanumeric | Numeric | Numeric (With Sign) |
| :--------: | :----------: | :-----: | :-----------------: |
| A..
A(n) | X..
X(n) | 9...
9(n)
9...V9...
9(n)V9(m)
9(n)V9... | S9...
S9(n)
S9...V9...
S9(n)V9(m)
S9(n)V9... |


## 類別(`Category`)資料

- [文字 (`Alphabetic`/`Alphanumeric`)](docs/get-the-picture/cobol-picture/category/alphabetic-alphanumeric.md)
- [數字 (`Numeric`)](docs/get-the-picture/cobol-picture/category/numeric.md)
- [`S9`數字轉換規則](docs/get-the-picture/other-topics/pic-s9-overpunch.md)


## 語意(`Semantic`)資料

- [日期 (`Date`)](docs/get-the-picture/cobol-picture/semantic/date-time/date.md)
- [時間 (`Time`)](docs/get-the-picture/cobol-picture/semantic/date-time/time.md)
- [時間戳記 (`Timestamp`)](docs/get-the-picture/cobol-picture/semantic/date-time/timestamp.md)
- [布林值 (`Boolean`)](/docs/get-the-picture/cobol-picture/semantic/boolean.md)


📖 更多關於 [PICTURE Clause Codec](docs/get-the-picture/cobol-picture/codec.md) ...



# USAGE 子句

![USAGE clause](docs/get-the-picture/usage-clause.png)

`USAGE` 定義欄位在記憶體中的儲存方式,影響資料的物理編碼與運算行為。
- DISPLAY(預設):以可讀**字元**存放,每個數字或字母對應一個 byte,便於輸入輸出與檢視。
- ***COMPUTATIONAL***:用**電腦原生格式**儲存,只用於 `Numeric` 欄位。
- COMP-3(Packed Decimal):將兩個數字壓縮在一個 nibble,最後一個 nibble 用於符號,節省空間且方便算術運算。
- COMP-4(Binary)/ COMP-5(Native Binary):以二進位形式存放,運算效率高 (對 COBOL 而言),但不可直接讀取文字。
- COMP-6(Unsigned Packed Decimal):非標準 COBOL 定義。與 COMP-3 方式一樣,但是沒有 sign nibble。


USAGE 項目的適用範圍:
| Class | Category/Semantic | Usage |
| :---: | :---------------: | ----- |
| Alphabetic | Alphabetic | DISPLAY |
| Alphanumeric | Alphanumeric | DISPLAY |
| Numeric | Numeric | DISPLAY
COMP (Binary)
COMP-3 (Packed Decimal)
COMP-4 (Binary)
COMP-5 (Native Binary)
COMP-6 (Unsigned Packed Decimal) |
| Date-Time | Date
Time
Timestamp | DISPLAY |


📖 更多關於 [COMPUTATIONAL 轉換規則](/docs/get-the-picture/other-topics/cobol-computational.md) ...



# Performance

## 數據內容
- 根據**櫃買中心** (OTC) 規格改寫的 `T30.CPY` (包含註解):DataItem 24 個
- 部分**櫃買中心** (OTC) 的 `T30.DAT`:漲跌幅度資料 55 筆


執行指令:

> dotnet run -c Release --project GetThePicture.Benchmarks\GetThePicture.Benchmarks.csproj --filter *

> dotnet run -c Release --project GetThePicture.Benchmarks\GetThePicture.Benchmarks.csproj --anyCategories {BenchmarkCategory}


## 跑分結果
```bash
BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.7840/25H2/2025Update/HudsonValley2)
Intel Core i5-10400 CPU 2.90GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK 8.0.418
[Host] : .NET 8.0.24 (8.0.24, 8.0.2426.7010), X64 RyuJIT x86-64-v3
DefaultJob : .NET 8.0.24 (8.0.24, 8.0.2426.7010), X64 RyuJIT x86-64-v3
```

> 1 µs = 1000 ns


### Wrapper

| Method | Mean | Error | StdDev |
|---------------------- |---------:|----------:|----------:|
| Wrapper_Read_String | 4.362 μs | 0.0176 μs | 0.0156 μs |
| Wrapper_Write_String | 4.267 μs | 0.0222 μs | 0.0186 μs |
| Wrapper_Read_Integer | 4.511 μs | 0.0249 μs | 0.0233 μs |
| Wrapper_Write_Integer | 5.450 μs | 0.0198 μs | 0.0165 μs |
| Wrapper_Read_Decimal | 5.895 μs | 0.0376 μs | 0.0333 μs |
| Wrapper_Write_Decimal | 9.589 μs | 0.0614 μs | 0.0574 μs |

> ⚠️ T30 的資料內沒有進行 `COMP`,目前的 Wrapper 跑分算是 Best Case。
> ⚠️ Wrapper 只做**單筆欄位**讀取。


### DISPLAY

Integer: `PIC 9(18)` / `PIC S9(18)`
Decimal: `PIC S9(5)V9(2)`

| Method | Mean | Error | StdDev |
|----------------------------- |----------:|---------:|---------:|
| Display_Read_Integer | 79.69 ns | 0.447 ns | 0.418 ns |
| Display_Write_Integer | 113.33 ns | 0.418 ns | 0.370 ns |
| Display_Read_Signed_Integer | 98.95 ns | 0.496 ns | 0.464 ns |
| Display_Write_Signed_Integer | 183.39 ns | 0.948 ns | 0.840 ns |
| Display_Read_Decimal | 97.51 ns | 0.309 ns | 0.274 ns |
| Display_Write_Decimal | 206.42 ns | 0.992 ns | 0.928 ns |


### COMP-3

Integer: `PIC 9(18)` / `PIC S9(18)`
Decimal: `PIC S9(5)V9(2)`

| Method | Mean | Error | StdDev |
|--------------------------- |----------:|---------:|---------:|
| Comp3_Read_Integer | 87.85 ns | 0.218 ns | 0.182 ns |
| Comp3_Write_Integer | 88.29 ns | 0.446 ns | 0.372 ns |
| Comp3_Read_Signed_Integer | 84.39 ns | 0.440 ns | 0.412 ns |
| Comp3_Write_Signed_Integer | 91.66 ns | 0.343 ns | 0.304 ns |
| Comp3_Read_Decimal | 96.58 ns | 0.642 ns | 0.601 ns |
| Comp3_Write_Decimal | 151.53 ns | 1.131 ns | 1.058 ns |


### COMP-4 (BE)

Integer: `PIC 9(18)` / `PIC S9(18)`

| Method | Mean | Error | StdDev |
|--------------------------- |----------:|---------:|---------:|
| Comp4_Read_Integer | 41.56 ns | 0.201 ns | 0.178 ns |
| Comp4_Write_Integer | 129.20 ns | 0.395 ns | 0.330 ns |
| Comp4_Read_Signed_Integer | 42.06 ns | 0.154 ns | 0.129 ns |
| Comp4_Write_Signed_Integer | 132.84 ns | 0.555 ns | 0.463 ns |


### COMP-5

Integer: `PIC S9(18)`

| Method | Mean | Error | StdDev |
|----------------------- |----------:|---------:|---------:|
| Comp5_Read_Integer_BE | 40.91 ns | 0.223 ns | 0.209 ns |
| Comp5_Write_Integer_BE | 132.44 ns | 0.655 ns | 0.580 ns |
| Comp5_Read_Integer_LE | 40.76 ns | 0.253 ns | 0.224 ns |
| Comp5_Write_Integer_LE | 132.85 ns | 0.747 ns | 0.663 ns |


### COMP-6

Integer: `PIC 9(18)`

| Method | Mean | Error | StdDev |
|-------------------- |---------:|---------:|---------:|
| Comp6_Read_Integer | 84.26 ns | 0.365 ns | 0.323 ns |
| Comp6_Write_Integer | 92.26 ns | 0.246 ns | 0.192 ns |



# 參考

Rocket Software ACUCOBOL-GT extend (V10.5.0) : [USAGE Clause](https://docs.rocketsoftware.com/bundle/acucobolgt_dg_1050_html/page/BKRFRFDATAS043.html)
IBM Enterprise COBOL for z/OS (6.5.0) : [USAGE clause](https://www.ibm.com/docs/en/cobol-zos/6.5.0?topic=entry-usage-clause)
IBM Enterprise COBOL for z/OS (6.5.0) : [RECORD KEY clause](https://www.ibm.com/docs/en/cobol-zos/6.5.0?topic=section-record-key-clause)
IBM COBOL for Linux on x86 (1.2.0) : [Classes and categories of data](https://www.ibm.com/docs/en/cobol-linux-x86/1.2.0?topic=relationships-classes-categories-data)