Welcome to the October, 1995 Issue of the C/370 Newsletter

IBM Corp 1995

                  370 370 370 370 370 370 370 370 370 370
              370 370 370 370 370 370 370 370 370 370 370 370
              370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370
         370 370 370
         370 370 370
         370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
             370 370 370 370 370 370 370 370 370 370 370 370 370
             370 370 370 370 370 370 370 370 370 370 370 370
                  370 370 370 370 370 370 370 370 370 370

C/370(TM) Compiler News

October 1995 Volume 3 Number 4


Table of Contents

Welcome to the October, 1995 Issue of the C/370 Newsletter

  • In This Issue
  • C/C++ for MVS/ESA Version 3 Release 2 Announced
  • XPG4(**) Support
  • C++/MVS(TM) Support Under OpenEdition MVS
  • NIST
  • Locale Definition Utility XPG4 Support
  • Interlanguage Communication Support
  • Switchable NL Messages
  • C/C++ Model Tool
  • Options, Pragmas, and Macros
  • Database Access Class Library Utility
  • The Debug Tool
    Using the Collection Class Libraries
  • Step 1
  • Step 2
  • You ask, we answer
    Missed our Previous Editions?
    A word from your editor
    Coming Soon
  • Reader's Comment Form

  • Welcome to the October, 1995 Issue of the C/370 Newsletter

    In This Issue

    ( )

    C/C++ for MVS/ESA Version 3 Release 2 Announced

    Enhancements in IBM C/C++ for MVS/ESA Version 3 Release 2 are made to support both OpenEdition(TM) and Object-Oriented Programming on MVS. In addition, National Language support is enhanced and a new utility and new tool are introduced.

    XPG4(**) Support

    C/C++ for MVS/ESA is enhanced to enable you to write C applications that utilize the expanded application programming interfaces (APIs) that have been added to MVS/ESA SP Version 5 Release 2.2.

    The support of these expanded APIs allow MVS/ESA SP Version 5 Release 2.2 to conform to the XPG4 (X/Open(**) Portability Guide 4) Base Profile Branding requirements of X/Open and a significant set of the functions defined by the X/Open XPG4.2 (X/Open CAE Specification System Interfaces and Headers Issue 4, Version 2), single UNIX(**) specification (previously referred to as Universal UNIX (UU), Spec1170, and Common API Specification (CASPEC)). In particular, IBM C/C++ for MVS/ESA Version 3 Release 2, conforms to the C Language as defined in ISO(**)/IEC 9899:1990(E), Programming Languages-C (ISO C) and in X/Open Specification, Programming Languages, Issue 3 (X/Open C). Support of XPG4 Base Branding and a significant portion of XPG4.2 will give you the confidence that the UNIX application interfaces on MVS/ESA SP Version 5 Release 2.2 meet standardized requirements and will enable you to port a wide variety of applications from UNIX to take advantage of the robustness, reliability, and scalability of the MVS/ESA system.

    C++/MVS(TM) Support Under OpenEdition MVS

    C++/MVS is enhanced to support OpenEdition MVS. Using C++, you can now use object-oriented technology including SOMobjects(TM) for MVS to build OpenEdition applications. The support of C++/MVS under OpenEdition MVS includes:

    NIST

    The Federal Information Processing Standards (FIPS) specifications are a series of US government procurement standards managed and maintained on behalf of the US Department of Commerce by the National Institute of Standards and Technology (NIST). The C/MVS portion of the compiler will be validated for conformance to FIPS 160 (C language) by NIST. The NIST certification of C/C++ for MVS/ESA directly supports IBM's intention to gain XPG4 base branding for MVS/ESA SP Version 2 Release 2.2.

    Locale Definition Utility XPG4 Support

    C/C++ for MVS/ESA provides a Locale Definition Utility. This supports the creation of separate files of cultural data, or locales, which can be referenced dynamically by an application using the library functions of Language Environment(TM).

    Locales can be used to customize the information that defines how a C/C++ application works in the end-user's environment, with respect to differences in national language, culture, and the data encoding schemes (coded character sets). This allows you to change the formatting convention for date, time, numeric, and monetary data, and to process data using the appropriate character classification and character collation tables. The Locale Definition Utility and locales support are continually enhanced to support new standards. Locales are enhanced to conform to XPG4 and POSIX(**) 1003.2.

    The C/C++ runtime under Language Environment implements the wchar-t type and its associated conversion functions which provide support for Double Byte Character Sets such as EBCDIC-DBCS. The library also implements a set of wchar-t I/O directives and a comprehensive set of wchar-t string functions, including the shift-state dependent functions multibyte support extensions defined by the ISO/IEC Programming Language C Amendment 1.

    Interlanguage Communication Support

    Interlanguage communication (ILC) from C to FORTRAN has been tested successfully with C/C++ for MVS/ESA Version 3 Release 1. C/C++ for MVS/ESA has been enhanced in this release to support ILC from C++ to FORTRAN as well. Used in conjunction with the ILC facilities provided by the runtime libraries, C or C++ applications can now call or be called by other languages such as FORTRAN, COBOL, PL/I, or Assembler. The ILC facilities enable you to use the language best suited for the job.

    Switchable NL Messages

    National Language Versions of C/C++ for MVS/ESA that support the English and Japanese languages are now installable together. You can select or switch, at compiler invocation time, the national language when developing your application. If you wish to have the freedom of choice in the use of any of the supported national languages while working with the compiler, you no longer have to install and maintain two separate images of the product. The English and Japanese message files are now packaged and shipped on the same tape. This support is consistent with a similar support that is currently available with Language Environment for MVS and VM.

    In addition, IBM C/C++ for MVS/ESA Version 3 Release 2 improves many of the messages and diagnostics so that they are consistent with the messages contained in other members of the IBM C/C++ family of products, which includes VisualAge(TM) C++ for OS/2(TM), C Set ++(TM) for AIX(TM), C Set ++ for Solaris(**) and VisualAge C++ for OS/400.

    C/C++ Model Tool

    The C/C++ Model Tool provides online help when you are using the C/C++ library and compiler to create C or C++ applications. When used in conjunction with the ISPF editor, you can select information for each library function or pragma. For the pragmas, read-only help and modifiable pragma models will be dropped into your edit session. For the library functions, read-only function prototypes and other information will be dropped into your edit session. Read-only information can be made modifiable. The read-only help will disappear when you save the data set member, leaving only the the newly created application. The C/C++ Model Tool will help enhance your productivity when developing C/C++ applications using C/C++ for MVS/ESA.

    Options, Pragmas, and Macros

    Improvements and additions are made to the C/C++ for MVS/ESA compiler options, pragmas, and macros. Some compiler options have been extended to support additional C++ and OpenEdition functions. Existing pragma support is improved by adding more suboptions and additional predefined macros have been added.

    Database Access Class Library Utility

    A new tool, the Database Access Class Library Utility, is introduced to generate DB2(TM) data access classes. Today, the C/C++ for MVS/ESA development environment allows you to create applications which access DB2 relational databases. You can use C code to interface with DB2 in a procedural manner. With the Database Access Class Library utility, you will be able to now use classes to access DB2 in an object-oriented manner. The Database Access Class Library utility generates classes, based on a relational database schema, which contain classes representing persistent objects. By incorporating these classes into your applications, you can work with persistent objects the same way you do with transient objects.

    IBM intends to enhance its support for C/C++ application development, targeting MVS, by extending the IBM VisualAge C++ workstation function with enhancements specific to mainframe programmer needs. As the workstation and host members of the IBM VisualAge C++ family of application development tools become more closely aligned, you will be able to choose the development platform most appropriate to the application being developed without having to worry about learning new tools. Tools will be provided to allow you more flexibility in building client/server applications.

    C/C++ for MVS/ESA is a key development tool in the Object-Oriented Solution for MVS, and in support of SOMobjects for MVS and will be generally available on December 22, 1995.


    The Debug Tool

    The Debug Tool shipped with C/C++ for MVS/ESA is a program-testing and analysis aid that helps you examine, monitor, and control the execution of programs written in C/C++, COBOL, or PL/I or programs with a mixture of these languages. You can also use C syntax and call C functions directly from the Debug Tool to 'patch' your code. The Debug Tool debugs a program as it runs on the host system in the native environment (CICS(TM), IMS(TM), DB2, SQL/DS).

    The Debug Tool provides the following debugging environments.

    1. Full-Screen Session

      Debug Tool provides an interactive full-screen interface on a 3270 device. The full-screen interface is made up of session panel windows containing information about your debugging session.

    2. Batch Mode Session

      Debug Tool command files provide mechanism to predefine a series of Debug Tool commands to be performed on a executing batch application. Neither terminal input nor user interaction is required for batch debugging of applications.

    3. Line Mode Session

      Enter Debug Tool commands on the command line and receive debugging information, one line at a time, while you are programming.

    The Debug Tool Full-Screen session provides:

    1. a Source window to view your program source or listing;
    2. a Log window, which records commands and other interactions between the Debug Tool and your program;
    3. a Monitor window in which to monitor changes in your program.

    You can adjust the window sizes with the cursor and change the relative window location by typing your preferences on a template.

    Using the Full-Screen session you may follow the execution of a program in the listing view to quickly and effectively identify and correct errors in the code. You can step through your program or set breakpoints which:

    1. allows you to monitor and interrupt the flow of a program to help you to identify errors easily and to correct them quickly;
    2. animates execution of the program in a visual form so that you can step through the execution of the program;
    3. gives you "step" and "go" control to focus on a problem area or resume execution of the application program;
    4. allows you to add, remove, enable or disable breakpoints dynamically;
    5. executes commands at a breakpoint with/without user interaction;
    6. displays and change variables at breakpoints or monitor program variable changes during program execution;
    7. simulates exception conditions to test error handling routines;
    8. allows you to pinpoint possible bottlenecks in the code through frequency of statement execution displayed in the source or listing view;
    9. assists with performance evaluation of a program by monitoring the frequency of statement execution;
    10. allows interactive and batch debugging of CICS applications;
    11. allows interactive, batch and cooperative debugging of IMS under Batch Terminal Simulator (BTS).

    Batch mode debugging provides you with an alternative when it is inconvenient or inefficient to debug in interactive mode and with greater schedule flexibility. Hot debugging provides support to invoke the debugger when an error condition occurs, when an attention occurs or via a call from an application program. This function can save you time by identifying errors where replication is difficult.

    Debug Tool captures all debug and language commands as the program executes on the host in the native host environment. This allows you to capture the debug tool session so that:

    1. The session can be used to ensure that the function contained within an application is consistent once a change has been made. You can submit the log to the application in batch mode. Checking the output from debug tool (the new Debug Tool log) or a comparison of the resulting output from the application will indicate any changes in expected output from the application.
    2. The session can also be edited to set new breakpoints and restart to obtain more information on the next debug of the program without reediting, recompiling and relinking the program.
    3. The session can also be sent to another programmer to obtain assistance on debugging an application.
    4. Debug sessions do not have to be run manually each time an application is maintained. The debug log is captured once and can be rerun until the developer wishes to alter the function within the application.

    For more information on the Debug Tool please refer to the Debug Tool User's Guide and Reference (SC09-2137-00).


    Using the Collection Class Libraries

    A C++ collection is a C++ class implementing an abstract concept that allows you to manipulate objects in a group. Collections (the simplest I can think of is an array) are used to store and manage elements (or objects) of a user-defined type. Different collections have different internal structures, and different access methods for storage and retrieval of objects.

    This article will introduce many C++ concepts by stepping through the development of a simple program that builds a simple collection of integer elements and adds some elements to the collection.

    Step 1

    : Defining a Simple Collection of Objects

    Requirements

    The collection must consist of elements of an integer type. The integer type is to be known as type Bicycle, so that we can change the members of the type. The program adds three integers to the collection. Their values are unimportant. The collection is to be a bag.

    Setup

    We will use an editor to create and edit two files:

    Implementation

    The implementation should use typedefs to define the element and collection types, so that if the element or collection type changes later, the changes will be automatically reflected in any code that uses the typedef.

    Defining the Element Type

    Use a typedef to define a Bicycle as a synonym for an int. By using a typedef, you make it easier to change the element type later, without having to change anything outside the element's type (or class) definition:

             // in bike.h
             typedef int Bicycle;
    

    Notes:

    Defining the Collection Type

    Use a typedef to define a collection type called MyCollectionType. The collection type refers to a bag collection whose elements are Bicycles.

             typedef IBag <Bicycle> MyCollectionType;
    

    In this typedef, IBag is the default implementation for a bag, Bicycle is a template argument representing the element type, and MyCollectionType is the type name given to the type being defined (a bag of Bicycle elements).

    Instantiating a Collection

    Now that you have defined a typedef for both the element and the collection types, you can instantiate a collection with a type specifier and a name:

             MyCollectionType MyCollection;
    

    Place this definition at global scope so that all functions have access to the collection and its members. Functions other than main() are defined in subsequent steps.

    Adding Elements

    You can use Flat Collection Member Functions to determine what functions you need to use to manipulate elements of a collection. If you consult the C/C++ for MVS/ESA Class Library Reference Manual (SC09-2001), you will find that the add() function is the function needed for this step. The syntax for add() is stated as:

             void add (Element const& element);
    

    For a collection named MyCollection, you can add elements using the following syntax:

             MyCollection.add(aBicycle);
    

    Where aBicycle is a Bicycle (in this case an integer). To add three elements, place code such as the following in main.C:

             void main() {
                Bicycle a,b,c;
                a=458;
                b=12;
                c=365;
                MyCollection.add(a);
                MyCollection.add(b);
                MyCollection.add(c);
             }
    

    Include Files

    Above any typedefs or instantiations that use Collection Classes, you must include the header file for the collection. The chapter on bags in the Class Library Reference tells you what the header file is for the default implementation. You should add the following code to the start of bike.h, and include bike.h in main.C:

             // in bike.h
             #include <ibag.h>
    
             // in main.C
             #include "bike.h"
    

    The files should now contain code similar to the following:

    bike.h

             #include <ibag.h>
             typedef int Bicycle;
             typedef IBag <Bicycle> MyCollectionType;
             MyCollectionType MyCollection;
    

    main.C

             #include "bike.h"
    
             void main() {
                Bicycle a,b,c;
                a=458;
                b=12;
                c=365;
                MyCollection.add(a);
                MyCollection.add(b);
                MyCollection.add(c);
             }
    

    Running the Program

    The program does not produce any output, so it appears to do nothing. In fact, it adds three elements to a collection of integers. The collection is lost on program termination. The program is useless in practical terms, but does demonstrate some basic Collection Class concepts. Later steps build on the code in this step, and provide greater functionality, including output of elements.

    Bag defines a number of element type functions as being required:

    You did not have to define these functions in the above example, because for the built-in type int, and by extension the user-defined type Bicycle, these functions are already defined by the language.

    Step 2

    : Adding, Listing, and Removing Elements

    This step moves the code for adding elements to a separate function, and implements functions for listing and removing elements as well. These functions are called from a main program that dispatches the appropriate function based on the user's choice of a menu option.

    Requirements

    The code in the main() function must be replaced by a menu system that gives the user the following options:

    1. Add an item
    2. List all items
    3. Remove an item
    4. Show stock information
    5. Exit program

    Options 1 to 3 must be implemented through functions. Option 5 can be implemented by calling exit() or by exiting the scope of the menu selection loop and main(). You do not need to implement the function to show stock information in this step. Instead, you can implement a function that prints an error message stating that the function is not yet implemented. For all options except the exit option, after the appropriate function returns, the menu should be redisplayed and the user should be able to enter another selection.

    Setup

    Copy the file bike.h from the Step1 dataset to the Step2 dataset, and then change your current dataset to the Step2 dataset. You will also create two other files. The three files now are:

    Implementation

    You need to replace the body of the main() function with the menu handling and function dispatching code. You will make use of I/O Stream Library input and output to implement the functions that add, list, or remove items. One advantage of using the I/O Stream Library instead of functions like printf() and scanf() is that, when the element type is changed, you can define input and output operators for the type, and the I/O Stream Library input and output functions will continue to work without change.

    You should include iostream.h at the start of step.C so that you can use the cin, cout, and cerr streams that are predefined by the iostream class. You should also include the header file bike.h so that you can access the Bicycle class and associated functions.

             #include <iostream.h>
             #include "bike.h"
    

    Adding Items

    Before the definition of main(), define a function addItem() that requests user input for the item, then adds the item to the collection. The item is added using the add() function described in the first step. Here is one way to implement such a function:

             // in step.C
             void addItem() {
                Bicycle tbike;
                cout << "Enter item: ";
                cin >> tbike;
                while (cin.fail()) {
                   cin.clear();
                   cin.ignore(1000,'\n');
                   cerr << "Input error, please re-enter: ";
                   cin >> tbike;
                }
                MyCollection.add(tbike);
             }
    

    Note: You should also add a declaration for this and subsequent functions in main.C.

    The function uses a temporary Bicycle object to contain the input until the element is copied into the collection. The function displays a prompt, reads input, and tests for valid input. The while (cin.fail()) block clears any input errors and asks for input again. Once the element is successfully read from input, it is added to the collection.

    Because tbike is actually an int in the current version, an operator >> is already defined for it. Later, when you change the Bicycle type to a user-defined class, you will have to add an operator>> for that class.

    Listing Items

    Before you can list all items, you must define a function that prints a single item. This function can then be invoked by the allElementsDo() member function of MyCollection. Any function invoked by allElementsDo() must have a return type of IBoolean, and must have two arguments: a const reference to the argument and a pointer to void. The pointer to void is used to pass additional arguments to the applied function, if required by the function. For the printing function in this step you do not need to pass additional arguments, because the function does not use them. In such cases you pass a void* second argument:

             // in step.C
             IBoolean printItem (Bicycle const& bike, void*/*Not used*/) {
                cout << bike << endl;
                return True;
             }
    

    The printItem() function should always return True because it should display the value of each element of the collection. If you wanted certain values of elements to cause printing to halt, you would have the function return False for any such element. A return value of False causes the allElementsDo() function to stop iterating over the collection.

    Just as there was no need to define an input operator for Bicycle, there is no need to define an output operator either, as long as Bicycle represents an int.

    Now define the function listItems() to call the printItem() function for each element of the collection. Use the allElementsDo() function for the collection, and use the printItem() function as argument. allElementsDo() calls the function for every element of the collection.

             // in step.C
             void listItems() {
                MyCollection.allElementsDo( printItem );
             }
    

    Removing Items

    To remove an element from a collection, you need to use the remove() member function. remove() returns True if the element was found in the collection and was removed, or it returns False if the element was not found in the collection. Your removal function should print an error if the element is not successfully removed. In the version below, the condition that determines whether removal was successful actually invokes the remove() function:

             // in step.C
             void removeItem() {
                Bicycle tbike;
                cout << "Enter item to remove: ";
                cin >> tbike;
                while (cin.fail()) {
                   cin.clear();
                   cin.ignore(1000,'\n');
                   cerr << "Input error, please re-enter: ";
                   cin >> tbike;
                }
                if (!MyCollection.remove(tbike))
                   cerr << "Item not found!\n";
             }
    

    Showing Stock Information

    For now, you can define this function to display an error message without changing the collection:

             // in step.C
             void showStock() {
                cerr << "Function not implemented yet!\n";
             }
    

    Main Menu

    Finally, change the code in main() to display the menu items, accept input, and take appropriate action. Because this code will remain relatively unchanged for subsequent steps, place it in a separate file, main.C, and include step.C before the code of main(). The code should look like the following:

    main.C

     #include <iostream.h>
     #include <stdlib.h> // for use of exit() function
     void addItem(), listItems(), showStock(), removeItem();
    
     void main() {
     enum Choices { Add, List, Stock, Remove, Exit };
     int menuChoice=0;
     char* menu[5] = {"Add an item",
                                "List items",
                                "Show stock information",
                                "Remove an item",
                                "Exit" };
      while (menuChoice!=5) {
        cout << "\n\n\nSimple Stock Management System\n\n";
        for (int i=0;i<5;i++)
          cout << i+1 << ". " << menu[i]        << '\n';
          cout << "\nEnter a selection (1-5): ";
          cin >> menuChoice;
          while (cin.fail()) {
             // get input again if nonnumeric was entered
             cin.clear();
             cin.ignore(1000,'\n');
             cerr << "Enter a selection between 1&5!\n";
             cin >> menuChoice;
           }
           switch (menuChoice) {
             case 1: addItem(); break;
             case 2: listItems(); break;
             case 3: showStock(); break;
             case 4: removeItem(); break;
             case 5: exit(0);
             default: cerr << "Enter a selection between 1&5!\n";
        }
      }
     }
    

    Step.C

     #include <iostream.h>
     #include <ibag.h>
     #include "bike.h"
    
     void addItem() {
        Bicycle tbike;
        cout << "Enter item: ";
        cin >> tbike;
        while (cin.fail()) {
           cin.clear();
           cin.ignore(1000,'\n');
           cerr << "Input error, please re-enter: ";
           cin >> tbike;
        }
        MyCollection.add(tbike);
     }
    
     IBoolean printItem (Bicycle const& bike, void*/*Not used*/) {
        cout << bike << endl;
        return True;
     }
    
     void listItems() {
        MyCollection.allElementsDo( printItem );
     }
    
     void removeItem() {
        Bicycle tbike;
        cout << "Enter item to remove: ";
        cin >> tbike;
        while (cin.fail()) {
           cin.clear();
           cin.ignore(1000,'\n');
           cerr << "Input error, please re-enter: ";
           cin >> tbike;
        }
        if (!MyCollection.remove(tbike))
           cerr << "Item not found!\n";
     }
    
     void showStock() {
        cerr << "Function not implemented yet!\n";
     }
    

    Running the Program

    Compile main.C and step.C, link them, and run the program. You can enter elements into the collection, list the elements, remove them, or exit from the program. If you select the option to display stock information, an error message is displayed and no action is taken.

    Elements appear to be ordered

    If you enter more than one integer into the collection, and then list the collection's elements, the collection may have been sorted from the smallest to the largest element. Do not rely on this ordering relation, because a Bag is an unordered, unsorted collection, and changes to your code or Collection Classes could change the order in which elements are accessed.

    Multiple equal elements are supported: If you add the number seven to the collection three times and list the items, the number seven appears three times. If you then remove the number seven once, the number seven still appears twice. A bag supports multiple equal elements.

    In subsequent issues of this newsletter, we will change the element type, the collection class and the implementation variant of this sample program.


    You ask, we answer

    These questions are culled from a variety of sources: from various question and answer databases, from customer calls, and from our own experiences. If you have a question you'd like answered, please send it to IBMMAIL(CAIBMRXZ) or inetc370 @ vnet.ibm.com. We'll answer your question and perhaps print your question and answer in the next newsletter.

    Question-Convert Packed decimal to/from character

    Can you give me an example of a C routine to convert packed decimal to/from character?

    Answer

    Here's a small sample that you may be able to use.

    #include <decimal.h>
    
    /*printf allows you to specify values for '*' as first parms*/
    #define d_to_t(a,b,c,d)  sprintf(a,"%D(*,*)",c,d,b);
    
    /*scanf does not - hard code them*/
    #define t_to_d(a,b)  sscanf(b,"%D(3,2)",&a);
    
    /*if you can have a buffer around,build it,then use it*/
    #define t_to_d_with_buff(a,b,c,d)        \
    {                                        \
     /* setup printf template buffer */      \
     sprintf(tempbuff,"%%D(%d,%d)\0",c,d);   \
     sscanf(b,tempbuff,&a);                  \
    }
    
    main(){
    decimal(3,2)  y;
    decimal(3,2)  x;
    char z[20] =" ";
    char tempbuff[20] = " ";
    
    /*set and print both x and y to show different*/
    y=1.5;
    x=9.9;
    printf("y is %D(3,2)\n",y);
    printf("x is %D(3,2)\n",x);
    
    /*initial conversion to string*/
    d_to_t(z,y,3,2)
    printf("z is >%s<\n",z);
    
    /*now convert string to dec using hardcoded format in define*/
    t_to_d(x,z)
    printf("x is %D(3,2)\n",x);
    
    /* reset ... "nothing up my sleeve" */
    x=9.9;
    printf("x is %D(3,2)\n",x);
    
    /* convert string to dec using dynamic print template */
    t_to_d_with_buff(x,z,3,2)
    printf("x is %D(3,2)\n",x);
    }
    

    Question-Converting TSO application to IMS BMP

    I have a TSO application written using C/370 with the following modules:

    1. Logic.

      Uses environment variables like getenv and setenv and also name/token calls.

    2. Data Base management module

      Adding/Deleting/Updating records to (ESDS VSAM)/BSAM files using calls : fopen, fwrite, fread, fupdate and flocate.

    I would like to put this application in BATCH (i.e Batch Message Processing - BMP) using additional DL/I calls to access IMS DB. Will this application work?

    Answer

    Nothing unusual here. We certainly support the access methods (VSAM/BSAM) as well as QSAM (under V2R2 and LE 1.3+) if you are not doing any seeking in the file through our own internal extensions to the ANSI(**) f* function descriptions. DL/I calls are handled through the C library function ctdli().

    Question-User Defined Storage Management

    What is the right approach to take to provide user defined storage management for the C++ runtime stack when mixing ASM and C++? Or is there one?

    Answer

    If you're asking if you can have assembler call C++, providing the address of the stack, or the address of a stack manager, the answer is no.

    If you're wanting to share the stack with C++, use EDCPRLG and EDCEPIL macros.

    If you mean you want to control the stack's initial size, increment and above/below the line location, then you want the STACK runtime option. If you want to control the values that get put into that storage at stack creation/free time, it's the STORAGE option.

    If you're wanting to allocate user heap storage, to allocate off of for your program needs:

        CEECRHP - create user heap
        CEEGTST - obtain storage from user heap
        CEEFRST - free storage obtained from CEEGTST
        CEEDSHP - discard user heap created with CEECRHP
    

    Question-DSName from a DDName

    Do you have a piece of sample code that uses svc99() to get the DSName associated with a DDName? Also, which releases of fldata support this?

    Answer

    fldata() supports this as of V1R3M0 of the LE/370 library, or in V2R2 of the C/370 library. It's not supported in V2R1. In any case, this ought to get you going.

    #include <stdio.h>
    #include <string.h>
    
    int main() {
     #define HIGHBIT 0x80000000
     struct __S99struc parmlist = {0};
     parmlist.__S99RBLN = 20;
     /* S99VRBIN (verb code 07) is for Information Retrieval */
     parmlist.__S99VERB = 7;
     char *textUnits[2];
     char text0[15];
     char text1[51];
     char *ddname="MYDDNAME";
    
     /* DINDDNAM (key 0001) is the DDname you want info about */
     memcpy(text0,"\0\x01\0\x01\0\x08\0\0\0\0\0\0\0\0",15);
     /* DINRTDSN (key 0005) is the DSName returned by SVC99 */
     memset(text1,'\0', 51);
     memcpy(text1,"\0\x05\0\x01\0\x2c",6);
     textUnits[0] =text0;
     textUnits[1]=text1;
     int len=strlen(ddname);
     textUnits[0][5] = len;
     memcpy(&textUnits[0][6] , ddname, len+1);
     parmlist.__S99TXTPP = textUnits;
     textUnits[1] = (char *)((long unsigned)
                               textUnits[1]) | HIGHBIT);
    
     /* if svc99() worked and length(dsn) > 0 */
     if ((svc99(&parmlist) == 0) && textUnits[1][5] > 0 )
       printf("dsn was %.44s\n", &(textUnits[1][6]));
     else {
       printf("svc99() failed\n");
     }
    }
    

    Question-C/370 program name

    We have the following problem, and I was wondering whether there was any neat solution to it. Our version control system running under TSO, takes C/370 source from user supplied input datasets, and copies it to a temporary dataset (we are not sure whether this is really necessary, but that is the way it works), and then hands over that temporary dataset to the C/370 compiler. The compiler then considers that datasetname to be the program name, so we end up having program names like: 'SYS95219.T162422.XT02BK#X.R0274210', which is not very useful. It looks like changing the way our version control system works is not very easy, so I wondered whether there was any way of changing the program name from within the compiler. It looks to me as if I want to redefine the predefined macro __FILE__, but doing this plainly from within my source, gives me a compile error. Is there any other way to help us out, and get a more sensible program name in our listings.

    Answer

    I'm afraid you're stuck. We look to see what dataset name is defined for the SYSIN DD statement and use that. Since JES creates the name to be unique, you end up with the rather strange looking name you have. __FILE__ is defined by the compiler, and cannot be redefined.

    Perhaps you might want to consider the naming of the temporary dataset to a meaningful name, then add a delete step at the end of the job, since only &&'s are deleted automatically.

    Question-Passing a parameter String

    I'm running a program compiled and linked with AD/Cycle(TM) C/370 and LE/370 C, and passing it a parameter string. I have specified #pragma runopts(noargparse, noredir) because I want to process the complete string as is.

    If I pass it a string with a quote mark, I get the following unwanted message:

    CEE3193I The invocation command parameter string contained an
    unmatched quote character.
    

    The program runs fine. I just want the run-time argument processor to keep quiet. I know I'm passing a quote mark. What do I do?

    Answer

    LE options processor considers everything before the first '/' to be candidates for its runtime options. User parms should be separated from the runtime environment parms by inserting a slash (/) between them. If you only have user parms, prefix them with a slash and LE should keep quiet.

    Question-File data

    After reading through some C and C/370 manuals I am still stuck with the following question: How do I get the full file name when a file has been opened using a "dd:datain" statement. The function fldata suggests something very useful, but turned out to return only "dd.:datain" statement instead of the full file name, which I wanted. Then there is the svc99 function, but I am afraid that that will be just another more elaborate way of getting my dd statement back again (I did not try that because the syntax of that call was not clear to me from the example).

    Answer

    fldata() was intended to describe what was opened, from a rather direct view (eg. if fopen() by ddname, then that ddname is the dataset name).

    svc99() can give you back the information you need. The example in the book is for performing an allocation, not a query. For queries, you need to use verb code 7. Here is some code that really runs. Try it out as a separate program, so you can verify the information is what you need before integrating it into existing programs.

     #include <stdlib.h>
     #include <stdio.h>
     #include <string.h>
    
     #define MASK 0x80000000
    
     int main(void)
     {
     FILE *rf;
      int rc;
      struct __S99struc parmlist;
      char *s??(04??) = {            /*array of text pointers*/
       "\0\x01\0\x01\0\x03""DD1",    /*length 3, value 'dd1' */
       "\0\x05\0\x01\0\x2C"\
       "                                            ",
                                     /*length 44 (x2C), init ' '*/
       "\0\x06\0\x01\0\x08        "  /*length 8, member name  */
       "\0\x0A\0\x01\0\x02  "};      /*dsorg: x0200 is PO     */
    
       memset(&parmlist, 0, sizeof(parmlist));
       parmlist.__S99RBLN = 20;
       parmlist.__S99VERB = 7;
       parmlist.__S99TXTPP = s;        /*ptr-ptr-text units*/
       s??(3??) = (char *)((long unsigned) (s??(3??)) | MASK);
    
       rc = svc99(&parmlist);
       if (rc != 0)
          printf(" Error code = %d   Information code = %d\n",
                 parmlist.__S99ERROR, parmlist.__S99INFO);
    
       /* s(0)+6 is DD name (you supplied) */
       /* s(1)+6 is DSname (associated with ddname) */
       /* s(2)+6 is member name (or blank if no member) */
       /* s(3)+6 is dsorg (hex): 0200 is 'PO' */
     }
    

    Question-C/370 equivalent of C++ __OS2__ macro

    We recently installed C/370 V1R2 on our host system, and a programmer wants to know the C/370 equivalent of the __OS2__ 'pre-defined macro'. I understand this parm to be an environment variable, which may need to be provided when porting programs from one platform to another. Is there a comparable variable in the C/370 environment?

    Answer

    No, there's no equivalent in C/370.

    Question-Dynamic Allocation - negative return code

    I am getting negative return codes from DYNALLOC. How do I find the meaning of these negative return codes? Are they documented in any manual?

    Answer

    The return code from dynalloc() is the value returned by the underlying call to SVC 99. The __dyn_t structure's __infocode and __errorcode fields contain the reason code values from the SVC 99 request block fields S99INFO and S99ERROR. The book I use for these values is the MVS/ESA System Programming Library: Application Development Guide (GC28-1852).

    The code for dynalloc() returns the following negative values:

     -1   if it couldn't malloc() the temporary storage it needed,
          or if it's called under CICS,
     -3   if it's called under CMS
    

    Other than that, dynalloc() returns whatever SVC 99 gave it. One thing that comes to mind is that really big unsigned numbers look negative when they're printed out as signed numbers.

    Question-LRECL & BLKSIZE altered when DYNALLOC used with tape

    I can successfully allocate a DASD data set. However, when I switch to tape (CART) the LRECL and BLKSIZE are changed. The original LRECL and BLK were 41 and 32759. These were changed to 80 and 32760. I tried it with a larger LRECL (90) but got the same results. I could not find any restrictions in the manual.

    Answer

    The program was failing when it opened a tape file that was created with the dynalloc library function. The problem was that the recfm and lrecl were being changed. The program was using the fopen option of recfm=*. The JFCB for the file did not have the lrecl or recfm in it. The file was not allocated. The tape file is created on open and can not use the recfm=* option. This option is only supported for DASD files. The Release 2.1 product documentation does not spell this out. This limitation has been documented in the Release 2.2 manuals and also in the LE documentation. You need to pass the lrecl and recfm for the file on the fopen statement. This will be required for all files that require a lrecl or recfm that is different from the C-supplied defaults.

    Question-C/370 & VSAM KSDS performance

    I am migrating a PL/I application to C/370 and am wondering about performance with a VSAM KSDS. Under PL/I, I can write the keys out in order and the job runs very quickly. Under C/370 (5688-188 V2R2 & 5688-187 V2R1), even if the keys are placed in order by the program before they are written, the entire KSDS is searched for each key to be written, making the performance slow. Is there an option with C/370 which works like the PL/I option:

    WRITEFILE(filename)FROM(character_string)KEYFROM(key)
    
    so that the keys are not searched after every write?

    Answer

    The C KSDS VSAM I/O is implemented like this:

    If you open the file in a "w" mode, C/370 assumes you are in initial load mode and that the records are in sequence and it creates the RPL with the SEQ option. If it detects keys that are out of sequence, it will close and reopen with the DIR option and continue to input the rest of the records with direct insert. However, if you are updating an existing dataset, then it always does direct insert and it will never do any sequential insert. If you are creating a new one, then the performance should be the same as PL/I.

    Question-EDC0185

    When compiling with the LE/370 compiler in a CICS environment, we get the message:

    EDC0185 function dfhexec has not been prototyped prior to use.
    

    I would have assumed that the CICS translator would have inserted the correct statement to avoid getting this warning. Can you suggest a way to remove this warning warning?

    Answer

    The translator should have inserted a piece of code into your program before passing it on to the compiler:

     #ifndef __dfhtemps
     #pragma linkage(dfhexec,OS)  /* force OS linkage */
     void dfhexec();  /* Function to call CICS */
       #define __dfhtemps 1
          signed short int    dfhb0020,   *dfhbp020 = &dfhb0020 ;
          signed short int    dfhb0021,   *dfhbp021 = &dfhb0021 ;
          signed short int    dfhb0022,   *dfhbp022 = &dfhb0022 ;
          signed short int    dfhb0023,   *dfhbp023 = &dfhb0023 ;
          signed short int    dfhb0024,   *dfhbp024 = &dfhb0024 ;
          signed short int    dfhb0025,   *dfhbp025 = &dfhb0025 ;
          unsigned char       dfhc0010,   *dfhcp010 = &dfhc0010 ;
          unsigned char       dfhc0011,   *dfhcp011 = &dfhc0011 ;
          signed short int    dfhdummy;
     #endif
    

    Please look for this in the translator output. Typically, this output is sent to a temp file (ie. &&somename) which is processed by the compiler. You can override the associated DDname (SYSPUNCH) and have a peek at what the translator did. Ensure that you are looking at the right thing. The translator also produces a listing that goes to DD SYSPRINT - these are not the same - only the SYSPUNCH is used by the compiler.

    You should also make sure that the correct margins are set for the code in case the first column (which has the '#' sign in it) is getting lost and confusing the compiler. The translator should insert its code before your code, but some pragma's may end up ahead. If you have open comments on the pragma's (that would have been closed in a subsequent line) some or all of the translator-inserted code may be getting ignored.

    Question-Multiple CSECTS and C/370

    We are trying to do some performance analysis on some software we have written using the AD/Cycle C/370 V1R2 compiler under MVS. In order to get some better numbers from STROBE(**), the performance analysis package, we would like to add a #pragma CSECT to each of the source modules. They will give each of the source modules its own CSECT name and, therefore, make the STROBE report easier to read.

    Does anyone know of any negative side effects of doing this? I can't imagine that this would alter the performance in any way. Is there any reason not to run in production with all of these (hundreds) CSECTs?

    Answer

    There are NO known NEGATIVE side-effects. There are some positive ones (unnamed csects are considered to be private, so cannot EASILY replace a single csect via a relink).

    The code should be no larger than it was without the name, and should not behave any differently.

    ProgramArt(**) is making some changes to their STROBE product to provide better monitoring under LE/370 (ie. Language Environment for MVS & VM), so you may want to have a talk with them before going too far.

    Question-Long running 'C' program

    We have an application 'C' program that was coded for a UNIX/PC environment. The purpose of the program is to translate some records from one record format/type to another format/type. Apparently, when this program runs in a UNIX environment, processing is 'normal', records get read/massaged/written and it runs in a reasonable amount of time.

    This same program was re-compiled with C/370. I do not know how much 'tweaking' was done to get it to compile; I suspect it was very minimal.

    When this program executes on the mainframe, it runs for a VERY long time. In some of the test runs, we are pushing 16,000 records through it and end up cancelling the job after about 4 hours!

    I then used STROBE to look at the job to see what may be happening in the program. They found that most of the time was spent in modules ibmbgst/ibmbfst/ibmbpgr1 in lmod ibmbliia. From the brief description, it stated these modules get/free/manage storage for PL/I (and probably 'C').

    We are using C/370 v2r1 at about the 9409 maintenance level. I was wondering if there was anything that needs to be considered, especially in the I/O area, when porting a 'C' program from the UNIX/PC arena to the mainframe. Are there certain types of instructions that should be avoided, or other instructions that should be added to execute more 'efficiently' on the mainframe?

    Answer

    It may be all that's needed is some storage management tuning. With a low initial storage allocation, a C/370 program can still run but may have to call operating system services frequently to allocate and free storage.

    This can be a high overhead, and may account for what you're seeing.

    To tune the space management settings, you can use the REPORT run-time option to generate a report showing how your program utilized run-time storage. Chapter 17 of SC09-1384-01, the V2R1 C/370 Programming Guide tells how you can use the report to find optimum settings for the space management parameters. When the program is running with satisfactory performance, you can turn the REPORT option off again.

    Question-Call IDCAMS from C/370

    I want to call IDCAMS from a C/370 program to do a LISTCAT. Is this possible, and how would I do it?

    Answer

    A system("listcat ...") function call should do it. You will also need an "include <stdlib.h>". The C/370 Programming Guide has detailed information about the system() function.

    Question-Language option does not work in source program

    I specified RUN-TIME OPTION LANG(UE) on my source program but the output character was Japanese. The same result appeared under MVS batch, too. IBM C/370 Programming Guide describes the default national language is UEnglish.

     ---- User source program ----
     #pragma runopts(LANG(UE),REPORT)
     #include <stddef.h>
     #include <stdio.h>
     #include <stdlib.h>
     main()
     {
        FILE *fp;
        if (( fp = fopen("dd:12345678", "w"))== NULL){
            perror("fopen");
            exit(1);
            }
        printf("Hummmm");
        exit(2);
     }
     ---- fopen output ----
      fopen: JAPANESE LANGUAGE      <=== note !!!
    

    Answer

    Sorry to say that PERROR() is not sensitive to LANG(xx) at all for C/370 Library Version 2. It is sensitive though for LE/370 1.3 and up. There is a way around it, but it is a little complicated. If you are really interested, read on.

    Let me first try to explain the problem. The module EDCEMSGS contains all the messages for PERROR(). There are 2 versions of that module. The English one which is shipped with HCLB202, and the Kanji one which is shipped with JCLB212. After installing HCLB202, you will get the English messages. If you install JCLB212, the Kanji version replaces the English one. This is how the product was designed and packaged. All these problems have been solved for later releases.

    Now, how can we get English and Kanji messages :

    1. Create a new SEDCLINK and copy module EDCXV to it.
    2. Create a new AEDCLIBO.
    3. Copy the English version of EDCEMSGS from the product tape. The following JCL will help you do it :
      //COPEMSG  EXEC PGM=IEBCOPY
      //SYSPRINT DD SYSOUT=*
      //SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(3,1))
      //SYSUT4   DD UNIT=SYSDA,SPACE=(CYL,(3,1))
      //PRODTAPE DD DSN=HCLB202.F4,DISP=OLD,UNIT=TAPE,
      //             LABEL=(5,SL),VOL=SER=CLB202
      //TARGET   DD DSN=new.private.dataset.aedclibo,DISP=SHR
      //SYSIN DD *
         COPYMOD   INDD=PRODTAPE,OUTDD=TARGET
         SELECT M=(EDCEMSGS)
      
    4. Linkedit the English version of EDCEMSGS into EDCXV. The following JCL will help you do it :
      //SEDCLNK1  EXEC PGM=IEWL,REGION=500K,
      //          PARM='RENT,MAP,RMODE=ANY,AMODE=31,NCAL'
      //SYSPRINT DD SYSOUT=*
      //SYSLMOD  DD DSNAME=new.private.dataset.sedclink,
      //            DISP=SHR
      //AEDCLIBO DD DSNAME=new.private.dataset.aedclibo,
      //            DISP=SHR
      //SYSUT1   DD UNIT=SYSDA,SPACE=(CYL,(1,1))
      //SYSLIN   DD *
         INCLUDE   AEDCLIBO(EDCEMSGS)
         INCLUDE   SYSLMOD(EDCXV)
         ENTRY     @@EDCXV
         NAME      EDCXV(R)
      
    5. To get the English messages, STEPLIB to the new SEDCLINK.

    Question-@@rcinit uses lots of CPU

    My CICS C programs spend a lot of time in @@rcinit. The CICS transactions are C programs only - no COBOL / PL/I / Assembler programs are called. I would like to know what @@rcinit is for. What is its function? Can I do anything to improve performance of @@rcinit?

    This is the source for the 2 programs which cause excessive usage of @@rcinit.

    Calling program:

     #pragma strings(readonly)
     #include <cics.h>
     #include <string.h>
     #include <stdio.h>
     #include <stdlib.h>
     #include <stddef.h>
     void main()
     {
     double count       ;
     int    resp        ;
       printf("\nfvctest started");
       EXEC CICS ADDRESS EIB(dfheiptr) RESP(resp) ;
       for ( count = 0; count > 5000 ; count++ )
         {
          EXEC CICS LINK PROGRAM("FVCTEST1") RESP(resp) ;
         }
       printf("\nfvctest ended");
       return ;
     }
    

    Called program:

     #pragma strings(readonly)
     #include <cics.h>
     #include <string.h>
     #include <stdio.h>
     #include <stdlib.h>
     #include <stddef.h>
     void main()
     {
     int    resp        ;
       EXEC CICS ADDRESS EIB(dfheiptr) RESP(resp) ;
       EXEC CICS RETURN ;
     }
    

    Answer

    The @@rcinit routine will initialize the static variables in the program. Unless the program has huge and/or many static variables declared as initialized to specific values (e.g. static int num = 3) then it should not spend too much time in @@rcinit. If the program does have many initialized static variables then do the following if you can:

    1. do not initialize the static variable (e.g. static int num;)
    2. get rid of static variables if possible

    We measured 62% of the total CPU for this task in @@rcinit. Adding static strings did not seem to influence @@rcinit usage. Additionally, if the second program is written as a function of the first program, i.e. we do not use EXEC CICS LINK, we see no usage of @@rcinit.

    Routine @@rcinit is invoked per C main program therefore if the 2nd program was written as the function inside the first program then @@rcinit was only invoked once. The sample programs given are very simple therefore the percentage of time spent in @@rcinit could be shown abnormally large i.e. for small programs C initialization overhead looks worse and for larger C programs the initialization overhead gets smaller percentage-wise.

    Question-EDCXTOVF (a.k.a @@XTOVFN)

    We're running an SPC application and measuring the path length through the code.

    We can see that @@XTOVFN uses as many instructions as our whole application server routines and 11% of our whole runtime cost including our client code.

    Therefore we are interested in knowing what it does and whether we can do anything to tune/improve it. The C SPC description doesn't say what this function does.

    Answer

    @@XTOVF function is used to allocate secondary stack segments, when a request is made via compiler generated code for a new stack and there isn't enough space in the primary stack.

    To improve the performance of your application, I suggest run the application once with run-time option "report", and specify initial stack size accordingly (say 20% more than what the report shows your application needs). Your objective should be to eliminate all calls to @@XTOVF function once your application is in production. The trade off is storage space versus execution time.


    Missed our Previous Editions?

    If you did not get a copy of any of our previous editions, just let us know and we will be more than happy to send them to you.


    A word from your editor

    If you haven't already sent for your free subscription to this newsletter, now is the time to mail it in. So far, we have almost been able to keep to our plan of 4 issues a year. If you prefer, mail or fax your business card to the address/phone number on the Reader's Comment Form. You can also subscribe to this newsletter via INTERNET. Just send a message containing your name, full mailing address and phone number, in case we have to talk to you to inetc370 @ vnet.ibm.com or IBMMAIL(CAIBMRXZ).

    For the many of you sending in the reply forms with your comments, we may need to call you to discuss your comments further. Please keep those cards, letters, faxes and messages coming in to us so that we can continue to provide this service. We really thank the many of you who have already sent your comments and subscriptions in. It's a great help if you include your phone number. Thanks!


    Coming Soon

    In future issues, we'll have some performance tips and answer some more of your questions. Thanks for reading; please let us know what you think of this newsletter.

    +----------
    ------------------------------------------------------------
    +
    

    This newsletter was produced by the IBM Software Solutions Toronto Laboratory. For further information on any of the products mentioned, please contact your local IBM office, or an authorized IBM Business Partner.

    Numerous product references in this publication are registered trademarks or trademarks of International Business Machines Corporation, unless otherwise indicated. IBM Canada Ltd., a related company is a licensee.

    This newsletter was created and marked for processing using IBM BookMaster ® (Program Number 5688-015) and IBM Document Composition Facility (DCF)(Program Number 5748-XX9). The final copy was printed on an IBM 3825 Page Printer, an Advanced Function Printer.

    This newsletter is © Copyright IBM Corporation 1995. In Canada - © Copyright IBM Canada Ltd. 1995. | +-------------------------------------------------------------------+


    C/370 Compiler News Volume 3 Number 4 October/95 Issue

    Reader's Comment Form

    1. Did you find this newsletter useful?

    2. Is there any way you think we could improve this newsletter?

    3. Is there any C/370 compiler-related subject you would like to see addressed in this newsletter?

    ____________________________________________________________________

    ____________________________________________________________________

    ____________________________________________________________________

    ____________________________________________________________________

    ____________________________________________________________________

    ____________________________________________________________________

    ____________________________________________________________________

    ____________________________________________________________________

    ____________________________________________________________________

    ____________________________________________________________________

    Please note:

    Thank you for your cooperation and help. You can either mail this form to us, hand it into an IBM office for forwarding or send a message containing your full mailing address and phone number to IBMMAIL(CAIBMRXZ) or inetc370 @ vnet.ibm.com.

    You can also fax the form to us. Our fax number is 416-448-6057. Please mark your fax for the attention of Gord Sinclair. Thanks.

    C/370 Compiler News Volume 3 Number 4 October/95 Issue

    Reader's Comment Form




    Footnotes:

    ( ) Products marked (TM) or ® are trademarks or registered trademarks of International Business Machines Corporation, unless otherwise indicated. Company, product or service marked (**) may be a trademark or service mark of others.