Progress0 of 0 lessons

ISPF Library Services and Shared Lists: Managing ISPF Libraries

ISPF Library services provide programmatic access to ISPF libraries, enabling programs to initialize library access, open libraries, list members, search for members, and manage library resources. Shared lists allow multiple programs to share library member information, improving efficiency and enabling coordination. Understanding Library services and shared lists is essential for building ISPF applications that work with panel libraries, message libraries, and other ISPF library types. This tutorial covers Library service functions, library access patterns, member enumeration, shared list operations, and best practices.

Library services extend REXX and other programming languages with the ability to work with ISPF libraries programmatically. Whether you need to enumerate panel library members, search for specific messages, or coordinate library access between multiple programs, Library services provide the necessary functions. Learning to use Library services and shared lists enables you to build sophisticated ISPF applications. This tutorial provides comprehensive guidance for using Library services effectively.

Understanding ISPF Libraries

ISPF libraries are partitioned datasets (PDS or PDSE) that contain ISPF components.

What are ISPF Libraries?

ISPF libraries:

  • Contain ISPF components (panels, messages, skeletons, etc.)
  • Are typically PDS or PDSE datasets
  • Organize components by member name
  • Can be concatenated for searching
  • Are accessed through Library services

Types of ISPF Libraries

Common ISPF library types:

  • Panel libraries - contain ISPF panels
  • Message libraries - contain ISPF messages
  • Skeleton libraries - contain skeleton templates
  • Table libraries - contain ISPF tables
  • Application libraries - contain application-specific components

Library Concatenation

Libraries can be concatenated:

  • Multiple libraries searched in order
  • First match is used
  • Enables library hierarchy
  • User libraries searched before system libraries

Library concatenation allows you to override system components with user-specific versions.

Library Service Functions

Library services provide functions for library management.

LMINIT - Initialize Library Access

LMINIT initializes access to a library:

  • Sets up library connection
  • Returns dataset ID for operations
  • Required before other library operations
  • Does not open library for access

Example:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*REXX*/ parse arg libname address ispexec /* Initialize library access */ 'LMINIT DATASETID(id) DATASET('"'"libname"'"')' if rc <> 0 then do say 'Error initializing library:' libname say 'Return code:' rc exit 8 end say 'Library initialized, ID:' id /* Use library */ 'LMFREE DATASETID(id)' exit 0

This example:

  • Initializes access to specified library
  • Receives dataset ID in variable id
  • Checks return code for errors
  • Frees resources when done

LMINIT Parameters

LMINIT parameters:

  • DATASETID(id) - variable to receive library ID (required)
  • DATASET(dsn) - library dataset name (required)
  • OPTION(options) - initialization options (optional)

The DATASETID parameter receives a unique identifier used for subsequent library operations.

LMOPEN - Open Library

LMOPEN opens a library for access:

  • Opens library after LMINIT
  • Prepares library for member operations
  • Required for LMMLIST and member access
  • Can specify open mode

Example:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*REXX*/ parse arg libname address ispexec /* Initialize */ 'LMINIT DATASETID(id) DATASET('"'"libname"'"')' if rc <> 0 then exit 8 /* Open for input */ 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc <> 0 then do say 'Error opening library' 'LMFREE DATASETID(id)' exit 8 end /* Library is now open for operations */ 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0

LMOPEN must be called after LMINIT and before member operations.

LMOPEN Options

LMOPEN open modes:

  • INPUT - read-only access
  • OUTPUT - write access
  • UPDATE - read/write access

Choose the appropriate mode based on your operations - use INPUT for read-only operations to prevent accidental modifications.

LMMLIST - List Library Members

LMMLIST lists library members:

  • Enumerates library members
  • Returns member names and information
  • Can filter by name pattern
  • Continues until all members processed

Example:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*REXX*/ parse arg libname address ispexec /* Initialize and open */ 'LMINIT DATASETID(id) DATASET('"'"libname"'"')' if rc <> 0 then exit 8 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc <> 0 then do 'LMFREE DATASETID(id)' exit 8 end /* List all members */ member_count = 0 do forever 'LMMLIST DATASETID(id) MEMBER(member) STATS(YES)' if rc <> 0 then leave member_count = member_count + 1 say 'Member:' member end say 'Total members:' member_count /* Cleanup */ 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0

This example:

  • Opens library for input
  • Loops through all members
  • Displays each member name
  • Counts total members
  • Cleans up resources

LMMLIST with Filtering

LMMLIST can filter members by name pattern:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*REXX*/ parse arg libname pattern address ispexec 'LMINIT DATASETID(id) DATASET('"'"libname"'"')' if rc <> 0 then exit 8 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc <> 0 then do 'LMFREE DATASETID(id)' exit 8 end /* List members matching pattern */ do forever 'LMMLIST DATASETID(id) MEMBER(member) PATTERN('"'"pattern"'"')' if rc <> 0 then leave say 'Found member:' member end 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0

Pattern matching allows you to find specific members, such as all panels starting with "MY" or all messages ending with "ERR".

LMMFIND - Find Library Member

LMMFIND searches for a specific member:

  • Searches for member by name
  • Returns whether member exists
  • Faster than LMMLIST for single member
  • Useful for existence checks

Example:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*REXX*/ parse arg libname membername address ispexec 'LMINIT DATASETID(id) DATASET('"'"libname"'"')' if rc <> 0 then exit 8 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc <> 0 then do 'LMFREE DATASETID(id)' exit 8 end /* Search for member */ 'LMMFIND DATASETID(id) MEMBER('"'"membername"'"')' if rc = 0 then do say 'Member' membername 'found' end else do say 'Member' membername 'not found' end 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0

LMMFIND is more efficient than LMMLIST when you only need to check if a specific member exists.

LMCLOSE - Close Library

LMCLOSE closes an open library:

  • Closes library opened with LMOPEN
  • Releases library resources
  • Required before LMFREE
  • Should be called when done with library

Example:

text
1
2
3
4
5
6
7
8
/*REXX*/ address ispexec 'LMINIT DATASETID(id) DATASET(MY.LIBRARY)' 'LMOPEN DATASETID(id) OPTION(INPUT)' /* Use library */ 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0

Always close libraries before freeing them to ensure proper cleanup.

LMFREE - Free Library Resources

LMFREE frees library resources:

  • Frees resources allocated by LMINIT
  • Releases library connection
  • Required for cleanup
  • Prevents resource leaks

Example:

text
1
2
3
4
5
6
7
/*REXX*/ address ispexec 'LMINIT DATASETID(id) DATASET(MY.LIBRARY)' if rc <> 0 then exit 8 /* Use library */ 'LMFREE DATASETID(id)' exit 0

Always call LMFREE to free resources, even if errors occur.

Library Access Patterns

Common patterns for library access.

Basic Library Access Pattern

Standard pattern for library operations:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*REXX*/ address ispexec /* 1. Initialize */ 'LMINIT DATASETID(id) DATASET(libname)' if rc <> 0 then exit 8 /* 2. Open */ 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc <> 0 then do 'LMFREE DATASETID(id)' exit 8 end /* 3. Use library */ /* ... library operations ... */ /* 4. Close */ 'LMCLOSE DATASETID(id)' /* 5. Free */ 'LMFREE DATASETID(id)' exit 0

This pattern ensures proper resource management and cleanup.

Error Handling Pattern

Pattern with comprehensive error handling:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*REXX*/ address ispexec 'CONTROL ERRORS RETURN' lib_id = '' /* Initialize */ 'LMINIT DATASETID(lib_id) DATASET(libname)' if rc <> 0 then do say 'LMINIT failed, RC=' rc exit 8 end /* Open */ 'LMOPEN DATASETID(lib_id) OPTION(INPUT)' if rc <> 0 then do say 'LMOPEN failed, RC=' rc 'LMFREE DATASETID(lib_id)' exit 8 end /* Use library */ signal on error /* ... library operations ... */ signal off error /* Cleanup */ 'LMCLOSE DATASETID(lib_id)' 'LMFREE DATASETID(lib_id)' exit 0 error: say 'Error during library operations' if lib_id <> '' then do 'LMCLOSE DATASETID(lib_id)' 'LMFREE DATASETID(lib_id)' end exit 8

This pattern ensures cleanup even if errors occur during operations.

Multiple Library Pattern

Working with multiple libraries:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*REXX*/ address ispexec /* Initialize multiple libraries */ 'LMINIT DATASETID(id1) DATASET(LIB1)' if rc <> 0 then exit 8 'LMINIT DATASETID(id2) DATASET(LIB2)' if rc <> 0 then do 'LMFREE DATASETID(id1)' exit 8 end /* Open both */ 'LMOPEN DATASETID(id1) OPTION(INPUT)' 'LMOPEN DATASETID(id2) OPTION(INPUT)' /* Use libraries */ /* Cleanup */ 'LMCLOSE DATASETID(id1)' 'LMCLOSE DATASETID(id2)' 'LMFREE DATASETID(id1)' 'LMFREE DATASETID(id2)' exit 0

Each library requires its own initialization, opening, and cleanup sequence.

Shared Lists

Shared lists enable multiple programs to share library member information.

What are Shared Lists?

Shared lists:

  • Contain library member information
  • Can be shared between programs
  • Enable coordination between applications
  • Improve efficiency by avoiding duplicate work
  • Are identified by names

Creating Shared Lists

Shared lists are created through library operations:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*REXX*/ address ispexec /* Initialize library */ 'LMINIT DATASETID(id) DATASET(MY.LIBRARY)' if rc <> 0 then exit 8 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc <> 0 then do 'LMFREE DATASETID(id)' exit 8 end /* Build shared list */ list_name = 'MYLIST' do forever 'LMMLIST DATASETID(id) MEMBER(member) STATS(YES)' if rc <> 0 then leave /* Add to shared list */ 'LMMADD LIST('"'"list_name"'"') MEMBER('"'"member"'"')' end 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0

This creates a shared list containing all library members that can be accessed by other programs.

Accessing Shared Lists

Other programs can access shared lists:

text
1
2
3
4
5
6
7
8
9
10
/*REXX*/ address ispexec list_name = 'MYLIST' /* Access shared list */ do forever 'LMMFIND LIST('"'"list_name"'"') MEMBER(member)' if rc <> 0 then leave say 'Member from shared list:' member end exit 0

Shared lists allow programs to coordinate without each building the list separately.

Shared List Coordination

Shared lists enable coordination:

  • One program builds the list
  • Other programs access the list
  • Reduces duplicate processing
  • Enables synchronized operations

This is useful when multiple programs need to work with the same set of library members.

Practical Examples

Real-world examples of Library services usage.

Enumerate Panel Library

List all panels in a panel library:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*REXX*/ parse arg panellib address ispexec 'LMINIT DATASETID(id) DATASET('"'"panellib"'"')' if rc <> 0 then exit 8 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc <> 0 then do 'LMFREE DATASETID(id)' exit 8 end say 'Panels in' panellib':' panel_count = 0 do forever 'LMMLIST DATASETID(id) MEMBER(panel) STATS(YES)' if rc <> 0 then leave panel_count = panel_count + 1 say panel_count'.' panel end say 'Total panels:' panel_count 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0

This script enumerates all panels in a panel library, useful for documentation or analysis.

Search for Panel

Search for a specific panel across multiple libraries:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*REXX*/ parse arg panelname address ispexec /* Search in user library */ 'LMINIT DATASETID(id) DATASET(USER.PANELS)' if rc = 0 then do 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc = 0 then do 'LMMFIND DATASETID(id) MEMBER('"'"panelname"'"')' if rc = 0 then do say 'Panel found in USER.PANELS' 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0 end 'LMCLOSE DATASETID(id)' end 'LMFREE DATASETID(id)' end /* Search in system library */ 'LMINIT DATASETID(id) DATASET(SYS1.ISPPLIB)' if rc = 0 then do 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc = 0 then do 'LMMFIND DATASETID(id) MEMBER('"'"panelname"'"')' if rc = 0 then do say 'Panel found in SYS1.ISPPLIB' 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0 end 'LMCLOSE DATASETID(id)' end 'LMFREE DATASETID(id)' end say 'Panel' panelname 'not found' exit 8

This searches for a panel in multiple libraries, simulating library concatenation behavior.

Build Member List with Filtering

Build a list of members matching a pattern:

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*REXX*/ parse arg libname pattern address ispexec 'LMINIT DATASETID(id) DATASET('"'"libname"'"')' if rc <> 0 then exit 8 'LMOPEN DATASETID(id) OPTION(INPUT)' if rc <> 0 then do 'LMFREE DATASETID(id)' exit 8 end /* Build list */ member_list = '' do forever 'LMMLIST DATASETID(id) MEMBER(member) PATTERN('"'"pattern"'"')' if rc <> 0 then leave if member_list = '' then member_list = member else member_list = member_list member end say 'Matching members:' member_list 'LMCLOSE DATASETID(id)' 'LMFREE DATASETID(id)' exit 0

This builds a space-separated list of members matching a pattern, useful for further processing.

Best Practices

Follow these best practices when using Library services:

  • Always check return codes - handle errors appropriately
  • Use proper cleanup sequence - LMCLOSE before LMFREE
  • Handle errors gracefully - free resources on errors
  • Use appropriate open mode - INPUT for read-only
  • Filter when possible - use patterns to reduce processing
  • Validate library names - check existence before operations
  • Document library usage - explain library dependencies
  • Use shared lists efficiently - avoid duplicate list building

Common Mistakes

Avoid these common mistakes:

  • Forgetting LMFREE - causes resource leaks
  • Not checking return codes - missing errors
  • Wrong open mode - using OUTPUT for read operations
  • Not closing before freeing - improper cleanup sequence
  • Infinite loops - not handling LMMLIST end condition
  • Assuming library exists - not validating library name
  • Not freeing on errors - resource leaks on failures

Explain It Like I'm Five

Imagine ISPF Library services like a library card system:

  • LMINIT - Getting your library card (registering to use the library)
  • LMOPEN - Opening the library door (starting to use the library)
  • LMMLIST - Looking at the card catalog (seeing all the books/members)
  • LMMFIND - Asking the librarian for a specific book (finding one member)
  • LMCLOSE - Closing the library door (finishing your visit)
  • LMFREE - Returning your library card (giving up access)
  • Shared Lists - A shared reading list that multiple people can use

Just like you need to get a library card before using the library, you need to initialize library access before using Library services. And just like you return your card when done, you free library resources when finished!

Exercises

Practice using Library services:

  • Create a REXX script that lists all members in a library
  • Build a script that searches for a specific member across multiple libraries
  • Implement a member enumeration tool with pattern filtering
  • Create a shared list builder that other programs can access
  • Build a library comparison tool that finds members in one library but not another

Test Your Knowledge

1. What service initializes library access?

  • LMOPEN
  • LMINIT
  • LMMLIST
  • LMSTART

2. What service lists library members?

  • LMLIST
  • LMMLIST
  • LMSHOW
  • LMDISPLAY

3. What service opens a library for access?

  • LMINIT
  • LMOPEN
  • LMSTART
  • LMACCESS

4. What service frees library resources?

  • LMCLOSE
  • LMFREE
  • LMEND
  • LMRELEASE

5. What are shared lists used for?

  • Sharing datasets
  • Sharing library member lists between programs
  • Sharing variables
  • Sharing panels