XL C-C++ Programming Guide PDF
XL C-C++ Programming Guide PDF
XL C/C++
Programming Guide
SC09-4765-13
Note
Before using this information and the product it supports, read the information under Notices on page 1019.
This edition applies to z/OS XL C/C++ compiler in version 1, release 13, modification 0 of z/OS (5694-A01) and to all
subsequent releases and modifications until otherwise indicated in new editions.
This edition replaces SC09-4765-12.
Copyright IBM Corporation 1996, 2012.
US Government Users Restricted Rights Use, duplication or disclosure restricted by GSA ADP Schedule Contract
with IBM Corp.
Contents
Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . xv
Tables. . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
Part 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Chapter 11. Performing z/OS UNIX file system I/O operations . . . . . . 123
Creating files . . . . . . . . . . . . . . . . . . . . . . . . . 123
Opening files . . . . . . . . . . . . . . . . . . . . . . . . . 124
Reading from z/OS UNIX file system files . . . . . . . . . . . . . . 128
Opening and reading from z/OS UNIX file system directory files . . . . . . 129
Writing to z/OS UNIX file system files . . . . . . . . . . . . . . . . 129
Flushing records . . . . . . . . . . . . . . . . . . . . . . . . 130
Setting positions within files . . . . . . . . . . . . . . . . . . . . 130
Closing files . . . . . . . . . . . . . . . . . . . . . . . . . 131
Deleting files . . . . . . . . . . . . . . . . . . . . . . . . . 131
Pipe I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Low-level z/OS UNIX I/O . . . . . . . . . . . . . . . . . . . . . 137
Example of z/OS UNIX file system I/O functions . . . . . . . . . . . . 137
fldata() behavior . . . . . . . . . . . . . . . . . . . . . . . . 142
File tagging and conversion . . . . . . . . . . . . . . . . . . . . 144
Access control lists (ACLs) . . . . . . . . . . . . . . . . . . . . 144
Chapter 14. Performing memory file and hiperspace I/O operations . . . 199
Using hiperspace operations . . . . . . . . . . . . . . . . . . . 199
Opening files . . . . . . . . . . . . . . . . . . . . . . . . . 200
Reading from files . . . . . . . . . . . . . . . . . . . . . . . 206
Writing to files . . . . . . . . . . . . . . . . . . . . . . . . . 207
Flushing records . . . . . . . . . . . . . . . . . . . . . . . . 208
Repositioning within files . . . . . . . . . . . . . . . . . . . . . 208
Closing files . . . . . . . . . . . . . . . . . . . . . . . . . 209
Removing memory files . . . . . . . . . . . . . . . . . . . . . 209
fldata() behavior . . . . . . . . . . . . . . . . . . . . . . . . 209
Example program . . . . . . . . . . . . . . . . . . . . . . . 210
Contents v
File I/O trace . . . . . . . . . . . . . . . . . . . . . . . . . 232
Locating the file I/O trace . . . . . . . . . . . . . . . . . . . . 233
Chapter 21. Building and using Dynamic Link Libraries (DLLs) . . . . . 279
Support for DLLs. . . . . . . . . . . . . . . . . . . . . . . . 279
DLL concepts and terms . . . . . . . . . . . . . . . . . . . . . 280
Loading a DLL . . . . . . . . . . . . . . . . . . . . . . . . 281
Managing the use of DLLs when running DLL applications . . . . . . . . 286
Creating a DLL or a DLL application . . . . . . . . . . . . . . . . 288
Building a simple DLL . . . . . . . . . . . . . . . . . . . . . . 288
Building a simple DLL application . . . . . . . . . . . . . . . . . 292
Creating and using DLLs . . . . . . . . . . . . . . . . . . . . . 293
DLL restrictions . . . . . . . . . . . . . . . . . . . . . . . . 294
Contents vii
Chapter 32. Using environment variables . . . . . . . . . . . . . . 467
Working with environment variables . . . . . . . . . . . . . . . . . 475
Environment variables specific to the z/OS XL C/C++ library. . . . . . . . 477
Propagating environment variables . . . . . . . . . . . . . . . . . 501
Chapter 35. Writing applications for Single UNIX Specification, Version 3 549
Announcing your intentions . . . . . . . . . . . . . . . . . . . . 549
Testing the environment . . . . . . . . . . . . . . . . . . . . . 550
What is different in SUSv3 . . . . . . . . . . . . . . . . . . . . 551
Symbols withdrawn in SUSv3 . . . . . . . . . . . . . . . . . . . 552
Candidates for removal in a future version . . . . . . . . . . . . . . 552
Implementation compliance . . . . . . . . . . . . . . . . . . . . 552
Chapter 43. Stepping through optimized code using the dbx debugger
utility . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
Steps for setting up a stopping point for dbx in optimized code . . . . . . . 615
Steps for using dbx to step through optimized code . . . . . . . . . . . 615
Contents ix
Part 7. Programming with Other Products . . . . . . . . . . . . . . . . . . 709
Chapter 48. Using the CICS Transaction Server (CICS TS) . . . . . . . 711
Developing XL C/C++ programs for the CICS environment . . . . . . . . 711
Preparing CICS for use with z/OS Language Environment . . . . . . . . 711
Designing and coding for CICS . . . . . . . . . . . . . . . . . . 712
Translating and compiling for reentrancy . . . . . . . . . . . . . . . 725
Prelinking and linking all object modules . . . . . . . . . . . . . . . 732
Defining and running the CICS program . . . . . . . . . . . . . . . 733
Chapter 61. Coded character set considerations with locale functions 885
Variant character detail . . . . . . . . . . . . . . . . . . . . . 885
Alternate code points . . . . . . . . . . . . . . . . . . . . . . 887
Coding without locale support by using a hybrid coded character set . . . . 887
Coded character set independence in developing applications . . . . . . . 889
Writing source code in coded character set IBM-1047 . . . . . . . . . . 900
Exporting source code to other sites . . . . . . . . . . . . . . . . 900
Converting existing work . . . . . . . . . . . . . . . . . . . . . 901
Considerations with other products and tools . . . . . . . . . . . . . 902
Contents xi
Support for the Curses library . . . . . . . . . . . . . . . . . . 1005
Notices . . . . . . . . . . . . . . . . . . . . . . . . . . 1019
Policy for unsupported hardware . . . . . . . . . . . . . . . . . 1021
Permission Notice . . . . . . . . . . . . . . . . . . . . . . . 1021
Programming Interface Information . . . . . . . . . . . . . . . . 1021
Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . 1022
Standards . . . . . . . . . . . . . . . . . . . . . . . . . . 1022
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . 1025
z/OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1025
z/OS XL C/C++ . . . . . . . . . . . . . . . . . . . . . . . . 1025
z/OS Metal C Runtime Library . . . . . . . . . . . . . . . . . . 1025
z/OS Run-Time Library Extensions. . . . . . . . . . . . . . . . . 1025
Debug Tool . . . . . . . . . . . . . . . . . . . . . . . . . 1025
z/OS Language Environment . . . . . . . . . . . . . . . . . . . 1026
Assembler. . . . . . . . . . . . . . . . . . . . . . . . . . 1026
COBOL. . . . . . . . . . . . . . . . . . . . . . . . . . . 1026
PL/I . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1026
VS FORTRAN . . . . . . . . . . . . . . . . . . . . . . . . 1026
CICS Transaction Server for z/OS . . . . . . . . . . . . . . . . . 1026
DB2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1026
IMS/ESA . . . . . . . . . . . . . . . . . . . . . . . . . . 1026
MVS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1026
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029
Contents xiii
xiv z/OS V1R13.0 XL C/C++ Programming Guide
Figures
1. Blocking fixed-length records . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2. Variable-length records on z/OS . . . . . . . . . . . . . . . . . . . . . . . . . 15
3. Memory file example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4. ASA Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5. ungetwc() Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6. Interleaving I/O with sync_with_stdio() . . . . . . . . . . . . . . . . . . . . . . . 63
7. Interleaving I/O without sync_with_stdio() . . . . . . . . . . . . . . . . . . . . . . 65
8. MVS example of redirecting three standard streams by ddnames . . . . . . . . . . . . . 71
9. Example of using stdout and stderr to share the same file. . . . . . . . . . . . . . . . 72
10. Example of passing text streams . . . . . . . . . . . . . . . . . . . . . . . . . 74
11. Example of passing record I/O streams . . . . . . . . . . . . . . . . . . . . . . 76
12. Example of command line redirection . . . . . . . . . . . . . . . . . . . . . . . 79
13. Generation data group example for C . . . . . . . . . . . . . . . . . . . . . . . 86
14. Generation data group example for C++ . . . . . . . . . . . . . . . . . . . . . . 87
15. How the operating system completes the DCB . . . . . . . . . . . . . . . . . . . 102
16. Example of reading updated records . . . . . . . . . . . . . . . . . . . . . . . 110
17. Example of signal handler . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
18. fldata() Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
19. Unnamed pipes example . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
20. Named pipes example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
21. Example of z/OS UNIX stream input and output functions . . . . . . . . . . . . . . . 137
22. Example of HFS stream input and output functions . . . . . . . . . . . . . . . . . . 141
23. fldata() structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
24. Types and advantages of VSAM data sets . . . . . . . . . . . . . . . . . . . . . 149
25. VSAM example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
26. KSDS example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
27. KSDS example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
28. RRDS example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
29. fldata() structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
30. fldata() structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
31. Removing members of a PDS . . . . . . . . . . . . . . . . . . . . . . . . . 204
32. Renaming members of a PDS . . . . . . . . . . . . . . . . . . . . . . . . . 205
33. fldata() structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
34. Memory file example, part 1 . . . . . . . . . . . . . . . . . . . . . . . . . . 211
35. Memory file example, part 2 . . . . . . . . . . . . . . . . . . . . . . . . . . 212
36. fldata() structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
37. fldata() example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
38. CELQPIPI MSGRTN example . . . . . . . . . . . . . . . . . . . . . . . . . 219
39. __amrc structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
40. Example of printing the __amrc structure . . . . . . . . . . . . . . . . . . . . . 224
41. __amrc2 structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
42. Example of using SIGIOERR . . . . . . . . . . . . . . . . . . . . . . . . . . 230
43. Sample File I/O Trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
44. Example of parameter lists For OS linkages . . . . . . . . . . . . . . . . . . . . 245
45. EDCXPRLG macro with an ALIAS statement . . . . . . . . . . . . . . . . . . . . 250
46. Call to an XPLINK routine with no parameters . . . . . . . . . . . . . . . . . . . 251
47. Call to an XPLINK routine with 5 parameters . . . . . . . . . . . . . . . . . . . . 252
48. Establishing the C run-time environment . . . . . . . . . . . . . . . . . . . . . . 253
49. Calling an intermediate C function from Assembler OS linkage . . . . . . . . . . . . . 254
50. Intermediate C routine calling a run-time library function . . . . . . . . . . . . . . . . 254
51. Establishing the XL C/C++ run-time environment. . . . . . . . . . . . . . . . . . . 255
52. Calling an intermediate XL C/C++ function from Assembler using OS linkage . . . . . . . . 255
53. Intermediate XL C/C++ routine calling a run-time library function . . . . . . . . . . . . . 256
Copyright IBM Corp. 1996, 2012 xv
54. Interface for preinitializable programs . . . . . . . . . . . . . . . . . . . . . . . 258
55. Preinitializing a C program (CCNGCA6) . . . . . . . . . . . . . . . . . . . . . . 262
56. Using the preinitializable program (CCNGCA7) . . . . . . . . . . . . . . . . . . . 264
57. Using the preinitializable program (CCNGCA8) . . . . . . . . . . . . . . . . . . . 265
58. JCL for running a preinitializable C program . . . . . . . . . . . . . . . . . . . . 267
59. Explicit use of a DLL in an application using the dllload() family of functions . . . . . . . . 283
60. Explicit use of a DLL in an application using the dlopen() family of functions . . . . . . . . 285
61. Using #pragma export to create a DLL executable module named BASICIO . . . . . . . . 289
62. Using #pragma export to create the triangle DLL executable module . . . . . . . . . . . 290
63. Using _Export to create the triangle DLL executable module . . . . . . . . . . . . . . 290
64. Summary of DLL and DLL application preparation and usage . . . . . . . . . . . . . . 294
65. Referencing functions and external variables in DLL code . . . . . . . . . . . . . . . 304
66. Pointer Assignment in DLL code. . . . . . . . . . . . . . . . . . . . . . . . . 305
67. Pointer assignment in non-DLL code . . . . . . . . . . . . . . . . . . . . . . . 306
68. File 1. Application A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
69. File 2. Application A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
70. File 3. Application B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
71. File 4. DLL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
72. DLL function pointer call in non-DLL code . . . . . . . . . . . . . . . . . . . . . 309
73. DLL function pointer call in non-DLL code . . . . . . . . . . . . . . . . . . . . . 310
74. C non-DLL code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
75. C DLL code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
76. C++ DLL code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
77. C++ DLL code calling an Assembler function . . . . . . . . . . . . . . . . . . . . 312
78. Comparison of function pointers in non-DLL code . . . . . . . . . . . . . . . . . . 313
79. C DLL code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
80. C non-DLL code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
81. File 1 C DLL code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
82. File 2 C DLL code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
83. File 3 C non-DLL code . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
84. Comparison of two DLL function pointers in non-DLL code . . . . . . . . . . . . . . . 315
85. Undefined comparison in DLL code (C or C++) . . . . . . . . . . . . . . . . . . . 316
86. Comparison of function pointers in DLL code (C or C++) . . . . . . . . . . . . . . . . 316
87. Valid comparisons in DLL code (C or C++) . . . . . . . . . . . . . . . . . . . . . 317
88. Application CCNGA2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
89. Application CCNGA2D1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
90. Application CCNGA2D2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
91. Application CCNGA2D3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
92. CCNGA2M1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
93. CCNGA2M2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
94. Comparison of struct li, alignments under ILP32 and LP64 . . . . . . . . . . . . . . . 335
95. Comparison of struct lii alignments under ILP32 and LP64 . . . . . . . . . . . . . . . 336
96. Comparison of struct ili alignments under ILP32 and LP64 . . . . . . . . . . . . . . . 337
97. Example of potential alignment problems when a struct is shared or exchanged among 32-bit
and 64-bit processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
98. Example of user-defined data padding for a structure that is shared or exchanged among 32-bit
and 64-bit processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
99. Referring to thread-specific data . . . . . . . . . . . . . . . . . . . . . . . . . 360
100. Controlling external static . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
101. Making strings constant . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
102. Example of controllong the memory area . . . . . . . . . . . . . . . . . . . . . 372
103. How to Make String Literals Modifiable . . . . . . . . . . . . . . . . . . . . . . 373
104. Referencing objects in the writable static area, Part 1 . . . . . . . . . . . . . . . . . 374
105. Referencing objects in the writable static area, Part 2 . . . . . . . . . . . . . . . . . 375
106. Arithmetic operators example . . . . . . . . . . . . . . . . . . . . . . . . . . 380
107. Relational operators example . . . . . . . . . . . . . . . . . . . . . . . . . . 381
Figures xvii
164. Sample Freestanding z/OS Routine . . . . . . . . . . . . . . . . . . . . . . . 625
165. Link edit control statements used to build a freestanding z/OS routine . . . . . . . . . . . 626
166. Compile and link using EDCCL . . . . . . . . . . . . . . . . . . . . . . . . . 626
167. Sample reentrant freestanding z/OS routine . . . . . . . . . . . . . . . . . . . . 626
168. Building and running a reentrant freestanding z/OS routine . . . . . . . . . . . . . . . 627
169. System exit example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630
170. Example of function used in a persistent C environment . . . . . . . . . . . . . . . . 634
171. Using a persistent C environment . . . . . . . . . . . . . . . . . . . . . . . . 635
172. Example of user routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
173. Example of application service routine . . . . . . . . . . . . . . . . . . . . . . 640
174. Example of server initialization stub . . . . . . . . . . . . . . . . . . . . . . . 644
175. Example of server message stub-LIFO . . . . . . . . . . . . . . . . . . . . . . 646
176. Example of server message stub-FIFO . . . . . . . . . . . . . . . . . . . . . . 647
177. Example of server message stub-GET . . . . . . . . . . . . . . . . . . . . . . 649
178. Example of server message stub-TERM . . . . . . . . . . . . . . . . . . . . . . 650
179. Example of routine to generate abend . . . . . . . . . . . . . . . . . . . . . . 654
180. Example of routine to get storage . . . . . . . . . . . . . . . . . . . . . . . . 655
181. Example of routine to free storage . . . . . . . . . . . . . . . . . . . . . . . . 656
182. Location of user exits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668
183. Interface for Assembler user exits . . . . . . . . . . . . . . . . . . . . . . . . 673
184. CEEAUE_FLAGS format . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
185. Exit_list and hook_exit control blocks . . . . . . . . . . . . . . . . . . . . . . . 683
186. Computational independence . . . . . . . . . . . . . . . . . . . . . . . . . . 686
187. Example of a C program running without MTF . . . . . . . . . . . . . . . . . . . 687
188. Processor usage with one parallel function . . . . . . . . . . . . . . . . . . . . . 689
189. Sample program using one parallel function . . . . . . . . . . . . . . . . . . . . 690
190. Processor usage with two parallel function . . . . . . . . . . . . . . . . . . . . . 690
191. Sample program using two parallel functions . . . . . . . . . . . . . . . . . . . . 691
192. Processor use with multiple instances of the same parallel function . . . . . . . . . . . . 692
193. Sample program using multiple instances of the same parallel function . . . . . . . . . . 693
194. Basic MTF layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695
195. Identifying Computationally-Independent Code . . . . . . . . . . . . . . . . . . . 698
196. Sample code as a parallel function . . . . . . . . . . . . . . . . . . . . . . . . 698
197. Scheduling instances of a parallel function . . . . . . . . . . . . . . . . . . . . . 699
198. Main task program to call dot product function . . . . . . . . . . . . . . . . . . . 699
199. Sample code to be changed to use MTF . . . . . . . . . . . . . . . . . . . . . 700
200. Sample code (main routine) . . . . . . . . . . . . . . . . . . . . . . . . . . 701
201. Sample code (routine to create parallel functions) . . . . . . . . . . . . . . . . . . 702
202. Sample JCL to compile and link main task program . . . . . . . . . . . . . . . . . 703
203. Sample JCL to compile and link parallel functions . . . . . . . . . . . . . . . . . . 703
204. Source code for EDCMTFS . . . . . . . . . . . . . . . . . . . . . . . . . . 704
205. Example run-time JCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
206. Example illustrating how to use EXEC CICS commands . . . . . . . . . . . . . . . . 714
207. Format of data written to a CICS data queue . . . . . . . . . . . . . . . . . . . . 717
208. Example illustrating error handling under CICS . . . . . . . . . . . . . . . . . . . 723
209. Example illustrating how to use EXEC CICS commands . . . . . . . . . . . . . . . . 727
210. Child C program after translation . . . . . . . . . . . . . . . . . . . . . . . . 728
211. JCL to translate and compile a C program . . . . . . . . . . . . . . . . . . . . . 731
212. JCL to translate and compile a C++ program . . . . . . . . . . . . . . . . . . . . 731
213. Prelinking and linking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
214. JCL to install z/OS XL C/C++ application programs . . . . . . . . . . . . . . . . . . 734
215. C/370 CALLing CSP under TSO. . . . . . . . . . . . . . . . . . . . . . . . . 736
216. z/OS XL Ctransferring control to CSP under TSO using the XFER/DXFR statement . . . . . . 738
217. CSP CALLing z/OS XL C under TSO . . . . . . . . . . . . . . . . . . . . . . . 740
218. CSP transferring control to z/OS XL C under TSO using the XFER statement . . . . . . . . 741
219. CSP CALLing z/OS XL C under CICS . . . . . . . . . . . . . . . . . . . . . . 744
Figures xix
xx z/OS V1R13.0 XL C/C++ Programming Guide
Tables
1. Syntax examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxvi
2. C control to ASA characters . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3. Summary of prototype functions . . . . . . . . . . . . . . . . . . . . . . . . . 25
4. Kinds of I/O supported by z/OS XL C/C++ . . . . . . . . . . . . . . . . . . . . . 27
5. I/O categories and environments that support them . . . . . . . . . . . . . . . . . . 28
6. fopen() defaults for LRECL and BLKSIZE when creating OS files . . . . . . . . . . . . . 33
7. C control to ASA characters translation table . . . . . . . . . . . . . . . . . . . . 47
8. Manipulating wide character arrays . . . . . . . . . . . . . . . . . . . . . . . . 59
9. Standard C and C++ streams . . . . . . . . . . . . . . . . . . . . . . . . . . 61
10. z/OS XL C/C++ Redirection symbols . . . . . . . . . . . . . . . . . . . . . . . 67
11. Output destinations under z/OS XL C/C++ . . . . . . . . . . . . . . . . . . . . . 68
12. z/OS XL C/C++ Interleaved output . . . . . . . . . . . . . . . . . . . . . . . . 69
13. Association of standard streams with ddnames . . . . . . . . . . . . . . . . . . . . 71
14. Standard stream behavior differences . . . . . . . . . . . . . . . . . . . . . . . 77
15. PDSE and PDS differences . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
16. Rules for possible concatenations . . . . . . . . . . . . . . . . . . . . . . . . 90
17. Other devices supported for input and output . . . . . . . . . . . . . . . . . . . . 94
18. Parameters for the fopen() and freopen() functions for z/OS OS I/O . . . . . . . . . . . . 95
19. fopen() defaults for LRECL and BLKSIZE when creating OS files . . . . . . . . . . . . 102
20. C control to ASA characters . . . . . . . . . . . . . . . . . . . . . . . . . . 107
21. Parameters for the fopen() and freopen() functions for z/OS UNIX file system I/O . . . . . . 127
22. Summary of VSAM data set characteristics and allowable I/O operations. . . . . . . . . . 151
23. Keywords for the fopen() and freopen() functions for VSAM data sets . . . . . . . . . . . 155
24. Summary of VSAM record I/O operations . . . . . . . . . . . . . . . . . . . . . 164
25. AMODE31 application XADDR support . . . . . . . . . . . . . . . . . . . . . . 167
26. Summary of fseek() and ftell() parameters in text and binary . . . . . . . . . . . . . . 170
27. Summary of VSAM text I/O operations . . . . . . . . . . . . . . . . . . . . . . 171
28. Summary of VSAM binary I/O operations . . . . . . . . . . . . . . . . . . . . . 171
29. Keywords for the fopen() and freopen() functions for terminal I/O. . . . . . . . . . . . . 190
30. Keywords for the fopen() and freopen() functions for memory file I/O . . . . . . . . . . . 201
31. __last_op codes and diagnosis information . . . . . . . . . . . . . . . . . . . . . 225
32. Linkage used by C or C++ Interlanguage Programs . . . . . . . . . . . . . . . . . 238
33. Comparison of non-XPLINK and XPLINK register conventions. . . . . . . . . . . . . . 246
34. Load service routine parameters. . . . . . . . . . . . . . . . . . . . . . . . . 271
35. Delete service routine parameters . . . . . . . . . . . . . . . . . . . . . . . . 272
36. Get-storage service routine parameters . . . . . . . . . . . . . . . . . . . . . . 272
37. Free-storage service routine parameters . . . . . . . . . . . . . . . . . . . . . . 273
38. Exception router service routine parameters . . . . . . . . . . . . . . . . . . . . 273
39. Attention router service routine parameters . . . . . . . . . . . . . . . . . . . . . 275
40. Attention handler parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 275
41. Message router service routine parameters. . . . . . . . . . . . . . . . . . . . . 276
42. Summary of DLL concepts and terms . . . . . . . . . . . . . . . . . . . . . . . 280
43. Example programs to demonstrate compiling options . . . . . . . . . . . . . . . . . 302
44. Examples of how to compile two source modules and list result . . . . . . . . . . . . . 302
45. Referencing functions and external variables . . . . . . . . . . . . . . . . . . . . 303
46. Comparison of ILP32 and LP64 addressing capabilities . . . . . . . . . . . . . . . . 325
47. Comparison of ILP32 and LP64 data models . . . . . . . . . . . . . . . . . . . . 325
48. ILP32 and LP64 type size comparisons for signed and unsigned data types . . . . . . . . 326
49. Example of diagnostic messages generated from code that is not ready to be migrated from
ILP32 to LP64 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
50. Comparison of ILP32 and LP64 processing and run-time options. . . . . . . . . . . . . 332
51. Comparison of data structure member lengths produced from the same code . . . . . . . . 334
52. Example of possible change of result after conversion from signed number to unsigned long 338
Copyright IBM Corp. 1996, 2012 xxi
53. Example of possible change of result after conversion from unsigned int variable to signed long 338
54. Example of possible change of result after conversion from signed long long variable to signed
long . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
55. Example of possible change of result after conversion from unsigned long long variable to
unsigned long . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
56. Example of possible change of result after conversion from signed long long variable to signed
long . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
57. Example of possible change of result after conversion from unsigned long long variable to signed
long . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
58. Examples of pointer declarations that can be made under LP64 . . . . . . . . . . . . . 341
59. Example of source code that explicitly converts an integer to a pointer . . . . . . . . . . 343
60. Example of truncation problem with a pointer cast conversion . . . . . . . . . . . . . . 343
61. Type of an integer constant . . . . . . . . . . . . . . . . . . . . . . . . . . 344
62. An attempt to share pointers between 32-bit and 64-bit processes . . . . . . . . . . . . 345
63. Example of unexpected behavior resulting from use of unsuffixed numbers . . . . . . . . . 346
64. Example of using LONG_MAX macros in a printf subroutine . . . . . . . . . . . . . . 347
65. Example of source code that successfully shares pointers between ILP32 and LP64 programs 349
66. Functions used in creating multi-threaded applications . . . . . . . . . . . . . . . . 353
67. Functions to change default attributes. . . . . . . . . . . . . . . . . . . . . . . 353
68. Functions used to control individual threads in a multi-threaded environment . . . . . . . . 354
69. Functions that allow for synchronization between threads . . . . . . . . . . . . . . . 355
70. Functions used with thread-specific data. . . . . . . . . . . . . . . . . . . . . . 359
71. Cancellation point summary . . . . . . . . . . . . . . . . . . . . . . . . . . 363
72. Functions used to control cancellability . . . . . . . . . . . . . . . . . . . . . . 363
73. Functions used for cleanup purposes . . . . . . . . . . . . . . . . . . . . . . . 364
74. Declarations of fixed-point decimal constants . . . . . . . . . . . . . . . . . . . . 378
75. Examples of Fixed-Point decimal constants and their attributes . . . . . . . . . . . . . 378
76. Intermediate results (without overflow in n or p) . . . . . . . . . . . . . . . . . . . 382
77. Intermediate results (in the general form) . . . . . . . . . . . . . . . . . . . . . 382
78. Operators used with decimal data types . . . . . . . . . . . . . . . . . . . . . . 384
79. C/C++ functions that support floating-point . . . . . . . . . . . . . . . . . . . . . 399
80. Special purpose C/C++ functions that support floating-point. . . . . . . . . . . . . . . 401
81. Functions that establish a signal handler . . . . . . . . . . . . . . . . . . . . . 412
82. Other signal-related functions . . . . . . . . . . . . . . . . . . . . . . . . . . 412
83. Hardware exceptions - Default run-time messages and system actions . . . . . . . . . . 417
84. Software exceptions - Default run-time messages and system actions with POSIX(OFF) 417
85. Default signal processing with POSIX(ON) . . . . . . . . . . . . . . . . . . . . . 419
86. Original versions of fdlibm functions . . . . . . . . . . . . . . . . . . . . . . . 494
87. Standard general-instruction prototypes . . . . . . . . . . . . . . . . . . . . . . 503
88. Built-in general-instruction prototypes . . . . . . . . . . . . . . . . . . . . . . . 505
89. PLO helper macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
90. Compare and load prototypes . . . . . . . . . . . . . . . . . . . . . . . . . 523
91. Compare and swap prototypes . . . . . . . . . . . . . . . . . . . . . . . . . 524
92. Double compare and swap prototypes . . . . . . . . . . . . . . . . . . . . . . 524
93. Compare and swap and store prototypes . . . . . . . . . . . . . . . . . . . . . 525
94. Compare swap and double store prototypes . . . . . . . . . . . . . . . . . . . . 525
95. Compare and swap and triple store prototypes . . . . . . . . . . . . . . . . . . . 526
96. Decimal instruction prototypes . . . . . . . . . . . . . . . . . . . . . . . . . 527
97. Floating-point instruction prototypes . . . . . . . . . . . . . . . . . . . . . . . 528
98. Decimal floating-point instruction prototypes for IEEE operations . . . . . . . . . . . . . 529
99. Decimal floating-point instruction prototypes for IEEE . . . is operations . . . . . . . . . . 531
100. Decimal floating-point instruction prototypes for IBM Instructions . . . . . . . . . . . . . 532
101. Hexadecimal floating-point instruction prototypes . . . . . . . . . . . . . . . . . . 538
102. Binary floating-point instruction prototypes . . . . . . . . . . . . . . . . . . . . . 539
103. Built-in functions for transactional memory . . . . . . . . . . . . . . . . . . . . . 542
104. SUSv3 options and option groups . . . . . . . . . . . . . . . . . . . . . . . . 550
Tables xxiii
xxiv z/OS V1R13.0 XL C/C++ Programming Guide
About this document
This document provides information about implementing programs that are written
in C and C++. It contains advanced guidelines and information for developing C and
C++ programs to run under z/OS.
Note: As of z/OS V1R7, the z/OS C/C++ compiler has been rebranded to z/OS XL
C/C++.
You may notice changes in the style and structure of some of the contents in this
document; for example, headings that use uppercase for the first letter of initial
words only, and procedures that have a different look and format. The changes are
ongoing improvements to the consistency and retrievability of information in our
documents.
Syntax diagrams pictorially display the order and parts (options and arguments) that
comprise a command statement. They are read from left to right and from top to
bottom, following the main path of the horizontal line.
For users accessing the Information Center using a screen reader, syntax diagrams
are provided in dotted decimal format.
Symbols
The following symbols may be displayed in syntax diagrams:
Symbol Definition
Indicates the beginning of the syntax diagram.
Indicates that the syntax diagram is continued to the next line.
Indicates that the syntax is continued from the previous line.
Indicates the end of the syntax diagram.
Syntax items
Syntax diagrams contain many different items. Syntax items include:
v Keywords - a command name or any other literal information.
v Variables - variables are italicized, appear in lowercase, and represent the name
of values you can supply.
v Delimiters - delimiters indicate the start or end of keywords, variables, or
operators. For example, a left parenthesis is a delimiter.
v Operators - operators include add (+), subtract (-), multiply (*), divide (/), equal
(=), and other mathematical operations that may need to be performed.
Note: If a syntax diagram shows a character that is not alphanumeric (for example,
parentheses, periods, commas, equal signs, a blank space), enter the character as
part of the syntax.
Syntax examples
The following table provides syntax examples.
Table 1. Syntax examples
Item Syntax example
Required item.
KEYWORD required_item
Required items appear on the main path of the
horizontal line. You must specify these items.
Required choice.
KEYWORD required_choice1
A required choice (two or more items) appears
in a vertical stack on the main path of the
required_choice2
horizontal line. You must choose one of the
items in the stack.
Optional item.
KEYWORD
Optional items appear below the main path of
the horizontal line.
optional_item
Optional choice.
KEYWORD
An optional choice (two or more items) appears
in a vertical stack below the main path of the
optional_choice1
horizontal line. You may choose one of the optional_choice2
items in the stack.
Default.
default_choice1
Default items appear above the main path of
the horizontal line. The remaining items
KEYWORD
(required or optional) appear on (required) or optional_choice2
below (optional) the main path of the horizontal optional_choice3
line. The following example displays a default
with optional items.
Variable.
KEYWORD variable
Variables appear in lowercase italics. They
represent names or values.
This document is updated weekly and lists documentation changes before they are
incorporated into z/OS publications.
To access the z/OS Basic Skills Information Center, open your Web browser to the
following Web site, which is available to all users (no login required):
http://publib.boulder.ibm.com/infocenter/zos/basics/index.jsp
IBM or any other organizations will only use the personal information that you
supply to contact you about the issues that you submit.
New information:
v A new environment variable has been added to provide enhanced I/O abend
recovery support; see _EDC_IO_ABEND on page 494 for more information.
v The abend= parameter has been added to the fopen() and freopen() functions;
this parameter controls if the run-time library should attempt to recover from an
abend that is issued during an I/O operation. In addition, the rlse and norlse
keywords have been added to the space= parameter. See Table 18 on page 95
for more information.
v Support for 10 new text locales has been added; see Table 140 on page 937 for
details.
v Support for new standard and built-in general instruction prototypes has been
added; for more information, see Table 88 on page 505.
v New built-in functions have been added to mark the beginning and end of
transactions, and to diagnose the reasons for failure. For detailed information,
see Built-in functions for transaction execution on page 541.
Changed information:
v Information about the preservation of the contents of high registers has been
added to Get-storage service routine on page 272 and Free-storage service
routine on page 273.
v Information about large file support has been clarified in Chapter 10, Performing
OS I/O operations, on page 81.
v Figure 157 on page 556 (saved options information layout) has been updated.
v Reference information about using UCS-2 codeset conversion has been updated
in Codeset conversion using UCS-2 on page 880.
Deleted information:
v Information about using fseek() and ftell() in binary files been removed.
v Information about default signal processing with POSIX(ON) for the SIGDCE
event has been removed.
New information:
v Information has been added for the z/OS XL C/C++ support for accessing an
extended addressable VSAM KSDS data set through an alternate index. For the
details, see Chapter 12, Performing VSAM I/O operations, on page 147.
Changed information:
v Updated getdate_err on page 1008 in Appendix J, External variables, on page
1007.
v An restriction has been added to the _BPXK_AUTOCVT and _BPXK_CCSIDS
environment variables in Chapter 32, Using environment variables, on page
467.
v Updated Chapter 58, Customizing a time zone, on page 847.
v The "Readers' Comments - We'd Like to Hear from You" section at the back of
this publication has been replaced with a new section How to send your
comments to IBM on page xxix. The hardcopy mail-in form has been replaced
with a page that provides information appropriate for submitting readers
comments to IBM.
New information:
v Information has been added for the support of z/OS XL C/C++ compiler direction.
Using built-in library functions and macros on page 577 has been updated to
indicate replacing wcsxxx() functions with their corresponding wmemxxx()
functions, whenever possible.
The C-library built-in functions described in Table 111 on page 583 have been
updated with new information.
Using functions in the system programming C environment on page 620 has
been updated to indicate that 4 new functions are available as built-in.
v A new compiled ASCII locale has been added to Table 140 on page 937.
v File I/O trace on page 232 and Locating the file I/O trace on page 233 has
been added to Chapter 18, Debugging I/O programs, on page 221.
Changed information:
v Updates have been made to fldata() behavior on page 119.
v IEEE binary and decimal floating-point can be supported in a CICS environment.
See Using IEEE floating-point on page 398.
v Table 79 on page 399 has been updated with more C/C++ functions that support
floating point.
v A note in Chapter 10, Performing OS I/O operations, on page 81 has been
updated to indicate z/OS XL C/C++ does not support non-VSAM keyed data sets.
v Updates have been made to Identifying hardware and software signals on page
415 and Default handling of signals on page 418.
v Updates have been made to Overview of the layout functions on page 904 and
Using the layout functions on page 909.
The C run-time functions are available if the corresponding C header files are used.
C I/O can be used by C++ when the C run-time library functions are used.
The z/OS XL C/C++ compiler supports three types of input and output: text streams,
binary streams, and record I/O. Text and binary streams are both ANSI standards;
record I/O is an extension for z/OS XL C. Record I/O is not supported by either the
USL I/O Stream Class Library or the Standard C++ I/O stream classes.
Note: If you have written data in one of these three types and try to read it as
another type (for example, reading a binary file in text mode), you may not get the
behavior that you expect.
Text streams
Text streams contain printable characters and, depending on the type of file, control
characters. Text streams are organized into lines. Each line ends with a control
character, usually a new-line. The last record in a text file may or may not end with
a control character, depending on what kind of file you are using. Text files
recognize the following control characters:
\a Alarm.
\b Backspace.
\f Form feed.
\n New-line.
\r Carriage return.
\t Horizontal tab character.
\v Vertical tab character.
\x0E DBCS shift-out character. Indicates the beginning of a DBCS string, if
MB_CUR_MAX>1 in the definition of the locale that is in effect. For more
information about __MBCURMAX, see Chapter 8, z/OS XL C Support for the
double-byte character set, on page 51.
\x0F DBCS shift-in character. Indicates the end of a DBCS string, if
MB_CUR_MAX>1 in the definition of the locale that is in effect. For more
information about __MBCURMAX, see Chapter 8, z/OS XL C Support for the
double-byte character set, on page 51.
Control characters behave differently in terminal files (see Chapter 13, Performing
terminal I/O operations, on page 189) and ASA files (see Chapter 7, Using ASA
text files, on page 47).
Record I/O
Record I/O is an extension to the ISO standard. For files opened in record format,
z/OS XL C/C++ reads and writes one record at a time. If you try to write more data
to a record than the record can hold, the data is truncated. For record I/O, z/OS XL
C/C++ allows only the use of fread() and fwrite() to read and write to files. Any
other functions (such as fprintf(), fscanf(), getc(), and putc()) will fail. For
record-oriented files, records do not change size when you update them. If the new
record has fewer characters than the original record, the new data fills the first n
characters, where n is the number of characters of the new data. The record will
remain the same size, and the old characters (those after n) are left unchanged. A
subsequent update begins at the next boundary. For example, if you have the string
"abcdefgh":
a b c d e f g h
and you overwrite it with the string "1234", the record will look like this:
1 2 3 4 e f g h
z/OS XL C/C++ record I/O is binary. That is, it does not interpret any of the data in
a record file and therefore does not recognize control characters. The only
exception is for file categories that do not support records, such as the UNIX file
system (also known as POSIX I/O). For these files, z/OS XL C/C++ uses new-line
characters as record boundaries.
The next chapter (Chapter 4, Using the Standard C++ Library I/O Stream Classes,
on page 21) describes a third major model, the object-oriented model.
In the record model of I/O, records and blocks have the following attributes:
RECFM Specifies the format of the data or how the data is organized on the
physical device.
LRECL Specifies the length of logical records (as opposed to physical
ones). Variable length records include a count field that is normally
not available to the programmer.
BLKSIZE Specifies the length of physical records (blocks on the physical
device).
Record formats
Use the RECFM attribute to specify the record format. The records in a file using the
record model have one of the following formats:
v Fixed-length (F)
v Variable-length (V)
v Undefined-length (U)
These formats support the following additional options for RECFM. The record formats
and the options associated with them are discussed in the following sections.
A Specifies that the file contains ASA control characters.
B Specifies that a file is blocked. A blocked file can have more than one
record in each block.
M Specifies that the file contains machine control characters.
S Specifies that a file is either in standard format (if it is fixed) or spanned (if it
is variable). In a standard file, every block must be full before another one
starts. In a spanned file, a record can be longer than a block. If it is, the
record is divided into segments and stored in consecutive blocks.
Fixed-format records
These are the formats you can specify for RECFM if you want to use a fixed-format
file:
F Fixed-length, unblocked
FA Fixed-length, ASA print-control characters
FB Fixed-length, blocked
FM Fixed-length, machine print-control codes
FS Fixed-length, unblocked, standard
FBA Fixed-length, blocked, ASA print-control characters
FBM Fixed-length, blocked, machine print-control codes
FBS Fixed-length, blocked, standard
FSA Fixed-length, unblocked, standard, ASA print-control characters
FSM Fixed-length, unblocked, standard, machine print-control codes
FBSM Fixed-length, blocked, standard, machine print-control codes
FBSA Fixed-length, blocked, standard, ASA print-control characters.
In general, all references to files with record format FB also refer to FBM and FBA.
The specific behavior of ASA files (such as FBA) is explained in Chapter 7, Using
ASA text files, on page 47.
If the records are FB, some blocks may contain fewer records than others, as shown
in Figure 1 on page 11.
Block Block
Mapping C types to fixed format: This section describes the following formats:
v Binary
v Text (non-ASA)
v Text (ASA)
v Record
Binary On binary input and output, data flows over record boundaries.
Because all fixed-format records must be full, z/OS XL C/C++
completes any incomplete output record by padding it with nulls
(\0) when you close the file. Incomplete blocks are not padded.
On input, nulls are visible and are treated as data.
For example, if record length is set to 10 and you are writing 25
characters of data, z/OS XL C/C++ will write two full records, each
containing 10 characters, and then an incomplete record containing
5 characters. If you then close the file, z/OS XL C/C++ will
complete the last record with 5 nulls. If you open the file for
reading, z/OS XL C/C++ will read the records in order. z/OS XL
C/C++ will not strip off the nulls at the end of the last record.
Text (non-ASA)
When writing in a text stream, you indicate the end of the data for a
record by writing a new-line (\n) or carriage return (\r) to the
stream. In a fixed-format file, the new-line or carriage return will not
appear in the external file, and the record will be padded with
blanks from the position of the new-line or carriage return to
LRECL. (A carriage return is considered the same as a new-line
because the \r is not written to the file.)
For example, if you have set LRECL to 10, and you write the string
"ABC\n" to a fixed-format text file, z/OS XL C/C++ will write this to
the physical file:
A B C
file pointer
and you call fgets() to read the line of text, fgets() places the
string "ABC\n" in your input buffer.
1 2 3 4 5 6
file pointer
A B C D E F ...
You can lengthen and shorten records the same way as you can for
non-ASA files. For more information about ASA, refer to Chapter 7,
Using ASA text files, on page 47.
Record As with fixed-format text files, a record can hold LRECL characters.
Every call to fwrite() is considered to be writing a full record. If
you write fewer than LRECL characters, z/OS XL C/C++ completes
the record with enough nulls to make it LRECL characters long. If
you try to write more than that, z/OS XL C/C++ truncates the data.
Variable-format records
In a file with variable-length records, each record may be a different length. The
variable length formats permit both variable-length records and variable-length
blocks. The first 4 bytes of each block are reserved for the Block Descriptor Word
(BDW); the first 4 bytes of each record are reserved for the Record Descriptor Word
(RDW), or, if you are using spanned files, the Segment Descriptor Word (SDW).
Illustrations of variable-length records are shown in Figure 2 on page 15.
The value of LRECL must be greater than 4 to accommodate the RDW or SDW.
The value of BLKSIZE must be greater than or equal to the value of LRECL plus 4.
You should not use a BLKSIZE greater than LRECL plus 4 for an unblocked data
set. Doing so results in buffers that are larger than they need to be. The largest
amount of data that any one record can hold is LRECL bytes minus 4.
For striped data sets, a block is padded out to its full BLKSIZE. This makes
specifying an unnecessarily large BLKSIZE very inefficient.
Record format (RECFM): You can specify the following formats for variable-length
records:
V Variable-length, unblocked
VA Variable-length, ASA print control characters, unblocked
VB Variable-length, blocked
VM Variable-length, machine print-control codes, unblocked
VS Variable-length, unblocked, spanned
VBA Variable-length, blocked, ASA print control characters
VBM Variable-length, blocked, machine print-control codes
VBS Variable-length, blocked, spanned
VSA Variable-length, spanned, ASA print control characters
VSM Variable-length, spanned, machine print-control codes
VBSA Variable-length, blocked, spanned, ASA print control characters
VBSM Variable-length, blocked, spanned, machine print-control codes
Note: In general, all references in this guide to files with record format VB also refer
to VBM and VBA. The specific behavior of ASA files (such as VBA) is explained in
Chapter 7, Using ASA text files, on page 47.
Spanned records: A spanned record is opened using both V and S in the format
specifier. A spanned record is a variable-length record in which the length of the
record can exceed the size of a block. If it does, the record is divided into segments
and accommodated in two or more consecutive blocks. The use of spanned records
allows you to select a block size, independent of record length, that will combine
optimum use of auxiliary storage with the maximum efficiency of transmission.
VS-format specifies that each block contains only one record or segment of a
record. The first 4 bytes of a block describe the block control information. The
VBS-format differs from VS-format in that each block in VBS-format contains as many
complete records or segments as it can accommodate, while each block in
VS-format contains at most one record per block.
V-format:
C1 C2 Record 1 C1 C2 Record 2 C1 C2
VB-format:
Block
VS-format:
Spanned Record
VBS-format:
Spanned Record
Note: If you need to see the BDWs, RDWs, or SDWs, you can
open and read a V-format file as a U-format file. See
Undefined-format records on page 16 for more information.
z/OS XL C/C++ never creates empty binary records for files opened
in V-format. See Writing to binary files on page 106 for more
information. An empty binary record is one that contains only an
RDW, which is 4 bytes long. On input, empty records are ignored.
Text (non-ASA)
Record boundaries are used in the physical file to represent the
Undefined-format records
Everything in an undefined-format file is treated as data, including control
characters and record boundaries. Blocks in undefined-format records are
variable-length; each block is considered a record.
Record format (RECFM): You can specify the following formats for
undefined-length records:
U Undefined-length
UA Undefined-length, ASA print control characters
UM Undefined-length, machine print-control codes
U, UA, and UM formats permit the processing of records that do not conform to F- and
V-formats. The operating system treats each block as a record; your program must
perform any additional blocking or deblocking.
You can read any file in U-format. This is useful if, for example, you want to see the
BDWs and RDWs of a file that you have written in V-format.
If the file is opened in binary mode, any new-line characters previously written to
the file are visible on input. z/OS XL C/C++ memory file I/O and Hiperspace
memory file I/O are based on the byte stream model (see Chapter 14, Performing
memory file and hiperspace I/O operations, on page 199 for more information).
UNIX file system I/O, defined by POSIX, is also based on the byte stream model.
See Chapter 11, Performing z/OS UNIX file system I/O operations, on page 123
for information about I/O with UNIX file system.
A B C \n D E F \n ...
If you are using files with this model, do not use new-line
characters in your output. If you do, they will create extra record
boundaries. If you are unsure about the data being written or are
writing numeric data, use binary instead of text to avoid writing a
byte that has the hex value of a new-line.
There are two base classes, ios and streambuf, from which all other I/O stream
classes are derived. The ios class and its derivative classes are used to implement
formatting of I/O and maintain error state information of stream buffers implemented
with the streambuf class.
The I/O stream classes use OBJECTMODEL(COMPAT). They cannot be used with
other classes that use OBJECTMODEL(IBM), within the same inheritance
hierarchy. For more information, see OBJECTMODEL in z/OS XL C/C++ User's
Guide.
Note: The only exception is that cerr is unit-buffered (that is, ios::unitbuf is set).
A filebuf object is associated with each ifstream, ofstream, and fstream object.
When the filebuf is flushed, it writes to the underlying C stream, which has its own
buffer. The filebuf object follows every fwrite() to the underlying C stream with
an fflush().
Mixing the Standard C++ I/O stream classes, USL I/O stream class
library, and C I/O library functions
It is not recommended to mix the usage of the Standard C++ I/O stream classes,
USL I/O Stream Class Library, and C I/O library functions.
The USL I/O stream class library uses a separate buffer, which means that you
would need to flush the buffer after each call to cout either by setting ios::unitbuf
or by calling sync_with_stdio().
You should avoid switching between the formatted extraction functions of the C++
I/O stream classes and C stdio library functions whenever possible. You should
also avoid switching between versions of these classes.
For more information on mixing the I/O stream classes refer to Interleaving the
standard streams with sync_with_stdio() on page 63 and Interleaving the standard
streams without sync_with_stdio() on page 64.
For z/OS XL C++, overloaded fstream, ifstream, and ofstream constructors, and
open() member functions, with an additional parameter, are provided so you can
specify z/OS XL C fopen() mode values. You can use this additional parameter to
specify any z/OS XL C fopen() mode value except type=record. If you choose to
To open a file stream with a previously opened z/OS UNIX file descriptor, use the
fdopen() function.
To open files with UNIX file system low-level I/O, use the open() function. For more
information about opening files in UNIX file system, see Chapter 11, Performing
z/OS UNIX file system I/O operations, on page 123.
Prototypes of functions
Table 3 summarizes the prototypes of various functions. For more detailed
information about the C I/O stream functions, see z/OS XL C/C++ Run-Time Library
Reference. For more detailed information about the C++ I/O stream classes, see
Standard C++ Library Reference, which discusses the Standard C++ I/O stream
classes.
Table 3. Summary of prototype functions
Type of function Prototype
C Library Functions FILE *fopen(const char *filename, const char *mode);
// ifstream::open()
void open(const char* fname, int mode=ios::in,
int prot=filebuf::openprot);
// ofstream constructor
ofstream(const char* fname, int mode=ios::out,
int prot=filebuf::openprot);
// ofstream::open()
void open(const char* fname, int mode=ios::out,
int prot=filebuf::openprot);
// fstream::open()
void open(const char* fname, int mode,
int prot=filebuf::openprot);
// filebuf::open()
filebuf* open(const char* fname, int mode,
int prot=filebuf::openprot);
Note: CICS Data Queues and z/OS Language Environment Message File do not
apply in AMODE 64 applications. Hiperspace Memory Files are opened as (regular)
Memory Files since the size of a (regular) Memory File can exceed 2GB in AMODE
64 applications.
Table 4. Kinds of I/O supported by z/OS XL C/C++
Type of I/O Suggested Uses and Supported Devices Model Page
OS I/O Used for dealing with the following kinds of files: Record 81
v Generation data group
v MVS sequential DASD files
v Regular and extended partitioned data sets
v Tapes
v Printers
v Punch data sets
v Card reader data sets
v MVS inline JCL data sets
v MVS spool data sets
v Striped data sets
v Optical readers
UNIX file system I/O Used under z/OS UNIX System Services (z/OS UNIX) to support Byte stream 123
data sets in the UNIX file system, and access the byte-oriented
UNIX file system files according to POSIX .1 and XPG 4.2
interfaces. This increases the portability of applications written on
UNIX-based systems to z/OS XL C/C++ systems.
VSAM I/O Used for working with VSAM data sets. Supports direct access to Record 147
records by key, relative record number, or relative byte address.
Supports entry-sequenced, relative record, and key-sequenced
data sets.
Terminal I/O Used to perform interactive input and output operations with a Record 189
terminal.
Memory Files Used for applications requiring temporary I/O files without the Byte stream 199
overhead of system data sets. Fast and efficient.
Hiperspace Memory Used to deal with memory files as large as 2 gigabytes. Byte stream 199
Files
CICS Data Queues Used under the Customer Information Control System (CICS). Record 213
CICS data queues are automatically selected under CICS for the
standard streams stdout and stderr for C, or cout and cerr for
C++. The CICS I/O commands are supported through the
Command Level interface. The standard stream stdin under C (or
cin under C++) is treated as an empty file under CICS.
z/OS Language Used when you are running with z/OS Language Environment. The Record 215
Environment Message message file is automatically selected for stderr under z/OS
File Language Environment. For C++, automatic selection is of cerr.
Table 5 on page 28 lists the environments that z/OS XL C/C++ supports, and which
categories of I/O work in which environment.
OS files
z/OS XL C/C++ treats a file as an OS file, provided that it is not a CICS data
queue, or a UNIX file system, VSAM, memory, terminal, or Hiperspace file.
Terminal files
When you are running with the run-time option POSIX(OFF) under interactive TSO,
z/OS XL C/C++ associates streams to the terminal. You can also call fopen() to
open the terminal directly if you are running under TSO (interactive or batch), and
either the file name you specify begins with an asterisk (*), or the ddname has been
allocated with a DSN of *.
When running with POSIX(ON), z/OS XL C/C++ associates streams to the terminal
under TSO and a shell if the file name you have specified fits one of the following
criteria:
v Under TSO (interactive and batch), the name must begin with the sequence
//*, or the ddname must have been allocated with a DSN of *.
Interactive IMS and CICS behave differently from what is described here. For more
information about terminal files with interactive IMS and CICS see Chapter 9, Using
C and C++ standard streams and redirection, on page 61.
If you are running with POSIX(ON) outside a shell, you must use the regular z/OS XL
C/C++ I/O functions for terminal I/O. If you are running with POSIX(ON) from a shell,
you can use the regular z/OS XL C/C++ I/O functions or the POSIX low-level
functions (such as read()) for terminal I/O.
While a memory file exists, you can just use another fopen() or freopen() that
specifies the memory file's name. As sample program CCNGOF1 shows in Figure 3,
you do not have to specify type=memory.
/* this example shows how fopen() may be used with memory files */
#include <stdio.h>
char text[3], *result;
FILE * fp;
int main(void)
{
fp = fopen("a.b", "w, type=memory"); /* Opens a memory file */
fprintf(fp, "%d\n",10); /* Writes to the file */
fclose(fp); /* Closes the file */
fp = fopen("a.b", "r"); /* Reopens the same */
/* file (already */
/* a memory file) */
if ((result=fgets(text,3,fp)) !=NULL) /* Retrieves results */
printf("value retrieved is %s\n",result);
fclose(fp); /* Closes the file */
return(0);
}
A valid memory file name will match current file restrictions on a real file. Thus, a
memory file name that is classified as UNIX file system can have more characters
than can one classified as an MVS file name.
If you are not running under CICS, you can open a Hiperspace memory file as
follows:
fp = fopen("a.b", "w, type=memory(hiperspace)");
If you specify hiperspace and you are running in a CICS environment, z/OS XL
C/C++ opens a regular memory file. If you are running with the run-time options
You cannot use fopen() or freopen() to specify this kind of I/O. It is the category
selected automatically when you call any ANSI functions that reference stdout and
stderr under CICS. If you reference either of these in a C or C++ program under
CICS, z/OS XL C/C++ attempts to open the CESO (stdout) or CESE (stderr)
queue. If you want to write to any other queue, you should use the CICS-provided
interface.
See Chapter 16, Language Environment Message file operations, on page 215 for
more information on z/OS Language Environment message files.
When you call fopen() and specify a write mode (w, wb, w+, wb+, w+b) for an
existing file, z/OS XL C/C++ uses the default values for fopen() if:
v the data set is opened by the data set name or
v the data set is opened by ddname and the DD statement does not have any
attributes filled in.
These defaults are listed in Table 6 on page 33. To force z/OS XL C/C++ to use
existing attributes when you are opening a file, specify recfm=* (or recfm=+) on the
fopen() or freopen() call.
Certain categories of I/O may ignore or simulate some attributes such as BLKSIZE
or RECFM that are not physically supported on the device. Table 4 on page 27 lists
all the categories of I/O that z/OS XL C/C++ supports and directs you to where you
can find more information about them.
If you are creating a file and you do not select a record size, z/OS XL C/C++ uses a
default. See fopen() defaults on page 32 for details on how defaults are
calculated.
If you are creating a file and do not select a block size, z/OS XL C/C++ uses a
default. The defaults are listed in Table 6 on page 33.
fopen() defaults
You cannot specify a file attribute more than once on a call to fopen() or freopen().
If you do, the function call fails. If the file attributes specified on the call to fopen()
differ from the actual file attributes, fopen() usually fails. However, fopen() does
not fail if:
v The file is opened for w, w+, wb, or wb+, and the file is neither an existing PDS or
PDSE nor an existing file opened by a ddname that specifies DISP=MOD. In such
instances, fopen() attributes override the actual file attributes. However, if
recfm=* (or recfm=+) is specified on the fopen(), any attributes that are not
specified either on the fopen() or for the ddname will be retrieved from the
existing file. If the final combination of attributes is invalid, the fopen() will fail.
v The file is opened for reading (r or rb) with recfm=U. Any other specified
attributes should be compatible with those of the existing data set.
In calls to fopen(), the LRECL, BLKSIZE, and RECFM parameters are optional. (If
you are opening a file for read or append, any attributes that you specify must
match the existing attributes.)
If you do not specify file attributes for fopen() (or for an I/O stream object), you get
the following defaults.
RECFM defaults
If recfm is not specified in a fopen() call for an output binary file, recfm defaults to:
v recfm=VB for spool (printer) files
v recfm=FB otherwise
If recfm is not specified in a fopen() call for an output text file, recfm defaults to:
v recfm=F if _EDC_ANSI_OPEN_DEFAULT is set to Y and no LRECL or BLKSIZE
specified. In this case, LRECL and BLKSIZE are both defaulted to 254.
v recfm=VBA for spool (printer) files.
v recfm=U for terminal files.
v recfm=VB for MVS files.
v recfm=VB for all other OS files.
If recfm is not specified for a record I/O file, you will get the default of recfm=VB.
In Table 6, the value max represents the maximum block size for the device. These
are the current default maximum block sizes for several devices that z/OS XL
C/C++ supports:
Device Block Size
DASD 6144
3203 Printer 132
3211 Printer 132
4245 Printer 132
2540 Reader 80
2540 Punch 80
2501 Reader 80
3890 Document Processor 80
TAPE 32760
For more information about specific default block sizes, as returned by the DEVTYPE
macro, refer to z/OS DFSMS Using Data Sets.
For DASD files that do not have recfm=U, if you specify blksize=0 on the call to
fopen() or freopen() and you have DFP Release 3.1 or higher, the system
determines the optimal block size for your file. If you do not have the correct level
of DFP or you specify blksize=0 for a ddname instead of specifying it on the
fopen() or freopen() call, z/OS XL C/C++ behaves as if you had not specified the
blksize parameter at all.
For information about block sizes for different categories of I/O, see the chapters
listed in Table 4 on page 27.
To determine the maximum LRECL and BLKSIZE values for the various file types
and devices available on your operating system, refer to the chapters listed in
Table 4 on page 27.
DDnames
DD names are specified by prefixing the DD name with DD:. All the following
forms of the prefix are supported:
v DD:
v dd:
v dD:
v Dd:
The DD statement enables you to write C source programs that are independent of
the files and input/output devices they will use. You can modify the parameters of a
file (such as LRECL, BLKSIZE, and RECFM) or process different files without
recompiling your program.
v How to create a DDname under MVS batch
To create a ddname under MVS batch, you must write a JCL DD statement. For
the C file PARTS.INSTOCK, you would write a JCL DD statement similar to the
following:
//STOCK DD DSN=PARTS.INSTOCK, . . .
UNIX file system files can be allocated with a DD card, as shown in the following
example:
//STOCK DD PATH=/u/parts.instock,
// PATHOPTS=(OWRONLY,OCREAT,OTRUNC),
// PATHMODE=(SIRWXU,SIRWXO,SIRWXG)
When defining DD, do not use DD ... FREE=CLOSE for unallocating DD
statements. The C library may close files to perform some file operations such as
freopen(), and the DD statement will be unallocated.
For more information on writing DD statements, refer to the JCL manuals listed in
z/OS Information Roadmap.
v How to create a DDname under TSO
To create a ddname under TSO, you must write an ALLOCATE command. For the
declaration shown above for the C file STOCK, you should write a TSO ALLOCATE
statement similar to the following:
ALLOCATE FILE(STOCK) DATASET(PARTS.INSTOCK)
You can also allocate UNIX file system files with TSO ALLOCATE commands. For
example:
You do not always need to describe the characteristics of the data in files both
within the program and outside it. There are, in fact, advantages to describing the
characteristics of your data in only one place.
Opening a file by ddname may require the merging of information internal and
external to the program. If any conflict is detected that will prevent the opening of a
file, fopen() returns a NULL pointer to indicate that the file cannot be opened. See
z/OS XL C/C++ Run-Time Library Reference for more information on fopen().
Note: You can open a ddname only with fopen() or freopen(). open() does not
interpret ddnames as such.
Note: Files cannot be opened under CICS when you have specified the POSIX(ON)
run-time option.
MAP 0010: Under TSO, MVS batch, IMS POSIX(ON) on page 36 shows how
z/OS XL C/C++ determines what type of file to open under TSO, MVS batch, and
interactive IMS with POSIX(ON). For information on the types of files shown in the
chart, see the appropriate chapter in the I/O section.
001
Is type=memory specified?
Yes No
002
003
Continue at Step 017 on page 37.
004
Continue at Step 008.
005
Is hiperspace specified?
Yes No
006
z/OS XL C/C++ opens a regular memory file.
007
z/OS XL C/C++ opens a memory file in Hiperspace.
008
009
010
011
z/OS XL C/C++ opens an OS file.
012
z/OS XL C/C++ opens the existing memory file.
013
Continue to Step 032 on page 38.
014
015
z/OS XL C/C++ removes the asterisk from the name unless the asterisk is
the only character, and proceeds to Step 028 on page 38.
016
z/OS XL C/C++ opens a terminal file.
017
018
019
z/OS XL C/C++ opens a UNIX file system file.
020
z/OS XL C/C++ opens the existing memory file.
021
022
023
z/OS XL C/C++ opens a UNIX file system file called either *DD:ddname
or DD:ddname.
024
z/OS XL C/C++ opens the existing memory file.
025
026
z/OS XL C/C++ opens an OS file.
027
z/OS XL C/C++ opens a UNIX file system file.
028
029
030
z/OS XL C/C++ opens an OS file.
031
z/OS XL C/C++ opens the existing memory file.
032
033
034
***ERROR***
035
z/OS XL C/C++ opens the existing memory file.
036
037
z/OS XL C/C++ opens an OS file.
038
z/OS XL C/C++ opens a UNIX file system file.
MAP 0020: Under TSO, MVS batch, IMS POSIX(OFF) on page 40 shows how
z/OS XL C/C++ determines what type of file to open under TSO, MVS batch, and
interactive IMS with POSIX(OFF). For information on the types of files shown in the
chart, see the appropriate chapter in the I/O section.
001
Is type=memory specified?
Yes No
002
003
Continue at Step 017 on page 41.
004
Continue at Step 008.
005
Is hiperspace specified?
Yes No
006
z/OS XL C/C++ opens a regular memory file.
007
z/OS XL C/C++ opens a memory file in Hiperspace.
008
009
010
011
z/OS XL C/C++ opens an OS file.
012
z/OS XL C/C++ opens the existing memory file.
013
Continue at Step 021.
014
015
z/OS XL C/C++ removes the asterisk from the name unless the asterisk is
the only character, and proceeds to Step 017.
016
z/OS XL C/C++ opens a terminal file.
017
018
019
z/OS XL C/C++ opens an OS file.
020
z/OS XL C/C++ opens the existing memory file.
021
022
023
***ERROR***
024
z/OS XL C/C++ opens the existing memory file.
025
026
z/OS XL C/C++ opens an OS file.
027
z/OS XL C/C++ opens a UNIX file system file.
MAP 0030: Under CICS on page 43 shows how z/OS XL C/C++ determines what
type of file to open under CICS. For information on the types of files shown in the
chart, see the appropriate chapter in the I/O section.
001
Is type=memory specified?
Yes No
002
003
The fopen() call fails.
004
z/OS XL C/C++ opens that memory file.
005
Is hiperspace specified?
Yes No
006
z/OS XL C/C++ opens the specified memory file.
007
The fopen() call ignores the hiperspace specification and opens the memory file.
z/OS XL C/C++ uses buffers to map C I/O to system-level I/O. When z/OS XL
C/C++ performs I/O operations, it uses one of the following buffering modes:
v Line buffering - characters are transmitted to the system as a block when a
new-line character is encountered. Line buffering is meaningful only for text
streams and UNIX file system files.
v Full buffering - characters are transmitted to the system as a block when a buffer
is filled.
v No buffering - characters are transmitted to the system as they are written. Only
regular memory files and UNIX file system files support the no buffering mode.
The buffer mode affects the way the buffer is flushed. You can use the setvbuf()
and setbuf() library functions to control buffering, but you cannot change the
buffering mode after an I/O operation has used the buffer, as all read, write, and
reposition operations do. In some circumstances, repositioning alters the contents of
the buffer. It is strongly recommended that you only use setbuf() and setvbuf()
before any I/O, to conform with ANSI, and to avoid any dependency on the current
implementation. If you use setvbuf(), z/OS XL C/C++ may or may not accept your
buffer for its internal use. For a hiperspace memory file, if the size of the buffer
specified to setvbuf() is 8K or more, it will affect the number of hiperspace blocks
read or written on each call to the operating system; the size is rounded down to
the nearest multiple of 4K.
For record I/O files, buffering is meaningful only for blocked files or for record I/O
files in z/OS UNIX file system using full buffering. For unblocked files, the buffer is
full after every write and is therefore written immediately, leaving nothing to flush.
For blocked files or fully-buffered UNIX file system files, however, the buffer can
contain one or more records that have not been flushed and that require a flush
operation for them to go to the system.
You may not see output if a program that is using input and output fails, and the
error handling routines cannot close all the open files.
z/OS XL C/C++ translates control characters in ASA files opened for text processing
(r, w, a, r+, w+, a+ functions). On input, z/OS XL C/C++ translates ASA
characters to sequences of control characters, as shown in Table 7. On output,
z/OS XL C/C++ performs the reverse translation. The following sequences of control
characters are translated, and the resultant ASA character becomes the first
character of the following record.
Table 7. C control to ASA characters translation table
C Control Character ASA Character Description
Sequence
\n '' skip one line
\n\n '0' skip two lines
\n\n\n '-' skip three lines
\f '1' new page
\r '+' overstrike
If you are writing to the first record or byte of the file and the output data does not
start with a translatable sequence of C control characters, the ' ' ASA control
character is written to the file before the specified data.
z/OS XL C/C++ does not translate or verify control characters when you open an
ASA file for binary or record I/O.
#include <stdio.h>
#define MAX_LEN 80
int main(void) {
FILE *fp;
int i;
char s[MAX_LEN+1];
return(0);
}
fp = fopen("asa.file", "r");
for (i = 0; i < 5; i++) {
fscanf(fp, "%s", s[0]);
printf("string = %s\n",s);
}
}
The program writes five records to the file asa.file, as follows. Note that the last
record is 9034. The last single '\n' does not create a record with a single control
character (' '). If this same file is opened for read, and the getc() function is called
to read the file 1 byte at a time, the same characters as those that were written out
by fputs() in the first program are read.
0abcdef
1
+345
-
9034
\n\n\nHELLO WORLD
x = ftell()
If you then update the ASA character to a form feed ('\f'), the logical ASA
position x no longer exists:
\fHELLO WORLD
If you call fseek() with the logical position x, it repositions to the next valid
character, which is the letter 'H':
\fHELLO WORLD
fseek() to pos x
v If you try to shorten a record when you are updating it, z/OS XL C/C++ adds
enough blank padding to fill the record.
v The ASA character can represent up to three new-lines, which can increase the
logical record length by 1 or 2 bytes.
v Extending a fixed logical record on update implies that the logical end of the line
follows the last written non-blank character.
Note: Be careful when you update an ASA file with data containing more than
one consecutive new-line: the result of the update depends on how the original
ASA records were structured.
v If you are writing data to a non-blocked file without intervening flush or reposition
requests, each record is written to the system on completion (that is, when a
'\n', '\r' or '\f' character is written or when the file is closed).
If you are writing data to a blocked file without intervening flush or reposition
requests, and the file is opened in full buffering mode, the block is written to the
system on completion of the record that fills the block. If the blocked file is line
buffered, each record is written to the system on completion.
If you are writing data to a spanned file without intervening flush or reposition
requests, and the record spans multiple blocks, each block is written to the
system once it is full and the user writes an additional byte of data.
v If a flush occurs while an ASA character indicating more than one new-line is
being updated, the remaining new-lines will be discarded and a read will continue
at the first data character. For example, if '\n\n\n' is updated to be '\n\n' and
a flush occurs, then a '0' will be written out in the ASA character position.
Note: The z/OS XL C++ compiler does not have native support for multibyte
characters. The support described here is what z/OS XL C provides; for C++, you
can take advantage of this support by using interlanguage calls to C code. Please
refer to Chapter 19, Using Linkage Specifications in C or C++, on page 237 for
more information.
If the sequence of bytes ends with the shift-in character, the state remains initial,
making this sequence represent a 4-byte multibyte character. Multibyte characters
of various lengths can be normalized by the set of z/OS XL C library functions and
encoded in units of one length. Such normalized characters are called wide
characters; in z/OS XL C they are represented by two bytes. Conversions between
multibyte format and wide character format can be performed by string conversion
functions such as wcstombs(), mbstowcs(), wcsrtombs(), and mbsrtowcs(), as well
by the family of the wide character I/O functions. MB_CUR_MAX is defined in the
stdlib.h header file. Depending on its value, either of the following happens:
v When MB_CUR_MAX is 1, all bytes are considered single-byte characters; shift-out
and shift-in characters are treated as data as well.
v When MB_CUR_MAX is 4:
On input, the wide character I/O functions read the multibyte character from
the streams, and convert them to the wide characters.
On output, they convert wide characters to multibyte characters and write
them to the output streams.
Both binary and text streams have orientation. Streams opened with type=record
do not. There are three possible orientations of a stream:
Non-oriented
A stream that has been associated with an open file before any I/O
operation is performed. The first I/O operation on a non-oriented stream will
set the orientation of the stream. The fwide() function may be used to set
the orientation of a stream before any I/O operation is performed. You can
use the setbuf() and setvbuf() functions only when I/O has not yet been
performed on a stream. When you use these functions, the orientation of
Once you have established a stream's orientation, the only way to change it is to
make a successful call to the freopen() function, which removes a stream's
orientation.
The wchar.h header file declares the WEOF macro and the functions that support
wide character input and output. The macro expands to a constant expression of
type wint_t. Certain functions return WEOF type when the end-of-file is reached on
the stream.
Note: The behavior of the wide character I/O functions is affected by the LC_CTYPE
category of the current locale, and the setting of MB_CUR_MAX. Wide-character input
and output should be performed under the same LC_CTYPE setting. If you change
the setting between when you read from a file and when you write to it, or vice
versa, you may get undefined behavior. If you change it back to the original setting,
however, you will get the behavior that is documented. See the introduction of this
chapter for a discussion of the effects of MB_CUR_MAX.
Opening files
You can use the fopen() or freopen() library functions to open I/O files that contain
multibyte characters. You do not need to specify any special parameters on these
functions for wide character I/O.
For a detailed description of unformatted and formatted I/O functions, see z/OS XL
C/C++ Run-Time Library Reference.
The wide-character input/output functions maintain global shift state for multibyte
character streams they read or write. For each multibyte character they read,
wide-character input functions change global shift state as the mbrtowc() function
would do. Similarly, for each multibyte character they write, wide-character output
functions change global shift state as the wcrtomb() function would do.
When you are using wide-oriented input functions, multibyte characters are
converted to wide characters according to the current shift state. Invalid double-byte
character sequences cause conversion errors on input. As z/OS XL C uses
wide-oriented functions to read a stream, it updates the shift state when it
encounters shift-out and shift-in characters. Wide-oriented functions always read
complete multibyte characters. Byte-oriented functions do not check for complete
multibyte characters, nor do they maintain information about the shift state.
Therefore, they should not be used to read multibyte streams.
For binary streams, no validation is performed to ensure that records start or end in
initial shift state. For text streams, however, all records must start and end in initial
shift state.
All other output functions do not support the wchar_t data type. However, all of the
output functions support multibyte character output for text streams if MB_CUR_MAX is
4.
For a detailed description of unformatted and formatted I/O functions, see z/OS XL
C/C++ Run-Time Library Reference.
Control characters written before the shift-in are treated as multibyte data and are
not interpreted or validated.
When you close the file, z/OS XL C ensures that the file ends in initial shift state.
This may require adding a shift-in and possibly a padding character to complete the
last multibyte character, if it is not already complete. If padding is needed in this
case, z/OS XL C does not raise SIGIOERR.
Multibyte characters are never split across record boundaries. In addition, all
records end and start in initial shift state. When a shift-out is written to the file,
either directly or indirectly by wide-oriented functions, z/OS XL C calculates the
maximum number of complete multibyte characters that can be contained in the
record with the accompanying shift-in. If multibyte output (including any required
shift-out and shift-in characters) does not fit within the current record, the behavior
depends on what type of file it is (a memory file has no record boundaries and so
never has this particular problem). For a standard stream or terminal file, data is
wrapped from one record to the next. Shift characters may be added to ensure that
the first record ends in initial shift state and that the second record starts in the
required shift state.
For files that are not standard streams, terminal files, or memory files, any attempt
to write data that does not fit into the current record results in data truncation. In
such a case, the output function returns an error code, raises SIGIOERR, and sets
errno and the error flag. Truncation continues until initial state is reached and a
new-line is written to the file. An entire multibyte stream may be truncated, including
the shift-out and shift-in, if there are not at least two bytes in the record. For a
wide-oriented stream, truncation stops when a wchar_t new-line character is written
out.
Byte-oriented output functions do not interpret binary data. If you use them for
writing multibyte data, ensure that your data is correct and ends in initial shift state.
If you update a record after you call fgetpos(), the shift state may change. Using
the fpos_t value with the fsetpos() function may cause the shift state to be set
incorrectly.
Flushing buffers
You can use the library function fflush() to flush streams to the system. For more
information about fflush(), see the z/OS XL C/C++ Run-Time Library Reference.
The action taken by the fflush() library function depends on the buffering mode
associated with the stream and the type of stream. If you call one z/OS XL C
program from another z/OS XL C program by using the ANSI system() function, all
open streams are flushed before control is passed to the callee. A call to the POSIX
system() function does not flush any streams to the system. For a POSIX system
call, we recommend that you do a fflush() before the system call.
Calling fflush() has no effect on the current record when you are writing new data
to a wide-oriented or byte-oriented multibyte stream, because the record is
incomplete.
ungetwc() considerations
ungetwc() pushes wide characters back onto the input stream for binary and text
files. You can use it to push one wide character onto the ungetwc() buffer. Never
use ungetc() on a wide-oriented file. After you call ungetwc(), calling fflush()
backs up the file position by one wide character and clears the pushed-back wide
character from the stream. Backing up by one wide character skips over shift
characters and backs up to the start of the previous character (whether single-byte
or double-byte). For text files, z/OS XL C counts the new-lines added to the records
as single-byte characters when it calculates the file position. For example, if you
have the following stream,
A B SO X'FE' X'7F' SI C
fp
You can set the _EDC_COMPAT environment variable before you open the file, so that
fflush() ignores any character pushed back with ungetwc() or ungetc(), and leaves
the file position where it was when ungetwc() or ungetc() was first issued. Any
characters pushed back are still cleared. For more information about _EDC_COMPAT,
see Chapter 32, Using environment variables, on page 467.
Use the fseek() or fsetpos() functions to reposition only to the start of a multibyte
character. If you reposition to the middle of a multibyte character, undefined
behavior can occur.
When you use the fsetpos() function to reposition within a file, the shift state is set
to the state saved by the function. Use this function to reposition to a wide
character that is not in the initial state.
ungetwc() considerations
For text files, the library functions fgetpos() and ftell() take into account the
character you have pushed back onto the input stream with ungetwc(), and move
the file position back by one wide character. The starting position for an fseek() call
with a whence value of SEEK_CUR also takes into account this pushed-back wide
character. Backing up one wide character means backing up either a single-byte
character or a multibyte character, depending on the type of the preceding
character. The implicit new-lines at the end of each record are counted as wide
characters.
For binary files, the library functions fgetpos() and ftell() also take into account
the character you have pushed back onto the input stream with ungetwc(), and
adjust the file position accordingly. However, the ungetwc() must push back the
same type of character just read by fgetwc(), so that ftell() and fgetpos() can
save the state correctly. An fseek() with an offset of SEEK_CUR also accounts for
the pushed-back character. Again, the ungetwc() must unget the same type of
character for this to work properly. If the ungetwc() pushes back a character in the
opposite state, you will get undefined behavior.
You can make only one call to ungetwc(). If the current logical file position is
already at or before the first wchar in the file, a call to ftell() or fgetpos() after
ungetwc() fails.
When you are using fseek() with a whence value of SEEK_CUR, the starting point
for the reposition also accounts for the presence of ungetwc() characters and
compensates as ftell() and fgetpos() do. Specifying a relative offset other than 0
is not supported and results in undefined behavior.
Closing files
z/OS XL C expects files to end in initial shift state. For binary byte-oriented files,
you must ensure that the ending state of the file is initial state. Failure to do so
results in undefined behavior if you reaccess the file again. For wide-oriented
streams and byte-oriented text streams, z/OS XL C tracks new data that you add. If
necessary, z/OS XL C adds a padding byte to complete any incomplete multibyte
character and a shift-in to end the file in initial state.
By default, the standard streams are opened implicitly the first time they are
referenced. You do not have to declare them or call their open() member functions
to open them. For example, with no preceding declaration or open() call, the
following statement writes the decimal number n to the cout stream.
cout << n << endl;
For more detailed information about C++ I/O streaming, see the following:
v z/OS XL C/C++ Run-Time Library Reference discusses the C I/O stream
functions
v Standard C++ Library Reference discusses the Standard C++ I/O stream classes
Table 9. Standard C and C++ streams
Stream Purpose Functions that use it
name
C standard streams and their related functions
stdin The input device from which your C program usually getchar()
retrieves its data. getchar_unlocked()
gets()
gets_unlocked()
scanf()
scanf_unlocked()
vscanf()
vscanf_unlocked()
wscanf()
wscanf_unlocked()
vwscanf()
vwscanf_unlocked()
stdout The output device to which your C program normally printf()
directs its output. printf_unlocked()
puts()
puts_unlocked()
putchar()
putchar_unlocked()
vprintf()
vprintf_unlocked()
wprintf()
wprintf_unlocked()
vwprintf()
vwprintf_unlocked()
stderr The output device to which your C program directs perror()
its diagnostic messages. z/OS XL C/C++ uses perror_unlocked()
stderr to collect error messages about exceptions
that occur.
C++ standard streams and the operators typically used with them
Stream Purpose Common usage
name
On I/O operations requiring a file pointer, you can use stdin, stdout, or stderr in
the same manner as you would any other file pointer.
If you are running with POSIX(ON), standard streams are opened during initialization
of the process, before the application receives control. With POSIX(OFF), the default
behavior is for the C standard streams to open automatically on first reference. You
do not have to call fopen() to open them. For example, if the following statement is
specified without a preceding fopen() statement, it writes the decimal number n to
the stdout stream.
printf("%d\n",n);
By default, stdin interprets the character sequence /* as indicating that the end of
the file has been reached. See Chapter 13, Performing terminal I/O operations, on
page 189 for more information.
Where the streams go depends on what kind of environment you are running under.
These are the defaults:
v Under interactive TSO, all three standard streams go to the terminal.
v Under MVS batch, TSO batch, and IMS (batch and interactive):
stdin goes to dd:sysin. If dd:sysin does not exist, all read operations from
stdin will fail.
stdout goes first to dd:sysprint. If dd:sysprint does not exist, stdout looks
for dd:systerm and then dd:syserr. If neither of these files exists, z/OS XL
C/C++ opens a sysout=* data set and sends the stdout stream to it.
stderr will go to the z/OS Language Environment message file. In AMODE 64
applications, stderr goes to dd:sysout.
Note: When a standard stream is allocated to a large format sequential data set,
the stream will be opened without repositioning (noseek). In this situation, the
open is initially attempted with repositioning (seek), fails with an ABEND 213-14
You can also redirect the standard streams to other files. See Redirecting standard
streams and sections following.
//
// Example of interleaving USL I/O with sync_with_stdio()
//
// tsyncws.cxx
#include <stdio.h>
#include <fstream.h>
int main() {
ios::sync_with_stdio();
cout << "object: to show that sync_with_stdio() allows interleaving\n "
" standard input and output on a per character basis\n" << endl;
int main() {
cout << "object: to illustrate interleaving input and output\n "
" without sync_with_stdio()\n" << endl;
cin.getline(string1, 80);
rc = gets(string2);
cin.getline(string3, 80);
Note that, C++ standard streams are implemented in terms of C standard streams.
Therefore, cin, cout, cerr, and clog are implicitly redirected when the
corresponding C standard streams are redirected. These streams can be redirected
by assignment, as described in Assigning the standard streams on page 68. If
freopen() is applied to a C standard stream, creating a binary stream or one with
"type=record", then behavior of the related stream is undefined.
Note: If you specify a redirection in a system() call, after system() returns, the
streams are redirected back to those at the time of the system() call.
Notes:
1. If you use the NOREDIR option on a #pragma runopts directive, or the
NOREDIR compile-time option, you cannot redirect standard streams on the
command line using the preceding list of symbols.
2. If you want to pass one of the redirection symbols as an argument, you can
enclose it in double quotation marks. For example, the following passes the
string "here are the args including a <" to prog and redirects stdout to
redir1 output a.
prog "here are args including a <" >"redir1 output a"
3. TSO (batch and online) and MVS batch support command line arguments. CICS
and IMS do not.
4. When two options specifying redirection conflict with each other, or when you
redirect a standard stream more than once, the redirection fails. If you do the
latter, you will get an abend. For example, if you specify
2>&1
and then
1>&2
z/OS XL C/C++ uses the first redirection and ignores any subsequent ones. If
you specify
>a.out
and then
1>&2
the redirection fails and the program abends.
5. A failed attempt to redirect a standard stream causes your program to fail in
initialization.
You must ensure that the streams are appropriate; for example, do not assign a
stream opened for w to stdin. Doing so would cause a function such as getchar()
called for the stream to fail, because getchar() expects a stream to be opened for
read access.
Again, you must ensure that the assigned stream is appropriate; for example, do
not assign an fstream opened for ios::out only to cin. This will cause a
subsequent read operation to fail.
You can redirect stderr by specifying a ddname on the MSGFILE run-time option and
not redirecting stderr elsewhere (such as on the command line). The default
ddname for the z/OS Language Environment MSGFILE is SYSOUT. See z/OS
Language Environment Programming Guide for more information on MSGFILE.
MSGFILE considerations
z/OS XL C/C++ makes a distinction between types of error output according to
whether the output is directed to the MSGFILE, to stderr, or to stdout:
Table 11. Output destinations under z/OS XL C/C++
Destination of Type of Message Produced by Default Destination
Output
MSGFILE output z/OS Language z/OS Language MSGFILE ddname
Environment Environment
messages (CEExxxx) conditions
z/OS XL C/C++ z/OS XL C/C++ MSGFILE ddname
language messages unhandled conditions
(EDCxxxx)
Notes:
1. When you are using one of the z/OS UNIX shells, stderr will go to file descriptor 2,
which is typically the terminal. See Chapter 16, Language Environment Message file
operations, on page 215 for more information about z/OS Language Environment
message files.
2. When you are using one of the z/OS UNIX shells, stdout will go to file descriptor 1,
which is typically the terminal.
All stderr output is by default sent to the MSGFILE destination, while stdout output
is sent to its own destination. When stderr is redirected to stdout, both share the
stdout destination. When stdout is redirected to stderr, both share the stderr
destination.
If you specified one of the DDs used in the stdout open search order as the DD for
the MSGFILE option, then that DD will be ignored in the stdout open search.
Table 12 describes the destination of output to stderr and stdout after redirection
has occurred. Whenever stdout and stderr share a common destination, the
output is interleaved. The default case is the one where stdout and stderr have
not been redirected.
Table 12. z/OS XL C/C++ Interleaved output
stderr not stderr redirected to stderr redirected to
redirected destination other stdout
than stdout
stdout not stdout to itself stderr stdout to itself stderr Both to stdout
redirected to MSGFILE to its other destination
stdout redirected to stdout to its other stdout to its other Both to the new
destination other destination stderr to destination stderr to stdout destination
than stderr MSGFILE its other destination
stdout redirected to Both to MSGFILE Both to the new stdout to stderr
stderr stderr destination stderr to stdout
Because the topic of JCL statements goes beyond the scope of this book, only
simple examples will be shown here.
Suppose you have a program called BATCHPGM, with 1 required parameter DEBUG.
The output from BATCHPGM is to be directed to a sequential data set called
MAINT.LOG.LISTING. You can use the following JCL statements:
//JOBname JOB...
. //STEP01 EXEC PGM=BATCHPGM,PARM=DEBUG >MAINT.LOG.LISTING
.
.
The following JCL redirects output to an unqualified data set using the same
program name, parameter and output data set as the example above:
Figure 8 shows excerpt from an MVS example job stream that demonstrates the
redirection of the three standard streams by using ddnames. In the example, your
program name is MONITOR and the input to MONITOR is to be retrieved from a
sequential data set called SAFETY.CHEM.LIST. The output of MONITOR is to be
directed to a partitioned data set member called YEAREND.ACTION(CHEM), and any
errors generated by MONITOR are to be written to a sequential data set called
YEAREND.MONITOR.ERRLIST. To redirect the standard streams using DD statements,
you could use the JCL statements shown in Figure 8.
//JOBname JOB...
. //STEP01 EXEC PGM=MONITOR,PARM=MSGFILE(SYSERR)/
.
.
//SYSIN DD DSN=SAFETY.CHEM.LIST,DISP=OLD
//SYSERR DD DSN=YEAREND.MONITOR.ERRLIST,DISP=MOD
. //SYSPRINT DD DSN=YEAREND.ACTION(CHEM),DISP=OLD
.
.
//JOBname JOB...
//STEP01 EXEC PGM=HOCKEY,PARM=/ 2>&1
//SYSIN DD DSN=HOCKEY.PLAYER.LIST,DISP=SHR
//SYSPRINT DD DSN=HOCKEY.OUTPUT,DISP=(OLD),DCB=...
Figure 9. Example of using stdout and stderr to share the same file
If you want to redirect to a UNIX file system file, you can modify the above
examples to use the PATH and PATHOPT options described in DDnames on page 34.
Under TSO
You can redirect standard streams in the following ways:
v From the freopen() library function call
v From the command line
v Using the parameter list in a CALL command
Under IMS
Under IMS online and batch, you can redirect the C standard streams in any of the
following ways:
v with direct assignment
v with the freopen() function
v with ddnames
Under CICS
There are several ways to redirect C standard streams under CICS:
v You can assign a memory file to the stream (for example, stdout=myfile).
v You can use freopen() to open a standard stream as a memory file.
v You can use CICS facilities to direct where the stream output goes.
If you assign a file pointer to a stream or use freopen() on it, you will not be able
to use C functions to direct the information outside or elsewhere in the CICS
environment. Once access to a CICS transient data queue has been removed,
either by a call to freopen() or fclose(), or by the assignment of another file
pointer to the stream, z/OS XL C/C++ does not provide a way to regain access.
Once C functions have lost access to the transient data queues, you must use the
CICS-provided facilities to regain it.
CICS provides a facility that enables you to direct where a given transient data
queue, the default standard stream implementation, will go, but you must configure
this facility before a CICS cold start.
A system() call occurs when one z/OS XL C/C++ program calls another z/OS XL
C/C++ program by using the ANSI system() function, which z/OS XL C/C++ uses if
you are not running with POSIX(ON). Standard streams are inherited across calls to
the ANSI system() function. With a POSIX system() function, file descriptors 0, 1,
and 2 will be mapped to standard streams stdin, stdout and stderr in the child
process. The behavior of these streams is similar to binary streams called with the
ANSI system() function.
Inheritance includes any redirection of the stream as well as the open mode of the
stream. For example, if program A reopens stdout as "A.B" for "wb" and then calls
program B, program B inherits the definition of stdout. If program B reopens stdout
as "C.D" for "ab" and then uses system() to call program C, program C inherits
stdout opened to "C.D" for append. Once control returns to the calling program, the
definitions of the standard streams from the time of the system() call are restored.
For example, when program B finally returns control to program A, stdout is
restored to "A.B" opened for "wb".
The file position and the amount of data that is visible in the called and calling
programs depend on whether the standard streams are opened for binary, text, or
record I/O.
The behavior of the C standard streams across a system() call indicates the
behavior of all standard streams since they are implemented in terms of the C
standard streams.
Memory files are always opened in binary mode, even if you specify text. Any
standard streams redirected to memory files and passed across system() calls will
be treated as binary files. UNIX file system files are also treated as binary files,
because they do not contain any real record boundaries. Memory files are not
passed across calls to the POSIX system() function.
OUTPUT
------
no ---> from the child
ab01 ---> from root
When you write to a spanned file, the file position moves to the beginning of the
next record, if that record exists. If not, the position moves to the end of the
incomplete record.
For non-spanned standard streams opened for output, if the caller has created a
text record missing an ending control character, the last record is hidden from the
called program. The called program can append new data if the stream is open in
append mode. Any appends made by the called program will be after the last
record that was complete at the time of the system() call.
When the called program terminates, it completes any new unfinished text record
with a new-line; the addition of the new-line does not move the file position. Once
When control returns to the original caller, any incomplete record hidden at the time
of the system() call is restored to the end of the file. If the called program is at EOF
when it is terminated and the caller was within an incomplete record at the time of
the system() call, the position upon return is restored to the original record offset at
the time of the system() call. This position is usually the end of the incomplete
record. Generally, if the caller is writing to a standard stream and does not complete
the last record before it calls system(), writes continue to add to the last record
when control returns to the caller. For example:
printf("test");
printf("abc");
system("hello"); ------> int main(void) { printf("hello world\n");}
printf("def\n");
If stdout had been opened for "w+" in this example, and a reposition had been
made to the character b before the system() call, upon return, the incomplete
record "abc" would have been restored and the position would have been at the
b. The subsequent write of def would have performed an update to give test
hello world adef.
Input with sync_with_stdio(): When cin is open in text mode (the default), and
sync_with_stdio() has been called, the input across a system() call behaves the
same as stdin:
v The child program begins reading at the next record boundary, that is, unread
data in the current record in the parent is hidden.
v When the child program returns, the parent program begins reading at the next
record boundary, that is, unread data in the current record in the child is lost.
In the example shown in Figure 11, stdout is a variable-length record I/O file.
fwrite("test",1,4,stdout);
fwrite("abc",1,3,stdout);
system("hello"); ------> int main(void) {
fwrite("def",1,3,stdout); fwrite("hello world",1,11,stdout)
}
In the default inheritance model, the behavior of C standard streams is such that a
child main() function cannot affect the standard streams of the parent. The child
can use the parent's definition or redirect a standard stream to a new location, but
when control returns to the parent, the standard stream reverts back to the
definition of the parent. In the global model, the C standard streams, stdin, stdout,
and stderr, can be redirected to a different location while running in a child main()
function and have that redirection stay in effect when control returns to the parent.
You can use the _EDC_GLOBAL_STREAMS environment variable to set standard
stream behavior to the global model. For more information, see
_EDC_GLOBAL_STREAMS on page 492.
Notes:
1. The following environments do not allow global standard stream behavior as an
option:
v POSIX(ON)
v CICS
v SPC
v AMODE 64
2. You must identify the behavior of the standard streams to the C run-time library
before initialization of the first C main in the environment. The default behavior
The most important difference is that when redirection is done at system() call time,
the redirection takes effect for the entire C environment. When the child program
terminates, the standard stream definitions do not revert back to what they were
before the system() call.
Redirecting stderr to stdout, or stdout to stderr, does not flush the redirected
stream. Any data in the buffer remains there until the stream is redirected again, to
something other than stdout or stderr. Only then is the buffer flushed.
#include <stdio.h>
#include <stdlib.h>
main() {
int rc;
printf("line 1\n");
printf("line 2");
fprintf(stderr,"line 3\n");
fprintf(stderr,"line 4");
rc=system("PGM=CHILD,PARM=/ >stdout.file 2>&1;")
printf("line 5\n");
fprintf(stderr,"line 6\n");
}
CHILD.C
#include <stdio.h>
main() {
printf("line 7\n");
fprintf(stderr,"line 8\n");
stderr = freopen("stderr.file","w",stderr);
printf("line 9\n");
fprintf(stderr,"line 10\n");
}
Attention: If the stdout or stderr stream has data in its buffer and it is redirected
to stderr or stdout, then the data is lost if stdout or stderr is not redirected again.
Note: If either stdout or stderr is using global behavior, but not both, then any
redirection of stdout or stderr to stderr or stdout is ignored.
Direct assignment
You can directly assign the C standard streams in any main program. This
assignment does not have any effect on the global standard stream. No flush is
done and the new definition is not passed on to a child program nor back to a
parent program. Once you directly assign a standard stream, there is no way to
re-associate it with the global standard stream.
freopen()
When you use freopen() to redirect a standard stream, the stream is closed,
causing a flush, and then redirected. The new definition affects all C mains currently
using the global stream.
fclose()
When a global standard stream is closed, only direct assignment can be used to
begin using the standard stream again. That use would only be for the main
performing the direct assignment. There is no way to get back global behavior for
the standard stream that was closed.
OS I/O supports text, binary, and record I/O, in three record formats: fixed (F),
variable (V), and undefined (U). For information about using wide-character I/O with
z/OS XL C/C++, see Chapter 8, z/OS XL C Support for the double-byte character
set, on page 51.
This topic describes C I/O stream functions as they can be used within C++
programs. If you want to use the C++ I/O stream classes instead, see Chapter 4,
Using the Standard C++ Library I/O Stream Classes, on page 21 for general
information. For more detailed information, see Standard C++ Library Reference,
which discusses the Standard C++ I/O stream classes
Opening files
To open an OS file, you can use the Standard C functions fopen() or freopen().
These are described in general terms in z/OS XL C/C++ Run-Time Library
Reference. Details about them specific to all z/OS XL C/C++ I/O are discussed in
the "Opening Files" section. This section describes considerations for using fopen()
and freopen() with OS files.
qualifier
// ' ( member ) '
+ number
0
& qualifier
&&
Note: The single quotation marks in the filename syntax diagram must be matched;
if you use one, you must use the other.
qualifier1.qualifier2(member)
fp = fopen("//&&myfile","wb+");
fp2 = fopen("//&&myfile","wb+");
The Resource Access Control Facility (RACF) expects the data set name to have
a high-level qualifier that is defined to RACF. RACF uses the entire data set name
when it protects a tape data set.
When you enclose a name in single quotation marks, the name is fully qualified.
The file opened is the one specified by the name inside the quotation marks. If the
name is not fully qualified, z/OS XL C/C++ does one of the following:
v If your system does not use RACF, z/OS XL C/C++ does not add a high-level
qualifier to the name you specified.
v If you are running under TSO (batch or interactive), z/OS XL C/C++ appends the
TSO user prefix to the front of the name. For example, the statement
fopen("a.b","w"); opens a data set tsoid.A.B, where tsoid is the user prefix. If
the name is fully qualified, z/OS XL C/C++ does not append a user prefix. You
can set the user prefix by using the TSO PROFILE command with the PREFIX
parameter.
v If you are running under z/OS batch or IMS (batch or online), z/OS XL C/C++
appends the RACF user ID to the front of the name.
If you want your code to be portable between the VM/CMS and z/OS systems and
between memory files and disk files, use a name of the format name1.name2, where
name1 and name2 are up to 8 characters and are delimited by a period, or use a
ddname. You can also add a member name.
For example, the following piece of code can run under Language Environment for
VM and z/OS Language Environment:
FILE *stream;
stream = fopen("parts.instock", "r");
Using a DDname
The DD statement enables you to write C or C++ source programs that are
independent of the files and input/output devices they use. You can modify the
parameters of a file or process different files without recompiling your program.
To open a file by ddname under z/OS batch, you must define the ddname first. You
can do this in any of the following ways:
v In batch (z/OS, TSO, or IMS), you can write a JCL DD statement. For the
declaration shown above for the C or C++ file PARTS.INSTOCK, you write a JCL
DD statement similar to the following:
//STOCK DD DSN=USERID.PARTS.INSTOCK,DISP=SHR
When defining DD, do not use DD ... FREE=CLOSE for unallocating DD
statements. The C library may close files to perform some file operations such as
freopen(), and the DD statement will be unallocated.
If you use SPACE=RLSE on a DD statement, z/OS XL C/C++ releases space only if
all of the following are true:
The file is open in w, wb, a, or ab mode
It is not simultaneously open for read
No positioning functions (fseek(), ftell(), rewind(), fgetpos(), fsetpos())
have been performed.
For more information on writing DD statements, refer to the job control language
(JCL) manuals listed in z/OS Information Roadmap.
v Under TSO (interactive and batch), you can issue an ALLOCATE command. The
DD definition shown above for the C file STOCK has an equivalent TSO ALLOCATE
command, as follows:
ALLOCATE FILE(STOCK) DATASET(PARTS.INSTOCK) SHR
See z/OS Information Roadmap for manuals containing information on TSO
ALLOCATE.
v In the z/OS environment, you can use the svc99() or dynalloc() library functions
to define ddnames. For information about these functions, refer to z/OS XL
C/C++ Run-Time Library Reference.
DCB parameter: The DCB (data control block) parameter of the DD statement
allows you to describe the characteristics of the data in a file and the way it will be
processed at run time. The other parameters of the DD statement deal chiefly with
the identity, location, and disposition of the file. The DCB parameter specifies
information required for the processing of the records themselves. The
subparameters of the DCB parameter are described in z/OS MVS JCL User's Guide.
You cannot use the DCB parameter to override information already established for
the file in your C or C++ program (by the file attributes declared and the other
attributes that are implied by them). DCB subparameters that attempt to change
information already supplied by fopen() or freopen() are ignored. An example of
the DCB parameter is:
DCB=(RECFM=FB,BLKSIZE=400,LRECL=40)
If you want to open a generation data set by data set name with fopen() or
freopen(), you will require a model. This model specifies parameters for the group,
including the maximum number of generations (the generation index). You can
define such a model by using the Access Method Services DEFINE command. For
more information on the DEFINE command, see z/OS DFSMS Access Method
Services for Catalogs. Note also that fopen() does not support a DCB= parameter. If
you want to change the parameters, alter the JCL that describes the model and
open it in w mode.
z/OS uses an absolute generation and version number to catalog each generation.
The generation and version numbers are in the form GxxxxVyy, where xxxx is an
unsigned 4-digit decimal generation number (0001 through 9999) and yy is an
unsigned 2-digit decimal version number (00 through 99). For example:
v A.B.C.G0001V00 is generation data set 1, version 0, in generation data group
A.B.C.
v A.B.C.G0009V01 is generation data set 9, version 1, in generation data group
A.B.C.
The number of generations kept depends on the size of the generation index.
When you open a GDG by relative number, z/OS XL C/C++ returns the relative
generation in the __dsname field of the structure returned by the fldata() function.
You cannot use the rename() library function to rename GDGs by relative
generation number; rename GDG data sets by using their absolute names.
The example shown in Figure 13 on page 86 is valid only for C. The sample
program (CCNGOS1) defines a GDG. The fopen() fails because it tries to change
the RECFM of the data set.
fp = fopen("MYGDG(+1)", "a,recfm=F");
if (fp == NULL)
{
printf("Error...Unable to open file\n");
printf("errno ... %d\n",errno);
perror("perror ... ");
}
printf("Finished\n");
}
/>
fp = fopen("MYGDG(+1)", "a,recfm=F");
if (fp == NULL)
{
printf("Error...Unable to open file\n");
printf("errno ... %d\n",errno);
perror("perror ... ");
}
printf("Finished\n");
}
A relative number used in the JCL refers to the same generation throughout a job.
The (+1) used in the example above exists for the life of the entire job and not just
the step, so that fopen()'s reference to (+1) did not create another new data set
but accessed the same data set as in previous steps.
Note: You cannot use fopen() to create another generation data set because
fopen() does not fully support the DCB parameter.
You specify a member by enclosing its name in parentheses and placing it after the
data set name. For example, the following JCL refers to member A of the data set
MY.DATA:
//MYDD DD DSN=userid.MY.DATA(A),DISP=SHR
You can specify members on calls to fopen() and freopen(). You can specify
members when you are opening a data set by its data set name or by a ddname.
When you use a ddname and a member name, the definition of the ddname must
not also specify a member. For example, using the DD statement above, the
following will fail:
fp = fopen("dd:MYDD(B)","r");
You cannot open a PDS or PDSE member using the modes a, ab, a+, a+b, w+, w+b,
or wb+. If you want to perform the equivalent of the w+ or wb+ mode, you must first
open the file as w or wb, write to it, and then close it. Then you can perform updates
by reopening the file in r+ or rb+ mode. You can use the C library functions ftell()
or fgetpos() to obtain file positions for later updates to the member. Normally,
opening a file in r+ or rb+ mode enables you to extend a file by writing to the end;
however, with these modes you cannot extend a member. To do so, you must copy
the contents of the old member plus any extensions to a new member. You can
remove the old member by using the remove() function and then rename the new
member to the old name by using rename().
All members have identical attributes for RECFM, LRECL, and BLKSIZE. For PDSs,
you cannot add a member with different attributes or specify a RECFM of FBS, FBSA,
or FBSM. z/OS XL C/C++ verifies any attributes you specify.
For PDSEs, z/OS XL C/C++ checks to make sure that any attributes you specify
are compatible with those of the existing data set. Compatible attributes are those
that specify the same record format (F, V, or U) and the same LRECL. Compatibility
of attributes enables you to choose whether to specify blocked or unblocked format,
because PDSEs reblock all the records. For example, you can create a PDSE as FB
LRECL=40 BLKSIZE=80, and later open it for read as FB LRECL=40 BLKSIZE=1600 or F
At the start of each partitioned data set is its directory, a series of records that
contain the member names and starting locations for each member within the data
set. You can access the directory by specifying the PDS or PDSE name without
specifying a member. You can open the directory only for read; update and write
modes are not allowed. The only RECFM that you can specify for reading the
directory is RECFM=U. However, you do not need to specify the RECFM, because
z/OS XL C/C++ uses U as the default.
z/OS DFSMS Using Data Sets contains more detailed explanations about how to
use PDSs and PDSEs.
the first call to fopen() finds member C from PDS1, even though there is also a
member C in PDS2. The second call finds member D from PDS2, because PDS2 is the
first PDS in the concatenation that contains this member. The member C in PDS2 is
inaccessible.
When you are concatenating partitioned data sets, be aware of the DCB attributes
for them. The concatenation is treated as a single data set with the following
attributes:
v RECFM= the RECFM of the first data set in the concatenation
v LRECL= the LRECL of the first data set in the concatenation
v BLKSIZE= the largest BLKSIZE of any data set in the concatenation
If the first data set is in ASA format, all subsequent data sets must be ASA as well.
The preceding rules apply to ASA files if you add an A to the RECFMs specified.
If you do not follow these rules, undefined behavior occurs. For example, trying to
read a fixed-format member as RECFM=V could cause an exception or abend.
Repositioning is supported as it is for regular PDSs and PDSEs. If you try to read
the directory, you will be able to read only the first one.
//MYDD DD userid.PDS1(A),DISP=SHR
// DD userid.PDS2(E),DISP=SHR
// DD userid.DATA,DISP=SHR
creates a concatenation that contains two members and a regular sequential data
set. You can read or update all of these in order. In partitioned concatenations, you
can read only one member at a time.
z/OS XL C/C++ does not support concatenating data sets that do not have
compatible DCB attributes. The rules for compatibility are the same as those for
partitioned concatenations.
If all the data sets in the concatenation support repositioning, you can reposition
within a concatenation by using the functions fseek(), ftell(), fgetpos(),
fsetpos(), and rewind(). If the first one does not, all of the repositioning functions
except rewind() fail for the entire concatenation. If the first data set supports
repositioning but a subsequent one does not, you must specify the noseek
parameter on the fopen() or freopen() call. If you do not, fopen() or freopen()
opens the file successfully; however, an error occurs when the read position gets to
the data set that does not support repositioning.
Note: Concatenated and multivolume data sets only tolerate single buffering mode.
//MYDD DD *
record 1
record 2
record 3
/*
The // at the beginning of the data set starts in column 1. The statement
fopen("DD:MYDD","rb"); opens a data set with lrecl=80, blksize=80, and
recfm=FB. In this example, the delimiter indicating the end of the data set is /*. In
some cases, your data may contain this string. For example, if you are using C
source code that contains comments, z/OS XL C/C++ treats the beginning of the
first comment as the end of the in-stream data set. To avoid this occurrence, you
can change the delimiter by specifying DLM=nn, where nn is a two-character
delimiter, on the DD statement that identifies the file. For example:
//MYDD DD *,DLM=
#include <stdio.h>
/* Hello, world program */
int main() {printf("Hello, world\n"); }
@@
For more information about in-stream data sets, see z/OS MVS JCL User's Guide.
To open an in-stream data set, call the fopen() or freopen() library function and
specify the ddname of the data set. You can open an in-stream data set only for
reading. Specifying any of the update, write, or append modes fails. Once you have
opened an in-stream data set, you cannot acquire or change the file position except
by rewinding. This means that calls to the fseek(), ftell(), fgetpos(), and
fsetpos() for in-stream data sets fail. Calling rewind() causes z/OS XL C/C++ to
reopen the file, leaving the file position at the beginning.
You can concatenate regular sequential data sets and in-stream data sets. If you do
so, note the following:
v If the first data set is in-stream, you cannot acquire or change the file position for
the entire concatenation.
v If the first data set is not in-stream and supports repositioning, you must specify
the noseek parameter on the fopen() or freopen() call that opens the
concatenation. If you do not, fopen() or freopen() opens the file successfully;
however, an error occurs when the read position gets to the in-stream.
v The in-stream data set is treated as FB 80 and the concatenation rules for
sequential concatenation apply.
On a DD statement, you specify SYSOUT=x, where x is the output class. If the class
matches the JOB statement MSGCLASS, the output appears with the job log. You can
specify a SYSOUT data set and get the job MSGCLASS by specifying SYSOUT=*. If you
want to create a job stream within your program, you can specify INTRDR on the DD
statement. This sends your SYSOUT data set to the internal reader to be read as
an input job stream. For example,
//MYDD DD SYSOUT=(A,INTRDR)
For more details about the SYSOUT parameter, refer to z/OS MVS JCL User's
Guide.
You can specify DCB attributes for a SYSOUT data set on a DD statement or a call
to fopen() or freopen(). If you do not, z/OS XL C/C++ uses the following defaults:
Binary or Record I/O RECFM=VB LRECL=137 BLKSIZE=882
Text I/O RECFM=VBA LRECL=137 BLKSIZE=882
Tapes
z/OS XL C/C++ supports standard label (SL) tapes. If you are creating tape files,
you can only open them by ddname. z/OS XL C/C++ provides support for opening
tapes in read, write, or append mode, but not update. When you open a tape for
read or append, any data set control block (DCB) characteristics you specify must
match those of the existing data set exactly. The repositioning functions are
available only when you have opened a tape for read. For tapes opened for write or
append, calling rewind() has no effect; calls to any of the other repositioning
functions fail. To open a tape file for write, you must open it by ddname.
When you open a tape file for output, the data set name you specify in the JCL
must match the data set name specified in the tape label, even if the existing tape
file is empty. If this is not the case, you must either change the JCL to specify the
correct data set name or write to another tape file, or reinitialize the tape to remove
the tape label and the data. You can use IEBGENER with the following JCL to create
an empty tape file before passing it to the subsequent steps:
Note: For tapes, the value for UNIT= can be TAPE or CART.
The repositioning functions are available when you have opened a multivolume data
set for r,r+,rb,rb+,w+,wb+,a+,ab+. Repositioning multivolume data sets opened for
w,wb,a,ab is not allowed because it would be meaningless. For multivolume data
sets opened for write, calling rewind() has no effect; calls to any of the other
repositioning functions fail.
//MYDD DD DSNAME=TEST.TWO,DISP=(NEW,CATLG),
// VOLUME=(,,,3,SER=(333001,333002,333003)),
// SPACE=(TRK,(9,10)),UNIT=(3390,P)
This creates a data set that may span up to three volumes. For more information
about the VOLUME parameter on DD statements, refer to z/OS MVS JCL User's
Guide.
Notes:
1. Simultaneous readers (files that can support sharing by a writer and one or
more readers) are not supported for multivolume data sets.
2. Concatenated and multivolume data sets only tolerate single buffering mode.
Striped data sets also facilitate repositioning once the relative block number is
known. z/OS XL C/C++ exploits this capability when it uses fseek() to reposition.
This can result in substantial savings for applications that use ftell() and fseek()
with data sets that have RECFMs of V, U, and FB (not FBS). data sets. When a data
set is striped, an fseek() can seek directly to the specified block just as an
fsetpos() or rewind() can. For a normal data set with the aforementioned
RECFMs, z/OS XL C/C++ has to read forward or rewind the data set to get to the
desired position. Depending on how large the data set is, this can be quite
inefficient compared to a direct reposition. Note that for such data sets, striping
pads blocks to their maximum size. Therefore, you may be wasting space if you
have short records.
A large format sequential data set is specified using the DSNTYPE=LARGE keyword on
a JCL DD statement or using the dynamic allocation equivalent. z/OS XL C/C++
does not support the allocation of a large format sequential data set using fopen()
or freopen().
Other devices
z/OS XL C/C++ supports several other devices for input and output. You can open
these devices only by ddname. Table 17 lists a number of these devices and
describes which record formats are valid for them. None of the devices listed can
be opened for update except the DUMMY data set.
Table 17. Other devices supported for input and output
Device Valid open modes Repositioning? fldata()__device
Printer w, wb, a, ab No __PRINTER
Card reader r, rb rewind() only __OTHER
Card punch w, wb, a, ab No __OTHER
Optical reader r, rb rewind() only __OTHER
DUMMY data set r, rb, r+, rb+, r+b, w, rewind() only __DUMMY
wb, w+, wb+ w+b, a,
ab, a+, ab+, a+b
SUBSYS= r, rb No __OTHER
Note: For all devices above that support open modes a or ab, the modes are treated as if
you had specified w or wb.
z/OS XL C/C++ queries each device to find out its maximum BLKSIZE.
The DUMMY data set is not truly a device, although z/OS XL C/C++ treats it as one.
To use the DUMMY data set, specify DD DUMMY in your JCL. On input, the DUMMY data
set always returns EOF; on output, it is always successful. This is the way to specify
a DUMMY data set:
//MYDD DD DUMMY
For more information on DUMMY data sets, see z/OS MVS JCL User's Guide.
The following scenarios exist where QSAM (noseek) is requested, but the z/OS XL
C/C++ Run-Time Library switches to BSAM with NOTE and POINT macros requested
(seek):
v The data set is opened for update (r+, rb+, w+, wb+, a+, ab+)
v The data set is already opened for write (or update) in the same C process
v The data set is RECFM=FBS opened for append (a, ab, a+, ab+)
v The data set is LRECL=X
v The data set is the directory of a partitioned data set (PDS or PDSE)
v The data set is a member of a partitioned data set where the member was not
specified at allocation, but rather specified at fopen() or freopen()
Note: Repositioning is not allowed when noseek is requested, even if there was a
switch to seek.
recfm=
z/OS XL C/C++ allows you to specify any of the 27 possible RECFM types
(listed in Fixed-format records on page 10, Variable-format records on page
13, and Undefined-format records on page 16), as well as the z/OS XL C/C++
RECFMs * and A.
When you are opening an existing file for read or append (or for write, if you
have specified DISP=MOD), any RECFM that you specify must match that of the
existing file, except that you may specify recfm=U to open any file for read, and
you may specify recfm=FBS for a file created as recfm=FB. Specifying recfm=FBS
indicates to z/OS XL C/C++ that there are no short blocks within the file. If there
are, undefined behavior results.
For variable-format OS files, the RDW, SDW, and BDW contain the length of
the record, segment, and block as well as their own lengths. If you open a file
for read with recfm=U, z/OS XL C/C++ treats each physical block as an
undefined-format record. For files created with recfm=V, z/OS XL C/C++ does
not strip off block descriptor words (BDWs) or record descriptor words (RDWs),
and for blocked files, it does not deblock records. Using recfm=U is helpful for
viewing variable-format files or seeing how records are blocked in the file.
When you are opening an existing PDS or PDSE for write and you specify a
RECFM, it must be compatible with the RECFM of the existing data set. FS and
FBS formats are invalid for PDS members. For PDSs, you must use exactly the
same RECFM. For PDSEs, you may choose to change the blocked attribute (B),
because PDSEs perform their own blocking. If you want to read a PDS or
PDSE directory and you specify a RECFM, it must be recfm=U.
Specifying recfm=A indicates that the file contains ASA control characters. If you
are opening an existing file and you specify that ASA characters exist
(>recfm=A) when they do not, the call to fopen() or freopen() fails. If you create
a file by opening it for write or append, the A attribute is added to the default
RECFM. For more information about ASA, see Chapter 7, Using ASA text files,
on page 47.
Specifying recfm=* causes z/OS XL C/C++ to fill in any attributes that you do
not specify, taking the attributes from the existing data set. This is useful if you
want to create a new version of a data set with the same attributes as the
previous version. If you open a data set for write and the data set does not
exist, z/OS XL C/C++ uses the default attributes specified in fopen() defaults
on page 32. This parameter has no effect when you are opening for read or
append, and when you use it for non-DASD files.
recfm=+ is identical to recfm=* with the following exceptions:
v If there is no record format for the existing DASD data set, the defaults are
assigned as if the data set did not exist.
v When append mode is used, the fopen() fails.
96 z/OS V1R13.0 XL C/C++ Programming Guide
lrecl= and blksize=
The LRECL that you specify on the fopen() call defines the maximum record
length that the C library allows. Records longer than the maximum record length
are not written to the file. The first 4 bytes of each block and the first 4 bytes of
each record of variable-format files are used for control information. For more
information, see Variable-format records on page 13.
The maximum LRECL supported for fixed, undefined, or variable-blocked-
spanned format sequential disk files is 32760. For other variable-length format
disk files the maximum LRECL is 32756. Sequential disk files for any format
have a maximum BLKSIZE of 32760. The record length can be any size when
opening a spanned file and specifying lrecl=X. You can now specify lrecl=X on
the fopen() or freopen() call for spanned files. If you are updating an existing
file, the file must have been originally opened with lrecl=X for the open to
succeed. lrecl=X is useful only for text and record I/O.
When you are opening an existing file for read or append (or for write, if you
have specified DISP=MOD), any LRECL or BLKSIZE that you specify must match
that of the existing file, except when you open an F or FB format file on a disk
device without specifying the noseek parameter. In this case, you can specify
the S attribute to indicate to z/OS XL C/C++ that the file has no imbedded short
blocks. Files without short blocks improve z/OS XL C/C++'s performance.
BLKSIZE=0 will be ignored for an existing data set opened for read or append.
When you are opening an existing PDS or PDSE for write and you specify an
LRECL or BLKSIZE, it must be compatible with the LRECL or BLKSIZE of the
existing data set. For PDSs, you must use exactly the same values. For
PDSEs, the LRECL must be the same, but the BLKSIZE may be different if you
have changed the blocking attribute as described under the RECFM parameter
above. You can change the blocking attribute, because PDSEs perform their
own blocking. The BLKSIZE you choose should be compatible with the RECFM
and LRECL. When you open the directory of a PDS or PDSE, do not specify
LRECL or BLKSIZE; z/OS XL C/C++ uses the defaults. See Table 19 on page
102 for more information.
space=(units,(primary,secondary,directory) [rlse | norlse])
This keyword enables you to specify the space parameters for the allocation of
a z/OS data set. It applies only to z/OS data sets that you open by filename
and do not already exist. If you open a data set by ddname, this parameter has
no effect. You cannot specify any whitespace inside the value for the space
keyword. You must specify at least one value with this parameter. Any
parameter that you specify will be validated for syntax. If that validation fails,
then the fopen() or freopen() will fail even if the parameter would have been
ignored.
The supported values for units are as follows:
v Any positive integer indicating BLKSIZE
v CYL (mixed case)
v TRK (mixed case)
The primary quantity, the secondary quantity, and the directory quantity all must
be positive integers. The primary quantity is always required.
If you specify values only for units and primary, you do not have to specify the
inside set of parentheses. You can use a comma to indicate a quantity is to
take the default value. For example:
The last parameter, rlse or norlse , controls the disposition of the unused space.
If you open a new file for write and specify the space keyword, by default, any
unused space will be released when the file is closed. You can preserve the
allocated space by specifying norlse. For example:
You can specify only the values indicated on this parameter. If you specify any
other values, fopen() or freopen() fails. Any values not specified are omitted
on the allocation. These values are filled by the system during SVC 99
processing.
type=
You can omit this parameter. If you specify it, the only valid value for OS I/O is
type=record, which opens a file for record I/O.
acc=
This parameter is not valid for OS I/O. If you specify it, z/OS XL C/C++ ignores
it.
password=
This parameter is not valid for OS I/O. If you specify it, z/OS XL C/C++ ignores
it.
asis
If you use this parameter, z/OS XL C/C++ does not convert your filenames to
upper case. The use of the asis parameter is strongly discouraged, because
most of the I/O services used by z/OS XL C/C++ require uppercase filenames.
byteseek
When you specify this parameter and open a file in binary mode, all
repositioning functions (such as fseek() and ftell()) use relative byte offsets
from the beginning of the file instead of encoded offsets. In previous releases of
z/OS XL C/C++, byteseeking was performed only for fixed format binary files. To
have the byteseek parameter set as the default for all your calls to fopen() or
freopen(), you can set the environment variable _EDC_BYTE_SEEK to Y. See
Chapter 32, Using environment variables, on page 467 for more information.
noseek
Specifying this parameter on the fopen() call disables the repositioning
functions ftell(), fseek(), fgetpos(), and fsetpos() for as long as the file is
open. When you have specified NOSEEK and have opened a disk file for read
only, the only repositioning function allowed on the file is rewind(), if the device
supports rewinding. Otherwise, a call to rewind() sets errno and raises
SIGIOERR, if SIGIOERR is not set to SIG_IGN. Calls to ftell(), fseek(),
fsetpos(), or fgetpos() return EOF, set errno, and set the stream error flag on.
The use of the noseek parameter may improve performance when you are
reading and writing data sets.
Buffering
z/OS XL C/C++ uses buffers to map C I/O to system-level I/O. When z/OS XL
C/C++ performs I/O operations, it uses one of the following buffering modes:
v Line buffering characters are transmitted to the system when a new-line
character is encountered. Line buffering is meaningless for binary and record I/O
files.
v Full buffering characters are transmitted to the system when a buffer is filled.
You can use the setvbuf() and setbuf() library functions to set the buffering mode
before you perform any I/O operation to the file. setvbuf() fails if you specify
unbuffered I/O. It also fails if you try to specify line buffering for an FBS data set
opened in text mode, where the device does not support repositioning. This failure
happens because z/OS XL C/C++ cannot deliver records at line boundaries without
violating FBS format. Do not try to change the buffering mode after you have
performed any I/O operation to the file.
For all files except stderr, full buffering is the default, but you can use setvbuf() to
specify line buffering. For binary files, record I/O files, and unblocked text files, a
block is written out as soon as it is full, regardless of whether you have specified
line buffering or full buffering. Line buffering is different from full buffering only for
blocked text files.
Multiple buffering
Multiple buffering (or asynchronous I/O) is supported for z/OS data sets. Multiple
buffering is not supported for a data set opened for read at the same time that
another file pointer has it opened for write or append. When you open files for
multiple buffering, blocks are read into buffers before they are needed, eliminating
the delay caused by waiting for I/O to complete. Multiple buffering may make I/O
less efficient if you are seeking within or writing to a file, because seeking or writing
may discard blocks that were read into buffers but never used.
If you specify both NCP and BUFNO, z/OS XL C/C++ takes the greater of the two
values, up to the maximum for the applicable value. For example, if you specify a
BUFNO of 120 and you are using BSAM, which uses NCP instead, z/OS XL C/C++ will
use NCP=99.
If you do not specify either, z/OS XL C/C++ defaults to single buffering, except in
the following cases, where z/OS XL C/C++ uses the system's default BUFNO and
performs multiple buffering for both reading and writing:
v If you open a device that does not support repositioning, and specify read-only or
write-only mode (r, rb, w, wb, a, ab).
v If you specify the NOSEEK parameter on the call to fopen() or freopen(), and
specify read-only or write-only mode. When you specify NOSEEK, you get multiple
buffering for both reads and writes.
Note: Multiple buffering is ignored for concatenated and multivolume data sets.
If you do not specify RECFM when you are creating a new file, z/OS XL C/C++
uses the following defaults:
v If recfm is not specified in a fopen() call for an output binary file, recfm defaults
to:
recfm=VB for spool (printer) files,
recfm=FB otherwise.
v If recfm is not specified in a fopen() call for an output text file, recfm defaults to:
recfm=F if _EDC_ANSI_OPEN_DEFAULT is set to Y and no LRECL or BLKSIZE
specified. In this case, LRECL and BLKSIZE are both defaulted to 254.
recfm=VBA for spool (printer) files.
recfm=U for terminal files
recfm=V if the LRECL or BLKSIZE is specified
recfm=VB for all other OS files.
If recfm is not specified for a record I/O file, you will get the default of recfm=VB.
Table 19 on page 102 shows the defaults for LRECL and BLKSIZE when the z/OS
XL C/C++ compiler creates an OS file. Information from the C or C++ program
overrides that from the DD statement and the tape label. Information from the DD
statement overrides that from the data set label.
TAPE LABEL
Record format=FB
Record length=100
Block size=400
Recording density=1600
Table 19. fopen() defaults for LRECL and BLKSIZE when creating OS files
lrecl specified? blksize specified? RECFM LRECL BLKSIZE
no no All F 80 80
All FB 80 maximum integral
multiple of 80 less
than or equal to max
All V, VB, VS, or VBS minimum of 1028 or max
max4
All U 0 max
yes no All F lrecl lrecl
All FB lrecl maximum integral
multiple of lrecl less
than or equal to max
All V lrecl lrecl+4
All U 0 lrecl
no yes All F or FB blksize blksize
All V, VB, VS, or VBS minimum of 1028 or blksize
blksize4
All U 0 blksize
Note: All includes the standard (S) specifier for fixed formats, the ASA (A) specifier, and the machine control character
(M) specifier.
In Table 19, the value max represents the maximum reasonable block size for the
device. These are the current default maximum block sizes for several devices that
z/OS XL C/C++ supports:
Device Default maximum block size
For more information about specific default block sizes as returned by the DEVTYPE
macro, refer to z/OS DFSMS Using Data Sets.
You can perform multiple buffering under z/OS. See Multiple buffering on page
100 for details.
fread() is the only interface allowed for reading record I/O files. A read operation
directly after a write operation without an intervening call to fflush(), fsetpos(),
fseek(), or rewind() fails. z/OS XL C/C++ treats the following as read operations:
v Calls to read functions that request 0 bytes
v Read requests that fail because of a system error
v Calls to the ungetc() function
You can set up a SIGIOERR handler to catch read or write system errors. See the
debugging section in this book for more details.
For ASA variable text files, if a file was created without a control character as its
first byte, the first byte defaults to the ' ' character. When the file is read back, the
first character is read as a new-line.
For undefined format text files, reading a file causes a new-line character to be
inserted at the end of each record. On input, a record containing a single blank
character is considered an empty record and is translated to a new-line character.
Trailing blanks are preserved for each record.
For files opened in fixed text format, rightmost blanks are stripped off a record at
input, and a new-line character is placed in the logical record. This means that a
record consisting of a single new-line character is represented by a fixed-length
record made entirely of blanks.
fread() returns the number of items read successfully, so if you pass a size
argument equal to 1 and a count argument equal to the maximum expected length
A failed read operation may lead to undefined behavior until you reposition
successfully.
Writing to files
You can use the following library functions to write to a file:
v fwrite()
v fwrite_unlocked()
v printf()
v printf_unlocked()
v fprintf()
v fprintf_unlocked()
v vprintf()
v vprintf_unlocked()
v vfprintf()
v vfprintf_unlocked()
v puts()
v puts_unlocked()
v fputc()
v fputc_unlocked()
v fputs()
v fputs_unlocked()
v putc()
v putc_unlocked()
v putchar()
v putchar_unlocked()
fwrite() is the only interface allowed for writing to record I/O files. See z/OS XL
C/C++ Run-Time Library Reference for more information on these library functions.
z/OS XL C/C++ counts a call to a write function writing 0 bytes or a write request
that fails because of a system error as a write operation.
If you are updating a file and a system failure occurs, z/OS XL C/C++ tries to set
the file position to the end of the last record updated successfully. For a
fully-buffered file, this is at the end of the last record in a block. For a line-buffered
file, this may be any record in the current block. If you are writing new data at the
time of a system failure, z/OS XL C/C++ puts the file position at the end of the last
If one user opens a file for writing, and another later opens the same file for
reading, the user who is reading the file can check for records that may have been
written past the end of the file by the other user. If the file is a spanned variable text
file, the reader can read part of a spanned record and reach the end of the file
before reading in the last segment of the spanned record.
The way z/OS XL C/C++ treats text files depends on whether they are in fixed,
variable, or undefined format, and whether they use ASA.
As with ASA files in other environments, the first character of each record is
reserved for the ASA control character that represents a new-line, a carriage return,
or a form feed. See Chapter 7, Using ASA text files, on page 47 for more
information.
Table 20. C control to ASA characters
C Control Character Sequence ASA Character Description
\n ' ' skip one line
\n\n '0' skip two lines
\n\n\n '-' skip three lines
\f '1' new page
\r '+' overstrike
Note: Using ftell() or fgetpos() values for positions that do not exist after you
have shortened records results in undefined behavior.
When you are updating a file, writing new data into an existing record replaces the
old data and, if the new data is longer or shorter than the old data, changes the
size of the logical record by changing the number of blank characters in the
physical record. When you extend a record, thereby writing over the old new-line, a
new-line character is implied after the last character of the update. Calling fflush()
flushes the data out to the file and inserts blank padding between the last data
character and the end of the record. Once you have called fflush(), you can call
any of the read functions, which begin reading at the new-line. Once the new-line is
read, reading continues at the beginning of the next record.
If you have not set _EDC_ZERO_RECLEN, z/OS XL C/C++ writes out a record
containing a single blank character to represent a single new-line. On input, a
record containing a single blank character is considered an empty record and is
translated to a new-line character. Note that a single blank followed by a new-line is
written out as a single blank, and is treated as just a new-line on input. When
_EDC_ZERO_RECLEN is set, writing a record containing only a new-line results in a
zero-length variable record.
For more information about environment variables, refer to Chapter 32, Using
environment variables, on page 467. For more information about how z/OS XL
C/C++ treats empty records in variable format, see Mapping C types to variable
format on page 15.
When you are writing data to a non-blocked file without intervening flush or
reposition requests, each record is written to the system when a new-line or
carriage return character is written or when the file is closed.
When you are writing data to a blocked file without intervening flush or reposition
requests, if the file is opened in full buffering mode, the block is written to the
system on completion of the record that fills the block. If the blocked file is line
buffered, each record is written to the system when it is completed. If you are using
full buffering for a VB format file, a write may not fill a block completely. The data
does not go to the system unless a block is full; you can complete the block with
another write. If the subsequent write contains more data than is needed to fill the
block, it flushes the current block to the system and starts writing your data to a
new block.
When you are writing data to a spanned file without intervening flush or reposition
requests, if the record spans multiple blocks, each block is written to the system
once it is full and the user writes an additional byte of data.
For ASA variable text files, if a file was created without a control character as its
first byte or record (after the RDW and BDW), the first byte defaults to the ' '
character. When the file is read back, the first character is read as a new-line.
Once a record has been written, you cannot change its length. If you try to shorten
a logical record by updating it with a shorter record, z/OS XL C/C++ completes the
record with blank padding. If you try to lengthen a record by updating it with more
data than it can hold, z/OS XL C/C++ truncates the new data. The only instance in
which this does not happen is when you extend an empty record so that it contains
a single byte. Any data beyond the single byte is truncated.
In all truncation cases, the SIGIOERR signal is raised if the action for SIGIOERR is not
SIG_IGN. The user error flag is set so that ferror() will return TRUE. For more
information about SIGIOERR, ferror(), and other I/O-related debugging tools, see
Chapter 18, Debugging I/O programs, on page 221. z/OS XL C/C++ continues to
discard new output until you complete the current record by writing a new-line or
carriage return character, close the file, or change the file position.
If you are writing to one of the standard streams, attempting to write more data than
a record can hold results in the data being split across multiple records.
When you update a record, you can update less than the full record. The remaining
data that you do not update is left untouched in the file.
When you are writing new records to a fixed-record I/O file, if you try to write a
short record, z/OS XL C/C++ pads the record with nulls out to LRECL.
At the completion of an fwrite(), the file position is at the start of the next record.
For new data, the block is flushed out to the system as soon as it is full.
Flushing buffers
You can use the library function fflush() to flush streams to the system. For more
information about fflush(), see z/OS XL C/C++ Run-Time Library Reference.
The action taken by the fflush() library function depends on the buffering mode
associated with the stream and the type of streams. If you call one z/OS XL C/C++
program from another z/OS XL C/C++ program by using the ANSI system()
#include <stdio.h>
int main(void)
{
FILE * fp, * fp2;
int rc, rc2, rc3, rc4;
fp = fopen("a.b","w+");
fprintf(fp,"first record");
rewind(fp);
return(0);
}
Binary streams
z/OS XL C/C++ treats line buffering and full buffering the same way for binary files.
If the file has a variable length or undefined record format, fflush() writes the
current record out. This may result in short records. In blocked files, this means that
the block is written to disk, and subsequent writes are to a new block. For fixed
files, no incomplete records are flushed.
For single-volume disk files in FBS format, fflush() flushes complete records in an
incomplete block out to the file. For all other types of FBS files, fflush() does not
flush an incomplete block out to the file.
For files in FB format, fflush() always flushes out all complete records in the
current block. For sequential DASD files, new completed records are added to the
end of the flushed block if it is short. For non-DASD or non-sequential files, any
new record will start a new block.
Text streams
v Line-Buffered Streams
fflush() has no effect on line-buffered text files, because z/OS XL C/C++ writes
all records to the system as they are completed. All incomplete new records
remain in the buffer.
v Fully Buffered Streams
Calling fflush() flushes all completed records in the buffer, that is, all records
ending with a new-line or carriage return (or form feed character, if you are using
ASA), to the system. z/OS XL C/C++ holds any incomplete record in the buffer
until you complete the record or close the file.
For ASA text files, if a flush occurs while an ASA character that indicates more than
one new-line is being updated, the remaining new-lines will be discarded and a
read will continue at the first data character. For example, if \n\n\n is updated to
be \n\n and a flush occurs, then a 0 will be written out in the ASA character
position.
Record I/O
z/OS XL C/C++ treats line buffering and full buffering the same way for record I/O.
For files in FB format, calling fflush() writes all records in the buffer to the system.
For single-volume disk files in FBS format, fflush() will flush complete records in an
incomplete block out to the file. For all other types of FBS files, fflush() will not
flush an incomplete block out to the file. For all other formats, calling fflush() has
no effect, because fwrite() has already written the records to disk.
ungetc() considerations
ungetc() pushes characters back onto the input stream for binary and text files.
ungetc() handles only single-byte characters. You can use it to push back as many
as four characters onto the ungetc() buffer. For every character pushed back with
ungetc(), fflush() backs up the file position by one character and clears all the
pushed-back characters from the stream. Backing up the file position may end up
A B C D
file pointer
For example, given the stream you can run the following code fragment:
fgetc(fp); /* Returns A and puts the file position at */
/* the beginning of the character B */
ungetc(Z,fp); /* Logically inserts Z ahead of B */
fflush(fp); /* Moves the file position back by one to A, */
/* removes Z from the logical stream */
If you want fflush() to ignore ungetc() characters, you can set the _EDC_COMPAT
environment variable. See Chapter 32, Using environment variables, on page 467
for more information.
With large file support enabled for AMODE 31 C/C++ applications, you can use the
following library functions for 64-bit offsets:
v fseeko()
v fseeko_unlocked()
v ftello()
v ftello_unlocked()
For AMODE 64 C/C++ applications, large files are automatically supported in the
LP64 programming model. All of the above functions (both lists) can be used with
64-bit offsets.
See z/OS XL C/C++ Run-Time Library Reference for more information on these
library functions.
Calling any of these functions flushes all complete and updated records out to the
system. If a repositioning operation fails, z/OS XL C/C++ attempts to restore the
original file position and treats the operation as a call to fflush(), except that it
does not account for the presence of ungetc() or ungetwc() characters, which are
lost. After a successful repositioning operation, feof() always returns 0, even if the
position is just after the last byte of data in the file.
The fsetpos() and fgetpos() library functions are generally more efficient than ftell()
and fseek(). The fgetpos() function can encode the current position into a structure
that provides enough room to hold the system position as well as position data
specific to C or C++. The ftell() function must encode the position into a single
word of storage, which it returns. This compaction forces fseek() to calculate
certain position information specific to C or C++ at the time of repositioning. For
variable-format binary files, you can choose to have ftell() return relative byte
offsets. In previous releases, ftell() returned only encoded offsets, which
contained the relative block number. Since you cannot calculate the block number
from a relative byte offset in a variable-format file, fseek() may have to read
through the file to get to the new position. fsetpos() has system position
information available within the the fpos_t structure and can generally reposition
directly to the desired location.
You can use the ftell() and fseek() functions to set the current position within all
types of files except for the following:
v Files on nonseekable devices (for example, printers)
v Partitioned data sets opened in w or wb mode.
Although repositioning within files opened for write mode is not available, you can
use fgetpos() and ftell() to save the current position, and this position can later
be used to reposition within the same file if opened in one of the modes where
reposition is allowed.
For AMODE 31 C/C++ applications, the repositioning functions can be used with
large format sequential data sets under the following conditions:
v The data set contains 256 TB - 256 bytes or less.
v The data set uses 2 GB blocks or less.
ungetc() considerations
For binary and text files, the library functions fgetpos() and ftell() take into
account the number of characters you have pushed back onto the input stream with
ungetc(), and adjust the file position accordingly. ungetc() backs up the file position
by a single byte each time you call it. For text files, z/OS XL C/C++ counts the
new-lines added to the records as single-byte characters when it calculates the file
position.
If you make so many calls to ungetc() that the logical file position is before the
beginning of the file, the next call to ftell() or fgetpos() fails.
If you want fgetpos() and fseek() to ignore ungetc() characters, you can set the
_EDC_COMPAT environment variable. See Chapter 32, Using environment variables,
on page 467 for details. ftell() is not affected by the setting of _EDC_COMPAT.
You do not need to acquire an offset from ftell() to seek to a relative position; you
may specify a relative offset to fseek() with a whence value of SEEK_SET.
However, you cannot specify a negative offset to fseek() when you have specified
SEEK_SET, because a negative offset would indicate a position before the
beginning of the file. Also, you cannot specify a negative offset with whence values
of SEEK_CUR or SEEK_END such that the resulting file position would be before
the beginning of the file. If you specify such an offset, fseek() fails.
If your file is not opened read-only, you can specify a position that is beyond the
current EOF. In such cases, a new end-of-file position is created; null characters are
automatically added between the old EOF and the new EOF.
fseek() support of byte offsets in variable-format files generally requires reading all
records from the whence value to the new position. The impact on performance is
greatest if you open an existing file for append in BYTESEEK mode and then call
ftell(). In this case, ftell() has to read from the beginning of the file to the
current position to calculate the required byte offset. Support for byteseeking is
intended to ease portability from other platforms. If you need better performance,
consider using ftell()-encoded offsets, see Encoded offsets on page 115.
Encoded offsets are values representing the block number and the relative byte
within that block, all within one long int. Because z/OS XL C/C++ does not
document its encoding scheme, you cannot rely on any encoded offset not returned
by ftell(), except 0, which is the beginning of the file. This includes encoded
offsets that you adjust yourself (for example, with addition or subtraction). When
you call fseek() with the whence value SEEK_SET, you must use either 0 or an
encoded offset returned from ftell(). For whence values of SEEK_CUR and
SEEK_END, however, you specify relative byte offsets. If you want to seek to a
certain relative byte offset, you can use SEEK_SET with an offset of 0 to rewind the
file to the beginning, and then you can use SEEK_CUR to specify the desired
relative byte offset.
In earlier releases, ftell() could determine position only for files with no more than
131,071 blocks. In the new design, this number increases depending on the block
size. From a maximum block size of 32,760, every time this number decreases by
half, the number of blocks that can be represented doubles. Using the large file
version of ftello() for a large format sequential data set increases the maximum
number of blocks that can be represented to 2 GB in AMODE 31 C/C++
applications.
If your file is not opened read-only, you can use SEEK_CUR or SEEK_END to
specify a position that is beyond the current EOF. In such cases, a new end-of-file
position is created; null characters are automatically added between the old EOF and
the new EOF. This does not apply to PDS members, as they cannot be extended.
For SEEK_SET, because you are restricted to using offsets returned by ftell(),
any offset that indicates a position outside the current file is invalid and causes
fseek() to fail.
When you call fseek() with the whence value SEEK_SET, you must use an encoded
offset returned from ftell(). For whence values of SEEK_CUR and SEEK_END,
however, you specify relative byte offsets. If you want to seek to a certain relative
byte offset, you can use SEEK_SET with an offset of 0 to rewind the file to the
beginning, and then you can use SEEK_CUR to specify the desired relative byte
offset. z/OS XL C/C++ counts new-line characters and skips to the next record each
time it reads one.
Unlike binary files you cannot specify offsets for SEEK_CUR and SEEK_END that
set the file position past the end of the file. Any offset that indicates a position
outside the current file is invalid and causes fseek() to fail.
In earlier releases, ftell() could determine position only for files with no more than
131071 blocks. In the new design, this number increases depending on the block
size. From a maximum block size of 32760, every time this number decreases by
seeks to relative record 6. You do not need to get an offset from ftell().
You cannot seek past the end or before the beginning of a file.
For files opened in fixed binary mode, incomplete records will be padded with null
characters when you close the file.
For files opened in variable binary mode, incomplete records are flushed to the
system. In a spanned file, closing a file can cause a zero-length segment to be
written. This segment will still be part of the non-zero-length record. For files
opened in undefined binary mode, any incomplete output is flushed on close.
Closing files opened in text mode causes any incomplete new record to be
completed with a new-line character. All records not yet flushed to the file are
written out when the file is closed.
For files opened for record I/O, closing causes all records not yet flushed to the file
to be written out.
When fclose() is used to close a stream associated with a z/OS data set, some
failures may be unrecoverable, and will result in an ABEND. These ABENDs may
include I/O ABENDs of the form x14 and x37. Control will not be returned to the
caller of fclose() to report the error. To process these types of errors, applications
need to use z/OS Language Environment condition handling to receive control (see
z/OS Language Environment Programming Guide), or register a signal handler for
SIGABND (see Chapter 28, Handling error conditions, exceptions, and signals, on
page 403).
If an application fails during fclose() with a x37 abend, and the application would
like to recover and perform any functions not related to file I/O, the following
technique can be used. Refer to Figure 17 on page 118 for an example.
1. Register a signal handler for SIGABND and SIGIOERR.
2. fopen() the file. The NOSEEK option cannot be specified.
3. Manipulate the file as needed by the application.
4. When the application is done with the file, fflush() the file, before any fclose() is
issued. This will ensure, if an x37 is going to occur during fflush() or fclose()
processing, that the x37 occurs in the fflush(), before the fclose() occurs.
5. An x37 abend occurs during fflush().
6. The signal handler will receive control.
7. Once inside the signal handler, any functions not related to file I/O may be
performed.
#include <stdio.h>
#include <stdlib.h>
#include <dynit.h>
#include <signal.h>
#include <setjmp.h>
void sighandler();
jmp_buf env;
FILE *f;
int main()
{
int rc;
int s=80;
int w;
char buff 80 ="data";
__dyn_t ip;
redo:
dyninit(&ip);
ip.__dsname="MY.DATASET";
ip.__status=__DISP_OLD;
ip.__ddname="NAMEDD";
ip.__conddisp=__DISP_CATLG;
rc=dynalloc(&ip);
f=fopen("DD:NAMEDD","wb");
if (f==0)
{ perror("open error");
return 12;
}
signal(SIGABND,sighandler);
signal(SIGIOERR,sighandler);
while (1)
{
if (setjmp(env))
{
dyninit(&ip);
ip.__ddname="NAMEDD";
ip.__conddisp=__DISP_CATLG;
rc= dynfree(&ip);
goto retry;
}
w=fwrite(buff,1,s,f);
}
fflush(f);
fclose(f);
retry:
goto redo;
}
void sighandler() {
fclose(f);
longjmp(env,1);
}
fldata() behavior
The format of the fldata() function is as follows:
The fldata() function is used to retrieve information about an open stream. The
name of the file is returned in filename and other information is returned in the
fldata_t structure, shown in Figure 18 on page 120. Values specific to this category
of I/O are shown in the comment beside the structure element. Additional notes
follow the figure. For more information on the fldata() function, refer to z/OS XL
C/C++ Run-Time Library Reference.
The Single UNIX Specification defines another type of file called STREAMS. Even
though the system interfaces are provided, it is impossible to have a valid STREAMS
file descriptor. These interfaces will always return a return code of -1 with errno set
to indicate an error such as, EBADF, EINVAL, or ENOTTY.
z/OS UNIX file system streams follow the binary model, regardless of whether they
are opened for text, binary, or record I/O. You can simulate record I/O by using
new-line characters as record boundaries.
For information on the z/OS UNIX file system and access to files within it from other
than the C or C++ language, see z/OS UNIX System Services User's Guide. For an
introduction to and description of the behavior of a POSIX-defined file system, see
Zlotnick, Fred, The POSIX.1 Standard: A Programmer's Guide,,Redwood City, CA:
The Benjamin/Cummings Publishing Company, Inc., 1991.
This topic describes C I/O stream functions as they can be used within C++
programs. If you want to use the C++ I/O stream classes instead, see Chapter 4,
Using the Standard C++ Library I/O Stream Classes, on page 21. For more
detailed information, see Standard C++ Library Reference. For information about
using wide-character I/O with z/OS XL C/C++, see Chapter 8, z/OS XL C Support
for the double-byte character set, on page 51.
Creating files
You can use library functions to create the following types of z/OS UNIX file system
files.
v Regular Files
v Link and Symbolic Link Files
v Directory Files
v Character Special Files
v FIFO Files
Regular files
Use any of the following C functions to create regular files in the z/OS UNIX file
system:
v creat()
v fopen()
v freopen()
v open()
For a description of these and other I/O functions, see z/OS XL C/C++ Run-Time
Library Reference.
Copyright IBM Corp. 1996, 2012 123
Link and symbolic link files
Use either of the following C functions to create z/OS UNIX file system link or
symbolic link files:
v link()
v symlink()
Directory files
Use the mkdir() C function to create a z/OS UNIX file system directory file.
FIFO files
Use the mkfifo() C function to create a FIFO file (named pipe) in the z/OS UNIX
file system.
Opening files
This section discusses the use of the fopen() or freopen() library functions to open
z/OS UNIX file system I/O files. You can also access z/OS UNIX file system files
using low-level I/O open() function. See Low-level z/OS UNIX I/O on page 137 for
information about low-level I/O, and z/OS XL C/C++ Run-Time Library Reference
for information about any of the functions listed above.
The name of a z/OS UNIX file system file can include characters chosen from the
complete set of character values, except for null characters. If you want a portable
filename, then choose characters from the POSIX .1 portable filename character
set.
The complete pathname can begin with a slash and be followed by zero, one, or
more filenames, each separated by a slash. If a directory is included within the
pathname, it may have one or more trailing slashes. Multiple slashes following one
another are interpreted as one slash.
If your program is running under POSIX(ON), all valid POSIX names are passed with
the asis fopen() parameter to the POSIX open() function.
You can access either z/OS UNIX file system files or MVS data sets from programs.
Programs accessing files or data sets can be executed with either the POSIX(OFF)
or POSIX(ON) run-time options. There are basic file naming rules that apply for z/OS
The POSIX run-time option determines the type of z/OS XL C/C++ services and I/O
available to your program. (See z/OS XL C/C++ User's Guide for a discussion of
the z/OS UNIX programming environment and overview of binding z/OS UNIX XL
C/C++ applications.)
Both the basic and special z/OS XL C/C++ file naming rules for z/OS UNIX file
system files are described in the sections that follow. Examples are provided. All
examples must be run with the POSIX(ON) option. For information about MVS data
sets, see Chapter 10, Performing OS I/O operations, on page 81.
z/OS UNIX file system files: The following is the format for the pathname
argument on the fopen() or freopen() function:
pathname
" /
.
dd: ddname
// DD: ( member ) "
The POSIX.1 standard defines pathname as the information that identifies a file. For
the z/OS UNIX implementation of the POSIX.1 standard, a pathname can be up to
1024 charactersincluding the null-terminating character. Optionally, it can begin
with a slash character (/) followed by directory names separated by slash
characters and a filename. For the pathname, each directory name or the filename
can be up to 255 characters long.
If you begin the pathname value with ./, the specified file in the working directory is
opened:
fopen("./parts.order", "w+")
Likewise, if you begin the pathname value with /, the specified file in the root
directory is opened:
fopen("/parts.order", "w+")
Chapter 11. Performing z/OS UNIX file system I/O operations 125
If you specify more than two consecutive slash characters anywhere in a pathname,
all but the first slash character is ignored, as in the following examples:
"//a.b" MVS data set prefix.a.b
"///a.b" z/OS UNIX file system file /a.b
"////a.b" z/OS UNIX file system file /a.b
"a////b.c" z/OS UNIX file system file a/b.c
"/a.b" z/OS UNIX file system file /a.b
"/a///b.c" z/OS UNIX file system file /a/b.c
For z/OS UNIX file system files, leading and trailing white spaces are significant.
For an application program that is to be run under POSIX(ON), you can include in
your program statements similar to the following to open the file parts.instock for
reading in the working directory:
FILE *stream;
To open the MVS data set user-prefix.PARTS.INSTOCK for reading, include statements
similar to the following in your program:
FILE *stream;
To open the file parts.instock in the working directory for reading, include
statements similar to the following in your program:
FILE *stream;
Note: Use of the z/OS XL C/C++ fork() library function from an application
program under z/OS UNIX does not replicate the data definition information of the
parent process in the child process. Use of any of the exec() library functions
deallocates the data definition information for the application process.
For the declaration just shown for the file parts.instock, you should write a JCL
DD statement similar to the following:
//PSTOCK DD PATH=/u/parts.instock,...
For more information on writing DD statements, you should refer to the job control
language (JCL) manual z/OS MVS JCL Reference.
To open the file by DD name under TSO/E, you must write an ALLOCATE command.
For the declaration of a file parts.instock, you should write a TSO/E ALLOCATE
command similar to the following:
ALLOCATE DDNAME(PSTOCK) PATH(/u/parts.instock)...
See z/OS TSO/E Command Reference for more information on TSO ALLOCATE.
recfm=
Ignored for z/OS UNIX file system I/O.
Chapter 11. Performing z/OS UNIX file system I/O operations 127
lrecl= and blksize=
Ignored for z/OS UNIX file system I/O, except that lrecl affects the value
returned in the __maxreclen field of fldata() as described below.
acc= Ignored for z/OS UNIX file system I/O.
password
Ignored for z/OS UNIX file system I/O.
space=
Ignored for z/OS UNIX file system I/O.
type= The only valid value for this parameter under the z/OS UNIX file system is
type=record. If you specify this, your file follows the z/OS UNIX file system
record I/O rules:
1. One record is defined to be the data up to the next new-line character.
2. When an fread() is done the data will be copied into the user buffer as
if an fgets(buf, size_item*num_items, stream) were issued. Data is
read into the user buffer up to the number of bytes specified on the
fread(), or until a new-line character or EOF is found. The new-line
character is not included.
3. When an fwrite() is done the data will be written from the user buffer
with a new-line character added by the RTL code. Data is written up to
the number of bytes specified on the fwrite(); the new-line is added by
the RTL and is not included in the return value from fwrite().
4. If you have specified an lrecl and type=record, fldata() of this stream
will return the lrecl you specified, in the __maxreclen field of the
__fileData return structure of stdio.h. If you specified type=record but
no lrecl, the __maxreclen field will contain 1024.
If type=record is not in effect, a call to fldata() of this stream will return
0 in the __maxreclen field of the __fileData return structure of stdio.h.
asis Ignored for z/OS UNIX file system I/O.
byteseek
Ignored for z/OS UNIX file system I/O.
noseek
Ignored for z/OS UNIX file system I/O.
OS Ignored for z/OS UNIX file system I/O.
abend=
Ignored for z/OS UNIX file system I/O.
fread() is the only interface allowed for reading record I/O files. See z/OS XL
C/C++ Run-Time Library Reference for more information on all of the above library
functions.
For z/OS UNIX low-level I/O, you can use the read() and readv() function. See
Low-level z/OS UNIX I/O on page 137.
Opening and reading from z/OS UNIX file system directory files
To open a z/OS UNIX file system directory, you can use the opendir() function.
You can use the following library functions to read from, and position within, z/OS
UNIX file system directories:
v readdir()
v seekdir()
v telldir()
Chapter 11. Performing z/OS UNIX file system I/O operations 129
v pwrite()
fwrite() is the only interface allowed for writing to record I/O files. See z/OS XL
C/C++ Run-Time Library Reference for more information on all of the above library
functions. For z/OS UNIX low-level I/O, you can use the write() and writev()
function.
Flushing records
You can use the library function fflush() to flush streams to the system. For more
information about fflush(), see z/OS XL C/C++ Run-Time Library Reference.
The action taken by the fflush() library function depends on the buffering mode
associated with the stream and the type of streams. If you call one z/OS XL C/C++
program from another z/OS XL C/C++ program by using the ANSI system()
function, all open streams are flushed before control is passed to the callee, and
again before control is returned to the caller. A call to the POSIX system() function
does not flush any streams.
For z/OS UNIX file system files, the fflush() function copies the data from the
run-time buffer to the file system. The fsync() function copies the data from the file
system buffer to the storage device.
With large file support enabled for AMODE 31 C/C++ applications, you can use the
following library functions for 64-bit offsets:
v fseeko()
v fseeko_unlocked()
v ftello()
v ftello_unlocked()
v lseek()
For AMODE 64 C/C++ applications, large files are automatically supported in the
LP64 programming model. All of the above functions (both lists) can be used with
64-bit offsets.
Closing files
You can use fclose(), freopen(), or close() to close a file. z/OS XL C/C++
automatically closes files on normal program termination, and attempts to do so
under abnormal program termination or abend. See z/OS XL C/C++ Run-Time
Library Reference for more information on these library functions. For z/OS UNIX
low-level I/O, you can use the close() function. When you use any exec() or
fork() function, files defined as marked to be closed are closed before control is
returned.
Deleting files
Use the unlink() or remove() z/OS XL C/C++ function to delete the following types
of z/OS UNIX file system files:
v Regular
v Character special
v FIFO
v Link files
Use the rmdir() z/OS XL C/C++ function to delete a z/OS UNIX file system
directory file. See z/OS XL C/C++ Run-Time Library Reference for more information
about these functions.
Pipe I/O
POSIX.1 pipes represent an I/O channel that processes can use to communicate
with other processes. Pipes are conceptually like z/OS UNIX file system files. One
process can write data into a pipe, and another process can read data from the
pipe.
z/OS UNIX XL C/C++ supports two types of POSIX.1-defined pipes: unnamed pipes
and named pipes (FIFO files).
An unnamed pipe is accessible only by the process that created the pipe and its
child processes. An unnamed pipe does not have to be opened before it can be
used. It is a temporary file that lasts only until the last file descriptor that references
it is closed. You can create an unnamed pipe by calling the pipe() function.
Chapter 11. Performing z/OS UNIX file system I/O operations 131
communicate with other processes that it did not fork, you should use the
POSIX.1-defined named pipe (FIFO special file) support. See Using named pipes
on page 133 for more information.
When you code the pipe() function to create a pipe, you pass a pointer to a
two-element integer array where pipe() puts the file descriptors it creates. One
descriptor is for the input end of the pipe, and the other is for the output end of the
pipe. You can code your application so that one process writes data to the input
end of the pipe and another process reads from the output end on a first-in-first-out
basis. You can also build a stream on the pipe by using fdopen(), and use buffered
I/O functions. The result is that you can communicate data between a parent
process and any of its child processes.
The opened pipe is assigned the two lowest-numbered file descriptors available.
z/OS UNIX provides no security checks for unnamed pipes, because such a pipe is
accessible only by the parent process that creates the pipe and any of the parent
process's descendent processes. When the parent process ends, an unnamed pipe
created by the process can still be used, if needed, by any existing descendant
process that has an open file descriptor for the pipe.
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main() {
int ret_val;
int pfd[2];
char buff[32];
char string1[]="String for pipe I/O";
Within the application program, you create a named pipe by coding a mkfifo() or
mknod() function. You give the FIFO a name and an access mode when you create
it. If the access mode allows all users read and write access to the named pipe,
any process that knows its name can use it to send or receive data.
Chapter 11. Performing z/OS UNIX file system I/O operations 133
Processes can use the open() function to access named pipes and then use the
regular I/O functions for files, such as read(), write(), and close(), when
manipulating named pipes. Buffered I/O functions can also be used to access and
manipulate named pipes. For more information on the mkfifo() and mknod()
functions and the file I/O functions, see z/OS XL C/C++ Run-Time Library
Reference.
The following steps outline how to use a named pipe from z/OS UNIX XL C/C++
application programs:
1. Create a named pipe using the mkfifo() function. Only one of the processes
that use the named pipe needs to do this.
2. Access the named pipe using the appropriate I/O method.
3. Communicate through the pipe with another process using file I/O functions:
a. Write data to the named pipe.
b. Read data from the named pipe.
4. Close the named pipe.
5. If the process created the named pipe and the named pipe is no longer needed,
remove that named pipe using the unlink() function.
A process running the following simple example program creates a new named pipe
with the file pathname pointed to by the path value coded in the mkfifo() function.
The access mode of the new named pipe is initialized from the mode value coded in
the mkfifo() function. The file permission bits of the mode argument are modified
by the process file creation mask.
Note: The two processes are related and have agreed to communicate through the
named pipe. They need not be related, however. Other authorized users can run
the same program and participate in (or interfere with) the process communication.
main()
{ /* start of program */
if ((mkfifo(fifoname,S_IRWXU)) != 0) {
printf("Unable to create a fifo; errno=%d\n",errno);
exit(1); /* Print error message and return */
}
/* perform a write */
n_elements = fwrite(str,1,strlen(str),wr_stream);
if (n_elements != (size_t) strlen(str)) {
printf("Fwrite returned %d, expected %d\n",
(int)n_elements,strlen(str));
exit(101);
}
exit(0); /* return success to parent */
}
Chapter 11. Performing z/OS UNIX file system I/O operations 135
/* get current flag settings of file */
if ((flags = fcntl(fileno(rd_stream),F_GETFL)) == -1) {
printf("fcntl returned -1 for %s\n",fifoname);
exit(3);
}
if (strncmp(char_ptr,str,strlen(str))) {
printf("\ncontents of char_ptr are %s ",
char_ptr);
printf("\ncontents of str are %s ",
str);
printf("\nThese should be equal");
exit(7);
}
ret_value = fclose(rd_stream);
if (ret_value != 0) {
printf("\nFclose failed for %s",fifoname);
printf("\nerrno is %d",errno);
exit(8);
}
ret_value = remove(fifoname);
if (ret_value != 0) {
printf("\nremove failed for %s",fifoname);
printf("\nerrno is %d",errno);
exit(9);
}
pid = wait(c_status);
if ((WIFEXITED(c_status) !=0) &&; (WEXITSTATUS(c_status) !=0)) {
printf("\nchild exited with code %d",WEXITSTATUS(c_status));
exit(10);
}
} /* end of else clause */
printf("About to issue exit(0), \
processing completed successfully\n");
exit(0);
}
Figure 21 is example code (CCNGHF3) that demonstrates the use of z/OS UNIX
stream input/output by writing streams to a file, reading the input lines, and
replacing a line.
#define _OPEN_SYS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#undef _OPEN_SYS
FILE *stream;
Figure 21. Example of z/OS UNIX stream input and output functions (Part 1 of 3)
Chapter 11. Performing z/OS UNIX file system I/O operations 137
int main(void)
{
if ((stream = fopen("./myfile.data","wb"))==NULL) {
perror("Error opening file");
exit(0);
}
for(i=0; i<12;i++) {
int len1 = strlen(string1);
rc = fwrite(string1, 1, len1, stream);
if (rc != len1) {
perror("fwrite failed");
printf("i = %d\n", i);
exit(99);
}
}
rc = fwrite(string2,1,sizeof(string2)-1,stream);
if (rc != sizeof(string2)-1) {
perror("fwrite failed");
exit(99);
}
for(i=0;i<12;i++) {
rc = fwrite(string1,1,sizeof(string1)-1,stream);
if (rc != sizeof(string1)-1) {
perror("fwrite failed");
printf("i = %d\n", i);
exit(99);
}
}
fclose(stream);
/* Read data stream and search for location of string2. */
/* EOF is not set until an attempt is made to read past the */
/* end-of-file, thus the fread is at the end of the while loop */
Figure 21. Example of z/OS UNIX stream input and output functions (Part 2 of 3)
if ((position=ftell(stream)) == -1L)
perror("Error saving file position.");
rc = fread(string4, 1, sizeof(string2)-1, stream);
}
fclose(stream);
/* Replace line containing string2 with string3 */
fd = open("test.data",O_RDWR);
x = write(fd,"a record",8);
if (x < 8){
perror("write failed\n");
}
rc = lseek(fd,0,SEEK_SET);
x = read(fd,buffer,8);
if (x < 8){
perror("read failed\n");
}
printf("data read is %.8s\n",buffer);
close(fd);
}
Figure 21. Example of z/OS UNIX stream input and output functions (Part 3 of 3)
To use 64-bit offset and file sizes, you must make the following changes in your
code:
1. Change any variables used for offsets in fseek() or ftell() that are int
or long to the off_t data type.
2. Define the _LARGE_FILES 1 feature test macro.
3. Replace fseek()/ftell() with fseeko()/ftello(). See z/OS XL C/C++
Run-Time Library Reference for descriptions of these functions.
4. Compile with the LANGLVL(LONGLONG) compiler option.
Notes:
1. These changes are compatible with your older files.
2. Large Files support (64bit offset and file sizes) is automatic in the LP64
programming model that is used in 64bit. The long data type is widened to
64bits. This enables fseek() and ftell() to work with the larger offsets with
no code change. The fseeko() and ftello() functions also work with 64bit
offsets since off_t is typedef'd as a long int.
Chapter 11. Performing z/OS UNIX file system I/O operations 139
The example program (CCNGHF4) in Figure 22 on page 141 provides the same
function as CCNGHF3, but it uses 64-bit offsets. The changed lines are marked in a
bold font.
#define _OPEN_SYS
#define _LARGE_FILES 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#undef _OPEN_SYS
FILE *stream;
int main(void)
{
if ((stream = fopen("./myfile.data","wb"))==NULL) {
perror("Error opening file");
exit(0);
}
for(i=0; i<12;i++) {
int len1 = strlen(string1);
rc = fwrite(string1, 1, len1, stream);
if (rc != len1) {
perror("fwrite failed");
printf("i = %d\n", i);
exit(99);
}
}
rc = fwrite(string2,1,sizeof(string2)-1,stream);
if (rc != sizeof(string2)-1) {
perror("fwrite failed");
exit(99);
}
for(i=0;i<12;i++) {
rc = fwrite(string1,1,sizeof(string1)-1,stream);
if (rc != sizeof(string1)-1) {
perror("fwrite failed");
printf("i = %d\n", i);
exit(99);
}
}
Figure 22. Example of HFS stream input and output functions (Part 1 of 2)
Chapter 11. Performing z/OS UNIX file system I/O operations 141
fclose(stream);
/* Read data stream and search for location of string2. */
/* EOF is not set until an attempt is made to read past the */
/* end-of-file, thus the fread is at the end of the while loop */
if ((position=ftello(stream)) == -1LL)
perror("Error saving file position.");
while(!feof(stream)) {
if (rc != sizeof(string2)-1) {
perror("fread failed");
exit(99);
}
if ((position=ftello(stream)) == -1LL)
perror("Error saving file position.");
fclose(stream);
/* Replace line containing string2 with string3 */
fd = open("test.data",O_RDWR);
x = write(fd,"a record",8);
if (x < 8){
perror("write failed\n");
}
strpos = lseek(fd,0LL,SEEK_SET); /* Note off_t is 64bits with _LARGE_FILES */
/* set and the off_t variable */
/* needs a 64bit constant of 0LL */
x = read(fd,buffer,8);
if (x < 8){
perror("read failed\n");
}
printf("data read is %.8s\n",buffer);
close(fd);
}
Figure 22. Example of HFS stream input and output functions (Part 2 of 2)
fldata() behavior
The format of the fldata() function is as follows:
The fldata() function is used to retrieve information about an open stream. The
name of the file is returned in filename and other information is returned in the
fldata_t structure, shown in Figure 23. Values specific to this category of I/O are
shown in the comment beside the structure element. Additional notes pertaining to
this category of I/O follow the figure. For more information on the fldata() function,
refer to z/OS XL C/C++ Run-Time Library Reference.
struct __fileData {
unsigned int __recfmF : 1, /* always off */
__recfmV : 1, /* always off */
__recfmU : 1, /* always on */
__recfmS : 1, /* always off */
__recfmBlk : 1, /* always off */
__recfmASA : 1, /* always off */
__recfmM : 1, /* always off */
__dsorgPO : 1, /* N/A -- always off */
__dsorgPDSmem : 1, /* N/A -- always off */
__dsorgPDSdir : 1, /* N/A -- always off */
__dsorgPS : 1, /* N/A -- always off */
__dsorgConcat : 1, /* N/A -- always off */
__dsorgMem : 1, /* N/A -- always off */
__dsorgHiper : 1, /* N/A -- always off */
__dsorgTemp: 1, /* N/A -- always off */
__dsorgVSAM: 1, /* N/A -- always off */
__dsorgHFS : 1, /* always on */
__openmode : 2, /* one of: */
/* __BINARY */
/* __RECORD */
__modeflag : 4, /* combination of: */
/* __READ */
/* __WRITE */
/* __APPEND */
/* __UPDATE */
__dsorgPDSE: 1, /* N/A -- always off */
__reserve2 : 8; /* */
__device_t __device; /* __HFS */
unsigned long __blksize, /* 0 */
__maxreclen; /* */
unsigned short __vsamtype; /* N/A */
unsigned long __vsamkeylen; /* N/A */
unsigned long __vsamRKP; /* N/A */
char * __dsname; /* */
unsigned int __reserve4; /* */
};
typedef struct __fileData fldata_t;
Notes:
1. The filename is the same as specified on the fopen() or freopen() function call.
2. The __maxreclen value is 0 for regular I/O (binary). For record I/O the value is
lrecl or the default of 1024 when lrecl is not specified.
3. The __dsname value is the real POSIX pathname.
Chapter 11. Performing z/OS UNIX file system I/O operations 143
File tagging and conversion
In general, the file system knows the contents of a file only as a set of bytes.
Applications which create and process bytes in a file know whether these bytes
represent binary data, text (character) data, or a mixture of both. File tags are file
metadata fields which describe the contents of a file. Enhanced ASCII includes the
following file tag fields:
txtflag A flag indicating if a file consists solely of character data encoded
by a single coded character set ID (CCSID).
file ccsid A 16 bit field specifying the CCSID of characters in the file.
Applications can explicitly tag files using new open() or fcntl() options, or
applications can allow the logical file system (LFS) to tag new files on first write,
fopen(). A new environment variable, _BPXK_CCSID, is used to assign a program
CCSID to an application, which LFS will use to tag new files on first write. LFS also
uses the program CCSID derived from _BPXK_CCSID to set up auto-conversion of
pure text datastreams. LFS attempts to set up auto-conversion when:
v Auto-conversion is enabled for an application by the _BPXK_AUTOCVT environment
variable
v The file txtflag flag is set indicating a pure text file
v The file and program CCSIDs do not match.
Automatic file conversion and file tagging include the following facilities:
v _OPEN_SYS_FILE_EXT feature test macro. For more information, see z/OS XL
C/C++ Run-Time Library Reference .
v _BPXK_AUTOCVT and _BPXK_CCSIDS environment variables. For more information,
see Chapter 32, Using environment variables, on page 467.
v z/OS Language Environment FILETAG run-time option. For more information, see
z/OS Language Environment Programming Reference.
v __chattr() and __fchattr() functions; F_SETTAG and F_CONTROL_CVT
arguments for the fcntl() function; options for the fopen(), popen(), stat(),
fstat(), and lstat() functions. For more information, see z/OS XL C/C++
Run-Time Library Reference.
Chapter 11. Performing z/OS UNIX file system I/O operations 145
146 z/OS V1R13.0 XL C/C++ Programming Guide
Chapter 12. Performing VSAM I/O operations
This chapter outlines the use of Virtual Storage Access Method (VSAM) data sets in
z/OS XL C/C++. Three I/O processing modes for VSAM data sets are available in
z/OS XL C/C++:
v Record
v Text Stream
v Binary Stream
For more information about the facilities of VSAM, see the list of DFSMS on page
1027 publications.
See Chapter 8, z/OS XL C Support for the double-byte character set, on page 51
for information about using wide-character I/O with z/OS XL C/C++.
Notes:
1. This chapter describes C I/O as it can be used within C++ programs.
2. The C++ I/O stream libraries cannot be used for VSAM I/O because these do
not support the record processing mode (where type=record is specified).
3. Starting in z/OS V1R10, the C/C++ run-time library provides support for VSAM
data sets in the extended addressing space on extended address volumes
(EAVs).
In addition to the primary VSAM access described above, for KSDS and ESDS,
there is also direct access by one or more additional key fields within each record.
These additional keys can be unique or non-unique; they are called an alternate
index (AIX).
Before a VSAM data set is used for the first time, its structure is defined to the
system by the Access Method Services DEFINE CLUSTER command. This command
defines the type of VSAM data set, its structure, and the space it requires.
Before a VSAM alternate index is used for the first time, its structure is defined to
the system by the Access Method Services DEFINE ALTERNATEINDEX command. To
enable access to the base cluster records through the alternate index, use the
DEFINE PATH command. Finally, to build the alternate index, use the BLDINDEX
command.
When you have built the alternate index, you call fopen() and specify the PATH in
order to access the base cluster through the alternate index. Do not use fopen() to
access the alternate index itself.
Note: You cannot use the BLDINDEX command on an empty base cluster.
FRED 69 M
ANDY
ANDY 70 M FRED
SUZAN 72 F JANE
JANE 75 F SUZAN
By sex (non-unique)
F
M
When choosing the VSAM data set type, you should base your choice on the most
common sequence in which you require data. You should follow a procedure similar
to the one suggested below to help ensure a combination of data sets and indexes
that provide the function you require.
The RBA value is stored in the C structure __amrc, which is defined in the C
<stdio.h> header file. The __amrc->__RBA field is defined as an unsigned int, and
therefore will contain only a 4-byte RBA value. The __amrc->__XRBA field is 8 bytes
(unsigned long long in AMODE 31 applications, and unsigned long in AMODE 64
applications), and therefore can hold the RBA for all locations within an extended
addressable VSAM data set.
You can access the field __amrc->__RBA, as shown in< xref refid="gvs1">. This
example code (CCNGVS1) can be converted to use __amrc->__XRBA with just a few
modifications. For more information about the __amrc structure, refer to Chapter 18,
#include <stdio.h>
#include <stdlib.h>
main() {
FILE *ESDSfile;
unsigned int myRBA;
char recbuff[100]="This is record one.";
int w_retcd;
int l_retcd;
int r_retcd;
printf("calling fopen(\"dd:esdsclus\",\"rb+,type=record\");\n");
ESDSfile = fopen("dd:esdsclus", "rb+,type=record");
printf("fopen() returned 0X%.8x\n",ESDSfile);
if (ESDSfile==NULL) exit;
return(0);
}
This section describes considerations for using fopen() and freopen() with VSAM
files. Remember that a VSAM file must exist and be defined as a VSAM cluster
before you call fopen().
File names for MVS data sets: Using a data set name
The following diagram shows the syntax for the filename argument on your fopen()
or freopen() call:
qualifier
// ' '
qualifier1.qualifier2
' Single quotation marks indicate that you are passing a fully-qualified data set
name, that is, one which includes the high-level qualifier. If you pass a data set
name without single quotation marks, the z/OS XL C/C++ compiler prefixes the
high-level qualifier (usually the user ID) to the name. See Chapter 10,
Performing OS I/O operations, on page 81 for information on fully qualified
data set names.
// Specifying these slashes indicates that the file names refer to MVS data sets.
qualifier
Each qualifier is a 1- to 8-character name. These characters may be
alphanumeric, national ($, #, @), the hyphen, or the character \xC0. The first
character should be either alphabetic or national. Do not use hyphens in names
for RACF-protected data sets.
You can join qualifiers with periods. The maximum length of a data set name is
generally 44 characters, including periods.
To open a data set by its name, you can code something like the following in your
C or C++ program:
infile=fopen("VSAM.CLUSTER1", "ab+, type=record");
If your data set is VSAM.CLUSTER1, your C or C++ program refers to this data set by
the ddname CFILE, and you want exclusive control of the data set for update, you
can write the DD statement:
//CFILE DD DSNAME=VSAM.CLUSTER1,DISP=OLD
FILE *infile;
To share your data set, use DISP=SHR on the DD statement. DISP=SHR is the default
for fopen() calls that use a data set name and specify any of the r,rb, rb+, and
r+b open modes.
Note: z/OS XL C/C++ does not check the value of shareoptions at fopen() time,
and does not provide support for read-integrity and write-integrity, as required to
share files under shareoptions 3 and 4.
Note: If a "key out of sequence" condition is encountered, the data set will
automatically be reopened with a mode string "ab+" and will no longer be in
create mode.
ab Open for writing.
rb+ or r+b
Open for reading, writing, and/or updating.
wb+ or w+b
Open for reading, writing, and/or updating. If the cluster is defined as
reusable, the existing contents of the cluster are destroyed. If the cluster is
defined as not reusable (clusters with paths are, by definition, not reusable),
the fopen() fails. However, if the cluster has been defined but not loaded,
this mode can be used to do the initial load of both reusable and non
reusable clusters.
ab+ or a+b
Open for reading, writing, and/or updating.
For text files, you can specify the following modes: r, w, a, r+, w+, and a+.
Note: For KSDS, KSDS AIX and ESDS AIX in text and binary I/O, the only valid
modes are r and rb, respectively.
Keyword descriptions
recfm=
Any values passed into fopen() are ignored.
lrecl= and blksize=
These keywords are set to the maximum record size of the cluster as
initialized in the cluster definition. Any values passed into fopen() are
ignored.
space=
This keyword is not supported under VSAM.
type=
If you use the type= keyword, the only valid value for VSAM data sets is
type=record. This opens a file for record I/O.
acc= For VSAM files opened with the keyword type=record, you can specify the
direction by using the acc=access_type keyword on the fopen() function
call. For text and binary files, the access direction is always forward.
Attempts to open a VSAM data set with acc=BWD for either binary or text
stream I/O will fail. The access_type can be one of the following:
FWD The acc=FWD keyword specifies that the file be processed in a
forward direction. When the file is opened, it will be positioned at
the beginning of the first physical record, and any subsequent read
operations sets the file position indicator to the beginning of the
next record. The default value for the access keyword is acc=FWD.
Note: When opening paths, records with duplicate alternate index keys are
processed in order of arrival time (oldest to newest) regardless of the
current processing direction.
password=
VSAM facilities provide password protection for your data sets. You access
a data set that has password protection by specifying the password on the
password keyword parameter of the fopen() function call; the password
resides in the VSAM catalog entry for the named file. There can be more
than one password in the VSAM catalog entry; data sets can have different
passwords for different levels of authorization such as reading, writing,
updating, inserting, or deleting. For a complete description of password
protection on VSAM files, see the list of publications given on DFSMS on
page 1027.
The password keyword has the following form, where x is a 1- to
8-character password, and n is the exact number of characters in the
password. The password can contain special characters such as blanks
and commas.
password=nx
If a required password is not supplied, or if an incorrect password is given,
fopen() fails.
asis This keyword is not supported for VSAM.
byteseek
When you specify this keyword and open a file in binary stream mode,
fseek() and ftell() use relative byte offsets from the beginning of the file.
This is the default setting.
noseek
This keyword is ignored for VSAM data sets.
OS This keyword is ignored for VSAM data sets.
rls= Indicates the VSAM RLS/TVS access mode in which a VSAM file is to be
opened. This keyword is ignored for non-VSAM files. The following values
are valid:
v nri No Read Integrity
v cr Consistent Read
v cre Consistent Read Explicit
To find out how to optimize VSAM performance by controlling the number of VSAM
buffers used for your data set, refer to z/OS DFSMS Access Method Services for
Catalogs.
typedef struct {
#ifndef _LP64
unsigned int __fill, /* version: either 0 or 1 */
__recnum; /* the key, starting at 1 */
#else
unsigned long __fill, /* version: either 0 or 1 */
__recnum; /* the key, starting at 1 */
#endif /* not _LP64 */
} __rrds_key_type;
In your source program, you can define an RRDS record structure as either:
or:
struct {
__rrds_key_type rrds_key; /* __fill value always 1 */
char *data;
} rrds_rec_1;
The z/OS XL C/C++ library recognizes which type of record structures you have
used by the value of rrds_key.__fill. Zero indicates that the data is contiguous
with rrds_key and 1 indicates that a pointer to the data follows rrds_key.
fread() reads one record from the system from the current file position. Thus, if
you want to read a certain record, you can call flocate() to position the file pointer
to point to it; the subsequent call to fread() reads in that record.
If you use an fread() call to request more bytes than the record about to be read
contains, fread() reads the entire record and returns the number of bytes read. If
you use fread() to request fewer bytes than the record about to read contains,
fread() reads the number of bytes that you specified and returns your request.
z/OS XL C/C++ VSAM Record I/O does not allow a read operation to immediately
follow a write operation without an intervening reposition. z/OS XL C/C++ treats the
following as read operations:
v Calls to read functions that request 0 bytes
v Read requests that fail because of a system error
v Calls to the ungetc() function
Calling fread() several times in succession, with no other operations on this file in
between, reads several records in sequence (sequential processing), which can be
forward or backward, depending on the access direction, as described in the
following.
v KSDS, KSDS AIX and ESDS AIX
The records are retrieved according to the sequence of the key of reference, or
in reverse key sequence.
Note: Records with duplicate alternate index keys are processed in order of
arrival time (oldest to newest) regardless of the current processing direction
v ESDS
The records are retrieved according to the sequence they were written to the file
(entry sequence), or in reverse entry sequence.
In general, C I/O does not allow a write operation to follow a read operation without
an intervening reposition or fflush(). z/OS XL C/C++ counts a call to a write
function writing 0 bytes or a write request that fails because of a system error as a
write operation. However, z/OS XL C/C++ VSAM record I/O allows a write to directly
follow a read. This feature has been provided for compatibility with earlier releases.
The process of writing to a data set for the first time is known as initial loading.
Using the fwrite() function, you can write to a new VSAM file in initial load mode
just as you would to a file not in initial load mode. Writing to a KSDS PATH or an
ESDS PATH in initial load mode is not supported.
If your fwrite() call does not try to write more bytes than the maximum record
size, fwrite() writes a record of the length you asked for and returns your request.
If your fwrite() call asks for more than the maximum record size, fwrite() writes
the maximum record size, sets errno, and returns the maximum record size. In
either case, the next call to fwrite() writes to the following record.
Note: If an fwrite() fails, you must reposition the file before you try to read or
write again.
v KSDS, KSDS AIX
Records are written to the cluster according to the value stored in the field
designated as the prime key.
You can load a KSDS in any key order but it is most efficient to perform the
fwrite() operations in key sequence.
v ESDS, ESDS AIX
Records are written to the end of the file.
v RRDS
Deleting records
To delete records, use the library function fdelrec(), a z/OS XL C/C++ extension to
the SAA C library. For more information on this function, see z/OS XL C/C++
Run-Time Library Reference.
v KSDS, KSDS PATH, and RRDS
To delete records, you must perform the following operations:
1. Open the VSAM file in update mode (rb+/r+b, ab+/a+b, or wb+/w+b specified
as the required positional parameter of the fopen() function call and
type=record).
2. If the file is not already positioned at the record you want to delete, reposition
to that record.
3. Read the record using the fread() function.
Once the record you want to delete has been read in, you must ensure that
no reading, writing, or repositioning operations are performed before
fdelrec().
4. Delete the record using the fdelrec() function.
Note: If the data set was opened with an access mode of rb+ or r+b, a read
operation can result in the locking of control intervals, depending on
shareoptions specification of the VSAM file. If after reading a record, you decide
not to delete it, you may need to unlock a control interval by performing a
file-positioning operation to the same record, such as an flocate() using the
same key.
v ESDS and ESDS PATH
VSAM does not support deletion of records in ESDS files.
flocate()
The flocate() C library function can be used to locate a specific record within a
VSAM data set given the key, relative byte address, or the relative record number.
The flocate() function also sets the access direction.
VSAM extended addressability support includes an 8 byte RBA for use with
positioning functions such as flocate(). flocate() supports RBA lengths of 4 and
8 bytes. Existing applications that use flocate() with a 4 byte RBA will continue
unaffected, but must use a key length of 8 to locate an RBA beyond 4GB.
The following flocate() parameters all set the access direction to backward and are
only valid for record I/O:
v __KEY_LAST (the key and key_len parameters are ignored)
v __KEY_EQ_BWD
v __RBA_EQ_BWD
Note: The __RBA_EQ and __RBA_EQ_BWD parameters are not valid for paths and are
not recommended for KSDS and RRDS data sets.
You can use the rewind() library function instead of calling flocate() with
__KEY_FIRST.
v KSDS, KSDS AIX, and ESDS AIX
The key parameter of flocate() for the options __KEY_EQ, __KEY_GE, and
__KEY_EQ_BWD is a pointer to the key of reference of the data set. The key_len
parameter is the key length as defined for the data set for a full key search, or
less than the defined key length for a generic key search (a partial key match).
For KSDSs, __RBA_EQ and __RBA_EQ_BWD are supported, but are not
recommended.
For __KEY_EQ_BWD the key_len parameter must be equal to the key length as
defined for the data set for a full key search.
Alternate indexes do not allow positioning by RBA.
v ESDS
The key parameter of flocate() is a pointer to the specified RBA value. The
key_len parameter is either 4 or 8 depending on the size of the RBA.
v RRDS
For __KEY_EQ, __KEY_GE, and __KEY_EQ_BWD, the key parameter of flocate() is a
pointer to an unsigned long integer containing the specified relative record
number. The key_len parameter is sizeof(unsigned long). For __RBA_EQ and
__RBA_EQ_BWD, the key parameter of flocate() is a pointer to the specified RBA.
However, seeking to RBA values is not recommended, because it is not
supported across control intervals. The key_len parameter is either 4 or 8
depending on the size of the RBA.
ftell() and fseek() offsets in record mode I/O are relative record offsets. For
example, the following call moves the file position to the start of the previous
record:
fseek(fp, -1L, SEEK_CUR);
You cannot use fseek() to reposition to a file position before the beginning of the
file or to a position beyond the end of the file.
rewind()
The rewind() function repositions the file position to the beginning of the file, and
clears the error setting for the file. rewind() does not reset the file access direction.
For example, a call to flocate() with __KEY_LAST sets the file pointer to the end of
the file and sets the access direction to backwards. A subsequent call to rewind()
sets the file pointer to the beginning of the file, but the access direction remains
backwards.
Notes:
1. The saved position is based on the relative position of the record within the data set. Subsequent insertions or deletions may
invalidate the saved position.
2. The saved position is based on the RBA of the record. Subsequent insertions, deletions or updates may invalidate the saved
position.
The C/C++ run-time library provides the following support for VSAM RLS/TVS:
v Specification of RLS/TVS-related keywords in the mode string of fopen() and
freopen().
v Specification of RLS/TVS-related text unit key values in the __dyn_t structure,
which is used as input to the dynalloc() function.
v Provides the application with VSAM return and reason codes for VSAM I/O
errors.
v Performs implicit positioning for files opened for RLS/TVS access.
VSAM RLS/TVS has three read integrity file access modes. These modes tell
VSAM the level of locking to perform when records are accessed within a file that
has not been opened in update mode. The access modes are:
nri No Read Integrity indicates that requests performed by the application are
not to be serialized with updates or erases of the records by other calling
programs. VSAM accesses the records without obtaining a lock on the
record.
cr Consistent Read indicates that requests performed by the application are to
be serialized with updates or erases of the records by other calling
programs. VSAM obtains a share lock when accessing the record. This lock
is released once the record has been returned to the caller.
cre Consistent Read Explicit indicates that requests performed by the
application are to be serialized with updates or erases of the records by
other requestors.VSAM obtains a share lock when accessing the record.
This lock is held until the application commits its changes. This ensures that
records read by the application are not changed by other requestors until
the application commits or aborts its changes. Consistent Read Explicit is
for use only by commit protocol applications.
VSAM RLS locks records to support record integrity. An application may wait for an
exclusive record lock if another user has the record locked. The application is also
subject to new locking errors such as deadlock or timeout errors.
If the file has been opened in update mode, and RLS=CR or RLS=CRE is specified,
VSAM also serializes access to the records within the file. However, the type of
serialization differs from non-update mode in the following ways:
v A reposition within the file causes VSAM to obtain a share lock for the record.
v A read of a record causes VSAM to obtain an exclusive lock for the record. The
lock is held until the record is updated in the file, or another record is read. If
RLS=CRE is specified (for commit protocol applications), the lock is held until the
application commits or aborts its changes.
Notes:
1. When a file is opened, it is implicitly positioned to the first record to be
accessed.
Error reporting
Errors are reported through the __amrc structure and the SIGIOERR signal. The
following are additional considerations for error reporting in a VSAM RLS
application:
v VSAM RLS/TVS uses the SMSVSAM server address space. When a file open
fails because the server is not available, the C run-time library places the error
return code and error value in the __amrc structure, and returns a null file
descriptor. Record management requests return specific error return/reason
codes, if the SMSVSAM server is not available. The server address space is
automatically restarted. To recover from this type of error, an application should
first close the file to clean up the file status, and then open the file prior to
attempting record management requests. The close for the file returns a return
code of 4, and an error code of 170(X'AA'). This is the expected result. It is not
an error.
v Opening a recoverable file for output is not supported. If you attempt to do so,
the open will fail with error return code 255 in the __amrc structure.
v Some of the VSAM errors, that are reported in the __amrc structure, are
situations from which an application can recover. These are problems that can
occur unpredictably in a sharing environment. Usually, the application can
recover by simply accessing another record. Examples of such errors are the
following:
RC 8, 21(X'15'): Request cancelled as part of deadlock resolution.
RC 8, 22(X'16'): Request cancelled as part of timeout resolution.
RC 8, 24(X'18'): Request cancelled because transaction backout is pending
on the requested record.
RC 8, 29(X'14'): Intra-luwid contention between threads under a given TCB.
The application can intercept errors by registering a condition handler for the
SIGIOERR condition. Within the condition handler, the application can examine
the information in the __amrc structure and determine how to recover from each
specific situation.
Restriction: z/OS XL C/C++ does not support XADDR for ESDS alternate indexes.
VSAM XADDR support includes an 8 byte relative byte address for use with
positioning functions such as flocate(). flocate() supports key lengths of 4 and 8
bytes. Existing applications that use flocate() to locate with a 4 byte relative byte
address will continue unaffected, but must use a key length of 8 to locate a record
within XADDR addresses.
The RBA field in the __amrc structure is set to -1 when applications access beyond
the addresses that can be represented by the 4 byte value, effectively appearing to
be EOF to any 4 byte RBA positioning (flocate()) calls. The __XRBA field will always
be updated with the address, and must be used in these cases.
For AMODE 31 applications repositioning within a VSAM data set, users of ftell()
and fseek() that need to access XADDR addresses, must use the large file version
of ftello() and fseeko() .
Note: AMODE 64 applications also have the above restrictions on XADDR support.
For complete details on these library functions, see z/OS XL C/C++ Run-Time
Library Reference.
VSAM extended addressability support includes an 8 byte RBA for use with
positioning functions such as flocate(). flocate() supports RBA lengths of 4 and
8 bytes. Existing applications that use flocate() with a 4 byte RBA will continue
unaffected, but must use a key length of 8 to locate an RBA beyond 4GB.
The following flocate() parameters all set the access direction to backward and are
not valid for text and binary I/O, because backwards access is not supported:
v __KEY_LAST (the key and key_len parameters are ignored)
v __KEY_EQ_BWD
v __RBA_EQ_BWD
You can use the rewind() library function instead of calling flocate() with
__KEY_FIRST.
v KSDS, KSDS AIX, and ESDS AIX
The key parameter of flocate() for the options __KEY_EQ and __KEY_GE is a
pointer to the key of reference of the data set. The key_len parameter is the key
length as defined for the data set for a full key search, or less than the defined
key length for a generic key search (a partial key match).
Alternate indexes do not allow positioning by RBA.
Note: The __RBA_EQ parameter is not valid for paths and is not recommended.
v ESDS
The key parameter of flocate() is a pointer to the specified RBA value. The
key_len parameter is either 4 or 8 depending on the size of the RBA.
v RRDS
For __KEY_EQ and __KEY_GE, the key parameter of flocate() is a pointer to an
unsigned long integer containing the specified relative record number. The
key_len parameter is sizeof(unsigned long). For __RBA_EQ, the key parameter of
flocate() is a pointer to the specified RBA. However, seeking to RBA values is
not recommended, because it is not supported across control intervals. The
key_len parameter is either 4 or 8 depending on the size of the RBA.
For AMODE 31 applications repositioning within a VSAM data set, users of ftell()
and fseek() that need to access positions beyond 4GB, must use the large file
version of ftello() and fseeko() .
Table 26 provides a summary of the fseek() and ftell() parameters in binary and
text.
Table 26. Summary of fseek() and ftell() parameters in text and binary
Type Mode ftell() return fseek() SEEK_CUR SEEK_END
values SEEK_SET
KSDS Binary relative byte offset relative byte offset relative byte offset relative byte offset
Text not supported zero only relative byte offset relative byte offset
ESDS Binary relative byte offset relative byte offset relative byte offset relative byte offset
Text not supported zero only relative byte offset relative byte offset
RRDS Binary encoded byte encoded byte relative byte offset relative byte offset
offset offset
Text encoded byte encoded byte relative byte offset relative byte offset
offset offset
PATH Binary not supported not supported not supported not supported
Text not supported not supported not supported not supported
Flushing buffers
You can use the C library function fflush() to flush data.
For text files, calling fflush() to flush an update to a record causes the new data
to be written to the file.
If you call fflush() while you are updating, the updates are flushed out to VSAM.
For ESDS binary files, if fclose() is called and there is a new record in the buffer
that is less than the maximum record size, this record is written to the file at its
current size. A new RRDS binary record that is incomplete when the file is closed is
filled with null characters to the record size.
A new ESDS or RRDS text record that is incomplete when the file is closed is
completed with a new-line.
Note: The __amrc struct is global and can be reset by another I/O operation (such
as printf()).
For definitions of these return codes and feedback codes, refer to the publications
listed in DFSMS on page 1027.
You can set up a SIGIOERR handler to catch read or write system errors. See
Chapter 18, Debugging I/O programs, on page 221 for more information.
VSAM examples
This section provides several examples of using I/O under VSAM.
KSDS example
The example in Figure 26 on page 174 shows a sample program (CCNGVS2) with
two functions from an employee record entry system with a mainline driver to
process selected options (display, display next, update, delete, create). The update
routine is an example of KSDS clusters, and the display routine is an example of
both KSDS clusters and alternate indexes.
For these examples, the clusters and alternate indexes should be defined as
follows:
v The KSDS cluster has a record size of 150 with a key length of 4 with offset 0.
v The unique KSDS AIX has a key length of 20 with an offset of 10.
v The non-unique KSDS AIX has a key length of 40 with an offset of 30.
Chapter 12. Performing VSAM I/O operations 173
The update routine is passed the following:
v data_ptr, which points to the information that is to be updated
v orig_data_ptr, which points to the information that was originally displayed using
the display option
v A file pointer to the KSDS cluster
By definition, the primary key is unique and therefore the employee number was
chosen for this key. The user_id is also a unique key; therefore, it was chosen as
the unique alternate index key. The name field may not be unique; therefore, it was
chosen as the non-unique alternate index key.
#include <stdio.h>
#include <string.h>
/* global definitions */
struct data_struct {
char emp_number[4];
char user_id[8];
char name[20];
char pers_info[37];
};
#define REC_SIZE 69
#define CLUS_KEY_SIZE 4
#define AIX_UNIQUE_KEY_SIZE 8
#define AIX_NONUNIQUE_KEY_SIZE 20
clearerr(fp);
rc = fread(buffer,1,REC_SIZE,fp);
if (rc != REC_SIZE || ferror(fp)) {
print_amrc();
printf("Error: reading old employee record failed\n");
return 40;
}
rc = fdelrec(fp);
if (rc != 0) {
print_amrc();
printf("Error: deleting old employee record failed\n");
return 50;
}
} /* end of checking for change in primary key */
else { /* Locate to current employee record */
rc = flocate(fp,&(data_ptr->emp_number),CLUS_KEY_SIZE,__KEY_EQ);
if (rc == 0) {
/* record exists, so update it */
rc = fread(buffer,1,REC_SIZE,fp);
if (rc != REC_SIZE || ferror(fp)) {
print_amrc();
printf("Error: reading old employee record failed\n");
return 60;
}
Figure 26. KSDS example (Part 3 of 5) Chapter 12. Performing VSAM I/O operations 177
178 z/OS V1R13.0 XL C/C++ Programming Guide
/* Non-unique Alternate Index Search */
else if (data_ptr->name[0] != \0) {
rc = flocate(aix_non_unique_fp,data_ptr->name,
AIX_NONUNIQUE_KEY_SIZE,__KEY_GE);
if (rc != 0) {
printf("Error: flocate with name failed\n");
return 30;
}
int main() {
FILE* clus_fp;
FILE* aix_ufp;
FILE* aix_nufp;
int i;
struct data_struct buf1, buf2;
char data[3][REC_SIZE+1] = {
" 1LARRY LARRY HI, IM LARRY, ",
" 2DARRYL1 DARRYL AND THIS IS MY BROTHER DARRYL, ",
" 3DARRYL2 DARRYL "
};
/* assume base cluster was loaded with at least one dummy record */
/* so aix could be defined */
aix_ufp = fopen("dd:aixuniq", "rb,type=record");
if (aix_ufp == NULL) {
print_amrc();
printf("Error: fopen(\"dd:aixuniq\"...) failed\n");
return 10;
}
/* assume base cluster was loaded with at least one dummy record */
/* so aix could be defined */
aix_nufp = fopen("dd:aixnuniq", "rb,type=record");
return 0;
}
The JCL in the sample code (CCNGVS3) in Figure 27 can be used to test the
example code in Figure 26 on page 174.
RRDS example
The sample program (CCNGVS4) in Figure 28 on page 184 illustrates the use of an
RRDS file. It performs the following operations:
1. Opens an RRDS file in record mode (the cluster must be defined)
2. Writes three records (RRN 2, RRN 10, and RRN 32)
3. Sets the file position to the first record
4. Reads the first record in the file
5. Deletes it
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <env.h>
struct rrds_struct {
__
rrds_key_type rrds_key;
char *rrds_buf;
};
main() {
FILE *fileptr;
RRDS_STRUCT RRDSstruct;
RRDS_STRUCT *rrds_rec = &RRDSstruct;
char buffer1[80] =
"THIS IS THE FIRST RECORD IN THE FILE. I"
"T WILL BE WRITTEN AT RRN POSITION 2. ";
char buffer2[80] =
"THIS IS THE SECOND RECORD IN THE FILE. I"
"T WILL BE WRITTEN AT RRN POSITION 10. ";
char buffer3[80] =
"THIS IS THE THIRD RECORD IN THE FILE. I"
"T WILL BE WRITTEN AT RRN POSITION 32. ";
char outputbuf[80];
unsigned long flocate_key = 0;
/*------------------------------------------------------------------*/
/*| select RRDS record structure 2 by setting __fill to 1 */
/*| */
/*| 1. open an RRDS file record mode (the cluster must be defined) */
/*| 2. write three records (RRN 2, RRN 10, RRN 32) */
/*------------------------------------------------------------------*/
rrds_rec->rrds_key.__fill = 1;
rrds_rec->rrds_key.__recnum = 10;
rrds_rec->rrds_buf = buffer2;
fwrite(rrds_rec,1,88, fileptr);
rrds_rec->rrds_key.__recnum = 32;
rrds_rec->rrds_buf = buffer3;
fwrite(rrds_rec,1,88, fileptr);
memset(outputbuf,0x00,80);
rrds_rec->rrds_buf = outputbuf;
fdelrec(fileptr);
/*------------------------------------------------------------------*/
/*| 6. locate last record in file and set access direction backwards*/
/*| 7. read the record */
/*| 8. update the record */
/*------------------------------------------------------------------*/
flocate(fileptr, &flocate_key,; sizeof(unsigned long), __KEY_LAST);
memset(outputbuf,0x00,80);
rrds_rec->rrds_buf = outputbuf;
memset(outputbuf,0x00,80);
memcpy(outputbuf,"THIS IS THE UPDATED STRING... ",30);
fupdate(rrds_rec,88,fileptr);
/*------------------------------------------------------------------*/
/*| 9. set _EDC_RRDS_HIDE_KEY environment variable */
/*|10. read the next record in sequence (ie. RRN 10) into a */
/*| + character string */
/*------------------------------------------------------------------*/
setenv("_EDC_RRDS_HIDE_KEY","Y",1);
memset(outputbuf,0x00,80);
fread(outputbuf, 1, 80, fileptr);
printf("The middle record in the file (read into char string):\n");
printf("%80s\n\n",outputbuf);
fclose(fileptr);
}
fldata() behavior
The format of the fldata() function is as follows:
The fldata() function is used to retrieve information about an open stream. The
name of the file is returned in filename and other information is returned in the
__device_t __device; /* */
unsigned long __blksize, /* */
__maxreclen; /* */
union { /* */
struct { /* */
unsigned short __vsam_type; /* */
unsigned long __vsam_keylen; /* */
unsigned long __vsam_RKP; /* */
} __vsam; /* */
#if __EDC_TARGET >= 0x41080000 /* */
struct { /* */
unsigned char __disk_access_method; /* */
unsigned char __disk_noseek_to_seek; /* */
long __disk_reserve[2]; /* */
} __disk;
#endif
} __device_specific;
char * __dsname; /* */
unsigned int __reserve4; /* */
};
typedef struct __fileData fldata_t;
Figure 29. fldata() structure Chapter 12. Performing VSAM I/O operations 187
Notes:
1. If you have opened the file by its data set name, the filename is fully qualified,
including quotation marks. If you have opened the file by ddname, filename is
dd:ddname, without any quotation marks. The ddname is uppercase.
2. The __dsname field is filled in with the data set name. The __dsname value is
uppercase unless the asis option was specified on the fopen() or freopen()
function call.
Note: You cannot use the z/OS XL C/C++ I/O functions for terminal I/O under
either IMS or CICS. Terminal I/O under CICS is supported through the CICS
command level interface.
This chapter describes C I/O stream functions as they can be used within C++
programs. If you want to use the C++ I/O stream classes instead, see Chapter 4,
Using the Standard C++ Library I/O Stream Classes, on page 21 for general
information. For more detailed information, see Standard C++ Library Reference,
which discusses the Standard C++ I/O stream classes.
Opening files
You can use the library functions fopen() or freopen() to open a file.
Terminal files opened in append mode are treated as if they were opened in write
mode.
recfm=
z/OS XL C/C++ allows you to specify any of the 27 possible RECFM types
(listed in Fixed-format records on page 10, Variable-format records on
page 13, and Undefined-format records on page 16). The default is
recfm=U. Any specification of ASA for the record format is ignored.
lrecl= and blksize=
The lrecl and blksize parameters allow you to set the record size and
block size, respectively. The maximum limits on lrecl values are as follows:
32771 For input z/OS variable terminals (data length of 32767)
32767 For input z/OS fixed and undefined terminals
32770 For output z/OS variable terminals (data length of 32766)
32766 For output z/OS fixed and undefined terminals
In fixed and undefined terminal files, blksize is always the size of lrecl. In
variable terminal files, blksize is always the size of lrecl plus 4 bytes. It is
not necessary to specify values for lrecl and blksize. If neither is
specified, the default values are used. The default lrecl sizes (not
including the extra 4 bytes in the lrecl of variable length types) are as
follows:
v Screen width for output terminals
v 1000 for input z/OS text terminals
v 254 for all other input terminals
space=
This parameter is accepted as an option for terminal I/O, but it is ignored. It
does not generate an error.
type=
type=record specifies that the file is to be opened for sequential record I/O.
The file must be opened as a binary file.
acc= This parameter is not valid for terminal I/O. If you specify it, your fopen()
call fails.
When you perform input and output in an interactive mode with the terminal, all
standard streams and all files with * as the first character of their names are
associated with the terminal. Output goes to the screen; input comes from the
keyboard.
An input EOF can be generated by a /* if you open a stream in text mode. If you
open the stream in binary or record mode, you can generate an EOF by entering a
null string.
Buffering
z/OS XL C/C++ uses buffers to map byte-level I/O (data stored in records and
blocks) to system-level C I/O.
The setvbuf() and setbuf() functions can be used to control buffering before any
read or write operation to the file. If you want to reset the buffering mode, you must
call setvbuf() or setbuf() before any other operation occurs on a file, because you
cannot change the buffering mode after an I/O operation to the file.
You can set up a SIGIOERR handler to catch read or write system errors. See
Chapter 18, Debugging I/O programs, on page 221 for more information.
A call to the rewind() function clears unread input data in the terminal buffer so that
on the next read request, the system waits for more user input.
Under TSO, the virtual line size of the terminal is used to determine the line length.
When reading from the terminal and the RECFM has been set to be F (for example,
by an ALLOCATE under TSO) in binary or record mode, the input is padded with
blanks to the record length.
On input, all terminal files opened for output flush their output, no matter what type
of file they are and whether a record is complete or not. This includes fixed terminal
files that would normally withhold output until a record is completed, as well as text
records that normally wait until a new-line or carriage return. In all cases, the data
is placed into one line with a blank added to separate output from different terminal
files. Fixed terminal files do not pad the output with blanks when flushing this way.
Note: This flush is not the same as a call to fflush(), because fixed terminal files
do not have incomplete records and text terminal files do not output until the
new-line or carriage return. This flush occurs only when actual input is required
from the terminal. When data is still in the buffer, that data is read without flushing
output terminal files.
Writing to files
You can use the following library functions to write to a terminal file; see z/OS XL
C/C++ Run-Time Library Reference for more information on these library functions.
v fwrite()
v fwrite_unlocked()
v printf()
v printf_unlocked()
v fprintf()
v fprintf_unlocked()
v vprintf()
v vprintf_unlocked()
If no record length is specified for the output terminal file, it defaults to the virtual
line size of the terminal.
On output, records are written one line at a time up to the record length. For all
output terminal files, records are not truncated. If you are printing a long string, it
wraps around to another line.
Flushing records
The action taken by the fflush() library function depends on the file mode. The
fflush() function only flushes buffers in binary files with Variable or Undefined
record format.
If you call one z/OS XL C/C++ program from another z/OS XL C/C++ program by
using the ANSI system() function, all open streams are flushed before control is
passed to the callee, and again before control is returned to the caller. If you are
running with POSIX(ON), a call to the POSIX system() function does not flush any
streams to the system.
Text streams
v Writing a new record:
Because a new-line character has not been encountered to indicate the
end-of-line, fflush() takes no action. The record is written as a new record
when one of the following takes place:
A new-line character is written.
The file is closed.
v Reading a record:
fflush() clears a previous ungetc() character.
Binary streams
v Writing a new record:
Record I/O
v Writing a new record: fflush() takes no action.
v Reading a record: fflush() takes no action.
You can also use rewind() when reading from the terminal to flush out your record
buffer for that stream.
Closing files
Use the fclose() library function to close a file. z/OS XL C/C++ automatically
closes files on normal program termination and attempts to do so under abnormal
program termination or abend. When closing a fixed binary terminal, z/OS XL
C/C++ pads the last record with blanks if it is incomplete.
See z/OS XL C/C++ Run-Time Library Reference for more information on this
library function.
fldata() behavior
The format of the fldata() function is as follows:
The fldata() function is used to retrieve information about an open stream. The
name of the file is returned in filename and other information is returned in the
fldata_t structure, shown in tFigure 30 on page 197. Values specific to this category
of I/O are shown in the comment beside the structure element. Additional notes
pertaining to this category of I/O follow the figure.
For more information on the fldata() function, refer to z/OS XL C/C++ Run-Time
Library Reference.
Notes:
1. The filename value is dd:ddname if the file is opened by ddname; otherwise, the
value is *. The ddname is uppercase.
2. Either __recfmF, __recfmV, or __recfmU will be set according to the recfm
parameter specified on the fopen() or freopen() function call.
Memory files can be written to, read from, and repositioned within like any other
type of file. Memory files exist for the life of your root program, unless you explicitly
delete them by using the remove() or clrmemf() functions. The root program is the
first main() to be invoked. Any main() program called by a system() call is known
as a child program. When the root program terminates, z/OS XL C/C++ removes
memory files automatically. Memory files may give you better performance than
other types of files.
This chapter describes C I/O streams as they can be used within C++ programs. If
you want to use the C++ I/O stream classes instead, see Chapter 4, Using the
Standard C++ Library I/O Stream Classes, on page 21 for general information. For
more detailed information, see Standard C++ Library Reference, which discusses
the Standard C++ I/O stream classes.
If your installation supports hiperspaces, and you are not using CICS, you can use
hiperspace memory files (see the appropriate book as listed in z/OS Information
Roadmap for more information on hiperspaces). Whereas a regular memory file
stores all the file data in your address space, a hiperspace memory file uses one
buffer in your address space, and keeps the rest of the data in the hiperspace.
Therefore, a hiperspace memory file requires only a certain amount of storage in
your address space, regardless of how large the file is. If you use setvbuf(), z/OS
XL C/C++ may or may not accept your buffer for its internal use. For a hiperspace
memory file, if the size of the buffer specified to setvbuf() is greater than 4K, then
only the first 4K of the user buffer will be used.
File-naming considerations
When you open a file using fopen() or freopen(), you must specify the filename (a
data set name) or the ddname.
Using a data set name: Files are opened with a call to fopen() or freopen() in
the format fopen("filename", "mode"). The following diagram shows the syntax for
the filename argument on your fopen() or freopen() call:
qualifier
// ' ( member ) '
When you enclose a name in single quotation marks, the name is fully qualified.
The file opened is the one specified by the name inside the quotation marks. If the
name is not fully qualified, z/OS XL C/C++ does one of the following:
v If your system does not use RACF, z/OS XL C/C++ does not add a high-level
qualifier to the name you specified.
v If you are running under TSO (batch or interactive), z/OS XL C/C++ appends the
TSO user prefix to the front of the name. For example, the statement
Using a DDname: You can specify names that begin with dd:, but z/OS XL C/C++
treats the dd: as part of the file name.
z/OS UNIX Considerations: Using the fork() library function from z/OS UNIX
application programs causes the memory file to be copied into the child process.
The memory file data in the child is identical to that of the parent at the time of the
fork(). The memory file can be used in either the child or the parent, but the data
is not visible in the other process.
Chapter 14. Performing memory file and hiperspace I/O operations 201
Table 30. Keywords for the fopen() and freopen() functions for memory file I/O (continued)
Keyword Allowed? Applicable? Notes
OS No No This parameter is not valid for memory file and
hiperspace I/O. If you specify OS, your
fopen() call fails.
recfm=
z/OS XL C/C++ parses your specification for these values. If they do not
have the correct syntax, your function call fails. If they do, z/OS XL C/C++
ignores their values and continues.
lrecl= and blksize=
z/OS XL C/C++ parses your specification for these values. If they do not
have the correct syntax, your function call fails. If they do, z/OS XL C/C++
ignores their values and continues.
acc= z/OS XL C/C++ parses your specification for these values. If they do not
have the correct syntax, your function call fails. If they do, z/OS XL C/C++
ignores their values and continues.
password=
This parameter is not valid for memory file and hiperspace I/O. If you
specify PASSWORD, your fopen() call fails.
space=
z/OS XL C/C++ parses your specification for these values. If they do not
have the correct syntax, your function call fails. If they do, z/OS XL C/C++
ignores their values and continues.
type=
To create a memory file, you must specify type=memory. You cannot specify
type=record; if you do, fopen() or freopen() fails. To create a hiperspace
memory file, you must specify type=memory(hiperspace).
asis If you use this parameter, you can specify mixed-case filenames, such as
JaMeS dAtA or pErCy.FILE. If you are running with POSIX(ON), asis is the
default.
byteseek
This parameter is ignored for memory file and hiperspace I/O.
noseek
This parameter is ignored for memory file and hiperspace I/O.
OS This parameter is not allowed for memory file and hiperspace I/O. If you
specify OS, your fopen() call fails.
Once a memory file has been created, it can be accessed by the module that
created it as well as by any function or module that is subsequently invoked
(including modules that are called using the system() library function), and by any
modules in the current chain of system() calls, if you are running with POSIX(OFF). If
you are running with POSIX(ON), the system() function is the POSIX one, not the
ANSI one, and it does not propagate memory files to a child program. Once the file
has been created, you can open it with the same name, without specifying the
type=memory parameter. You cannot specify type=record for a memory file.
If you specify a memory file name that has an asterisk (*) as the first character, a
name is created for that file. (You can acquire this name by using fldata().) For
example, you can specify fopen("*","type=memory");. Opening a memory file this
way is faster than using the tmpnam() function.
You cannot have any blanks or periods in the member name of a memory file.
Otherwise, all valid data set names are accepted for memory files. Note that if
invalid disk file names are used for memory files, difficulties could occur when you
try to port memory file applications to disk-file applications.
Memory files are always opened in fixed binary mode regardless of the open mode.
There is no blank padding, and control characters such as the new line are written
directly into the file (even if the fopen() specifies text mode).
You must decide whether a file is to be a hiperspace memory file before you create
it. You cannot change a memory file to a hiperspace memory file by specifying
type=memory(hiperspace) on a subsequent call to fopen() or freopen(). If the
hiperspace to store the file cannot be created, the fopen() or freopen() call fails.
Once you have created a hiperspace memory file, you do not have to specify
type=memory(hiperspace) on subsequent function calls that open the file.
Chapter 14. Performing memory file and hiperspace I/O operations 203
If you open a hiperspace memory file for read at the same time that it is opened for
write, you can attempt to read extensions made by the writer, even after the EOF
flag has been set on by a previous read. If such a read succeeds, the EOF flag is
set off until the new EOF is reached. If you have opened a file once for write and
one or more times for read, a reader can now read past the original EOF.
When you establish hat a memory file has members, you can rename and remove
all the members by specifying the file name and no members, just as with a PDS or
PDSE. None of the members can be open for you to perform this action. Once a
memory file is created with or without a member, another memory file with the same
name (with or without a member) cannot be created as well. For example, if you
open memory file a.b and write to it, z/OS XL C/C++ does not allow a memory file
named a.b(c) until you close and remove a.b. Also, if you create a memory file
named a.b(mbr1), you cannot open a file named a.b until you close and remove
a.b(mbr1).
Sample program CCNGMF1 (Figure 31) demonstrates the removal of all the
members of the data set a.b. After the call to remove(), neither a.b(mbr1) nor
a.b(mbr2) exists.
#include <stdio.h>
int main(void)
{
FILE * fp1, * fp2;
fp1=fopen("a.b(mbr1)","w,type=memory");
fp2=fopen("a.b(mbr2)","w,type=memory");
fwrite("hello, world\n", 1, 13, fp1);
fwrite("hello, world\n", 1, 13, fp2);
fclose(fp1);
fclose(fp2);
remove("a.b");
fp1=fopen("a.b(mbr1)","r,type=memory");
if (fp1 == NULL) {
perror("fopen():");
printf("fopen(\"a.b(mbr1)\"...) failed as expected: "
"the file has been removed\n");
}
else {
printf("fopen() should have failed\n");
}
return(0);
}
#include <stdio.h>
int main(void)
{
FILE * fp1, * fp2;
fp1=fopen("a.b(mbr1)","w,type=memory");
fp2=fopen("a.b(mbr2)","w,type=memory");
fclose(fp1);
fclose(fp2);
rename("a.b","c.d");
fp1=fopen("a.b(mbr1)","r,type=memory");
if (fp1 == NULL) {
perror("fopen():");
printf("fopen(\"a.b(mbr1)\"...) failed as expected: "
"the file has been renamed\n");
}
else {
printf("fopen() should have failed\n");
}
fp2=fopen("c.d(mbr2)","r,type=memory");
if (fp2 != NULL) {
printf("fopen(\"c.c(mbr1)\"...) worked as expected: "
"the file has been renamed\n");
}
else {
perror("fopen():");
printf("fopen() should have worked\n");
}
return(0);
}
Note: If you are using simulated PDSs, you can change either the name of the
PDS, or the member name. You cannot rename a.b(mbr1) to either c.d(mbr2) or
c.d, but you can rename a.b(mbr1) to a.b(mbr2), and a.b to c.d.
Memory files that are open as a sequential data set cannot be opened again with a
member name specified. Also, if a data set is already open with a member name,
the sequential data set version with only the data set name cannot be opened.
These operations result in fopen() returning NULL. For example, fopen() returns
NULL in the second line of the following:
fp = fopen("a.b","w,type=memory");
fp1 = fopen("a.b(m1)","w,type=memory");
Chapter 14. Performing memory file and hiperspace I/O operations 205
Buffering
Regular memory files are not buffered. Any parameters passed to setvbuf() are
ignored. Each character that you write is written directly to the memory file.
Hiperspace memory files are fully buffered. The size of the I/O buffer in your own
address space is 4KB.
The gets(), getchar(), scanf(), and vscanf() functions read from stdin, which
can be redirected to a memory or hiperspace memory file.
You can open an existing file for read one or more times, even if it is already open
for write. You cannot open a file for write if it is already open (for either read or
write). If you want to update or truncate a file or append to a file that is already
open for reading, you must first close all the other streams that refer to that file.
You can set up a SIGIOERR handler to catch read or write system errors that happen
when you are using hiperspace memory files. See Chapter 18, Debugging I/O
programs, on page 221 for more information.
Writing to files
You can use the following library functions to write to a file. See z/OS XL C/C++
Run-Time Library Reference for more information on these library functions.
v fwrite()
v fwrite_unlocked()
v printf()
v printf_unlocked()
v fprintf()
v fprintf_unlocked()
v vprintf()
v vprintf_unlocked()
v vfprintf()
v vfprintf_unlocked()
v puts()
v puts_unlocked()
v fputs()
v fputs_unlocked()
v fputc()
v fputc_unlocked()
v putc()
v putc_unlocked()
v putchar()
v putchar_unlocked()
The printf(), puts(), putchar(), and vprintf() functions write to stdout, which
can be redirected to a memory or hiperspace memory file.
In hiperspace memory files, each library function causes your data to be moved into
the buffer in your address space. The buffer is written to hiperspace each time it is
filled, or each time you call the fflush() library function.
z/OS XL C/C++ counts a call to a write function writing 0 bytes or or a write request
that fails because of a system error as a write operation. For regular memory files,
the only possible system error that can occur is an error in acquiring storage.
Chapter 14. Performing memory file and hiperspace I/O operations 207
Flushing records
fflush() does not move data from an internal buffer to a memory file, because the
data is written to the memory file as it is generated. However, fflush() does make
the data visible to readers who have a regular or hiperspace memory file open for
reading while a user has it open for writing.
Hiperspace memory files are fully buffered. The fflush() function writes data from
the internal buffer to the hiperspace.
The fclose() function also invokes fflush() when it detects an incomplete buffer
for a file that is open for writing or appending.
ungetc() considerations
ungetc() pushes characters back onto the input stream for memory files. ungetc()
handles only single-byte characters. You can use it to push back as many as four
characters onto the ungetc() buffer. For every character pushed back with ungetc(),
fflush() backs up the file position by one character and clears all the pushed-back
characters from the stream. Backing up the file position may end up going across a
record boundary.
If you want fflush() to ignore ungetc() characters, you can set the _EDC_COMPAT
environment variable. See Chapter 32, Using environment variables, on page 467
for more information.
Using fseek() to seek past the end of a memory file extends the file using null
characters. This may cause z/OS XL C/C++ to attempt to allocate more storage
than is available as it tries to extend the memory file.
When you use the fseek() function with memory files, it supports byte offsets from
SEEK_SET, SEEK_CUR, and SEEK_END.
All file positions from ftell() are relative byte offsets from the beginning of the file.
fseek() supports these values as offsets from SEEK_SET.
fgetpos() values generated by code from previous releases of the z/OS XL C/C++
compiler are not supported by fsetpos().
Closing files
Use the fclose() library function to close a regular or hiperspace memory file. See
z/OS XL C/C++ Run-Time Library Reference for more information on this library
function. z/OS XL C/C++ automatically closes memory files at the termination of the
C root main environment.
Performance tips
You should use hiperspace memory files instead of regular memory files when they
will be large (1MB or greater).
Regular memory files perform more efficiently if large amounts of data (10K or
more) are written in one request (that is, if you pass 10K or more of data to the
fwrite() function). You should use fopen("*", "type=memory") both to generate a
name for a memory file and to open the file instead of calling fopen() with a name
returned by tmpnam(). You can acquire the file's generated name by using fldata().
fldata() behavior
The fldata() function is used to retrieve information about an open stream; it has the
following format:
The name of the file is returned in filename and other information is returned in the
fldata_t structure, shown in Figure 33 on page 210. Values specific to this category
of I/O are shown in the comment beside the structure element. Additional notes
pertaining to this category of I/O follow. For more information on the fldata()
function, refer to z/OS XL C/C++ Run-Time Library Reference.
Chapter 14. Performing memory file and hiperspace I/O operations 209
struct __fileData {
unsigned int __recfmF : 1, /* always on */
__recfmV : 1, /* always off */
__recfmU : 1, /* always off */
__recfmS : 1, /* always off */
__recfmBlk : 1, /* always off */
__recfmASA : 1, /* always off */
__recfmM : 1, /* always off */
__dsorgPO : 1, /* N/A -- always off */
__dsorgPDSmem : 1, /* N/A -- always off */
__dsorgPDSdir : 1, /* N/A -- always off */
__dsorgPS : 1, /* N/A -- always off */
__dsorgConcat : 1, /* N/A -- always off */
__dsorgMem : 1, /* */
__dsorgHiper : 1, /* */
__dsorgTemp: 1, /* N/A -- always off */
__dsorgVSAM: 1, /* N/A -- always off */
__dsorgHFS : 1, /* N/A -- always off */
__openmode : 2, /* __BINARY */
__modeflag : 4, /* combination of: */
/* __READ */
/* __WRITE */
/* __APPEND */
/* __UPDATE */
__dsorgPDSE: 1, /* N/A -- always off */
__reserve2 : 8; /* */
__device_t __device; /* one of: */
/* __MEMORY */
/* __HIPERSPACE */
unsigned long __blksize, /* */
__maxreclen; /* */
unsigned short __vsamtype; /* N/A */
unsigned long __vsamkeylen; /* N/A */
unsigned long __vsamRKP; /* N/A */
char * __dsname; /* */
unsigned int __reserve4; /* */
};
typedef struct __fileData fldata_t;
Notes:
1. The filename is the fully qualified version of the filename specified on the
fopen() or freopen() function call. There are no quotation marks. However, if
the filename specified on the fopen() or freopen() function call begins with an
*, a unique filename is generated in the format ((n)), where n is an integer.
2. The __dsorgMem bit will be set on only for regular memory files.
3. The __dsorgHiper bit will be set on only for hiperspace memory files.
4. The __dsname is identical to the filename value.
Example program
The following examples show the use of a memory file. Program CCNGMF3 (Figure 34
on page 211) creates a memory file, calls program CCNGMF4 (Figure 35 on page
212), and redirects the output of the called program to the memory file. When
control returns to the first program, the program reads and prints the string in the
memory file.
fp = fopen("PROG.DAT","rb");
rc = fgets(buffer,sizeof(buffer),fp);
if (rc == NULL)
{
perror(" Error reading from file ");
exit(99);
}
printf("%s", buffer);
}
return(0);
}
Figure 35 on page 212 redirects the output of the called program to the memory
file.
Chapter 14. Performing memory file and hiperspace I/O operations 211
/* this example demonstrates the use of a memory file */
/* part 2 of 2-other file is CCNGMF3 */
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char item1[] = "Hello World\n";
int rc;
/* Write the data to the stdout which, at this point, has been
redirected to the memory file */
rc = fputs(item1,stdout);
if (rc == EOF) {
perror("Error putting to file ");
exit(99);
}
return(0);
z/OS XL C/C++ under CICS Transaction Server for z/OS (CICS TS) supports only
three kinds of I/O:
CICS I/O
z/OS XL C/C++ applications can access the CICS I/O commands through
the CICS command level interface. For detailed information, see CICS
Application Programming Guide and CICS Application Programming
Reference.
Files Memory files are the only type of file that z/OS XL C/C++ supports under
CICS. Hiperspace files are not supported. VSAM files can be accessed
through the CICS command level interface.
CICS data queues
Under CICS, z/OS XL C/C++ implements the standard output (stdout) and
standard error (stderr) streams as CICS transient data queues. These data
queues must be defined in the CICS Destination Control table (DCT) by the
CICS system administrator before the CICS cold start. Output from all
users' transactions that use stdout (or stderr) is written to the queue in the
order of occurrence.
To help differentiate the output, place a user's terminal name, the CICS
transaction identifier, and the time at the beginning of each line printed to
the queue. The queues are as follows:
Stream Queue
stdout CESO
stderr CESE
stdin Not supported
To access any other queues, you must use the command level interface.
Note: If you are using the C++ I/O stream classes, the standard stream cout maps
to stdout, which maps to CESO. The standard stream cerr and clog both map to
stderr, which maps to CESE. The standard stream cin is not supported under CICS.
For more general information about C++ I/O streaming, see Chapter 4, Using the
Standard C++ Library I/O Stream Classes, on page 21. For more detailed
information, see Standard C++ Library Reference, which discusses the Standard
C++ I/O stream classes
For information about using z/OS XL C/C++ and z/OS XL C/C++ under CICS TS,
see Chapter 48, Using the CICS Transaction Server (CICS TS), on page 711. For
information on using wide characters in the CICS TS environment, see Chapter 8,
z/OS XL C Support for the double-byte character set, on page 51.
Restriction: This chapter does not apply to AMODE 64. There is no MSGFILE
run-time option in AMODE 64. In AMODE 64, the stderr stream does not get
directed to the Language Environment message file. Anything that would normally
go to the Language Environment message file is now directed to the C stderr
stream, including when stderr is directed to stdout. For more information on
AMODE 64 see Chapter 23, z/OS 64-bit environment, on page 325.
The default open mode for the z/OS Language Environment message file is text.
Binary and record I/O modes are not supported.
This chapter also describes C I/O streams as they can be used within C++
programs. If you want to use the C++ I/O stream classes instead, see Chapter 4,
Using the Standard C++ Library I/O Stream Classes, on page 21 for general
information. For more detailed information, see:
v Standard C++ Library Reference discusses the Standard C++ I/O stream classes
The standard stream stderr defaults to using the z/OS Language Environment
message file. stderr will be directed to file descriptor 2, which is typically your
terminal if you are running under one of the z/OS UNIX shells. There are some
exceptions, however:
v If the application has allocated the ddname in the MSGFILE(ddname) run-time
parameter, your output will go there. The default is MSGFILE(SYSOUT).
v If the application has issued one of the POSIX exec() functions, or it is running
in an address space created by the POSIX fork() function and the application
has not dynamically allocated a ddname for MSGFILE, then the default is to use
file descriptor 2, if one exists. If it doesn't, then the default is to create a message
file in the user's current working directory. The message file will have the name
that is specified on the message file run-time option, the default being SYSOUT.
Opening files
The default is for stderr to go to the message file automatically. The message file
is available only as stderr; you cannot use the fopen() or freopen() library
function to open it.
v freopen() with the null string ("") as filename string will fail.
v Record format (RECFM) is always treated as undefined (U). Logical record
length (LRECL) is always treated as 255 (the maximum length defined by z/OS
Language Environment message file system write interface).
Writing to files
v Data written to the z/OS Language Environment message file is always
appended to the end of the file.
Flushing buffers
The fflush() function has no effect on the z/OS Language Environment message
file.
You cannot call fseek() on stderr when it is mapped to MSGFILE (the default routing
of stderr).
Closing files
Do not use the fclose() library function to close the z/OS Language Environment
message file. z/OS XL C/C++ automatically closes files on normal program
termination and attempts to do so under abnormal program termination or abend.
If the CELQPIPI MSGRTN service routine is specified and the standard stream
stderr has not been redirected, it defaults to using the CELQPIPI MSGRTN. The
remainder of this chapter describes the behavior of the standard stream stderr
when used in the application.
The CELQPIPI MSGRTN file is write-only. That is, the file is nonreadable and
nonseekable. The mode for this file is text append. Binary and record I/O modes
are not supported.
Opening files
The default behavior is that standard stream stderr will go to the CELQPIPI
MSGRTN. You cannot use the fopen() or freopen() library functions to open or
reopen the CELQPIPI MSGRTN.
v Using fopen() to assign a stream to stderr directs stderr away from the
CELQPIPI MSGRTN.
v A call to freopen() with the null string ("") as the filename string in an attempt to
reopen the CELQPIPI MSGRTN using a different mode will fail.
v Record format (RECFM) is always treated as undefined (U). Logical record
length (LRECL) is always treated as 255, which is the maximum length defined
by the write interface of the CELQPIPI MSGRTN file system.
Writing to files
v Data written to the CELQPIPI MSGRTN file is always appended to the end of the
file.
v When the data written is longer than 255 bytes, it is written to the CELQPIPI
MSGRTN file 255 bytes at a time, with the last write possibly less than 255
bytes. No truncation will occur.
v When the output data is shorter than the actual LRECL of the CELQPIPI
MSGRTN file, it is padded with blank characters by the z/OS Language
Environment system write interface.
Flushing buffers
The fflush() function has no effect on the CELQPIPI MSGRTN file.
fldata() behavior
The fldata() function is used to retrieve information about an open stream. The
name of the file is returned in filename and other information is returned in the
fldata_t structure, shown in Figure 36. Values specific to this category of I/O are
shown in the comment beside the structure element. For more information about
the fldata() function, see z/OS XL C/C++ Run-Time Library Reference.
struct __fileData {
unsigned int __recfmF : 1, /* */
__recfmV : 1, /* */
__recfmU : 1, /* always on */
__recfmS : 1, /* */
__recfmBlk : 1, /* */
__recfmASA : 1, /* */
__recfmM : 1, /* */
__dsorgPO : 1, /* */
__dsorgPDSmem : 1, /* */
__dsorgPDSdir : 1, /* */
__dsorgPS : 1, /* always on */
__dsorgConcat : 1, /* */
__dsorgMem : 1, /* */
__dsorgHiper : 1, /* */
__dsorgTemp: 1, /* */
__dsorgVSAM: 1, /* */
__dsorgHFS : 1, /* */
__openmode : 2, /* __TEXT */
__modeflag : 4, /* __APPEND */
__dsorgPDSE: 1, /* */
__vsamRLS : 3, /* */
__vsamEA : 1, /* */
__reserve2 : 4; /* */
__device_t __device; /* __MSGRTN */
unsigned long __blksize, /* 255 */
__maxreclen; /* 255 */
union { /* */
struct { /* */
unsigned short __vsam_type; /* */
unsigned long __vsam_keylen; /* */
unsigned long __vsam_RKP; /* */
} __vsam; /* */
struct { /* */
unsigned char __disk_access_method; /* */
unsigned char __disk_noseek_to_seek; /* */
long __disk_reserve[2]; /* */
} __disk;
} __device_specific;
char * __dsname; /* */
unsigned int __reserve4; /* */
};
typedef struct __fileData fldata_t;
#include <stdio.h>
int main(void) {
FILE *stream;
char filename[100];
fldata_t fileinfo;
int rc;
stream = stderr;
rc = fldata(stream, filename, &fileinfo);
if (rc != 0)
printf("fldata failed\n");
else
printf("filename is %s\n",filename);
}
The example in Figure 38 shows the use of the CELQPIPI MSGRTN file as the
default stderr.
#include <stdio.h>
#include <errno.h>
int main(void) {
FILE *stream;
stream = stderr;
errno = ETIME;
Perror("perror: Output redirects to the CELQPIPI MSGRTN file.");
}
The information provided with the return code of I/O functions and with the perror()
message associated with errno values may help you locate the source of errors and
the reason for program failure. Because return codes and errno values do not exist
for every possible system I/O failure, return codes and errno values are not useful
for diagnosing all I/O errors. This chapter discusses the use of the __amrc structure
and the __amrc2 structure. For information on return codes from I/O functions see
z/OS XL C/C++ Run-Time Library Reference. For information on errno values and
the associated perror() message see z/OS Language Environment Debugging
Guide.
Note: __amrc is not used to record I/O errors in UNIX file system files.
} __msg; 8
/* error message */
} __amrc_type;
Sample program CCNGDI1 (Figure 40) demonstrates how to print the __amrc
structure after an error has occurred to get information that may help you to
diagnose an I/O error. The program writes to a file until it is full. When the file is full,
the program fails. Following the I/O failure, the program makes a copy of the
__amrc structure, and prints the number of successful writes to the file, the errno,
the __last_op code, the abend system code and the return code.
int main(void) {
FILE *fp;
__amrc_type save_amrc;
char buffer[80];
int i = 0;
memset(buffer, A, 80);
return 0;
}
Note: See Using the SIGIOERR signal on page 229 for information on restrictions
that exist when comparing file pointers if you are using the __amrc2 structure.
struct {
int __error2; 1 */
FILE *__fileptr; 2 */
int __reserved[6];
}
1 This field is a secondary error code that is used to store the reason code
from specific macros. The __last_op codes that can be returned to
__amrc2 are __BSAM_STOW, __BSAM_BLDL, __IO_LOCATE, __IO_RENAME,
__IO_CATALOG and __IO_UNCATALOG. For information on the macros
associated with these codes, see Table 31. For more information about the
macros, see z/OS DFSMSdfp Diagnosis.
2 This field, __fileptr, of the __amrc2 structure is used by the signal
SIGIOERR to pass back a FILE pointer that can then be passed to fldata() to
get the name of the file causing the error. The __amrc2__fileptr will be
NULL if a SIGIOERR is raised before the file has been successfully opened.
#ifdef __cplusplus
extern "C" {
#endif
void iohdlr(int);
#ifdef __cplusplus
}
#endif
int main(void) {
FILE *fp;
char buffer[80];
int i = 0;
signal(SIGIOERR, iohdlr);
memset(buffer, A, 80);
return 0;
}
signal(SIGIOERR, iohdlr);
}
When control is given to a SIGIOERR handler, the __amrc2 structure field __fileptr
will be filled in with a file pointer. The __amrc2__fileptr will be NULL if a SIGIOERR
is raised before the file has been successfully opened. The only operation permitted
on the file pointer is fldata(). This operation can be used to extract information
about the file that caused the error. Other than freopen() and fclose(), all I/O
operations will fail since the file pointer is marked invalid. Do not issue freopen() or
fclose() in a SIGIOERR handler that returns control. This will result in unpredictable
behavior, likely an abend.
If you choose not to return from the handler, the file is still locked from all
operations except fldata(), freopen(), or fclose(). The file is considered open and
can prevent other incorrect access, such as an MVS sequential file opened more
than once for a write. Like all other files, the file is closed automatically at program
termination if it has not been closed explicitly already.
When you exit a SIGIOERR handler and do not return, the state of the file at closing
is indeterminate. The state of the file is indeterminate because certain control block
fields are not set correctly at the point of error and they do not get corrected unless
you return from the handler.
For example, if your handler were invoked due to a truncation error and you
performed a longjmp() out of your SIGIOERR handler, the file in error would remain
open, yet inaccessible to all I/O functions other than fldata(), fclose(), and
freopen(). If you were to close the file or it was closed at termination of the
program, it is still likely that the record that was truncated will not appear in the final
file.
You should be aware that for a standard stream passed across a system() call, the
state of the file will be indeterminate even after you return to te parent program. For
this reason, you should not jump out of a SIGIOERR handler. For further information
on system() calls and standard streams, see Chapter 9, Using C and C++
standard streams and redirection, on page 61.
I/O with files other than the file causing the error is perfectly valid within a SIGIOERR
handler. For example, it is valid to call printf() in your SIGIOERR handler if the file
causing the error is not stdout. Comparing the incoming file pointer to the standard
streams is not a reliable mechanism of detecting whether any of the standard
streams are in error. This is because the file pointer in some cases is only a pointer
If stdout or stderr are the originating files of a SIGIOERR, you should open a special
log file in your handler to issue messages about the error.
EDCTRACE File I/O Trace z/OS XL C/C++ Release: 410B0000 09/28/08 09:14:43 AM
fopen(/u/bryntco/hle7760/B49300/ut/tst/myfile.dat,w)
fldata:
__recfmF:1........ 0 __dsorgVSAM:1..... 0
__recfmV:1........ 0 __dsorgHFS:1...... 1
__recfmU:1........ 1 __openmode:2...... 1
__recfmS:1........ 0 __modeflag:4...... 2
__recfmBlk:1...... 0 __dsorgPDSE:1..... 0
__recfmASA:1...... 0 __reserve2:4...... 0
__recfmM:1........ 0 __device.......... 9
__dsorgPO:1....... 0 __blksize......... 0
__dsorgPDSmem:1... 0 __maxreclen....... 0
__dsorgPDSdir:1... 0 __vsamtype........ 0
__dsorgPS:1....... 0 __vsamkeylen...... 0
__dsorgConcat:1... 0 __vsamRKP......... 0
__dsorgMem:1...... 0 __access_method... 0 (0)
__dsorgHiper:1.... 0 __noseek_to_seek.. 0 (0)
__dsorgTemp:1..... 0
Trace Entries:
Function Name Trace Type
openhfs Entry
fwrite Entry
mwphfs Entry
wp124 Entry
__pcloseall Entry
cp124 Entry
If your application is running under z/OS UNIX and is either running in an address
space that you issued a fork() to, or if it is invoked by one of the exec family of
functions, the trace is written to the UNIX file system. Language Environment writes
the trace to one of the following directories in the specified order:
1. The directory found in environment variable _CEE_DMPTARG, if the directory is
found.
2. The current working directory, as long as the directory is writable and the
EDCTRACE path name does not exceed 1024 characters.
3. The directory found in environment variable TMPDIR, which is an environment
variable that indicates the location of a temporary directory if it is not /tmp.
4. The /tmp directory.
#pragma linkage(identifier,linkage)
declaration-list:
declaration
declaration-list declaration
Note that C++ is case-sensitive, but PL/I, COBOL, assembler, and FORTRAN are
not. In these languages, external names are mapped to uppercase. To ensure that
external names match across interlanguage calls, code the names in uppercase in
the C++ program, supply an appropriate #pragma map specification, or use the
NOLONGNAME compiler option. This will truncate and uppercase names for functions
without C++ linkage.
For example, the following specification declares the two functions ASMFUNC1 and
ASMFUNC2 to have operating system linkage. The function names are case-sensitive
and must match the definition exactly. You should also limit identifiers to 8 or fewer
characters.
extern "OS" {
int ASMFUNC1(void);
int ASMFUNC2(int);
}
Use the reference type parameter (type&) in C++ prototypes if the called language
does not support pass-by-value parameters or if the called routine expects a
parameter to be passed by reference.
Note: To have your program be callable by any of these other languages, include
an extern declaration for the function that the other language will call.
z/OS Language Environment provides a set of assembler macros for use with
64bit assembler programs. For information on writing 64bit assembler programs
see z/OS Language Environment Programming Guide for 64-bit Virtual Addressing
Mode.
Access to z/OS UNIX is intended to be through the z/OS UNIX XL C/C++ runtime
library only. The z/OS XL C/C++ compiler does not support the direct use of z/OS
UNIX callable services such as the assembler interfaces. You should not directly
use z/OS UNIX callable services from your z/OS XL C/C++ application programs,
because problems can occur with the processing of the following:
v Signals
v Library transfers
v fork()
v exec()
v Threads
There are comparable z/OS XL C/C++ runtime library functions for most z/OS
UNIX callable services, and you should use those instead. Do not call assembler
programs that access z/OS UNIX callable services.
Note: In this , "OS linkages" and "OS linkage" conventions refer to the following
group of specifications: OS, OS_UPSTACK, OS_DOWNSTACK, OS_NOSTACK,
OS31_NOSTACK and REFERENCE. "OS" is used in syntax diagrams and
examples as a representative specification. These specifications use different
stack conventions. For more information on these specifications, see Chapter 19,
Using Linkage Specifications in C or C++, on page 237.
v Use preinitialization to set up the z/OS Language Environment. See Retaining
the C environment using preinitialization on page 257 for information.
v Use the Language Environment CEEENTRY prolog macro with MAIN=YES
specified so that z/OS Language Environment is initialized.
Once you are in the assembler program, you can call other C or C++ programs
from the assembler.
Note: For C and C++, in XPLINK compiled code, the OS_UPSTACK and
OS_NOSTACK (or OS31_NOSTACK) linkages are used for declaring the linkage
convention of a routine that the C or C++ code is calling. You cannot define C or
C++ entry points as having OS_NOSTACK linkage. You define C or C++ entry points
with OS_UPSTACK linkage by compiling the translation units containing them with
the NOXPLINK compiler option. In NOXPLINK compiled code, the OS_DOWNSTACK
linkage is used to declare the linkage convention for a routine that the C or C++
code is calling. You define C or C++ entry points with OS_DOWNSTACK linkage by
compiling the translation units containing them with the XPLINK compiler option.
Just as C (or C++) linkage programs can call OS linkage programs, OS linkage
programs can call C linkage programs. An example of C linkage calling OS linkage,
which in turn calls C linkage (in this case, one of the z/OS XL C/C++ library
functions) is shown in Figure 48 on page 253.
In general, any type that can be passed between C and assembler can also be
passed between C++ and assembler. However, if a C++ class that uses features
not available to assembler (such as virtual functions, virtual base classes, private
and protected data, or static data members) is passed to assembler, the results will
be undefined.
Note: In C++, a structure is just a class declared with the keyword struct. Its
members and base classes are public by default. A union is a class declared with
the keyword union its members are public by default, and it holds only one member
at a time.
In the list, the first and third parameters are value parameters, and the second is an
address parameter.
R1
copy of P1 copy of P3
XPLINK Assembler
The XPLINK support provided by the assembler macros EDCXPRLG and
EDCXEPLG allows XPLINK C and C++ code to call routines that can be coded for
performance, or to perform a function that can not be readily done in C/C++. The
EDCXCALL macro allows XPLINK assembler to call routines in the same program
object, or in a DLL. The following z/OS Language Environment books provide more
information on XPLINK that may be useful to assembler programmers:
v z/OS Language Environment Programming Guide provides an overview of
XPLINK and what it means to the application programmer. It also describes the
Language Environment assembler support, including the CEEPDDA and
CEEPLDA macros, which can be used to define and reference data from
assembler.
v z/OS Language Environment Writing Interlanguage Communication Applications
provides information on how assembler routines interact with routines coded in
other high level languages.
v z/OS Language Environment Debugging Guide provides details on XPLINK,
including information on building parameter lists for calling other XPLINK
routines.
Table 33 shows the layout of the XPLINK interface. See z/OS Language
Environment Vendor Interfaces for additional information about register usage and
conventions, especially for details about passing parameters with XPLINK. For
information on the registers which are saved in the register savearea of the XPLINK
stack frame see z/OS Language Environment Programming Guide.
Table 33. Comparison of non-XPLINK and XPLINK register conventions
Non-XPLINK XPLINK
Stack Pointer Reg 13 Reg 4 (biased)
Return Address Reg 14 Reg 7
Entry point on entry Reg 15 Reg 6 (not guaranteed; a routine may be called via
branch relative)
Environment Reg 0 (writeable static) Reg 5
CAA Address Reg 12 Reg 12
Input Parameter List address in R1 Located at fixed offset 64 ('40'x) into the caller's stack
frame (remember the 2K bias on R4). Additionally, any
of General Registers 1, 2, and 3, and Floating Point
Registers 0, 2, 4, and 6, may be used to pass
parameters instead of the caller's stack frame.
Return code Reg 15 R3 (extended return value in R1,R2)
Start address of Caller's NAB value Caller's Reg 4 - DSA size
callee's stack frame
End address of Caller's NAB value + DSA size Caller's Reg 4
callee's stack frame
EDCPROL, the old version of EDCPRLG, is shipped for compatibility with Version 1 of
C/370 and is unchanged. However, you should use EDCPRLG if you can.
The advantage of writing assembler code using these macros is that the assembler
routine will then participate fully in the z/OS XL C/C++ environment, enabling the
assembler routine to call z/OS XL C/C++ functions. The macros also manage
automatic storage, and make the assembler code easier to debug because the
z/OS Language Environment control blocks for the assembler function will be
displayed in a formatted traceback or dump. See the Debug Tool documentation,
which is available at , for further information on z/OS Language Environment
tracebacks and dumps:
http://www-01.ibm.com/software/awdtools/debugtool/library/
You should not use EDCDSAD to access automatic memory if you have
specified DSALEN=NONE, since DSECT is addressable using R13.
EDCEPIL
name
name Is the optional name operand, which then becomes the label on the exit
from this code. The name does not have to match the prolog.
Note: If you specify EXPORT=YES, then you must use the GOFF
assembler option. For the entry point to be available as an exported DLL
function, you must specify the DYNAM(DLL) binder option, and the resulting
program object must reside in a PDSE or the UNIX file system.
XPLINK Call
Use the EDCXCALL macro to pass control from an XPLINK assembler program to
a control section at a specified entry point. It is meant to be used in conjunction
with the EDCXPRLG and EDCXEPLG macros. The target of EDCXCALL can be
resolved either statically (link-edited with the same program object) or dynamically
(imported from a DLL).
The EDCXCALL macro does not generate any return codes. Return information
may be placed in GPR 3 (and possibly GPRs 2 and 1, or the Floating Point
Registers) by the called program, as specified by XPLINK linkage conventions. The
EDCXCALL macro does not support extended return types. For more information,
refer to z/OS Language Environment Vendor Interfaces .
EDCXEPLG
name
name Is the optional name operand, which then becomes the label on the exit
from this code. The name does not have to match the prolog.
EDCDSAD
name
The Language Environment mapping macro CEEDSA can be used to map a DSA,
either non-XPLINK or XPLINK or both.
CEEDSA SECTYPE=XPLINK
name
There are other SECTYPE operands. SECTYPE=XPLINK will only produce an XPLINK
DSA mapping. For more information on CEEDSA see z/OS Language Environment
Programming Guide.
The first code example (CCNGCA4) shown in Figure 48 is a trivial C routine that
establishes the C run-time environment.
int main(void) {
CALLPRTF();
return(0);
}
The second part, shown in Figure 49 on page 254, is the assembler routine
(CNGCA2). It calls an intermediate C function that invokes a run-time library
function.
#include <stdio.h>
#pragma map(_printf4,@PRINTF4)
The first part (CCNGCA1), shown in Figure 51 on page 255, is a trivial XL C/C++
routine that establishes the XL C/C++ run-time environment. It uses extern OS to
int main(void) {
CALLPRTF();
}
The second part (CCNGCA2), shown in Figure 52, is the assembler routine. It calls
an intermediate XL C/C++ routine that invokes a run-time library function.
Figure 52. Calling an intermediate XL C/C++ function from Assembler using OS linkage
The third part of the example (CCNGCA3), shown in Figure 53 on page 256, is an
intermediate XL C/C++ routine that calls a run-time library function.
Note: When in FLOAT(AFP) mode the callee must save and restore FPR's 8 through
15.
If you are calling a C program multiple times from an assembler program, you can
establish the C environment and then repeatedly invoke the C program using the
already established C environment. You incur the overhead of initializing and
terminating the C environment only once instead of every time you invoke the C
program.
To maintain the C environment, you start the program with the C entry CEESTART,
and pass a special Extended Parameter List that indicates that the program is to be
preinitialized.
When you use preinitialization, you are initializing the library yourself with the INIT
call and terminating it yourself with the TERM call. In a non-preinitialized program, the
library closes any files you left open and releases storage. It does not do this in a
preinitialized program. Therefore, for every invocation of your preinitialized program,
you must release all allocated resources as follows:
v Close all files that were opened
v Free all allocated storage
v Release all fetched modules
If you do not release all allocated resources, you will waste memory.
Length of EPL
Token 1
Token 2
address
X'80000000' +
address LL Runtime Options
address
argc
pointer to
argv [argc-1]
argv [argc-1]
The LL field is a halfword containing the value of 16. The halfword that follows must
contain 0 (zero).
The Extended PLIST address field is a pointer to the Extended Parameter List
(EPL). The EPL is a vector of fullwords that consists of:
Length of extended parameter list
The length includes the 4 bytes for the length field. Valid decimal values are
20, 28, and 32.
First and second C environment tokens
These tokens are automatically returned during initialization; or, you can
use zeros for them when requesting a preinitialized CALL, and the effect is
that both an INIT and a CALL are performed.
Pointer to your program parameters
The layout of the parameters is shown in Figure 54 on page 258, Interface
for Preinitialization Programs. If no parameter is specified, use a fullword of
zeros.
Pointer to your run-time options
To point to the character string of run-time options, refer to Figure 54. The
character string consists of a halfword LL field that contains the length of
the list of run-time options, followed by the actual list of run-time options.
The length you specify in the first field of the extended parameter list makes it
known whether you have specified a request modifier code or not.
Run-Time options are applied only at initialization and remain until termination. You
must code PLIST(MVS) in the called C program in order for the preinitialization to
work.
Preinitializing a C program
Figure 55 on page 262 is a sample preinitialized C program that shows how to do
the following:
v Establish the C environment using an INIT request
v Pass run-time parameters to the C initialization routine
v Set up a parameter to the C program
v Repeatedly call a C program using the CALL request
v Communicate from the C program to the driving program using a return code
v End the C program using the TERM request
The parameters it expects are the file name in argv[1] and the return code in
argv[2]. The C program printf()s the value of the return code, writes a record to
the file name, and decrements the value in return code.
The assembler program that drives the C program establishes the C environment
and repeatedly invokes the C program, initially passing a value of 5 in the return
code. When the return code set by the C program is zero, the assembler program
terminates the C environment and exits.
Program CCNGCA6 (Figure 55 on page 262 ) does not include the logic that
would verify the correctness of any of the invocations. Such logic is imperative for
proper operations.
Program CCNGCA7 (Figure 56) shows how to use the preinitializable program.
#pragma runopts(PLIST(MVS))
#include <stdio.h>
#include <stdlib.h>
#define MAX_MSG 50
#define MAX_FNAME 8
#include <string.h>
Return codes
Preinitialized programs do not put their return codes in R15. If the address of the
return code is required, specify a parameter. Figure 55 on page 262 shows how you
can use the RUN_INDEX parameter to evaluate the address of a return code.
Run-time options
If run-time options are specified in the assembler program, the C program must be
compiled with EXECOPS in effect. EXECOPS is the default.
If starting with non z/OS Language Environment enabled assembler, the first
request modifier 4 environment creates a dummy environment (z/OS Language
Environment region-level control blocks) in addition to its own. The dummy
environment remains pointed to by the TCB when the initialization is complete. The
next initialization using request modifier 4 recognizes an existing environment that
supports chaining and the new environment will be chained. This permits the two
environments to share C memory files. Request modifier 4 environments in this
model can be initialized and terminated in any order.
If starting with a batch environment (for example, COBOL, PL/I or C), which
supports chaining by default, and during execution within that environment a call is
made to an assembler routine which initializes a request modifier 4 environment,
the z/OS Language Environment batch environment is recognized and the new
environment will be chained. This allows an initial batch environment to share C
memory files with the request modifier 4 environment. Request modifier 4
Sharing C memory files with request modifier 4 environments: You can use
request modifier 4 to create multiple Preinitialized Compatibility Interface (PICI) C
environments. When you create a new request modifier 4 environment, it is chained
under certain circumstances to the current environment.
The following list identifies the specific features that are or are not supported in the
multiple PICI C environment scenario:
v C memory files will be shared across all C environments (as long as at least one
C environment exists) that are on the chain. This includes all PICI C
environments that are initialized and possibly an initial batch C environment.
v Because the PICI C environments are chained, initialization and termination of
these PICI C environments can be performed in any order. The chaining also
requires that the C run-time library treat each PICI C environment as equal. In C
run-time library terms, each PICI C environment is considered a root enclave
(depth=0).
v Because there can be multiple C root enclaves, sharing of C standard streams
across the C root enclaves exhibits a special behavior. When a C standard
stream is referenced for the first time, its definition is made available to each of
the C root enclaves.
v C standard streams are inherited across the system() call boundary. When a
PICI C environment is initialized from a nested enclave, it does not inherit the
standard streams of the nested enclave. Instead, it shares the C standard stream
definitions at the root level.
v C regular (nonmemory, nonstandard stream) files are also shared across the
PICI C environments.
v Nested C enclaves are created using the system() call. The depth is relative to
the root enclave that owns the system() call chain. You can have two C
enclaves, other than the C root enclaves, with the same depth. You can do this
by calling one of the PICI C environments from a nested enclave and then using
system() in the PICI C environment.
v C regular (nonmemory, nonstandard stream) files opened in a system() call
enclave are closed automatically when the enclave ends.
v C regular (nonmemory, nonstandard stream) files that are opened in a PICI C
environment root enclave are not closed automatically until the PICI C
environment ends. Before returning to the caller, you should close streams that
are opened by the PICI C environment. If you do not, undefined behavior can
occur.
v C memory files are not removed until the last PICI C environment is ended.
You must supply any service routines pointed to in your service vector. When
called, these service routines require the following:
v Register 13 points to a standard 18fullword save area.
v Register 1 points to a list of addresses of parameters available to the routine.
v The third parameter in the list must be the address of the user word you
specified in the second field of the service vector.
The parameters available to each routine, and the return and reason codes that
each routine uses, are shown in the following section. The parameter addresses are
passed in the same order in which the parameters are listed.
The name length must not be zero. You can ignore the reserved field. It will contain
zeros. The load routine can set the following return/reason codes:
0/0 successful
4/4 unsuccessful module loaded above line when in AMODE 24
8/4 unsuccessful load failed
16/4 unrecoverable error occurred
The name length must not be zero. You can ignore the reserved field. It will contain
zeros. Every delete action must have a corresponding load action, and the task that
does the load must also do the delete. Counts of deletes and loads performed must
be maintained by the service routines.
Note: If this routine does not preserve the high registers across the call, Language
Environment may not preserve the high registers of the assembler driver program
across the call to Language Environment.
Note: If this routine does not preserve the high registers across the call, Language
Environment may not preserve the high registers of the assembler driver program
across the call to Language Environment.
During initialization, if the ESTAE and/or ESPIE options are in effect, the common
library puts the address of the common library exception handler in the first field of
the above parameter list, and sets the environment token field to a value that is
passed on to the exception handler. It also sets abend and check flags as
appropriate, and then calls your exception router to establish an exception handler.
The meaning of the bits in the abend flags are given by the following structure:
struct {
struct {
unsigned short abends : 1, /*control for system abends*/
reserved : 15;
} system;
struct {
unsigned short abends : 1, /*control for user abends*/
reserved : 15;
} user;
} abendflags;
The meaning of the bits in the check flags are given by the following structure:
struct {
struct {
unsigned short reserved : 1,
operation : 1,
privileged_operation : 1,
execute : 1,
protection : 1,
addressing : 1,
specification : 1,
data : 1,
fixed_overflow : 1,
fixed_divide : 1,
decimal_overflow : 1,
decimal_divide : 1,
exponent_overflow : 1,
exponent_divide : 1,
significance : 1,
float_divide : 1;
} type;
unsigned short reserved;
} checkflags;
The exception router service routine can set the following return/reason codes:
0/0 successful
4/4 unsuccessful the exit could not be (de)-established
16/4 unrecoverable error occurred
The attention router routine can set the following return/reason codes:
0/0 successful
4/4 unsuccessful the exit could not be (de)-established
16/4 unrecoverable error occurred
When an attention interrupt occurs, your attention router must invoke the attention
handler. Use the address in the attention handler field passing the parameters
shown in Table 40.
Table 40. Attention handler parameters
Parameter ASM Attributes Type
Environment token DS A Input
Return code DS F Output
Reason code DS F Output
The return/reason codes upon return from the attention handler are:
0/0 The attention interrupt has been or will be handled
If the address of the message is zero, your message router is expected to return
the size of the line to which messages are written (in the length field). The length
field allows messages to be formatted correctly, for example, broken at blanks. The
message routine must use the following return/reason codes:
0/0 successful
16/4 unrecoverable error occurred
This chapter defines DLL concepts and shows how to build simple DLLs.
Chapter 22, Building complex DLLs, on page 299 shows how to build complex
DLLs and discusses some of the compatibility issues of DLLs.
There are two types of DLLs: simple and complex. A simple DLL contains only DLL
code in which special code sequences are generated by the compiler for
referencing functions and external variables, and using function pointers. With these
code sequences, a DLL application can reference imported functions and imported
variables from a DLL as easily as it can non-imported ones.
A complex DLL contains mixed code, that is, some DLL code and some non-DLL
code. A typical complex DLL would contain some C++ code, which is always DLL
code, and some C object modules compiled with the NODLL compiler option bound
together.
The object code generated by the z/OS XL C++ compiler is always DLL code. Also,
the object code generated by the z/OS XL C compiler with either the DLL compiler
option or the XPLINK compiler option is DLL code. Other types of object code are
non-DLL code. For more information about compiler options for DLLs, see the z/OS
XL C/C++ User's Guide.
XPLINK compiled code and non-XPLINK compiled code cannot be statically mixed
(with the exception of OS_UPSTACK and OS_NOSTACK (or OS31_NOSTACK)
linkages). The XPLINK compiled code can only be bound together with other
XPLINK-compiled code. You can mix non-XPLINK compiled DLLs with XPLINK
compiled DLLs (the same is true for routines which you load with fetch()). The
z/OS XL C++ run-time library manages the transitions between the two different
linkage styles across the DLL and fetch() boundaries.
Notes:
1. There is inherent performance degradation when the z/OS XL C++ run-time
library transitions across these boundaries. In order for your application to
perform well, these transitions should be made infrequently. When using
XPLINK, recompile all parts of the application with the XPLINK compiler option
wherever possible.
2. As of z/OS V1R9, all support for the C/C++ IBM Open Class Library is
removed. For new code and enhancements to existing applications, the
Standard C++ Library should be used.
Note: All potential DLL executable modules are registered in the CICS PPT control
table in the CICS environment and are invoked at run time.
Loading a DLL
A DLL is loaded implicitly when an application references an imported variable or
calls an imported function. DLLs can be explicitly loaded by calling dllload() or
dlopen(). Due to optimizations performed, the DLL implicit load point may be
moved and the DLL will be loaded only if the actual reference occurs.
If the DLL contains static classes, constructors are run when the DLL is loaded.
This loading may occur before main(); in this case, the corresponding destructors
are run once when main() returns.
In the first situation, the DLL is loaded before main() is invoked, and if the DLL
contains C++ code, constructors are run before main() is invoked. In the other
situations, the DLL loading may be delayed until the time of the implicit call,
although optimization may move this load earlier.
If the DLL application references (imports) an exported DLL variable, that DLL may
be implicitly loaded before that DLL application is invoked (not necessarily before
main() is invoked). With XPLINK, the DLL will always be implicitly loaded before
invoking the DLL application that references (imports) a DLL variable or takes the
address of a DLL function.
Note: When a DLL is loaded, its writable static is initialized. If the DLL load
module contains C++ code, static constructors are run once at initial load time, and
static destructors are run once at program termination. Static destructors are run in
the reverse order of the static constructors.
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 281
Loading a DLL explicitly
The use of DLLs can also be explicitly controlled by the application code at the
source level. The application uses explicit source-level calls to one or more run-time
services to connect the reference to the definition. The connections for the
reference and the definition are made at run-time.
The DLL application writer can explicitly call the following run-time services:
v dllload(), which loads the DLL and returns a handle to be used in future
references to this DLL
v dllqueryfn(), which obtains a pointer to a DLL function
v dllqueryvar(), which obtains a pointer to a DLL variable
v dllfree(), which frees a DLL loaded with dllload()
The following run-time services are also available as part of the Single UNIX
Specification, Version 3:
v dlopen(), which loads the DLL and returns a handle to be used in future
references to this DLL
v dlsym(), which obtains a pointer to an exported function or exported variable
v dlclose(), which frees a DLL that was loaded with dlopen()
v dlerror(), which returns information about the last DLL failure on this thread that
occurred in one of the dlopen() family of functions
While you can use both families of explicit DLL services in a single application, you
cannot mix usage across those families. So a handle returned by dllload() can
only be used with dllqueryfn(), dllqueryvar(), or dllfree(). And a handle
returned by dlopen() can only be used with dlsym() and dlclose().
Because the dlopen() family of functions is part of the Single UNIX Specification,
Version 3, it should be used in new applications whenever cross-platform portability
is a concern.
For more information about the run-time services, see z/OS XL C/C++ Run-Time
Library Reference.
Note: You do not need to bind with the definition side-deck if you are calling the
DLL explicitly with the run-time services, since there are no references from the
source code to function or variable names in the DLL, for the binder to resolve.
Therefore the DLL will not be loaded until you explicitly load it with the dllload()
or dlopen() run-time service.
#include <dll.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
if (argc != 4) {
Syntax(argv[0]);
return(4);
}
dll = argv[1];
type = argv[2];
id = argv[3];
dllHandle = dllload(dll);
if (dllHandle == NULL) {
perror("DLL-Load");
fprintf(stderr, "Load of DLL %s failed\n", dll);
return(8);
}
Figure 59. Explicit use of a DLL in an application using the dllload() family of functions (Part 1
of 2)
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 283
if (strcmp(type, FUNCTION)) {
if (strcmp(type, VARIABLE)) {
fprintf(stderr,
"Type specified was not " FUNCTION " or " VARIABLE "\n");
Syntax(argv[0]);
return(8);
}
/*
* variable request, so get address of variable
*/
varPtr = (int*)(dllqueryvar(dllHandle, id));
if (varPtr == NULL) {
perror("DLL-Query-Var");
fprintf(stderr, "Variable %s not exported from %s\n", id, dll);
return(8);
}
value = *varPtr;
printf("Variable %s has a value of %d\n", id, value);
}
else {
/*
* function request, so get function descriptor and call it
*/
DLL_FN* fn = (DLL_FN*) (dllqueryfn(dllHandle, id));
if (fn == NULL) {
perror("DLL-Query-Fn");
fprintf(stderr, "Function %s() not exported from %s\n", id, dll);
return(8);
}
value = fn();
printf("Result of call to %s() is %d\n", id, value);
}
dllfree(dllHandle);
return(0);
}
Figure 59. Explicit use of a DLL in an application using the dllload() family of functions (Part 2
of 2)
Figure 60 on page 285 shows an example that uses the dlopen() family of
functions.
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
if (argc != 4) {
Syntax(argv[0]);
return(4);
}
dll = argv[1];
type = argv[2];
id = argv[3];
Figure 60. Explicit use of a DLL in an application using the dlopen() family of functions (Part
1 of 2)
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 285
/*
* get address of symbol (may be either function or variable)
*/
symPtr = (int*)(dlsym(dllHandle, id));
if (symPtr == NULL) {
fprintf(stderr, "dlsym() error: symbol %s not exported from %s: %s\n"
, id, dll, dlerror());
return(8);
}
if (strcmp(type, FUNCTION)) {
if (strcmp(type, VARIABLE)) {
fprintf(stderr,
"Type specified was not " FUNCTION " or " VARIABLE "\n");
Syntax(argv[0]);
return(8);
}
/*
* variable request, so display its value
*/
value = *(int *)symPtr;
printf("Variable %s has a value of %d\n", id, value);
}
else {
/*
* function request, so call it and display its return value
*/
value = ((DLL_FN *)symPtr)();
printf("Result of call to %s() is %d\n", id, value);
}
dlclose(dllHandle);
return(0);
}
Figure 60. Explicit use of a DLL in an application using the dlopen() family of functions (Part
2 of 2)
Loading DLLs
When you load a DLL for the first time, either implicitly or by an explicit dllload()
or dlopen(), writable static is initialized. If the DLL is written in C++ and contains
static objects, then their constructors are run.
You can load DLLs from a UNIX file system as well as from conventional data sets.
The following list specifies the order of a search for unambiguous and ambiguous
file names.
v Unambiguous file names
If the file has an unambiguous z/OS UNIX file system name (it starts with a ./
or contains a /), the file is searched for only in the UNIX file system.
If the file has an unambiguous MVS name, and starts with two slashes (//),
the file is only searched for in MVS.
v Ambiguous file names
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 287
Changing the search order for DLLs while the application is running (eg. changing
LIBPATH) may result in errors if ambiguous file names are used.
Sharing DLLs
DLLs are shared at the enclave level (as defined by the z/OS Language
Environment). A referenced DLL is loaded only once per enclave and only one copy
of the writable static is created or maintained per DLL per enclave. Thus, one copy
of a DLL serves all modules in an enclave regardless of whether the DLL is loaded
implicitly or explicitly. You can access the same DLL within an enclave both
implicitly and by explicit run-time services.
All accesses to a variable in a DLL in an enclave refer to the only copy of that
variable. All accesses to a function in a DLL in an enclave refer to the only copy of
that function.
Although only one copy of a DLL is maintained per enclave, multiple logical loads
are counted and used to determine when the DLL can be deleted. For a given DLL
in a given enclave, there is one logical load for each explicit dllload() or dlopen()
request. DLLs that are referenced implicitly may be logically loaded at application
initialization time if the application references any data exported by the DLL, or the
logical load may occur during the first implicit call to a function exported by the DLL.
DLLs are not shared in a nested enclave environment. Only the enclave that loaded
the DLL can access functions and variables.
Freeing DLLs
You can free explicitly loaded DLLs with a dllfree() or dlclose() request. This
request is optional because the DLLs are automatically deleted by the run-time
library when the enclave is terminated.
Implicitly loaded DLLs cannot be deleted from the DLL application code. They are
deleted by the run-time library at enclave termination. Therefore, if a DLL has been
both explicitly and implicitly loaded, the DLL can only be deleted by the run-time
when the enclave is terminated.
#pragma export(bopen)
#pragma export(bclose)
#pragma export(bread)
#pragma export(bwrite)
int bopen(const char* file, const char* mode) {
...
}
int bclose(int) {
...
}
int bread(int bytes) {
...
}
int bwrite(int bytes) {
...
}
#pragma export(berror)
int berror;
char buffer[1024];
...
Figure 61. Using #pragma export to create a DLL executable module named BASICIO
This example exports the functions bopen(), bclose(), bread(), bwrite(), and the
variable berror. The variable buffer is not exported.
Compiling with the EXPORTALL compiler option would export all the functions and the
buffer variable.
For example, Figure 62 on page 290 shows how to create a DLL executable
module named triangle using the #pragma export directive. This example exports
the functions getarea(), getperim(), the static member objectCount, and the
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 289
constructor for class triangle.
class triangle
{
public:
static int objectCount;
getarea();
getperim();
triangle(void);
};
#pragma export(triangle::objectCount)
#pragma export(triangle::getarea())
#pragma export(triangle::getperim())
#pragma export(triangle::triangle(void))
Figure 62. Using #pragma export to create the triangle DLL executable module
Similarly, Figure 63 shows how to create a DLL executable module named triangle
using the _Export keyword:
{
public:
static int _Export objectCount;
double _Export getarea();
double _Export getperim();
_Export triangle::triangle(void);
};
Figure 63. Using _Export to create the triangle DLL executable module
If you apply the _Export keyword to a class, then it automatically exports the static
members, defined functions, constructors, and destructors of that class, as shown in
the following example. This behavior is the same as using the EXPORTALL compiler
option.
class triangle
{
public:
static int objectCount;
double getarea();
double getperim();
triangle(void);
};
When compiling DLL application source code, the compiler generates object code in
such a way that references to external functions and variables can be resolved
statically or dynamically (that is, resolved to a DLL). If you are uncertain whether
non-XPLINK C source code references a DLL, you should specify the DLL or XPLINK
compiler options. Compiling source code as DLL application code eliminates the
potential compatibility problems that may occur when binding DLL application code
with non-DLL application code. See Chapter 22, Building complex DLLs, on page
299 for more information on compatibility issues.
The decision to use XPLINK needs to be made independently from the decision to
build a DLL application. While XPLINK compiled code is always DLL application
code, the XPLINK and non-XPLINK function call linkages are different. There is DLL
compatibility for XPLINK and non-XPLINK at the DLL boundary, but XPLINK and
non-XPLINK object modules cannot be mixed in the same DLL. Also, there is a
performance penalty when transitioning between XPLINK and non-XPLINK DLLs
(and vice versa). It is best to have a DLL application made up of all XPLINK or all
non-XPLINK executable modules to the extent that is possible. For more
information on XPLINK, see Using the XPLINK option on page 597.
Note: You can choose to store your DLL in a PDS load library, but only if it is
non-XPLINK. Otherwise, it must be stored in a PDSE load library or in the UNIX file
system. To target a PDS load library, prelink and link your code rather than using
the binder. For information on prelinking and linking, see the appendix on the
Prelinker in z/OS XL C/C++ User's Guide.
When binding the C object module as shown in Figure 61 on page 289, the binder
generates the following definition side-deck:
IMPORT CODE,BASICIO,bopen
IMPORT CODE,BASICIO,bclose
IMPORT CODE,BASICIO,bread
IMPORT CODE,BASICIO,bwrite
IMPORT DATA,BASICIO,berror
Note: You should also provide a header file containing the prototypes for exported
functions and external variable declarations for exported variables.
When binding the C++ object modules shown in Figure 62 on page 290, the binder
generates the following definition side-deck.
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 291
IMPORT CODE,TRIANGLE,getarea__8triangleFv
IMPORT CODE,TRIANGLE,getperim__8triangleFv
IMPORT CODE,TRIANGLE,__ct__8triangleFv
You can edit the definition side-deck to remove any functions and variables that you
do not want to export. You must maintain the file as a binary file with fixed format
and a record length of 80 bytes. Also, use proper binder continuation rules if the
IMPORT statement spans multiple lines, and you change the length of the
statement. In the above example, if you do not want to expose getperim(), remove
the control statement IMPORT CODE,TRIANGLE,getperim__8triangleFv from the
definition side-deck.
Notes:
1. Removing functions and variables from the definition side-deck does not
minimize the performance impact caused by specifying the EXPORTALL compiler
option.
2. Editing the side-deck is not recommended. If the DLL name needs to be
changed, you should bind using the appropriate name. Instead of using the
EXPORTALL compiler option, you should remove unnecessary IMPORT
statements by using explicit #pragma export statements or _Export directives.
The definition side-deck contains mangled names of exported C++ functions, such
as getarea__8triangleFv. To find the original function or variable name in your
source module, review the compiler listing, the binder map, or use the CXXFILT
utility, if you do not have access to the listings. This will permit you to see both the
mangled and demangled names. For more information, see filter utility in z/OS XL
C/C++ User's Guide.
The following code fragment illustrates how an application can use the DLL
described previously. Compile normally and bind with the definition side-deck
provided with the TRIANGLE DLL.
See Figure 64 on page 294 for a summary of the processing steps required for the
application (and related DLLs).
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 293
composed of multiple compilation units, except that they have multiple compiles and
a single bind for each DLL. For simplicity, this example assumes the following:
v ABC does not export variables or functions.
v XYZ and PQR do not use other DLLs.
v The application is completely non-XPLINK and written in C.
Bind Bind
XYZ.objdef PQR.objdef
Bind
Link
Figure 64. Summary of DLL and DLL application preparation and usage
DLL restrictions
Consider the following restrictions when creating DLLs and DLL applications:
Note: If the entry point for a DLL does not meet either of the above conditions,
Language Environment issues an error and terminates the application.
v In a DLL application that contains main(), main() cannot be exported.
v The AMODE of a DLL application must be the same as the AMODE of the DLL
that it calls.
v DLL facilities are not available:
Under MTF, CSP or SPC
To application programs with main() written in PL/I that dynamically call z/OS
XL C functions
v You cannot implicitly or explicitly perform a physical load of a DLL while running
C++ static destructors. However, a logical load of a DLL (meaning that the DLL
has previously been loaded into the enclave) is allowed from a static destructor.
In this case, references from the load module containing the static destructor to
the previously-loaded DLL are resolved.
v If a DLL contains static objects, the constructors are called during DLL load. ISO
C++ requires that the global objects must be defined within the same compilation
unit, but does not specify any order for these to be called; hence the objects are
constructed in the order that they are defined. z/OS XL C/C++ enhances the
standard behavior by providing #pragma priority to control the construction
order for all global objects within the same execution load module. For more
information, see the priority pragma in z/OS XL C/C++ Language Reference for
the details of this pragma. A DLL is one execution load module and the #pragma
priority allows you to control global object construction within a single DLL. On
the other hand, you still have no control over the initialization order across
different DLLs, or across a DLL application and the DLLs it references. If such
order is important, the DLL provider has to define a protocol for applications to
follow so that the interaction between the DLL and the applications happens in
the required manner. The protocol must be part of the DLL interface design. Take
note of the restriction in the previous bullet when defining such a protocol. A
simple example would be requiring an application to call a setup() function,
which is exported by a DLL, before any other references to the same DLL are
made. More elaborate designs are possible. The techniques for controlling static
initialization are well-discussed in C++ literature; you can reference, for example,
Item 47 of Scott Meyers's Effective C++, 50 Specific Ways to Improve Your
Programs and Designs.
v You cannot use the functions set_new_handler() or set_unexpected() in a DLL if
the DLL application is expected to invoke the new handler or unexpected function
routines.
v When using the explicit DLL functions in a multithreaded environment, avoid any
situation where one thread frees a DLL while another thread calls any of the DLL
functions. For example, this situation occurs when a main() function uses
dllload() or dlopen() to load a DLL, and then creates a thread that uses the
ftw() function. The ftw() target function routine is in the DLL. If the main()
function uses dllfree() or dlclose() to free the DLL, but the created thread
uses ftw() at any point, you will get an abend.
To avoid a situation where one thread frees a DLL while another thread calls a
DLL function, do either of the following:
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 295
Do not free any DLLs by using dllfree() or dlclose() (the z/OS Language
Environment will free them when the enclave is terminated).
Have the main() function call dllfree() or dlclose() only after all threads
have been terminated.
v For DLLs to be processed by IPA, they must contain at least one function or
method. Data-only DLLs will result in a compilation error.
v Use of circular DLLs may result in unpredictable behavior related to the
initialization of non-local static objects. For example, if a static constructor (being
run as part of loading DLL "A") causes another DLL "B" to be loaded, then DLL
"B" (or any other DLLs that "B" causes to be loaded before static constructors for
DLL "A" have completed) cannot expect non-local static objects in "A" to be
initialized (that is what static constructors do). You should ensure that non-local
static objects are initialized before they are used, by coding techniques such as
counters or by placing the static objects inside functions.
v DLLs are enclave-level resources and, when opening and closing DLLs in a
multithreaded environment, an application must control DLL load ordering with its
own serialization mechanism to avoid unpredictable results.
Example: Unless the application controls the order of DLL loads, unpredictable
results can occur when different threads perform the following operations at the
same time:
One thread uses a global symbol object handle, obtained via dlopen(), to
search for a symbol whose name has been defined in various DLLs with
different values.
Another thread closes the DLL that defines the symbol whose value is being
sought.
Improving performance
This section contains some hints on using DLLs efficiently. Effective use of DLLs
may improve the performance of your application. Following are some suggestions
that may improve performance:
v If you are using a particular DLL frequently across multiple address spaces, the
DLL can be installed in the LPA or ELPA. When the DLL resides in a PDSE, the
dynamic LPA services should be used (this will always be the case for XPLINK
applications). Installing in the LPA/ELPA may give you the performance benefits
of a single rather than multiple load of the DLL
v When writing XPLINK applications, avoid frequent calls from XPLINK to
non-XPLINK DLLs, and vice-versa. These transitions are expensive, so you
should build as much of the application as possible as either XPLINK or
non-XPLINK. When there is a relatively large amount of function calls compared
to the rest of the code, the performance of an XPLINK application can be
significantly better than non-XPLINK. It is acceptable to make calls between
XPLINK and non-XPLINK, when a relatively large amount of processing will be
done once the call is made.
v Be sure to specify the RENT option when you bind your code. Otherwise, each
load of a DLL results in a separately loaded DLL with its own writable static.
Besides the performance implications of this, you are likely to get incorrect
results if the DLL exports variables (data).
v Group external variables into one external structure.
v When using z/OS UNIX avoid unnecessary load attempts.
Note: DLL names are case sensitive in the UNIX file system. If you specify the
wrong case for your DLL that resides in the UNIX file system, it will not be found
in the UNIX file system.
v For IPA, you should only export subprograms (functions and C++ methods) or
variables that you need for the interface to the final DLL. If you export
subprograms or variables unnecessarily (for example, by using the EXPORTALL
option), you severely limit IPA optimization. In this case, global variable
coalescing and pruning of unreachable or 100% inlined code does not occur. To
be processed by IPA, DLLs must contain at least one subprogram. Attempts to
process a data-only DLL will result in a compilation error.
v The suboption NOCALLBACKANY of the compiler option DLL is more efficient
than the CALLBACKANY suboption. The CALLBACKANY option calls z/OS
Language Environment at run-time. This run-time service enables direct function
calls. Direct function calls are function calls through function pointers that point to
actual function entry points rather than function descriptors. The use of
CALLBACKANY will result in extra overhead at every occurrence of a call
through a function pointer. This is unnecessary if the calls are not direct function
calls.
Chapter 21. Building and using Dynamic Link Libraries (DLLs) 297
298 z/OS V1R13.0 XL C/C++ Programming Guide
Chapter 22. Building complex DLLs
Before you attempt to build complex DLLs, it is important to understand the
differences between the terms DLL, DLL code, and DLL application.
A DLL (Dynamic Link Library) is a file containing executable code and data bound
to a program at run time. The code and data in a DLL can be shared by several
applications simultaneously. It is important to note that compiling code with the DLL
option does not mean that the produced executable will be a DLL. To create a DLL,
you must use the #pragma export or EXPORTALL compiler option.
DLL code is code that can use a DLL. The following are DLL code:
v C++ code
v C code compiled using the DLL or XPLINK option
Code written in languages other than C++ and compiled without the DLL or XPLINK
option is non-DLL code.
If you link DLL code with non-DLL code, the resulting DLL or DLL application is
called complex. You might compile your code as non-DLL for the following reasons:
v Source modules do not use C or C++.
v To prevent problems which occur when a non-DLL function pointer call uses DLL
code. This problem takes place when a function makes a call through a function
pointer that points to a function entry rather than a function descriptor.
For complex DLLs and DLL applications that you compile without XPLINK, you can
use the CBA suboption of the DLL|NODLL compiler option. With this suboption, a
call is made, through a function pointer, to the z/OS Language Environment, for
each function call, at run time. This call eliminates the error that would occur when
a non-DLL function pointer passes a value to DLL code.
Note: In this book, unless otherwise specified, all references to the DLL|NODLL
compiler option assume suboption NOCBA. For more information, see the DLL
compiler option in z/OS XL C/C++ User's Guide.
If you specify the XPLINK compiler option, the CBA and NOCBA suboptions of DLL
and NODLL are ignored.
There are two ways to combine XPLINK and non-XPLINK code in the same
application:
v Compile each entire DLL with XPLINK or without XPLINK. The only interaction
between XPLINK and non-XPLINK code occurs at a DLL or fetch() boundary.
v Use the OS_UPSTACK, OS_NOSTACK, and OS31_NOSTACK linkage directive.
For more information, see the description of the linkage pragma in z/OS XL
C/C++ Language Reference.
XPLINK applications
XPLINK provides compatibility with non-XPLINK functions when calls are made
across executable modules, using either the DLL or fetch() call mechanism. You
should make a reference from XPLINK code into non-XPLINK code only if the
reference is by an imported function or variable, or the function pointer is a
parameter into the XPLINK code. This prevents incompatible references to a
non-XPLINK function entry point.
Non-XPLINK code can expose a function entry point directly to the XPLINK code:
v as a global variable
v as part of a structure that is passed as a parameter
v by passing an explicit return value
Prior to z/OS V1R8, a function entry point from a non-XPLINK application only
could be passed explicitly as an argument into a XPLINK function. This restriction
did not apply if you used the compiler option XPLINK(CALLBACK) or the
__callback qualifier where any such function pointers were used . Existing DLLs
compiled using one of these options do not need to be recompiled. The use of
these options can only be discontinued if the owner of the XPLink-compiled DLL is
certain that any non-XPLink-compiled DLL callers have been recompiled with z/OS
XL C/C++ V1R8 targetting z/OS Language Environment V1R8 or later, and those
applications are targetted for and running on z/OS Language Environment V1R8 or
later.
Non-XPLINK applications
To create a complex DLL or DLL application, you must comply with the following
rules that dictate how you compile source modules. The first decision you must
make is how you should compile your code. You determine whether to compile with
either the DLL or NODLL compiler option based on whether or not your code
references any other DLLs. Even if your code is a DLL, it is safe to compile your
code with the NODLL compiler option if your code does not reference other DLLs.
The second decision you must make is whether to compile with the default compiler
suboption for DLL|NODLL, which is NOCBA, or use the alternative suboption CBA.
This decision is based upon your knowledge of the code you reference. If you are
sure that you do not reference any function calls through function pointers that point
to a function entry rather than a function descriptor, use the NOCBA suboption.
Otherwise, you should use the CBA suboption.
As of V2R4 of OS/390 C/C++, use the following options to ensure that you do not
have undefined results as a result of the function pointer pointing to a function entry
rather than a function descriptor:
1. Compile your source module with the CBA suboption of DLL|NODLL. This
option inserts extra code whenever you have a function call through a function
pointer. The inserted code invokes a run-time service of z/OS Language
Environment which enables direct function calls through C/C++ function
pointers. Direct function calls are function calls through function pointers that
point to actual function entry points rather than function descriptors. The
drawback of this method is that your code will run slower. This occurs because
whenever you have function calls through function pointers z/OS Language
Environment is called at run time to enable direct function calls. See Figure 73
on page 310 for an example of the CBA suboption and an explanation of what
the called z/OS Language Environment routine does at run-time when using the
CBA suboption.
2. Compile your C source module with the NOCBA suboption of DLL|NODLL. This
option has the benefit of faster running but with more restrictions placed on your
coding style. If you do not follow the restrictions, your code may behave
unpredictably. See DLL restrictions on page 294 for more information.
Table 44 summarizes some of the ways that you could compile the two source
modules and list the results. Both modules are linked into a single executable.
Table 44. Examples of how to compile two source modules and list result
How Modules Were Compiled Result
v Source module 1 NODLL (NOCBA) fp contains a function descriptor. Execution of fp
v Source module 2 DLL(NOCBA) will succeed because it is valid to the address of
a function descriptor.
v Source module 1 DLL(NOCBA) fp contains the address of hello. The execution
v Source module 2 NODLL(NOCBA) of fp would abend because source module 1
expects fp to contain a function descriptor for
hello.
v Source module 1 DLL(CBA) fp contains a function descriptor. The generated
v Source module 2 DLL(NOCBA) code will function correctly. It will run slower than
if the source modules were compiled as
DLL(NOCBA) because it will use Language
Environment to make the function call.
v Source module 1 NODLL(CBA) A call to Language Environment made by the
v Source module 2 DLL(NOCBA) function call through the function pointer prevents
a problem that would have occurred had a direct
function call been made.
If you do not use the DLL compiler option, and your source module calls
imported functions or imported variables by name, there will be unresolved
references to these variables and functions at bind time. A DLL or DLL
application that does not comply with these rules may produce undefined
run-time behavior. For a detailed explanation of incompatibilities between DLL
and non-DLL code, see Compatibility issues between DLL and non-DLL code
on page 303.
Note: In rare cases, you may have to split a function into two functions before
you can successfully split the file.
Note: This section does not apply to XPLINK applications. XPLINK code is always
DLL code.
Table 45 and Figure 65 on page 304 illustrate DLL code referencing functions and
variables.
Table 45. Referencing functions and external variables
Function or Variable DLL
Imported Functions A function descriptor is created by the binder. The descriptor is in
the WSA class and contains the address of the function and the
address of the writable static area associated with that function.
The function address and the address of the WSA associated with
the function is resolved when the DLL is loaded. 1
Nonimported Functions Also called through the function descriptor but the function address
is resolved at link time. 3
Imported Variables A variable descriptor is created in the WSA by the binder. It
contains addressing information for accessing an imported
variable. The address is resolved when the DLL is loaded. 2
Nonimported Variables Direct access 4
x = 1; 2
... Var Des
...
g(); 3
addr(x)
...
...
int g(void) {
...
Func Des
}
... ...
addr(g)
y = 2; 4
... ...
Data
... ...
2 y 1 x
... ...
Pointer assignment
In DLL code and non-DLL code, the actual address of a variable is assigned to a
variable pointer. A valid variable pointer always points to the variable itself and
causes no compatibility problems.
Function pointers
In non-DLL code, the actual address of a nonimported function is assigned to a
function pointer. In DLL code, the address of a function descriptor is assigned to a
function pointer.
If you assign the address of an imported function to a pointer in non-DLL code, the
link step will fail with an unresolved reference. In a complex DLL or DLL application,
a pointer to a function descriptor may be passed to non-DLL code. A direct function
pointer (pointer to a function entry point) may be passed to DLL code. A parameter,
a return value, or an external variable can pass a function pointer or an external
variable.
In Figure 66, 1 assigns the address of the descriptor for the imported function f to
fp. 2 assigns the address of the imported variable x to xp. 3 assigns the
address of the descriptor for the nonimported function g to gp. 4 assigns the
address of the non-imported variable y to yp.
xxxxx y 1 x
... ...
In Figure 67 on page 306, 1 causes a bind error because the assignment to fp is
undefined. 2 causes a binder error because the assignment to xp is undefined.
3 assigns gp to the address of the nonimported function, g. 4 assigns the
address of the nonimported variable y to yp.
Data Data
... ...
xxxxx y 1 x
... ...
A function pointer in non-DLL code points to the function entry and a function
pointer call branches to the function address. However, a DLL function pointer
points to a function descriptor. A call made through this pointer in non-DLL code
results in branching to the descriptor.
z/OS XL C/C++ executes a DLL function pointer call in non-DLL code by branching
to the descriptor and executing the glue code that invokes the actual function.
C example
File 1 and File 2 are bound together to create application A. File 1 is compiled with
the NODLL option. File 2 is compiled with the DLL option (so that it can call the
DLL function sort()). File 3 is compiled as DLL to create application B. Application
A and B can both call the imported function sort() from the DLL in file 4.
Figure 68 shows how a file (File 1) of a complex DLL application is compiled with
the NODLL option
main() {
CmpFP* fp = comp;
int a[2] = {2,1};
callsort(a, 2, fp);
return(0);
}
Figure 69 shows how a file (File 2) of a complex DLL application is compiled with
the DLL option.
Figure 70 on page 308 shows how a simple DLL application is compiled with the
DLL option.
Figure 71 shows how a DLL is compiled with the NODLL option. File 4 is compiled
as NODLL and bound into a DLL. The function sort() will be exported to users of
the DLL.
Non-DLL function pointers can only safely be passed to a DLL if the function
referenced is naturally reentrant, that is, it is C code compiled with the RENT
compiler option, or is C code with no global or static variables. See the discussion
on the CBA option to see how to make a DLL that can be called by applications that
pass constructed reentrant function pointers.
non-DLL Application in C
DLL Code
branch to
... func entry
Compare
int compare (int el, int e2) { 4
...
... Language Environment
} 5
Main
typedev void (CMP_FP) (int, int);
void main(void)
int x [10];
CMP_FP* fp=&compare;
stubsort (fp, x, l0) ; 1
DLL
The reference keys in Figure 73 on page 310 illustrate the sequence of events.
Note that in 3, the user does not explicitly make a call to Language Environment.
The generated code for the fp function call makes the call to z/OS Language
Environment. z/OS Language Environment does the following at point4 in the
figure:
v Saves the DLL environment
v Establishes the application environment
v Branches to the user's function
v Reestablishes the DLL environment after execution of the function
v Returns control to the DLL.
#include <stdio.h>
extern void (*fp)(void);
void hello(void) {
printf("hello\n");
}
void goo(void) {
fp = hello; /* assign address of hello, to fp */
/* (refer to
Figure 67 on page 306). */
}
/*
* This function must be compiled as DLL(CBA)
*/
extern "OS" {
typedef void OS_FP(char *, int *);
}
extern "OS" OS_FP* ASMFN(char*);
Func Descriptor
non-DLL code C Library
...
... int printf(...
func addr
... }
if (fp1 == fp2) ...
... }
#include <stdio.h>
extern int foo(int (*fp1)(const char *, ...));
main ()
{
int (*fp)(const char *, ...);
fp = printf; /* assign address of a descriptor that */
/* points to printf. */
if (foo(fp))
printf("Test result is undefined\n");
}
#include <stdio.h>
extern int goo(int (*fp1)(const char *, ...));
main ()
{
int (*fp)(const char *, ...);
fp = printf; /* assign address of a descriptor that */
/* points to printf. */
if (goo(fp))
printf("Test result is undefined\n");
}
#include <stdio.h>
extern int foo(int (*fp1)(const char *, ...),
int (*fp2)(const char *, ...));
int goo(int (*fp1)(const char *, ...))
{
int (*fp2)(const char *, ...);
fp2 = printf; /* assign address of a different */
/* descriptor that points to printf. */
return (foo(fp1, fp2));
}
Func Des2
...
func addr
...
Note: Comparing a DLL function pointer to NULL is well defined, because when a
pointer variable is initialized to NULL in DLL code, it has a value zero.
main() {
void (*fa[2])();
int i;
fa[0] = dummy;
fa[1] = (void (*)())-1;
for(i=0;i<2;i++)
check_fp(fa[i]);
}
In both cases, the result is that the side-deck is produced for CCNGA2D3, so that
the DLLs that reference CCNGA2D3 can be built.
The CCNGA2 application (Figure 88 on page 318) imports functions and variables
from three DLLs: (Figure 89 on page 318, Figure 90 on page 319, and Figure 91 on
page 319). It is an example of an application that uses DLLs that call each other.
int main() {
int rc = 0;
if (var1_d2 == 200) {
printf("| var1_d2=<%d>\n",var1_d2++);
func1_d2(var1_d2);
}
/* ref DLL3 */
if (var1_d3 == 300) {
printf("| var1_d3=<%d>\n",var1_d3++);
func1_d3(var1_d3);
}
#include <stdio.h>
#include <stdio.h>
Application CCNGA2D3 (Figure 91) imports variables from Figure 89 on page 318
and Figure 90.
#include <stdio.h>
The first method uses the JCL in Figure 92 on page 321. The following processing
occurs:
1. CCNGA2D3 is compiled and bound to create a DLL. The binder uses the
control cards supplied through SYSIN to import variables from CCNGA2D1 and
CCNGA2D2. The binder also generates a side-deck CCNGA2D3 that is used in
the following steps.
2. CCNGA2D2 is compiled and bound to create a DLL. The binder uses the
control cards supplied through SYSIN to include the side-deck from
CCNGA2D3. The following steps use the binder which generates the side-deck
CCNGA2D2.
3. CCNGA2D1 is compiled and bound to create a DLL. The binder uses the
control cards supplied through SYSIN to include the side-decks from
CCNGA2D2 and CCNGA2D3. The following steps show the binder generating
the side-deck CCNGA2D1.
//jobcard information...
//PROC JCLLIB ORDER=(CBC.SCCNPRC, CEE.SCEEPROC)
//* CDLL2: -Compile CCNGA2D2
//*
//CDLL2 EXEC EDCC,INFILE=CBC.SCCNSAM(CCNGA2D2),
// OUTFILE=myid.OBJ(CCNGA2D2),DISP=SHR,
// CPARM=SO,LIST,DLL,EXPO,RENT,LONG
//*
//* CDLL1: -Compile CCNGA2D1
//*
//CDLL1 EXEC EDCC,INFILE=CBC.SCCNSAM(CCNGA2D1),
// OUTFILE=myid.OBJ(CCNGA2D1),DISP=SHR,
// CPARM=SO,LIST,DLL,EXPO,RENT,LONG
//*
//* CBDLL3: -Compile and bind CCNGA2D3 with NCAL
//* -Generate the side-deck CCNGA2D3
//* -The load module will not be kept, as it will not be
//* used
//*
//CBDLL3 EXEC EDCCB,INFILE=CBC.SCCNSAM(CCNGA2D3),
// CPARM=SO,LIST,DLL,EXPO,RENT,LONG,
// BPARM=NCAL
//COMPILE.SYSLIN DD DSN=myid.OBJ(CCNGA2D3),DISP=SHR
//BIND.SYSLIN DD DSN=myid.OBJ(CCNGA2D3),DISP=SHR
//BIND.SYSIN DD *
INCLUDE OBJ(CCNGA2D2)
INCLUDE OBJ(CCNGA2D1)
NAME CCNGA2D3(R)
/*
//BIND.SYSDEFSD DD DSN=myid.IMPORT(CCNGA2D3),DISP=SHR
//BIND.OBJ DD DSN=myid.OBJ,DISP=SHR
//*
The compiler changes the behavior of code only when compiling for the 64-bit
environment, which is specified by the LP64 compiler option.
The 32-bit data model for z/OS XL C/C++ compilers is ILP32 plus long long. This
data model uses the 4/4/4 data type size model and includes a long long type.
Table 48 on page 326 compares the type sizes for the different models.
LP64 is the 64-bit data model chosen by the Aspen working group (formed by
X/OPEN and a consortium of hardware vendors). LP64 is short for long-pointer 64.
It is commonly referred to as the 4/8/8 data type size model and includes the
integer/long/pointer type sizes, measured in bytes.
Note: Integers are the same size under the ILP32 and LP64 data models.
If the same source code is used to create a 32-bit and a 64-bit application, the
64-bit application will typically be larger than the 32-bit application. The 64-bit
application is unlikely to run faster than the 32-bit application unless it makes use of
the larger 64-bit addressability. Because most C programs are pointer-intensive, a
64-bit application can be close to twice as large as a 32bit application, depending
on how many global pointers and longs are declared. A 64-bit C++ program uses
almost twice the data as a 32-bit C++ program, due to the large number of pointers
the compiler uses to implement virtual function tables, objects, templates, and so
on. That is why the appropriate choice is to create a 32-bit application, unless 64-bit
addressability is required by the application or can be used to dramatically improve
its performance.
LP64 restrictions
The following restrictions apply under LP64:
v The ILP32 statement type=memory(hiperspace) is treated as type=memory under
LP64.
Hiperspace memory files are treated as regular memory files in a 64-bit
environment. All behavior is the same as for regular memory files.
v The ANSI system() function is not supported under LP64.
From an I/O perspective in a 64-bit environment, there is only the root program;
there are no child programs. This restriction affects at least the following types of
information:
Inheritance of standard streams
Sharing of memory files across enclaves
v The IMS and CICS environments are not supported under LP64.
References to these environments are valid under ILP32 only.
v User-supplied buffers are ignored for all but UNIX file system files under LP64.
References to user-supplied buffers are valid under ILP32 only.
v Under 64-bit data models, pointer sizes are always 64 bits.
The C Standard does not provide a mechanism for specifying mixed pointer size.
However, it might be necessary to specify the size of a pointer type to help
migrate a 32-bit application (for example, when libraries share a common header
between 32-bit and 64-bit applications).
Typically, a 32-bit application should be ported only if either of the following is true:
v It is required by a DLL or a supporting utility
v It must have 64-bit addressability
This is because:
v Porting programs to a 64-bit environment presents a modest technical effort
where good coding practices are used. Poor coding practices greatly increase
the programming effort.
Note: When doing so, examine all arithmetic calculations to make sure that
expansion and truncation of data values is done appropriately. Make sure
that no assumption is made that pointer values will fit into integer types.
__ 5. Use the INFO compiler option to identify the following potential problems:
v Functions not prototyped - Function prototypes allow the compiler to check
for mismatched parameters.
v Functions not prototyped - Return parameter mis-matched, especially
when the code expects a pointer. (For example, malloc and family)
v Assignment of a long or a pointer to an int - This type of assignment could
cause truncation. Even assignments with an explicit cast will be flagged.
v Assignment of an int to a pointer - If the pointer is referenced it might be
invalid.
A general guideline is to review the existing use of long data types throughout the
source code. If the values to be held in such variables, fields, and parameters will fit
in the range of [-231...231-1] or [0...232-1], then it is probably best to use int or
unsigned int instead. Also, review the use of the size_t type (used in many
subroutines), since its type is defined as unsigned long.
When you migrate a program from ILP32 to LP64, the data model differences might
result in unexpected behavior at execution time. Under LP64, the size of pointers
and long data types are 8 bytes, which can lead to conversion or truncation
problems. The WARN64 option can be used to detect these portability errors.
There are a few problems that WARN64 cannot find. For example, unions that use
longs or pointers that work under ILP32 might not work under LP64 .
union {
int *p; /* 32 bits / 64 bits */
int i; /* 32 bits / 32 bits */
};
union {
double d; /* 64 bits / 64 bits */
long l[2]; /* 64 bits / 128 bits */
};
Note: You can us the WARN64 option to help detect these portability errors. See
Using the WARN64 option to identify potential portability problems on page 330.
v A migration issue can exist if the program assumes that int, long and pointer
type are all the same size. The number of cases where program logic relies on
this assumption varies from application to application, depending on the coding
style and functionality of the application.
Note: Most unexpected behaviors occur at the limits of a type's value range.
v 32-bit applications that rely implicitly on internal data representations (for
example, those that cast a float pointer to an integer pointer, then manipulate the
bit patterns directly and encode such knowledge directly into the program logic)
can be difficult to migrate. In this case, certain assumptions are made about the
internal structure of a float representation and the size of int.
Note: The MEMLIMIT value specified in an IEFUSI exit routine overrides all other
MEMLIMIT settings.
The z/OS UNIX System Services ulimit command can be used to set the
MEMLIMIT default. For information, see z/OS UNIX System Services Command
Reference. For additional information about the MEMLIMIT system parameter, see
z/OS MVS Programming: Extended Addressability Guide.
As of z/OS V1R8 XL C/C++, the EDCI, EDCXI, EDCQI, CBCI, CBCXI, and CBCQI
cataloged procedures, which are used for IPA Link, contain the variable IMEMLIM,
which can be used to override the default MEMLIMIT value.
Availability of suboptions
Table 50 shows a comparison of the compiler and run-time options that are
available in each environment. For example, if you are developing a program to run
in either a 32bit or a 64bit environment, you must code it to ensure that the
high-performance linkage (XPLINK) option is in effect regardless of whether the
program is running under ILP32 or LP64.
Table 50. Comparison of ILP32 and LP64 processing and run-time options
ILP32 (32-bit environment) LP64 (64-bit environment)
XPLINK or non-XPLINK XPLINK only
32-bit dynamic linked libraries (DLLs) 64-bit DLLs
It is not possible to share a data structure between 32-bit and 64-bit processes,
unless the structure is devoid of pointer and long types. Unions that attempt to
share long and int types (or overlay pointers onto int types) will be aligned
differently or will be corrupted. For example, the virtual function table pointer,
inherent in many C++ objects, is a pointer and will change the size and alignment
of many C++ objects. In addition, the size and composition of the
compiler-generated virtual function table will change.
Note: The issue of changing structure size and alignment should not be a problem
unless the program makes assumptions about the size and/or composition of
structures.
Note: The only exception is a long double, which is always aligned on an 8-byte
boundary.
You can satisfy the rule of alignment by inserting pad members both between
members and at the end of a structure, so that the overall size of the structure is a
multiple of the structure's alignment.
In accordance with the z/OS rule of alignment (see z/OS basic rule of alignment),
the length of each data member produced by the source code depends on the
run-time environment, as shown in Table 51 on page 334.
int main(void) {
struct li{
long la;
int ia;
} li;
struct lii{
long la;
int ia;
int ib;
} lii;
struct ili{
int ia;
long la;
int ib;
} ili;
printf("length li = %d\n",sizeof(li));
printf("length lii = %d\n",sizeof(lii));
printf("length ili = %d\n",sizeof(ili));
}
ILP32 member length li = 8 1
lengths: length lii = 12 3
length ili = 12 3
LP64 member length li = 16 2
lengths: length lii = 16 3
length ili = 24 3
Notes:
1. In a 32-bit environment, both int and long int have 4-byte alignments, so each of
these members is aligned on 4-byte boundary. In accordance with the z/OS rule of
alignment, the structure as a whole has a 4-byte alignment. The size of struct li is 8
bytes. See Figure 94 on page 335.
2. In a 64-bit environment, int has a 4-byte alignment and long int has an 8-byte
alignment. In accordance with the z/OS rule of alignment, the structure as a whole has
an 8-byte alignment. See Figure 94 on page 335.
3. The struct lii and the struct ili have the same members, but in a different member
order. See Figure 95 on page 336 and Figure 96 on page 337. Because of the padding
differences in each environment:
v Under ILP32:
The size of struct lii is 12 bytes (4-byte long + 4-byte int + 4-byte int)
The size of struct ili is 12 bytes (4-byte int + 4-byte long + 4-byte int)
v Under LP64:
The size of struct lii is 16 bytes (8-byte long + 4-byte int + 4-byte int)
The size of struct ili is 24 bytes (4-byte int + 4-byte pad + 8-byte long + 4-byte
int + 4-byte pad)
The ILP32 and LP64 alignments for the structs defined by the code shown in
Table 51 are compared in Figure 94 on page 335, Figure 95 on page 336, and
Figure 96 on page 337.
Figure 94 on page 335 compares how struct li is aligned under ILP32 and LP64.
The structure has two members:
v The first (member la) is of type long
v The second (member ia) is of type int
ILP32
Member la Member ia
Struct li
Boundary 00 04
4-byte 4-byte
LP64
Member la Member ia Compiler inserted
padding
Struct li
Boundary 00 08
8-byte 8-byte
Figure 94. Comparison of struct li, alignments under ILP32 and LP64
Figure 95 on page 336 and Figure 96 on page 337 show structures that have the
same members, but in a different order. Compare these figures to see how the
order of the members impacts the size of the structures in each environment.
Figure 95 on page 336 compares how struct lii is aligned under ILP32 versus
LP64. struct lii has three members:
v The first (member la) is of type long
v The second (member ia) and third (member ib) are of type int
Under ILP32, each member is 4 bytes long and is aligned on a 4-byte boundary,
making the structure 12 bytes long. Under LP64, member la is 8 bytes long and is
aligned on an 8-byte boundary. Member ia and member ib are each 4 bytes long,
so the structure is 16 bytes long and can align on an 8-byte boundary without
padding.
Struct lii
Boundary 00 04 08
LP64
Member la Member ia Member ib
Struct lii
Boundary 00 08
8-byte 8-byte
Figure 95. Comparison of struct lii alignments under ILP32 and LP64
Figure 96 on page 337 compares how struct ili is aligned under ILP32 and
LP64. struct ili has three members:
v The first (member ia) is of type int
v The second (member la) is of type long
v The third (member ib) is of type int
Under ILP32, each member is 4 bytes long and is aligned on a 4-byte boundary,
making the structure 12 bytes long. Under LP64, the compiler inserts padding after
both member ia and member ib, so that each member with padding is 8 bytes long
(member la is already 8 bytes long) and are aligned on 8-byte boundaries. The
structure is 24 bytes long.
Struct ili
Boundary 00 04 08
LP64
Struct ili
Boundary 00 08 16
Figure 96. Comparison of struct ili alignments under ILP32 and LP64
Under LP64, all pointer types are 8 bytes in size. Assigning pointers to int types
and back again can result in a invalid address, and passing pointers to a function
that expects an int type will result in truncation. For example, the following
statement show an incorrect assignment.
int i;
int *p;
i = (int)p;
Note: The problem is harder to detect when casts are used. Although there is no
warning message, the problem still exists.
You should consider all types related to the long and unsigned long types. For
example, size_t, used in many subroutines, is defined under LP64 as unsigned
long.
Because of the difference in size for int and long under LP64, conversions to long
from other integral types might be executed differently that it was under ILP32.
Example of possible change of result after conversion from signed long long
variable to signed long: When a signed long long variable with values either
greater than UINT_MAX or less than 0 is converted to unsigned long, truncation will
not occur under LP64. The example in Table 54 will yield:
v 4294967295 (0xffffffff) 0 (0x0) under ILP32
v 18446744073709551615 (0xffffffffffffffff) 4294967296 (0x100000000) under LP64
Table 54. Example of possible change of result after conversion from signed long long
variable to signed long
Source: #include<stdio.h>
#include<limits.h>
void foo(signed long long ll)
{
unsigned long l = ll;
printf("%lu (0x%lx)\n", l, l);
}
void main()
{
foo(-1);
foo(UINT_MA X+ 1ll);
}
Compiler options: cc -Wc,"flag(i),warn64" -c warn4.c
Output: INFORMATIONAL CCN3743 ./warn4.c:564-bit portability:
possible change of result through conversion of long
long int type into unsigned long int type.
Example of possible change of result after conversion from signed long long
variable to signed long: Under LP64, when a signed long long variable with
values less than INT_MIN or greater than INT_MAX is converted to signed long,
truncation does not occur.
Table 56. Example of possible change of result after conversion from signed long long
variable to signed long
Source: #include<stdio.h>
#include<limits.h>
void foo(signed long long ll)
{
signed long l = ll;
printf("%ld (0x%lx)\n", l, l);
}
void main()
{
foo(INT_MIN - 1ll);
foo(INT_MAX + 1ll);
}
Compiler cc -Wc,"flag(i),warn64" -c warn5.c
options:
ILP32 output: INFORMATIONAL CCN3743 ./warn5.c:5 64-bit portability:
possible change of result through conversion of long
long int type into long int type.
2147483647 (0x7fffffff)
-2147483648 (0x80000000)
The size qualifier __ptr64 is not currently used; it is reserved so that a program
cannot use it. The size qualifier __ptr32 declares a pointer to be 32 bits in size.
This is ignored under ILP32.
Table 58. Examples of pointer declarations that can be made under LP64
int * __ptr32 p; /* 32-bit pointer */ 1, 3
int * r; /* 64-bit pointer, default to the models size */ 4
int * __ptr32 const q; /* 32-bit const pointer */ 1, 2, 3
Notes:
1. The qualifier qualifies the '*' before it.
2. q is a 32-bit constant pointer to an integer.
3. When __ptr32 is used, the program expects that the address of the pointer variable is
less than or equal to 31 bits. You might need to ensure this by calling a special run-time
function, such as the Language Environment run-time function __malloc31. You can call
__malloc31 whenever you use your own assembler routine to get storage, and want to
keep the addresses in structures and unions to a length of four bytes.
4. If a pointer declaration does not have the size qualifier, it defaults to the size of the data
model.
Notes:
1. Under ILP32, the pointers p and q are pointing to the same memory location.
2. Under LP64, the pointer q is likely pointing to an invalid address, which could
result in a segmentation fault when q is dereferenced.
3. Warning messages are generated for invalid conversions, as shown in Table 59.
Because both pointer size and long size are doubled in 64-bit mode, structures and
unions containing them as members are larger than they are in 32-bit mode.
Attention: The example in Table 62 on page 345 is for illustrative purposes only.
Sharing pointers between 32-bit and 64-bit processes is not recommended and will
likely yield incorrect results.
Notes:
1. When the source is compiled and executed under ILP32, the result indicates
that paddings have been inserted before the member p, and after the member
s. Three padding bytes have been inserted before the member p to ensure that
p is aligned to its natural 4-byte boundary. The alignment of the structure itself is
the alignment of its strictest member. In this example, it is a 4-byte alignment
because the member p has the strictest alignment. Two padding bytes are
inserted at the end of the structure to make the total size of the structure a
multiple of 4 bytes. This is required so that if you declare an array of this
structure, each element of the array will be aligned properly.
2. When the source is compiled and executed under LP64, the size of the
structure doubles because additional padding is required to force the member p
to fall on a natural alignment boundary of 8-bytes.
Figure 97 on page 346 illustrates how the compiler treats the source code shown in
Table 62 under ILP32 and LP64. Because the pointer is a different size in each
environment, they are aligned on different boundaries. This means that if the code
is compiled under both ILP32 and LP64, there are likely to be alignment problems.
Figure 98 on page 350 illustrates the solution, which is to define pad members of
type character that prevent the possibility of data misalignment. Table 65 on page
349 shows the necessary modifications to the code in Table 62.
Struct T
Boundary 00 04 08
LP64
Member c Member s
Struct T
Boundary 00 08 16
Figure 97. Example of potential alignment problems when a struct is shared or exchanged among 32-bit and 64-bit
processes.
Under LP64, you must also consider the maximum number of digits of the long and
unsigned long types. The ULONG_MAX is twenty digits long, and the LONG_MAX is
nineteen digits.
In Table 64, the code assumes that the long type is the same size as the int type
(as it would be under ILP32). That is, %d is used instead of %ld.
Table 64. Example of using LONG_MAX macros in a printf subroutine
Source: #include <stdio.h>
int main(void) {
printf("LONG_MAX( d) = %d\n",LONG_MAX);
printf("LONG_MAX( x) = %x\n",LONG_MAX);
printf("LONG_MAX(lu) = %lu\n",LONG_MAX);
printf("LONG_MAX(lx) = %lx\n",LONG_MAX);
}
LONG_MAX value: 9,223,372,036,854,775,807
Output: LONG_MAX( d) = -1
LONG_MAX( x) = ffffffff
LONG_MAX(lu) = 9223372036854775807
LONG_MAX(lx) = 7fffffffffffffff
Notes:
1. Under LP64:
v %ld must be used
v %x will give incorrect results and must be replaced by %p or %lx
2. A similar example would produce the same results for an unsigned long with a
ULONG_MAX value of 18,446,744,073,709,551,615.
There are many ways to use headers to handle code that is portable between
ILP32 and LP64. You can minimize the amount of conditional compilation code and
avoid having totally different sections of code for a ILP32 and LP64 structure
definitions if you adopt a coding convention that suits your environment.
If you provide a library to your application users and ship header files that define
the application programming interface of the library, consider shipping a single set
of headers that can support both 32-bit and 64-bit versions of your library. You can
use the type definitions in inttypes.h. For example, if you are currently shipping
32-bit versions of your header files, you could:
v Replace all fields of type long with type int32_t (or another 32-bit type)
v Similarly replace all fields for the unsigned variation
v If you cannot let a 64-bit application use a 64-bit pointer for a field, use the
__ptr32 qualifier.
#ifdef _LP64
#define LONG_MAX (9223372036854775807L)
#define LONG_MIN (-LONG_MAX - 1)
#define ULONG_MAX (18446744073709551615U)
#else
#define LONG_MAX INT_MAX
#define LONG_MIN INT_MIN
#define ULONG_MAX (UINT_MAX)
#endif /* _LP64 */
Notes:
1. The output for LONG_MAX is not really -1. The reason for the -1 is that:
v The printf subroutine handles it as an integer
The example in Table 65 shows how the source code in Table 62 on page 345 can
be modified to avoid the data alignment problem.
Table 65. Example of source code that successfully shares pointers between ILP32 and
LP64 programs
Source: struct T {
char c;
short s;
#if !defined(_LP64)
char pad1[4];
#endif
int *p;
#if !defined(_LP64)
char pad2[4];
#endif
} t;
ILP32/ LP64 size and member sizeof(t) = 16
layout: offsetof(t, c) = 0 sizeof(c) = 1
offsetof(t, s) = 2 sizeof(s) = 2
offsetof(t, p) = 8 sizeof(p) = 4
Figure 98 on page 350 shows the member layout of the structure with user-defined
padding. Because the pointer is a different size in each environment, it is aligned on
different a boundary in each environment. This means that if the code is compiled
under both ILP32 and LP64, there are likely to be alignment problems. This figure
illustrates the solution, which is to define pad members of type character that
prevent the possibility of data misalignment.
Note: When inserting paddings into structures, use an array of characters. The
natural alignment of a character is 1-byte, which means that it can reside anywhere
in memory.
Struct T
Boundary 00 04 08 12
LP64
Member c
Compiler-inserted
padding
Member s Compiler-inserted Member p
padding
Struct T
Boundary 00 08
8-byte 8-byte
Figure 98. Example of user-defined data padding for a structure that is shared or exchanged among 32-bit and 64-bit
processes.
The C++ language does not provide a default and always requires a prototype.
However, C++ has an implicit integer return type extension for legacy code.
A common problem is that the default return type of int might not remain the same
size as an associated pointer. For example, the function malloc() can cause
truncation when an unprototyped function returns a pointer. This is because an
unprototyped function is assumed to return an int (4 bytes).
You can use a conditional compiler directive such as #if defined _LP64 or #ifdef
_LP64 to select lines of code (such as printf statements) that are appropriate for
the data model that is invoked.
Functions
Table 66 lists the functions provided to implement a multi-threaded application.
Table 66. Functions used in creating multi-threaded applications
Function Purpose
pthread_create() Create a thread
pthread_join() Wait for thread termination
pthread_exit() Terminate a thread normally
pthread_detach() Detach a thread
pthread_self() Get your thread ID
pthread_equal() Compare thread IDs
pthread_once() Run a function once per process
pthread_yield() Yield the processor
Creating a thread
To use a thread you must first create a thread attribute object with the
pthread_attr_init() function. A thread attribute object defines the modifiable
characteristics that a thread may have. Refer to the description of
pthead_attr_init() in z/OS XL C/C++ Run-Time Library Reference for a list of the
attributes and their default values. When the thread attribute object has been
created, you may use the functions listed in Table 67 to change the default
attributes.
Table 67. Functions to change default attributes
Function Purpose
pthread_attr_init() Initialize a thread attribute object
pthread_attr_destroy() Delete a thread attribute object
pthread_attr_getguardsize() Gets the threadstack guardsize from the thread
attribute object
pthread_attr_setguardsize() Sets the threadstack guardsize in the thread attribute
object
The attribute object is only used when the thread is created. You can reuse it to
create other threads with the same attributes, or you can modify it to create threads
with other attributes. You can delete the attribute object with the
pthread_attr_destroy() function.
After you create the thread attribute object, you can then create the thread with the
pthread_create() function.
Table 68 lists functions that can be used to control the behavior of the individual
threads in a multi-threaded application. Refer to z/OS XL C/C++ Run-Time Library
Reference for more information on these functions.
Table 68. Functions used to control individual threads in a multi-threaded environment
Function Purpose
pthread_equal() Compares two thread IDs
pthread_yield() Allows threads to give up control
Models
Mutexes, condition variables, and read-write locks are used to communicate
between threads. These constructs may be used to synchronize the threads
themselves, or they can also be used to serialize access to common data objects
shared by the threads.
v The mutex, which is the simple type of lock, is exclusive. If a thread has a mutex
locked, the next thread that tries to acquire the same mutex is put in a wait state.
This is beneficial when you want to serialize access to a resource. This might
cause contention however if several threads are waiting for a thread to unlock a
mutex. Therefore, this form of locking is used more for short durations. If the
mutex is a shared mutex, it must be obtained in shared memory accessable
among the cooperating processes.
A thread in mutex wait will not be interrupted by a signal.
v A condition variable provides a mechanism by which a thread can suspend
execution when it finds some condition untrue, and wait until another thread
makes the condition true. For example, threads could use a condition variable to
insure that only one thread at a time had write access to a data set.
Threads in condition wait can be interrupted by signals.
v A read-write lock can allow many threads to have simultaneous read-only access
to data while allowing only one thread at a time to have write access. The
read-write lock must be allocated in memory that is writable. If the read-write lock
is a shared read-write lock, it must be obtained in shared memory accessable
among the cooperating processes.
Functions
Table 69 lists functions that allow for synchronization between threads.
Table 69. Functions that allow for synchronization between threads
Function Purpose
pthread_mutex_init() Initialize a Mutex
pthread_mutex_destroy() Destroy a Mutex
pthread_mutexattr_init() Initialize Default Attribute Object for a Mutex
pthread_mutexattr_destroy() Destroy Attribute Object for a Mutex
pthread_mutexattr_getkind_np() Get Kind Attribute for a Mutex
pthread_mutexattr_setkind_np() Set Kind Attribute for a Mutex
pthread_mutexattr_gettype() Get Type Attribute for a Mutex
pthread_mutexattr_settype() Set Type Attribute for a Mutex
pthread_mutexattr_getpshared() Get Process-shared Attribute for a Mutex
pthread_mutexattr_setpshared() Set Process-shared Attribute for a Mutex
pthread_mutex_lock() Acquire a Mutex Lock
pthread_mutex_unlock() Release a Mutex Lock
pthread_mutex_trylock() Allows lock to be tested
pthread_cond_init() Initialize a Condition Variable
Creating a mutex
To use the mutex lock you must first create a mutex attribute object with the
pthread_mutexattr_init() function. A mutex attribute object defines the modifiable
characteristics that a mutex may have. Refer to the description of
pthread_mutexattr_init() in z/OS XL C/C++ Run-Time Library Reference for a list
of these attributes and their defaults.
After the mutex attribute object has been created, you can use the following
functions to change the default attributes.
v pthread_mutexattr_getkind_np()
v pthread_mutexattr_setkind_np()
v pthread_mutexattr_gettype()
v pthread_mutexattr_settype()
v pthread_mutexattr_getpshared()
v pthread_mutexattr_setpshared()
The mutex attribute object is used only when creating the mutex. It can be used to
create other mutexes with the same attributes or modified to create mutexes with
different attributes. You can delete a mutex attribute object with the
pthread_mutexattr_destroy() function.
While using mutexes as the locking device, the following functions can be used:
v pthread_mutex_lock()
v pthread_mutex_unlock()
v pthread_mutex_trylock()
After the condition variable attribute object has been created, you may use the
following functions to change the default attributes:
v pthread_condattr_getkind_np()
v pthread_condattr_setkind_np()
v pthread_condattr_getpshared()
v pthread_condattr_setpshared()
The condition variable attribute object is used only when creating the condition
variable. It can be used to create other condition variables with the same attributes
or modified to create condition variables with different attributes. You can delete a
condition variable attribute object with the pthread_condattr_destroy() function.
After a condition variable attribute object has been created, the condition variable
itself can be created with the pthread_cond_init() function.
The read-write lock attribute object is used only when creating the read-write lock. It
can be used to create other read-write locks with the same attributes or modified to
create read-write locks with different attributes. You can delete a read-write attribute
object with the pthread_rwlockattr_destroy() function.
After the read-write attribute has been created, the read-write lock can be created
with the pthread_rwlock_init() function.
While using read-write locks as the locking device, the following functions can be
used:
v pthread_rwlock_rdlock()
v pthread_rwlock_tryrdlock()
v pthread_rwlock_wrlock()
v pthread_rwlock_trywrlock()
v pthread_rwlock_unlock()
Thread-specific data
While all threads can access the same memory, it is sometimes desirable to have
data that is (logically) local to a specific thread. The key/value mechanism provides
for global (process-wide) keys with value bindings that are unique to a thread.
You can also use the pthread_tag_np() function to set and query 65 bytes of thread
tag data associated with the caller's thread.
Model
The key/value mechanism associates a data key with each data item. When the
association is made, the key identifies the data item with a particular thread. This
data key is a transparent data object of type pthread_key_t. The contents of this
key are not exposed to the user.
The user gets a key by issuing the pthread_key_create() function. One of the
arguments on the pthread_key_create() function is a pointer to a local variable of
type pthread_key_t. This variable is then used with the pthread_setspecific()
function to establish a unique key value.
Functions
Table 70 lists functions that are used with thread-specific data.
Table 70. Functions used with thread-specific data
Function Purpose
pthread_key_create() Create a thread-specific data key
pthread_key_delete() Delete a thread-specific data key
pthread_getspecific() Retrieve the value associated with a thread-specific
key
pthread_setspecific() Associate a value with a thread-specific key
pthread_tag_np() Set and query the contents of the calling thread's tag
data
(void)pthread_key_create(&mykey,&mydestruct);
/*
Obtain some storage which this thread will manage (remember,
the main is also a thread), which we want freed by our
destructor upon thread termination. Associate the storage
pointer with the key using pthread_setspecific.
*/
thddataptr = (char *) malloc(100);
(void)pthread_setspecific(mykey,thddataptr);
Signals
Each thread has an associated signal mask. The signal mask contains a flag for
each signal defined by the system. The flag determines which signals are to be
blocked from being delivered to a particular thread.
Unlike the signal mask, there is one signal action per signal for all of the threads in
the process. Some signal functions work on the process level, having an impact on
multiple threads, while others work on the thread level, and only affect one
particular thread. For example, the function kill() operates at the process level,
whereas the functions pthread_kill() and sigwait() operate at the thread level.
The following are some other signal functions that operate on the process level and
can influence multiple threads:
v alarm()
v bsd_signal()
Generating a signal
A signal can be generated explicitly with the raise(), kill(), killpg(), or
pthread_kill() functions or implicitly with functions such as alarm() or by the
system when certain events occur. In all cases, the signal will be directed to a
specific thread running in a process.
The two primary functions for controlling signals are sigaction() and
sigprocmask(). sigaction() also includes bsd_signal(), signal(), and sigset().
sigaction()
sigaction() specifies the action when a signal is processed by the system. This
function is process-scoped instead of thread-specific. When a signal is generated
for a process, the state of each thread within that process determines which thread
is affected. The three types of signal actions are:
catcher Specifies the address of a function that will get control when the
signal is delivered
SIG_DFL Specifies that the system should perform default processing when
this signal type is generated
SIG_IGN Specifies that the system should ignore all signals of this type.
sigprocmask()
sigprocmask() specifies a way to control which set of signals interrupt a specific
thread. Because sigprocmask() is thread-scoped, it blocks the signal for only the
thread that issues the function.
Thread cancellation
When multiple threads are running in a process, thread cancellation permits one
thread to cancel another thread in that process. This is done with the
pthread_cancel() function, which causes the system to generate a cancel interrupt
and direct it to the thread specified on the pthread_cancel(). Each thread can
control how the system generates this cancel interrupt by altering the interrupt state
and type.
A thread may have the following interrupt states, in descending order of control:
disabled For short code sequences, the entire code sequence can be
disabled to prevent cancel interrupts. The pthread_setintr() and
pthread_setcancelstate() functions enable or disable cancel
interrupts in this manner.
controlled For larger code sequences where you want some control over the
interrupts but cannot be entirely disabled, set the interrupt type to
controlled/deferred and the interrupt state to enabled. The
pthread_setintrtype() and pthread_setcanceltype() functions
allow for this type of managed interrupt delivery by introducing the
concept of cancellation points.
Cancellation points consist of calls to a limited set of library
functions, documented below.
The user program can implicitly or explicitly solicit interrupts by
invoking one of the library functions in the set of cancellation points,
thus allowing the user to control the points within their application
where a cancel may occur.
asynchronous
For code sequences where you do not need any control over the
interrupt, set pthread_setintr()/pthread_setcancelstate() to
enable and pthread_setintrtype()/pthread_setcanceltype() to
asynchronous. This will allow cancel interrupts to occur at any point
within your program.
For example, if you have a critical code section (a sequence of code that needs to
complete), you would turn cancel off or prevent the sequence from being
interrupted. If the code is relatively long, consider running using the control
interrupt and as long as the critical code section doesn't contain any of the
functions that are considered cancellation points, it will not be unexpectedly
canceled.
For C++, destructors for automatic objects on the stack are run when a thread is
cancelled. The stack is unwound and the destructors are run in reverse order.
Cancellation Points
The library functions listed in Table 71 on page 363, and any of their callers, will
introduce cancellation points into a thread's execution.
Functions
Table 72 lists functions that are used to control the cancellability of a thread.
Table 72. Functions used to control cancellability
Function Purpose
pthread_cancel() Cancel a thread
pthread_setintr() Set thread cancellability state
pthread_setintrtype() Set thread cancellability type
pthread_testintr() Establish a cancellabilty point
pthread_setcancelstate() Set thread cancellability state
pthread_setcanceltype() Set thread cancellability type
pthread_testcancel() Establish a cancellability point
Cancelling a thread
Three possible scenarios may cancel a thread, one for each of the interrupt states
of the thread being canceled.
v One thread issues pthread_cancel() to another thread whose cancellability state
is enabled and controlled. In this case the thread being canceled continues to run
until it reaches an appropriate cancellation point. When the thread is eventually
cancelled, just prior to termination of the thread, any cleanup handlers which
have been pushed and not yet popped will be executed. Then if the thread has
any thread-specific data, the destructor functions associated with this data will be
executed.
v One thread issues pthread_cancel() to another thread whose interruption state
is enabled and asynchronous. In this case the thread being canceled is
terminated immediately, after any cleanup handlers and thread-specific data
destructor functions are executed, as in the first scenario.
v One thread issues pthread_cancel() to another thread whose interruption state
is disabled. In this case the cancel request is ignored and the thread being
canceled continues to run normally.
In the first two interrupt states, the caller of pthread_cancel() may get control back
before the thread is actually canceled.
A list or stack of cleanup handlers is maintained for each thread. When the thread
ends, all pushed but not yet popped cleanup routines are popped from the cleanup
stack and executed in last-in-first-out (LIFO) order. This occurs when the thread:
v Calls pthread_exit()
v Does a return from or reaches the end of the start routine (that gets controls as a
result of a pthread_create())
v Is canceled because of a pthread_cancel().
Functions
Table 73 lists functions that are used for thread clean up.
Table 73. Functions used for cleanup purposes
Function Purpose
pthread_cleanup_push() Establish a cleanup handler
pthread_cleanup_pop() Remove a cleanup handler
The stacksize attribute controls the size of the stack. In an SUSv3 application, calls
to pthread_attr_setstacksize() or pthread_attr_setstack() must provide a
stacksize of at least PTHREAD_STACK_MIN.If not provided, the initial increment
size is derived from the STACK64/THREADSTACK64 run-time options in AMODE
64, or STACK/THREADSTACK otherwise.
When used in conjunction with application-managed stack, the size of the storage
must be a multiple 4K on ILP32 (AMODE31) and 1M on L64 (AMODE64), and at
least PTHREAD_STACK_MIN in length.
Note: These restrictions specifically do not apply to UNIX file system. All opens
and closes by the C library that result in calls to an underlying access method for a
given MVS file must occur on the same thread. Therefore, the following specific
functions are prohibited from any thread except the owning thread (the one that
does the initial fopen()) of the file:
v fclose()
v freopen()
v rewind()
MVS files opened in update mode where repositioning functions are used after the
files have been extended are also restricted to the owning thread. This is because a
reposition might need to reopen the read DCB in order to be able to see the new
EOF marker. The run-time library does not enforce this restriction.
Multivolume data sets, files that are part of a concatenated ddname, and
hiperspace memory files are further restricted in multithreaded applications. All I/O
operations are restricted to the thread on which the file is opened.
When standard streams are directed to MVS files, they are governed by the
previous restrictions. Standard streams are directed to MVS files in one of two
ways:
v By default when a main() program is run from the TSO ready prompt or by a
JCL EXEC PGM= statement, that is, whenever it is not initiated by the exec()
function. This is regardless of whether you are running with POSIX(ON) or
POSIX(OFF). In these cases, the owning thread is the initial processing thread
(IPT), the thread on which main() is executed.
v By explicit action when the user redirects the streams by using command line
redirection, fopen(), or freopen(). The thread that is redirected (the IPT, if you
are using command line redirection) becomes the owning thread of the particular
standard stream. The usual MVS file thread affinity restrictions outlined above
apply until the end of program or until the stream is redirected to the UNIX file
system.
Any operation that violates these restrictions causes SIGIOERR to be raised and
errno to be set with the following associated message:
EDC5024I: An attempt was made to close a file that had been
opened on another thread.
Having more than one writer use separate file pointers to a single data set or
ddname is prohibited as always, regardless of whether the file pointers are used
from multiple threads or a single thread.
Multithreaded I/O
The getc(), getchar(), putc(), and putchar() functions have two versions, one
that is defined in the header file, stdio.h, which is a macro and the other which is
an actual library routine. The macros have better performance than their respective
function versions, but these macros are not thread safe, so in a multithreaded
application where _OPEN_THREADS feature test macro is defined, the macro version of
these functions are not exposed. Instead, the library functions are used. This is
done to ensure thread safety while multiple threads are executing.
Thread-scoped functions
Thread-scoped functions are functions that execute independently on each thread
without sharing intermediate state information across threads. For example,
strtok() preserves pointers to tokens independently on each thread, regardless of
the fact that multiple threads may be examining the same string in a strtok()
operation. Some examples of thread-scoped functions are:
v strtok()
v rand(), srand()
v mblen(), mbtowc()
v strerror()
v asctime(), ctime(), gmtime(), localtime()
v clock()
The following are examples of process-scoped functions, which means that a call to
these functions on one thread influences the results of calls to the same function on
another thread. For example, tmpnam() is required to return a unique name for
every invocation during the life of the process, regardless of which thread issues
the call.
v tmpnam()
v getenv()
v setenv()
v clearenv()
v putenv()
Thread scheduling
You can use the pthread_attr_setweight_np() and
pthread_attr_setsynctype_np() functions to establish priorities for threads. The
pthread_attr_setweight_np() threadweight variable can be set to the following:
__MEDIUM_WEIGHT
Each thread runs on a task. When the current thread exits, the task waits
for another thread to do a pthread_create(). The new thread runs on that
task.
__HEAVY_WEIGHT
The task is attached on pthread_create() and terminates when the thread
exits. When the thread exits, the associated task can no longer request
threads to process, and full MVS EOT resource manager cleanup occurs.
Note: The iconv_open() function tolerates converter names without a dash in the
name for all converter names containing dashes. For example, iconv_open()
tolerates the name IBM1047 for the IBM-1047 converter.
Reentrant programs are structured to allow multiple users to share a single copy of
an executable module or to use an executable module repeatedly without reloading.
C and C++ achieve reentrancy by splitting your program into two parts, which are
maintained in separate areas of memory until the program terminates:
v The first part, which consists of executable code and constant data, does not
change during program execution.
v The second part contains persistent data that can be altered. This part includes
the dynamic storage area (DSA) and a piece of storage known as the writable
static area.
For XPLINK, the writable static area is further logically subdivided into areas
called environments. Environments are optional, and each function can have its
own environment. When an XPLINK function is called, the caller must load
general purpose register 5 with the address of the environment of the called
function before control is given to the entry point of the called function.
If the program is installed in the Link Pack Area (LPA) or Extended Link Pack Area
(ELPA) of your operating system, only a single copy of the first (constant or
reentrant) part exists within a single address space. This occurs regardless of the
number of users that are running the program simultaneously. This reentrant part
may be shared across address spaces or across sessions. In this case, the
executable module is loaded only once. Separate concurrent invocations of the
program share or reenter the same copy of the write-protected executable module.
If the program is not installed in the LPA or ELPA area, each invocation receives a
private copy of the code part, but this copy may not be write-protected.
Each user running the program receives a private copy of the second (data or
non-reentrant) part. This part, the data area, is modifiable by each user.
If you use the XPLINK option, RENT is the default. If you override this default by
specifying NORENT, any parts of the program that are normally stored in the writable
static area go instead into a static area. If this static area is write-protected, you will
get a run-time failure because the function pointers for imported functions cannot be
modified to point to the function when the DLL containing the function is loaded and
the function address determined. For programs that are both XPLINK and NORENT,
all functions must be statically bound or explicitly loaded (dllload(), or fetch()).
You can force an external variable to be the part of the program that includes
executable code and constant data by using the #pragma variable(varname,
NORENT) directive. The program fragment in Figure 100 on page 371 illustrates how
this is accomplished.
int main(void) {
/* ... */
}
In this example, the source file is compiled with the RENT option. The external
variable rates are included in the executable code because #pragma
variable(rates, NORENT) is specified. The variable totals are included with the
writable static. Each user has a copy of the array totals, and the array rates are
shared among all users of the program.
The #pragma variable(varname, NORENT) does not apply to, and has no effect on,
program variables with the static storage class. Program variables with the static
storage class are always included in the writable static. An informational message
will appear if you do try to write to a non-reentrant variable when you specify the
CHECKOUT compiler option.
Note: You can also use the keyword const to ensure that a variable is not written.
See the const type qualifier in z/OS XL C/C++ Language Reference for more
information.
The ROCONST compiler option has the same effect as specifying the #pragma
variable (var_name, NORENT) for all constant variables (i.e. const qualified
variables). The option gives the compiler the choice of allocating const variables
outside of the Writable Static Area (WSA). For more information, see ROCONST |
NORCONST in z/OS XL C/C++ User's Guide.
You can force all strings in a given source file to be the part of the program that
includes executable code and constant data by using #pragma strings(readonly)
or the ROSTRING compiler option. Figure 101 on page 372 illustrates one way to
make the strings constant.
Figure 101 on page 372 shows a sample program (CCNGRE1) that makes strings
constant. The string "hello world\n" is included with the executable code because
#pragma strings(readonly) is specified. This can yield a performance and storage
benefit.
#pragma strings(readonly)
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return(0);
}
Ensure that you do not write to read-only strings. The following code tries to
overwrite the literal string "abcd" because 'chrs' is just a pointer:
char chrs[]= "abcd";
memcpy(chrs,"ABCD",4);
The ROSTRING compiler option has the same effect as #pragma strings(readonly) in
the program source. For more information, see ROSTRING | NOROSTRING in z/OS XL
C/C++ User's Guide.
As a programmer, you control where objects with global names and string literals
exist. You can use the #pragma variable(objname, NORENT) directive to specify that
the memory for an object with a global name is to be in the code area. You can use
the ROCONST compiler option to specify that all const variables go into the code area.
In Figure 102, the variable RATES exists in the executable code area because
#pragma variable(RATES,NORENT) has been specified. The variable totals exists in
writable static area. All users have their own copies of the array totals, but the
array RATES is shared among all users of the program.
/*------------------------------------------------------------------*/
/* RATES is constant and in code area */
#pragma variable(RATES, NORENT)
const float RATES[5] = { 1.0, 1.5, 2.25, 3.375, 5.0625 };
float totals[5];
/*------------------------------------------------------------------*/
By using the #pragma strings(writable) directive, you can ensure that the string
literals for that compilation unit will exist in the writable static area and be
modifiable. Figure 103, which shows sample program CCNGRE2, illustrates how to
make the string literals modifiable.
#pragma strings(writable)
#include <iostream.h>
int main(void)
{
char * s;
s = "wall\n"; // point to string literal
*(s+3) = k; // modify string literal
cout << s; // output "walk\n"
}
In this example, the string "wall\n" will exist in the writable static area because
#pragma strings(writable) is specified. This modifies the fourth character.
One way to modify data in the writable static area is to pass the address of the
writable static data item as a parameter to the assembler program. This may be
difficult in some cases. The following assembler macros makes this easier:
v EDCDXD
v EDCLA
v EDCDPLNK
Chapter 25. Reentrancy in z/OS XL C/C++ 373
These are in CEE.SCEEMAC(EDCDXD,EDCLA,EDCDPLNK). The restriction on the names of
writable static objects accessible in assembler code is that they are S-names. This
means that they may be at most 8 characters long and may contain only characters
allowed in external names by the assembler code.
The macro EDCDXD declares a writable static data item. EDCLA loads the address
of the writable static data item into a register. Using the EDCLA macro in assembler
code necessitates coding EDCDXD as well.
The EDCDPLNK macro defines reference writable static data with the z/OS binder.
This macro must appear before the first executable control section is initiated in the
assembler source module. If there is more than one assembler source program in
the input file, EDCDPLNK must precede every assembler source program in any input
file that defines or references writable static data. Figure 104 illustrates their use.
*********************************************************************
* this example shows how to reference objects in the writable *
* static area, from assembler code *
* part 1 of 2(other file is CCNGRE4) *
* *
* parameters: none *
* return: none *
* action: store contents of register 13 ( callers dynamic *
* storage area) in variable DSA which exists in *
* the writable static area *
* *
* Macros: EDCPRLG, EDCEPIL, EDCDXD, EDCLA in CEE.SCEEMAC *
*********************************************************************
XOBJHDR EDCDPLNK ;generate an XOBJ header
GETDSA CSECT
GETDSA AMODE ANY
GETDSA RMODE ANY
EDCPRLG ;prolog (save registers etc.)
EDCLA 1,DSA ;load register 1 with address of DSA
ST 13,0(,1) ;store contents of reg 13 in DSA
EDCEPIL ;epilog (restore registers etc.)
DSA EDCDXD 0F ;declaration of DSA in writable static
TBLDSA EDCDXD 20F ;definition of TBLDSA in writable static
END
In this example, the external variable TBLDSA is declared using the EDCDXD macro.
The size value of 0F (zero fullwords) indicates that DSA will be treated as an extern
declaration in C or C++. Because TBLDSA is an extern declaration and not a
definition, DSA must be defined in another C, C++, or assembler program. The
EDCLA macro loads the general purpose register 1 with the address of DSA, which
exists in the writable static area.
The external variable TBDLSA is declared using the EDCDXD macro. It is defined
because its size is 20F (20 fullwords or 80 bytes) and corresponds to an external
data definition in C or C++. When the program starts, TBDLSA is initialized to zero.
Because TBDLSA is an external data definition, there should not be another definition
of it in a C++, C, or assembler program.
When these macros are used, these pseudo-registers cannot be used within the
same assembler program.
Figure 105 shows sample program CCNGRE4, which illustrates how to call the
assembler program in Figure 104 on page 374.
#include <stdio.h>
#ifdef __cplusplus
extern "OS" {
#endif
void GETDSA(void); /* assembler routine modifies DSA */
#ifdef __cplusplus
}
#endif
int main(void) {
int i;
deeper(0);
for(i=0; i<sz; i++)
printf("depth %3d, DSA was at %p\n", i, TBLDSA[i]);
return 0;
}
Decimal data types are available only if the LANGLVL is EXTENDED by specifying
the LANGLVL(EXTENDED) compiler option. For more information, see LANGLVL in z/OS
XL C/C++ User's Guide.
You can use decimal data types to represent large numbers accurately, especially in
business and commercial applications for financial calculations. You can pass
decimal arguments in function calls and in define macros. You can also declare
decimal variables, data type definitions, arrays, structures, and unions that have
decimal members.
Note: The header file decimal.h defines DEC_DIG (the maximum number of digits n)
and DEC_PRECISION (the maximum precision p). Currently, there is a limit of a
maximum of 31 digits.
A fixed-point decimal constant has a numeric part and a suffix that specifies its data
type. The components of the numeric part may include a digit sequence
representing the integral part, followed by a decimal point (.), followed by a digit
sequence representing the fractional part. Either the integral part, the fractional part,
or both are present.
Each fixed-point decimal constant has the attributes number of digits (digits) and
number of decimal places (precision). Leading or trailing zeros are not discarded
when the digits and the precision are determined.
Syntax
decimal ( constant-expression )
, constant-expression
Arithmetic operators
Figure 106 shows how to use arithmetic operators, and then describes certain
arithmetic, assignment, unary, and cast operators in more detail. It summarizes how
to add, subtract, multiply and divide decimal variables.
int main(void)
{
printf("res_add =%D(*,*)\n",digitsof(res_add),
precisionof(res_add),res_add);
printf("res_sub =%D(*,*)\n",digitsof(res_sub),
precisionof(res_sub),res_sub);
printf("res_mul =%D(*,*)\n",digitsof(res_mul),
precisionof(res_mul),res_mul);
printf("res_div =%D(*,*)\n",digitsof(res_div),
precisionof(res_div), res_div);
return(0);
}
Refer to Intermediate results on page 382 for details on how to get the conversion
type during alignment of the decimal point.
Relational operators
Relational operators follow the arithmetic conversion rules defined in Using
operators on decimal data types on page 379.
Figure 107 shows you how to use a relational expression less than (<) for decimals.
In this example, decimal data types are compared with other arithmetic data types
(integer, float, double, long double). In addition, the implicit conversion of the
decimal data types is performed using the arithmetic conversion rules in Converting
decimal types on page 385. Leading zeros in the example are shown to indicate
the number of digits in the decimal data type. You do not need to enter leading
zeros in your decimal data type variable initialization. Refer to Intermediate results
on page 382 for details on how to get the conversion type during alignment of the
decimal point.
#include <decimal.h>
int main(void)
{
decimal(15,6) value = 000485860.085999d;
/*Perform relational operation between other data types and decimal*/
if (pdval < ival) printf("pdval is the smallest !\n");
if (pdval < fval) printf("pdval is the smallest !\n");
if (pdval < dval) printf("pdval is the smallest !\n");
if (pdval < lval) printf("pdval is the smallest !\n");
if (pdval < value) printf("pdval is the smallest !\n");
return(0);
}
Equality operators
Equality operators follow the arithmetic conversions defined in Using operators on
decimal data types on page 379. Where the operands have data types and values
suitable for the relational operators, the semantics for relational operators applies.
Note: Positive zero and negative zero compare equal. In the following example, the
expression always evaluates to TRUE:
Refer to Intermediate results for details on how to get the conversion type during
alignment of the decimal point.
Conditional operators
Conditional operators follow the arithmetic conversions defined in Using operators
on decimal data types on page 379. If both the second and third operands have an
arithmetic data type, the usual arithmetic conversions are performed to bring them
to a common data type. If both operands are decimal data types, the operands are
converted to the conversion type and the result has that data type.
Refer to Intermediate results for details on how to get the conversion type during
alignment of the decimal point.
Intermediate results
Use one of the following tables to calculate the size of the result. The tables
summarize the intermediate expression results with the four basic arithmetic
operators and conditional operators when applied to the decimal data types. Most of
the time, you can use Table 76 to calculate the size of the result. It assumes no
overflow. If overflow occurs, use Table 77 to determine the resulting data type.
You can use Table 77 to calculate the size of the result, whether there is an
overflow or not.
Table 77. Intermediate results (in the general form)
Expression (n, p)
x*y n = min(n + n, DEC_DIG)
p = min(p + p, DEC_DIG - min((n - p)
+ (n - p), DEC_DIG))
x/y n = DEC_DIG
p = max(DEC_DIG - ((n - p) + p), 0)
x+y ir = min(max(n - p, n - p) + 1, DEC_DIG)
p = min(max(p, p), DEC_DIG - ir)
n = ir + p
xy same rule as addition
z?x:y ir = max(n - p, n - p)
p = min(max(p, p), DEC_DIG - ir)
n = ir + p
Assignment operators
Assignment operators follow the arithmetic conversion rules defined in Using
operators on decimal data types on page 379. When values are assigned, an
SIGFPE exception may be raised if the operands contain values that are not valid.
Unary operators
Use the following unary operators to determine the digits in a decimal data type:
sizeof Determines the total number of bytes occupied by the decimal data
type
digitsof Determines the number of digits (n)
precisionof Determines the number of decimal digits (p)
sizeof operator
When you use the sizeof operator with decimal(n,p), the result is an integer
constant. The sizeof operator returns the total number of bytes occupied by the
decimal data type.
Each decimal digit occupies a halfbyte. In addition, a halfbyte represents the sign.
The number of bytes used by decimal(n,p) is the smallest whole number greater
than or equal to (n + 1)/2, that is, sizeof(decimal(n,p)) = ceil((n + 1)/2). The
sizeof result is calculated using this method because the z/OS XL C compiler uses
packed decimal to implement decimal data types.
Figure 108 shows an example of getting the total number of bytes occupied by the
decimal data type.
int y;
decimal (5, 2) x;
y = sizeof x; /* This would be calculated to be 3 bytes*/
/* (5+1)/2 = 3. */
Figure 108. Getting the total number of bytes occupied by the decimal data type
digitsof operator
When you use the digitsof operator with a decimal type, the result is an integer
constant. The digitsof operator returns the number of significant digits (n) in a
decimal type.
Figure 109 on page 384 shows an example of getting the total number of bytes
occupied by the decimal data type. This example gives you the number of digits (n)
in a decimal type.
Figure 109. Getting the total number of digits in the decimal data type
precisionof operator
When you use the precisionof operator with a decimal type, the result is an integer
constant. The precisionof operator tells you the number of decimal digits (p) of the
decimal type.
Figure 110 shows an example of getting the number of decimal digits in the decimal
data type. This example gives you the number of decimal digits (p) of the decimal
data type.
decimal (5, 2) x;
int p;
p = precisionof x; /* the result is p=2 */
Figure 110. Getting the number of decimal digits in the decimal data type
cast operator
You can use the cast operator convert the following types explicitly:
v Decimal types to decimal types
v Decimal types to and from floating-point types
v Decimal types to and from integer types
Notes:
1. When you are explicitly casting to a decimal type, the discarding of the leading
nonzero digits does not cause an exception at run-time. For more information
about suppressing compiler messages and run-time exceptions, refer to
Converting decimal types on page 385.
2. An implicit conversion to a decimal type with an even number of digits may not
clear the pad digit, but an explicit cast will clear the pad digit.
If the value of the decimal type to be converted is outside the range of values that
can be represented, the value of the decimal type is truncated. Truncation may
occur on either the integral part or the fractional part or both.
Figure 111 on page 386 shows an example of fractional part that cannot be
represented. Conversion of one decimal object to another decimal object with
smaller precision involves truncation on the right of the decimal point.
void func(void);
void dec_func(decimal( 7, 1 ));
decimal( 7, 4 ) x = 123.4567D;
decimal( 7, 1 ) y;
decimal( 7, 1 ) z = 123.4567D; /* z = 000123.4D <-- No message, */
/* No exception */
void func(void) {
decimal( 7, 1 ) a = 123.4567D; /* a = 000123.4D <-- No message, */
/* No exception */
y = x; /* y = 000123.4D <-- No message, No exception */
y = 123.4567D; /* y = 000123.4D <-- No message, No exception */
dec_func(x); /* <-- No message, No exception */
}
void func(void);
void dec_func(decimal( 5, 2 ));
decimal( 8, 2 ) w = 000456.78D;
decimal( 8, 2 ) x = 123456.78D;
decimal( 5, 2 ) y;
decimal( 5, 2 ) z = 123456.78D; /* <-- Compile-time error */
decimal( 5, 2 ) z1 = (decimal( 5, 2 )) 123456.78D;
/* z1 = 456.78D <-- No message, */
/* No exception */
void func(void) {
decimal( 5, 2 ) a = 123456.78D; /* <-- Checkout warning */
/* and exception */
decimal( 5, 2 ) a1 = (decimal( 5, 2 )) 123456.78D;
/* a1 = 456.78D <-- No message, */
/* No exception */
y = w; /* y = 456.78D <-- Checkout warning, No exception */
y = x; /* <-- Checkout warning and exception */
y = 123456.78D; /* <-- Checkout warning and exception */
dec_func(x); /* <-- Checkout warning and exception */
y = (decimal( 5, 2 )) w;
/* y = 456.78D <-- No message, No exception */
y = (decimal( 5, 2 )) x;
/* y = 456.78D <-- No message, No exception */
y = (decimal( 5, 2 )) 123456.78D;
/* y = 456.78D <-- No message, No exception */
dec_func((decimal( 5, 2 )) x);
/* <-- No message, No exception */
}
When a value of integer type is explicitly converted to decimal type, the conversion
proceeds as though these two steps are followed:
1. The integer type is converted to type decimal(10,0). A run-time exception can
never occur in this step.
2. Type decimal(10,0) is then converted to decimal(n,p). All rules for decimal
type to decimal type conversion apply in this step.
An unsigned integer type is converted to a positive decimal value.
If the value of the integral part cannot be represented by the decimal type, the
behavior is undefined.
#include <decimal.h>
float a = 12345678901234567890.1234567890d;
double b = 12345678901234567890.1234567890d;
long double c = 12345678901234567890.1234567890d;
When a conversion from a floating-point type is made with static or external variable
initialization, a compile-time error message is issued.
The result of the conversion may not be exact because the internal representation
of System/370 floating-point instructions is hexadecimal based if FLOAT(HEX) mode
is used. The mapping between the two representations is not one-to-one, even
when the value of a float type is within the range of the decimal type. Figure 116 is
an example of conversion from floating-point type.
#include <decimal.h>
A function may change the values of its parameters, but these changes cannot
affect the values of the arguments. However, it is possible to pass a pointer to a
decimal object, and the function may change the value of the decimal object to
which it points.
Use the scanf() family of functions to read the value of a decimal type:
v fscanf()
v scanf()
v sscanf()
For more information about these functions and their keywords, see the z/OS XL
C/C++ Run-Time Library Reference.
status = decchk ( x );
The function return status is the OR of all errors that were detected.
See the z/OS XL C/C++ Run-Time Library Reference for more information on the
decchk() library function.
See the z/OS XL C/C++ Run-Time Library Reference for more information on the
decabs() library function.
Programming examples
Programming examples CCNGDC3 and CCNGDC4 are shipped with the compiler.
#include <decimal.h>
/* Array of decimal(31,30) */
decimal(31,30) pd08[2];
int main(void)
{
pd01 = -789.45d; /* simple assignment */
pd06.m = digitsof(pd06.pd03) + precisionof(pd02); /* 23 + 4 */
pd06.pd03 = sizeof(pd01);
pd06.pd04[0] = pd02 + pd01; /* decimal addition */
*(pd06.pd04 + 1) = (decimal(10,2)) product(pd07->pd04[0], pd07->m);
pd07->pd04[2] = product(pd07->pd04[0], pd07->pd04[1]);
pd07->pd05 = &pd01; /* taking the address of a */
/* decimal variable */
/* These two statements are different */
pd08[0] = 1 / 3d;
pd08[1] = 1d / 3d;
return(0);
}
Figure 118 shows the output produced by Figure 117 on page 391.
pd01 = -789.45
pd02 = 1234.56000
pd06.m = 27, pd07->m = 27
pd06.pd03 = 6.0000000000, pd07->pd03 = 6.0000000000
pd06.pd04[0] = 445.11, pd07->pd04[0] = 445.11
pd06.pd04[1] = 12017.97, pd07->pd04[1] = 12017.97
pd06.pd04[2] = 5348886.87, pd07->pd04[2] = 5348886.87
*(pd06.pd05) = -789.45, *(pd07->pd05) = -789.45
pd08[0] = 0.333333333333333333333000000000
pd08[1] = 0.333333333333333333333333333333
Figure 119 on page 393 shows another sample program (CCNGDC4) that also uses
decimal type.
#include <decimal.h>
int main(void)
{
/* The results are different in the next two statements */
pd01 = pd01 + 1d;
pd02 = pd02 + 1d;
return(0);
}
Figure 120 shows the output produced by Figure 119. See Intermediate results on
page 382 to understand the output from this example and to see why decimal
variables with size 31 should be used with caution in arithmetic operations.
pd01 = 1235.5670
pd02 = 1235.5678
Note: The following unhandled divide message does not distinguish between a
decimal-divide condition and a fixed divide-by-zero condition:
CEE3211S The system detected a Decimal-divide exception.
You must ensure that valid packed decimal data is present when attempting to use
printf() or scanf() with run-time library decimal routines. No additional validation
is performed on decimal to ensure format correctness. Use the decchk() routine to
validate decimal data operands in such circumstances.
Additional considerations
v When the operands of a decimal operation contain nonvalid digits, the result is
undefined, and a run-time exception can occur. To validate a decimal number,
call the decchk() built-in function in your code.
v Code should be written in a manner that does not depend on the ability of the
run-time library to recover from a decimal overflow exception.
v In a multiprocessor configuration, decimal operations cannot be used safely to
update a shared storage location when the possibility exists that another
processor may also be updating that location. This possibility arises because the
bytes of a decimal operand are not necessarily accessed concurrently.
v If a decimal exception occurs in user code or library routines, the expected
results of the instruction causing the exception or the library routine where the
exception occurred are undefined. The results produced by the library routine's
execution are also undefined.
v If a SIGFPE handler is coded to handle decimal exceptions, it should reenable
itself before resuming normal execution or recovery from the error. This
reestablishes the exception environment and is consistent with good
programming practice.
Error messages
If an overflow occurs at run time, the exception handler issues the following
run-time error messages:
Unhandled exception. This result may be produced in a C-only environment only for
decimal overflow conditions. Fixed-point overflow exception is not allowed in the
Program Mask.
Note: The Program Mask in the Program Status Word (PSW) is enabled for
decimal overflow exceptions.
IBM301I ONCODE=0320 ZERODIVIDE CONDITION RAISED
The error messages for FIXEDOVERFLOW and ZERODIVIDE mean that either the
fixed-point overflow condition or the decimal overflow condition has caused the
condition reported.
Under CICS, decimal overflow condition exceptions are supported in CICS with C
and the following run-time message is produced:
EDCK017 ABEND=0320 Fixed or Decimal Overflow
Starting with z/OS V1R9 (including the Language Environment and C/C++
components), support was added for IEEE decimal floating-point, as defined by the
ANSI/IEEE Standard P754/D0.15.3, IEEE Standard for Floating-Point Arithmetic.
Floating-point numbers
The format of floating-point numbers can be either base 16 S/390 hexadecimal
format, base 2 IEEE-754 binary format, or base 10 IEEE-754 decimal format. The
formats are based on three operand lengths for hexadecimal and binary: short (32
bits), long (64 bits), and extended (128 bits). The formats are also based on three
operand lengths for decimal: _Decimal32 (32 bits), _Decimal64 (64 bits), and
_Decimal128 (128 bits).
A floating-point operand may be numeric or, for binary and decimal floating-point
only, positive or negative infinity, or nonnumeric (Not a Number, or NaN). A
floating-point number, has three components: a sign bit, a signed binary exponent,
and a significand. The significand consists of an implicit unit digit to the left of an
implied radix point, and an explicit fraction field to the right. The significand digits
are based on the radix, 2 (for binary floating-point), 10 (for decimal floating-point),
or 16 (for hexadecimal floating-point). The magnitude (an unsigned value) of the
number is the product of the significand and the radix raised to the power of the
exponent. The number is positive or negative depending on whether the sign bit is
zero or one, respectively. A nonnumeric binary or decimal floating-point operand
also has a sign bit, signed exponent, and fraction field.
Hexadecimal floating-point operands have formats that provide for exponents that
specify powers of the radix 16 and significands that are hexadecimal numbers. The
exponent range is the same for the short, long, and extended formats. The results
of most operations on hexadecimal floating-point data are truncated to fit into the
target format, but there are instructions available to round the result when
converting to a narrower format. For hexadecimal floating-point operands, the
implicit unit digit of the significand is always zero. Because the value if the
significand and fraction are the same, hexadecimal floating-point operations are
described in terms of the fraction, and the term significand is not used.
Binary floating-point operands have formats which provide for exponents that
specify powers of the radix 2 and significands that are binary numbers. The
exponent range differs for different formats, the range being greater for the longer
formats. In the long and extended formats, the exponent range is significantly
greater for binary floating-point data than for hexadecimal floating-point data. The
Decimal floating-point operands have formats that provide for exponents that
specify powers of the radix 10 and significands that are decimal numbers. The
exponent range differs for different formats, the range being greater for the longer
formats. The results of operations performed on decimal floating-point data are
rounded automatically to fit into the target format; the manner of rounding is
determined by a program-settable rounding mode.
When you use IEEE binary floating-point, make sure that you are in the same
rounding mode at compile time (specified by the ROUND(mode) option), as at run
time. Entire compilation units will be compiled with the same rounding mode
throughout the compilation. If you switch run-time rounding modes inside a function,
your results may vary depending upon the optimization level used and other
characteristics of your code; switch rounding mode inside functions with caution.
If you have existing data in hexadecimal floating-point (the original base 16 S/390
hexadecimal floating-point format), and have no need to communicate these data to
platforms that do not support this format, there is no reason for you to change to
IEEE binary floating-point format.
IEEE binary and decimal floating-point are fully supported in a CICS environment
only if CICS TS Version 4 or later is in use.
For information on the C/C++ functions that support floating-point, see the functions
listed in Table 79. For more information, see z/OS XL C/C++ Run-Time Library
Reference.
Table 79. C/C++ functions that support floating-point
absf() absl() acos() acosd32()
acosd64() acosd128() acosf() acosh()
acoshd32() acoshd64() acoshd128() acoshf()
acoshl() acosl() asin() asind32()
asind64() asind128() asinf() asinh()
asinhd32() asinhd64() asinhd128() asinhf()
asinhl() asinl() atan() atand32()
atand64() atand128() atanf() atanh()
atanhd32() atanhd64() atanhd128() atanhf()
atanhl() atanl() __atanpid32() __atanpid64()
__atanpid128() atan2() atan2d32() atan2d64()
atan2d128() atan2f() atan2l() cabs()
cabsf() cabsl() cacos() cacosf()
cacosh() cacoshf() cacoshl() cacosl()
carg() cargf() cargl() casin()
casinf() casinh() casinhf() casinhl()
casinl() catan() catanf() catanh()
catanhf() catanhl() catanl() cbrt()
cbrtd32() cbrtd64() cbrtd128() cbrtf()
In 31-bit applications, there are two basic ways to handle program checks and
ABENDs:
v POSIX or ANSI signals (SIGABND, SIGFPE, SIGILL, SIGSEGV)
v User condition handlers registered using CEEHDLR interface or the USRHDLR
run-time option.
In AMODE 64 applications, user condition handlers are not available. The basic
ways to handle program checks and ABENDs in AMODE 64 applications are:
v POSIX or ANSI signals (SIGABND, SIGFPE, SIGILL, SIGSEGV)
v Exception handlers registered using the __set_exception_handler() C run-time
library function. See AMODE 64 exception handlers on page 408 for more
information.
C++ exception handling is supported in all z/OS environments that are supported by
C++ (including CICS and IMS); you must run your application with the TRAP(ON)
run-time option. To turn off C++ exception handling, use the compiler option NOEXH.
For more information on this compiler option, see z/OS XL C/C++ User's Guide.
Note: If C++ exception handling is turned off you will get code which runs faster
but is not ANSI conformant.
If an object is thrown, and no catch clauses exist that will handle the thrown object,
the program will call terminate(). By default, terminate() calls abort(), and the
traceback produced will show that this has occurred. The traceback will not show
the point from which the object was originally thrown. Instead, it will show that the
object was thrown from the last encountered catch clause.
In sample routine CCNGCH1 (Figure 121 on page 405), sub1() throws object a.
Because sub1() does not have any catch clauses to handle a, C++ attempts to find
a suitable catch clause in the calling sub function, and then in the main function.
Because no catch clauses can be found to handle object a, the traceback will show
that object a was thrown from main().
#include <iostream.h>
#include <stdlib.h>
class A {
int i;
public:
A(int j) { i = j; cout << "A ctor: i= " << i << \n; }
A() { cout << "A dtor: i= " << i << \n; }
};
class B {
char c;
public:
B(char d) { c = d; cout << "B ctor: c= " << c << \n; }
B() { cout << "B dtor: c= " << c << \n; }
};
void sub(void);
void sub1(void);
main() {
try {
sub();
}
//traceback will show that the thrown object was from here because
//no catch clauses match the thrown object and the last rethrow
//occurred here.
catch(int i) { cout << "caught an integer" << \n; }
catch(char c) { cout << "caught a character" << \n; }
exit(55);
}
void sub() {
try {
sub1();
}
//neither catch clause will catch object a, so again a will be
//rethrown
catch(double d) { cout << "caught a double" << \n; }
catch(float f) { cout << "caught a float" << \n; }
return;
}
void sub1() {
A a(3001);
try {
throw(a);
}
//neither catch clause will catch object a, so a will be rethrown
catch(B b) { cout << "caught a B object" << \n; }
catch(short s) { cout << "caught a short" << \n; }
return;
}
If an object is thrown and a catch clause catches but then rethrows that object, or
throws another object, and no catch clauses exist for the rethrown or subsequently
thrown object, the traceback starts at the point from which the rethrow or
subsequent throw occurred. The first object thrown is considered to have been
caught and handled.
#include <iostream.h>
#include <stdlib.h>
int testeh(void);
class A {
int i;
public:
A(int j) { i = j; cout << "A ctor: i= " << i << \n; }
A() { cout << "A dtor: i= " << i << \n; }
};
class B {
char c;
public:
B(char d) { c = d; cout << "B ctor: c= " << c << \n; }
B() { cout << "B dtor: c= " << c << \n; }
};
A staticA(333);
B staticB(z);
void sub();
main() {
sub();
return(55);
}
void sub()
{
A c(3001);
try {
cout << "calling testeh" << \n;
testeh(); // int will be rethrown from testeh()
}
// no catch clauses for the rethrown int
catch(char c) { cout << "caught char" << \n; }
catch(short s) { cout << "caught short s = " << s << \n; }
cout << "this line should not be printed" << \n;
return;
}
testeh()
{
A a(2001),a1(1001);
B b(k);
short k=12;
int j=0,l=0;
try {
cout << "testeh running" << \n;
throw (6); // first throw: an int
}
catch(char c) { cout << "testeh caught char" << \n;}
catch(int j) { cout << "testeh caught int j = " << j << \n;
try { // int should be caught here
cout << "testeh again rethrowing" << \n;
throw; // rethrow the int
}
catch(char d) { cout << "char d caught" << \n; }
}
cout << "this line should not be printed" << \n;
return(0);
}
Exception handlers are are also stack-frame based, much like 31-bit user condition
handlers. If function a() registers an exception handler, future program checks and
ABENDs will drive that handler, until the handler is de-registered. This includes
program checks occurring in a() (after the registration), and in any called functions.
Function a() can deregister the handler using __reset_exception_handler(). After
this is done, program checks and ABENDs once again cause signals to be raised. If
function a() returns without calling __reset_exception_handler() to deregister its
handler, the handler will be automatically removed when a() returns.
If function a() registers handler ah(), and calls function b(), program checks and
ABENDs in b() will also go to ah(). However, b() can register its own handler, bh(),
in which case any program checks and ABENDs in b() or any functions it calls will
go to bh(). Exception handlers can be nested in this way as deep as required. If
they are not explicitly deregistered by calling __reset_exception_handler(), they are
automatically removed when the registering function returns. They are also
removed, whenever a longjump-type function (longjmp(), _longjmp(), siglongjmp(),
setcontext(), or C++ throw) causes control to jump back past the function that
registered the handler. (Example: a() registers handler ah(), and calls b(), which
registers handler bh(), and calls c(). Function c() longjumps back into a(). In this
case, bh() will be removed, but ah() will remain.)
Note: Whenever a program check or ABEND occurs, no more than one exception
handler will ever be driven, even when several nested handlers have been
registered. The active handler is the one that was most recently registered, and not
de-registered/removed. It will usually be the handler registered by the most
deeply-nested routine at the time of the program check or ABEND.
During C++ throw processing, as the Language Environment stack is unwound and
destructors for automatic C++ object are invoked, handlers registered by
When atexit() routines or C++ static destructors are run, any active exception
handlers at the time of the exit() or pthread_exit() have already been removed. If
these routines need recovery, thay can register their own exception handlers.
Handling exceptions
When the active exception handler is called after a program check or ABEND, it
receives a pointer to the CIB (Condition Information Block) for the error. It can
examine the CIB and associated MCH (Machine Check Handler record) to
determine what the error is. The handler can fix up whatever is required or take
dumps, etc. When it is finished, the only valid things it can do are:
v Long jump back to some earlier pre-defined recovery point (any of the several
longjump-type functions may be used -- longjmp(), _longjmp(), siglongjmp(),
setcontext(), or C++ throw.)
v Issue exit() or _exit()
v Issue pthread_exit()
v Issue __cabend(), abort(), etc
What it cannot do is return. If it returns, the system will automatically do
pthread_exit(-1) if POSIX(ON) is in effect, or exit(-1) if not.
When the active exception handler is given control, the handler is suspended, along
with all other handlers already registered. This means that any future program
checks/ABENDs will cause the usual signal processing to occur. The active handler
is re-enabled once it longjumps back. If it exits or returns, it is not re-activated, and
termination starts with no active exception handler. If an exception handler needs
exception handling recovery for its own program checks or ABENDs, it must register
its own exception handler. As usual, this new handler will become active, and will
get control for any program checks/ABENDs occurring in the outer exception
handler or any routines it calls.
Signal handlers
The basis for error handling in z/OS UNIX XL C/C++ application programs is the
generation, delivery, and handling of signals. Signals can be generated and
delivered as a result of system events or application programming. You can code
your application program to generate and send signals and to handle and respond
to signals delivered to it.
In general, for C++ programs you are encouraged to use try, throw, and catch to
perform exception handling. However, you can also use the z/OS XL C signal()
and raise() functions.
You can use the signal() function to perform one of the following actions:
v Ignore the condition. For example, use the SIG_IGN condition to specify
signal(SIGFPE,SIG_IGN).
v Reset the Global Error Table for default handling. For example, use the SIG_DFL
condition to specify signal(SIGSEGV,SIG_DFL).
v Register a function to handle the specific condition. For example, pass a pointer
to a function for the specific condition with signal(SIGILL,cfunc1). The function
registered for signal() must be declared with C linkage.
Note: TRAP(OFF) only blocks the handling of hardware (program checks) and
operating system (abend) conditions. It does not block software conditions such
those that are associated with a raise or CEESGL (31-bit mode). Any conditions
that are blocked because of TRAP(OFF) are not presented to any handlers
Combining C++ condition handling (using try, throw, and catch), with z/OS
Language Environment condition handling may result in undefined behavior.
For compatibility, z/OS XL C/C++ supports the three standards listed above, and
additional functions provided by XPG4.
Under z/OS XL C/C++, the primary function for establishing signal action is the
sigaction() function. However, there are a number of other functions that you can
use to effect signal processing. All signal types are accessible regardless of the
function used to establish the signal action.
Table 81 includes functions that will establish a signal handler for a signal action.
Table 81. Functions that establish a signal handler
BSD Function Purpose
bsd_signal() BSD version of signal()
sigaction() Examine and/or change a signal action
sigignore() Set disposition to ignore a signal
sigset() Change a signal action and/or a thread's signal mask
signal() Specify signal handling
Before you attempt to code your z/OS UNIX C/C++ application program to deliver
and handle signals, you should identify all the processes that might cause signal
conditions to be received by your application program's processes. You also need to
know which signal condition codes are valid for your z/OS UNIX C/C++ application
program and where the signal.h header file will be located and available to your
application program. Your system programmer or the application program's designer
should provide this information.
Note: Signal condition codes are defined in the signal.h include file.
You can code your application program to use the sigaction() function in different
ways. Two simplistic examples of using signals within z/OS UNIX C/C++ application
programs follow:
1. A process is forked but the process is aborted if the signal handler receives an
incorrect value.
2. A request is received from a client process to provide information from a
database. The server process is a single point of access to the database.
For descriptions of the supported z/OS XL C/C++ signal handling functions, see
z/OS XL C/C++ Run-Time Library Reference.
Note: If your z/OS UNIX C/C++ application program calls a program written in a
high-level language other than z/OS UNIX C/C++, you need to disable signal
handling to block all signals from the z/OS UNIX C/C++ application program. If the
called program encounters a program interrupt check situation, the results are
unpredictable.
Interrupting a program
Program interrupts or errors detected by the hardware and identified to the program
by operating system mechanisms are known as hardware signals. For example, the
hardware can detect a divide by zero and this result can be raised to the program.
Raising a signal
Signals that are explicitly raised by the user, by using the raise() function or using
z/OS UNIX with POSIX(ON) using the kill(), killpg(), or pthread_kill()
functions, are known as software signals.
The following signals are a list of signals supported with z/OS XL C/C++ under
POSIX(ON):
SIGABND System abend.
SIGABRT Abnormal termination (software only).
SIGALRM Asynchronous timeout signal generated as a result of an alarm().
SIGBUS Bus error.
SIGCHLD Child process terminated or stopped.
SIGCLD Child process terminated or stopped.
SIGCONT Continue execution, if stopped.
SIGDANGER Shutdown imminent.
The applicable hardware signals or exceptions are listed in Table 83 on page 417. It
also lists those hardware exceptions that are not supported (for example, fixed-point
overflow) and are masked.
The default run-time program mask is enabled for decimal overflow exceptions.
SIGABND considerations
When the SIGABND signal is registered with an address of a C handler using the
signal() function, control cannot resume at the instruction following the abend or
the invocation of raise() with SIGABND. If the C signal handler is returned, the
abend is percolated and the default behavior occurs. The longjmp() or exit()
function can be invoked from the handler to control the behavior.
If SIG_IGN is the specified action for SIGABND and an abend occurs (or SIGABND was
raised), the abend will not be ignored because a resume cannot occur. The abend
will percolate and the default action will occur.
Two macros are available in signal.h header file that provide information about an
abend. The __abendcode() macro returns the abend that occurred and __rsncode()
returns the corresponding reason code for the abend. These values are available in
a C signal handler that has been registered with the SIGABND signal. If you are
looking for the abend and reason codes, using these macros, they should only be
checked when in a signal handler. The values returned by the __abendcode() and
__rsncode() macros are undefined if the macros are used outside a registered
signal handler.
SIGIOERR considerations
When the SIGIOERR signal is raised, codes for the last operation will be set in the
__amrc structure to aid you in error diagnosis.
The default handling depends upon the signal that was raised. For more information
about the default handling of a given signal, see Table 83 on page 417, Table 84 on
page 417, and Table 85 on page 419.
Using z/OS UNIX: Table 85 on page 419 describes the default actions for signals
that may be delivered to C/C++ application programs running POSIX(ON).
001
Signal is raised. Is SIG_IGN set for the signal? Or is the signal blocked?
Yes No
002
Continue at Step 006.
003
004
Resume at the next instruction.
005
Condition is percolated for default behavior.
006
007
008
009
Continue at Step 017 on page 423.
010
Run C handler using ANSI rules and resume at the next instruction.
011
Run z/OS Language Environment user handler. The handler can resume,
percolate or promote the signal. See z/OS Language Environment
Programming Guide for more details.
012
013
Perform default processing.
014
015
Run C handler using POSIX rules and transfer control to the next instruction
following the asynchronous interrupt.
016
Run C handler using ANSI rules and transfer control to the next instruction following
asynchronous interrupt.
017
At stack frame 0?
Yes No
018
Default handling for the signal and percolate to next stack frame.
019
020
Perform default processing.
021
Run C handler using POSIX signal delivery rules and resume at next instruction.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
void handler(int);
#ifdef __cplusplus
}
#endif
int main(void) {
if (signal(SIGINT,handler) == SIG_ERR) {
perror("Could not set SIGINT");
abort();
}
/* add code here if desired */
raise(SIGINT);
/* add code here if desired */
return(0);
}
signal(SIGINT, handler);
printf("End processing?\n");
ch = getchar();
if (ch == y ch == Y)
exit(0);
Your z/OS UNIX XL C/C++ application program can take advantage of sockets or
XTI to communicate with a related application (server or client).
The z/OS UNIX socket API provides support for both UNIX domain sockets and
Internet domain sockets. UNIX domain sockets, or local sockets, allow interprocess
communication within MVS independent of TCP/IP. Local sockets behave like
traditional UNIX-domain sockets and allow processes to communicate with one
another on a single system. Internet sockets allow application programs to
communicate with others in the network using TCP/IP.
This chapter provides some background information about z/OS UNIX sockets and
about network communication in general. It is intended to provide an overview of
the programming concepts associated with using z/OS UNIX sockets and network
communication.
For information about using the socket API, see z/OS XL C/C++ Run-Time Library
Reference.
The internetworking technology called TCP/IP is named after its two main protocols:
Transmission Control Protocol (TCP) and Internet Protocol (IP). To understand
TCP/IP, you should be familiar with the following terms:
client A process that requests services on the network.
server A process that responds to a request for service from a client.
datagram The basic unit of information, consisting of one or more data
packets, which are passed across an Internet at the transport level.
packet The unit or block of a data transaction between a computer and its
network. A packet usually contains a network header, at least one
high-level protocol header, and data blocks. Generally, the format of
data blocks does not affect how packets are handled. Packets are
the exchange medium used at the Internetwork layer to send data
through the network.
These types of protocols are illustrated in Figure 125 on page 436 and in
Figure 126 on page 437.
What is a socket?
A socket can be thought of as an endpoint in a two-way communication channel.
Socket routines create the communication channel, and the channel is used to send
data between application programs either locally or over networks. Each socket
within the network has a unique name associated with it called a socket
descriptora fullword integer that designates a socket and allows application
programs to refer to it when needed.
Using an electrical analogy, you can think of the communication channel as the
electrical wire with its plug and think of the port, or socket, as the electrical socket
or outlet, as shown in Figure 124.
Application Application
A A
Application Application
B B
Application Application
C C
Application Application
D D
Application Application
E E
Application Application
F F
This figure shows many application programs running on a client and many
application programs on a server. When the client starts a socket call, a socket
connection is made between an application on the client and an application on the
server.
Sockets behave in some respects like UNIX files or devices, so they can be used
with such traditional operations as read() or write(). For example, after two
application programs create sockets and open a connection between them, one
program can use write() to send a stream of data, and the other can use read()
to receive it. Because each file or socket has a unique descriptor, the system knows
exactly where to send and to receive the data.
You can wait on a socket using the following asynchronous I/O functions:
v aio_read() - Asynchronous read from a socket
v aio_write() - Asynchronous write to a socket
v aio_cancel() - Cancel an asynchronous I/O request
v aio_suspend() - Wait for an asynchronous I/O request
v aio_error() - Retrieve error status for an asynchronous I/O operation
v aio_return() - Retrieve return status for an asynchronous I/O operation
You can suspend the invoking thread until a specified asynchronous I/O event,
timeout, or signal occurs. These functions are described in z/OS XL C/C++
Run-Time Library Reference.
Stream sockets
Stream sockets act like streams of information. There are no boundaries between
data, so communicating processes must agree on their own mechanism to
428 z/OS V1R13.0 XL C/C++ Programming Guide
distinguish information. Usually, the process sending information sends the length of
the data, followed by the data itself. The process receiving information reads the
length and then loops, accepting data until all of it has been transferred. Stream
sockets guarantee delivery of the data in the order it was sent and without
duplication. The stream socket interface defines a reliable connection-oriented
service. Data is sent without errors or duplication and is received in the same order
as it is sent. Flow control is built in, to avoid data overruns. No boundaries are
imposed on the data; the data is considered to be a stream of bytes.
Stream sockets are more common, because the burden of transferring the data
reliably is handled by the system rather than by the application.
Datagram sockets
The datagram socket interface defines a connectionless service. Datagrams are
sent as independent packets. The service provides no guarantees; data can be lost
or duplicated, and datagrams can arrive out of order. The size of a datagram is
limited to the size that can be sent in a single transaction. No disassembly and
reassembly of packets is performed.
If you are communicating with an existing application program, you must use the
same protocols as the existing application program. For example, if you
communicate with an application that uses TCP, you must use stream sockets. For
other application programs, you should consider the following factors:
v Reliability. Stream sockets provide the most reliable connection. Datagram
sockets are unreliable, because packets can be discarded, corrupted, or
duplicated during transmission. This may be acceptable if the application
program does not require reliability, or if the application program implements the
reliability on top of the sockets interface. The trade-off is the increased
performance available with datagram sockets.
v Performance. The overhead associated with reliability, flow control, packet
reassembly, and connection maintenance degrade the performance of stream
sockets in comparison with datagram sockets.
v Data transfer. Datagram sockets impose a limit on the amount of data
transferred in a single transaction. If you send less than 2048 bytes at a time,
use datagram sockets. As the amount of data in a single transaction increases,
use stream sockets.
Address families
Address families define different styles of addressing. All hosts in the same address
family use the same scheme for addressing socket endpoints. z/OS UNIX supports
three address familiesAF_INET, AF_INET6, and AF_UNIX. The AF_INET and
AF_INET6 address families define addressing in the IP domain. The AF_UNIX
address family defines addressing in the z/OS UNIX domain. In the z/OS UNIX
domain, address spaces can use the socket interface to communicate with other
address spaces on the same host.
Socket address
A socket address is defined by the sockaddr structure in the sys/socket.h include
file. The structure has three fields, as shown in the following example:
struct sockaddr {
unsigned char sa_len;
unsigned char sa_family;
char sa_data[14]; /* variable length data */
};
The sa_len field contains the length of the sa_data field. The sa_family field
contains the address family. It is AF_INET or AF_INET6 for the Internet domain and
AF_UNIX for the UNIX domain. The sa_data field is different for each address
family. Each address family defines its own structure, which can be overlaid on the
sockaddr structure. See Addressing within the AF_INET domain on page 431 and
Addressing within the AF_INET6 domain on page 431 for more information about
the Internet domain, and Addressing within the AF_UNIX domain on page 432 for
more information about the UNIX domain.
Internet addresses
Internet addresses represent a network interface. Every Internet address within an
administered AF_INET domain must be unique. On the other hand, it is not
necessary that every host have a unique Internet address; in fact, a host has as
many Internet addresses as it has network interfaces.
Ports
A port is used to distinguish between different application programs using the same
network interface. It is an additional qualifier used by the system software to get
data to the correct application program. Physically, a port is a 16-bit integer. Some
ports are reserved for particular application programs or protocols and are called
well-known ports.
Using network byte ordering for data exchanged between hosts allows hosts using
different architectures to exchange address information. See references in figures
Figure 128 on page 438, Figure 129 on page 439, and Figure 131 on page 440 for
examples of using the htons() call to put ports into network byte order. For more
information about network byte order, see z/OS XL C/C++ Run-Time Library
Reference.
Note: The socket interface does not handle application program data byte ordering
differences. Application program writers must handle byte order differences
themselves.
struct in_addr {
ip_addr_t s_addr;
struct sockaddr_in {
unsigned char sin_len;
unsigned char sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in6_addr {
union {
uint8_t _S6_u8[16];
uint32_t _S6_u32[4];
} _S6_un;
};
#define s6_addr _S6_un._S6_u8
struct sockaddr_in6 {
uint8_t sin6_len;
sa_family_t sin6_family;
in_port_t sin6_port;
uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
uint32_t sin6_scope_id;
};
struct sockaddr_un {
unsigned char sun_len;
unsigned char sun_family;
char sun_path[108]; /* pathname */
};
This structure is defined in the sockaddr_un structure found in sys/un.h include file.
The sun_len contains the length of the pathname in sun_path; sun_family field is
set to AF_UNIX; and sun_path contains the null-terminated pathname.
The conversation
The client and server exchange data using a number of functions. They can send
data using send(), sendto(), sendmsg(), write(), or writev(). They can receive
data using recv(), recvfrom(), recvmsg(), read(), or readv(). The following is an
example of the send() and recv() call:
The send() and recv() function calls specify the sockets on which to communicate,
the address in memory of the buffer that contains, or will contain, the data
(addr_of_data, addr_of_buffer), the size of this buffer (len_of_data, len_of_buffer),
and a flag that tells how the data is to be sent. Using the flag 0 tells TCP/IP to
transfer the data normally. The server uses the socket that is returned from the
accept() call.
These functions return the amount of data that was either sent or received.
Because stream sockets send and receive information in streams of data, it can
take more than one call to send() or recv() to transfer all the data. It is up to the
client and server to agree on some mechanism of signaling that all the data has
been transferred.
When the conversation is over, both the client and server call the close() function
to end the connection. The close() function also deallocates the socket, freeing its
space in the table of connections. To end a connection with a specific client, the
server closes the socket returned by accept(). If the server closes its original
socket, it can no longer accept new connections, but it can still converse with the
clients it is connected to. The following is an example of the close() call:
close(s);
The socket() function requires the address family (AF_INET), the type of socket
(SOCK_STREAM), and the particular networking protocol to use (when 0 is
specified, the system automatically uses the appropriate protocol for the specified
socket type). A new socket is allocated and returned.
bind()
At this point, an entry in the table of communications has been reserved for your
application program. However, the socket has no port or IP address associated with
it until you use the bind() function, which requires the following:
v The socket the server was just given
v The number of the port on which the server wishes to provide its service
v The IP address of the network connection on which the server is listening (to
understand what is meant by listening, see listen())
In C language, the server puts the port number and IP address into a sockaddr_in
structure, passing it and the socket to the bind() function. For example:
listen()
After the bind, the server has specified a particular IP address and port. Now it
must notify the system that it intends to listen for connections on this socket. In C,
the listen() function puts the socket into passive open mode and allocates a
backlog queue of pending connections. In passive open mode, the socket is open
for clients to contact. For example:
listen(s, backlog_number);
The server gives the socket on which it will be listening and the number of requests
that can be queued (known as the backlog_number). If a connection request arrives
before the server can process it, the request is queued until the server is ready.
accept()
Up to this point, the server has allocated a socket, bound the socket to an IP
address and port, and issued a passive open. The next step is for the server
actually to establish a connection with a client. The accept() call blocks the server
The server passes its socket to the accept() call. When the connection is
established, the accept() call returns a new socket representing the connection
with the client. When the server wishes to communicate with the client or end the
connection, it uses this new socket, client_sock. The original socket s is now ready
to accept connections with other clients. The original socket is still allocated, bound,
and opened passively. To accept another connection, the server calls accept()
again. By repeatedly calling accept(), the server can establish almost any number
of connections at once.
select()
The server is now ready to start handling requests on this port from any client with
the server's IP address and port number. Up to this point, it has been assumed that
the server will be handling only one socket. However, an application program is not
limited to one socket. Typically, a server listens for clients on a particular socket but
allocates a new socket for each client it handles. For maximum performance, a
server should operate only on those sockets that are ready for communication. The
select() call allows an application program to test for activity on a group of
sockets.
Note: The select() function can also be used with other descriptors, such as file
descriptors, pipes, or character special files.
To allow you to test any number of sockets with just a single call to select(), place
the sockets to test into a bit set, passing the bit set to the select() call. A bit set is
a string of bits where each possible member of the set is represented by a 0 or a 1.
If the member's bit is 0, the member is not in the set. If the member's bit is 1, the
member is in the set. Sockets are actually small integers. If socket 3 is a member
of a bit set, then the bit that represents it is set to 1 (on).
To be active, a socket is ready for reading data or for writing data, or an exceptional
condition may have occurred. Therefore, the server can specify three bit sets of
sockets in its call to the select() function: one bit set for sockets on which to
receive data; another for sockets on which to write data; and any sockets with
exception conditions. The select() call tests each socket in each bit set for activity
and returns only those sockets that are active.
A server that processes many clients at the same time can easily be written so that
it processes only those clients that are ready for activity.
To connect to the server, the client places the port number and the IP address of
the server into a sockaddr_in structure. If the client does not know the server's IP
address, but does know the server's host name, the gethostbyname() function or
the getaddrinfo() function is called to translate the host name into its IP address.
The client then calls connect(). The following is an example of the connect() call:
connect(s, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
When the connection is established, the client uses its socket to communicate with
the server.
See Figure 125 on page 436 for the general sequence of calls to be followed for
most socket routines using TCP, or stream sockets.
(Optional)
Bind socket s to a local address with the
Bind socket s to a local address with the
bind() call.
bind() call.
Connect socket s to a foreign host with the With the listen() call, alert the TCP/IP
connect() call. machine of your willingness to accept
connections.
Read and write data on socket s Read and write data on socket ns
using the send() and recv() calls, using the send() and recv() calls,
until all the data has been exchanged. until all the data has been exchanged.
Close socket s and end the TCP/IP session Close socket s with the close() call.
with the close() call.
Both connected and unconnected sockets send their data over the network without
verification. Consequently, after a packet has been accepted by the UDP interface,
the arrival and integrity of the packet cannot be guaranteed.
See Figure 126 on page 437 for the general sequence of calls to be followed for
most socket routines using UDP, or datagram, sockets.
Bind socket s to a local address with the Bind socket s to a local address with the
bind() call. bind() call.
(Optional) (Optional)
Connect socket s using the connect() Connect socket s using the connect()
call to associate s with the server address. call to associate s with the server address.
Send and receive data on socket s, Send and receive data on socket s,
using the sendto() and recvfrom() calls, using the sendto() and recvfrom() calls,
until all the data has been exchanged. until all the data has been exchanged.
Use the send() and recv() calls if connect() Use the send() and recv() calls if connect()
was called. was called.
Close socket s and end the session Close socket s and end the session
with the close() call. with the close() call.
#include
. <sys/socket.h>
.
.
int
. s;
.
.
s = socket(AF_INET, SOCK_STREAM, 0);
The code fragment in Figure 127 allocates a socket descriptor s in the Internet
address family. The domain parameter is a constant that specifies the domain
where the communication is taking place. A domain is the collection of
application programs using the same addressing convention. z/OS UNIX
supports three domains: AF_INET, AF_INET6, and AF_UNIX. The type
parameter is a constant that specifies the type of socket, which can be
SOCK_STREAM, or SOCK_DGRAM.
The protocol parameter is a constant that specifies the protocol to use. For
AF_INET, it can be set to IPPROTO_UDP for SOCK_DGRAM and
IPPROTO_TCP for SOCK_STREAM. Passing 0 chooses the default protocol. If
successful, the socket() call returns a positive integer socket descriptor. For
AF_UNIX, the protocol parameter must be 0. These values are defined in the
netinet/in.h include file.
2. After an application program has a socket descriptor, it can explicitly bind a
unique address to the socket, as in the example listed in Figure 128. For a
complete description, see z/OS XL C/C++ Run-Time Library Reference.
int
. bind(int s, struct sockaddr *name, int namelen);
.
.
int rc;
int s;
struct sockaddr_in myname;
This example binds socket descriptor s to the address 129.5.24.1 and port
1024 in the Internet domain. Servers must bind to an address and port to
become accessible to the network. The example in Figure 128 shows two
useful utility routines:
v inet_addr() takes an IPv4 Internet address in dotted-decimal form and
returns it in network byte order. Note that the inet_pton() function can take
either an IPv4 or IPv6 Internet address in its standard text presentation form
and return it in its numeric binary form. For a complete description, see
z/OS XL C/C++ Run-Time Library Reference.
int
. bind(int s, struct sockaddr_in name, int namelen);
.
.
int rc;
int s;
char *hostname = "myhost";
struct sockaddr_in myname;
struct hostent *hp;
hp = gethostbyname(hostname);
3. After binding to a socket, a server that uses stream sockets must indicate its
readiness to accept connections from clients. The server does this with the
listen() call, as illustrated in the example in Figure 130.
int
. listen(int s, int backlog);
.
.
int s;
int
. rc;
.
.
rc = listen(s, 5);
The listen() call tells the TCP/IP address space that the server is ready to
begin accepting connections, and that a maximum of five connection requests
can be queued for the server. Additional requests are ignored. For a complete
description, see z/OS XL C/C++ Run-Time Library Reference.
4. Clients using stream sockets begin a connection request by calling connect(),
as shown in Figure 131 on page 440.
The connect() call attempts to connect socket descriptor s to the server with
an address servername. This could be the server that was used in the previous
bind() example. The connect request is completed immediately and returns
control to the caller, regardless of the server accepting the connection. After a
successful return, the socket descriptor s is associated with the connection to
the server. For a complete description, see z/OS XL C/C++ Run-Time Library
Reference.
5. Servers using stream sockets accept a connection request with the accept()
call, as shown in the example listed in Figure 132.
int
. accept(int s, struct sockaddr *addr, int *addrlen);
.
.
int clientsocket;
int s;
struct sockaddr clientaddress;
int
. addrlen;
.
.
addrlen
. = sizeof(clientaddress);
.
.
clientsocket = accept(s, &clientaddress, &addrlen);
The sendto() and recvfrom() calls take additional parameters that allow the
caller to specify the recipient of the data or to be notified of the sender of the
data. For more information see z/OS XL C/C++ Run-Time Library Reference.
Usually, sendto() and recvfrom() are used for datagram sockets, and send()
and recv() are used for stream sockets.
fd_set readsocks;
fd_set writesocks;
fd_set exceptsocks;
struct timeval timeout;
int number_of_sockets;
int
. number_found;
.
.
/* number_of_sockets previously set to the socket number of largest
* integer value.
* Clear masks out.
*/
FD_ZERO(&readsocks);; FD_ZERO(&writesocks); FD_ZERO(&exceptsocks);
/* Set masks for socket s only */
FD_SET(s, &readsocks)
FD_SET(s, &writesocks)
FD_SET(s,
. &exceptsocks)
.
.
/* go into select wait for 5 minutes waiting for socket s to become
ready or the timer has popped*/
rc = select(number_of_sockets+1,
. &readsocks, &writesocks, &exceptsocks, &timeout);
.
.
/* Check rc for condition set upon exiting select */
number_found = select(number_of_sockets,
&readsocks, &writesocks, &exceptsocks, &timeout);
In this example, the application program uses bit sets to indicate that the
sockets are being tested for certain conditions and also indicates a timeout. If
the timeout parameter is NULL, the select() call blocks until a socket
becomes ready. If the timeout parameter is nonzero, select() waits up to this
amount of time for at least one socket to become ready on the indicated
conditions. This is useful for application programs servicing multiple
connections that cannot afford to block, waiting for data on one connection.
For a complete description, see z/OS XL C/C++ Run-Time Library Reference.
10. In addition to select(), application programs can use the ioctl() or fcntl()
calls to help perform asynchronous (nonblocking) socket operations. An
example of the use of the ioctl() call is listed in Figure 136 on page 443.
int
. close(int s);
.
.
int rc;
int s;
rc = close(s);
For a server that you want to be able to listen to all of the available stacks at the
same time, specify INADDR_ANY and it will be listening to all at once. Note that for an
IPv6 server, IN6ADDR_ANY can be specified allowing the server to listen for IPv4
and IPv6 connections from all stacks.
There are three ways that an INADDR_ANY or IN6ADDR_ANY program can associate
itself with a single stack:
v Call setibmopt(IBMTCP_IMAGE) - This sets a process so all future socket() calls
create sockets with only the one specified stack.
v The _BPXK_SETIBMOPT_TRANSPORT environment variable can be used in the PARM=
parameter of an MVS started proc to effectively issue a SETIBMOPT outside of the
program.
v Call ioctl(SIOCSETRTTD) - This associates an existing socket with the one
specified stack, removing the others.
You compile and bind your sockets application program in the same way as for any
other C language program. The process is shown conceptually in Figure 138 on
page 445. You must make sure that the z/OS UNIX socket application programs
have access to the files they need to compile and bind.
Application Object
object library
bind (SCEELKEX)
(or prelink and link)
Kernel
LFS
. . . file and socket
PFS PFS
descriptor assignments
HFS = Hierarchical File System LFS = Logical File System PFS = Physical File System
Figure 138. A conceptual overview of the compile, bind, and run steps
Note: In order to use AF_INET sockets, you must have release 3.1 or a later level
of TCP/IP installed on your system. In order to use AF_INET6 sockets, you must
have release z/OS V1R4 or later of TCP/IP installed on your system.
With the exception of described restrictions, you can code z/OS UNIX XL C/C++
application programs to take advantage of the documented APIs available as part of
the Communications Server IP.
z/OS UNIX application programs can use socket API calls from the TCP/IP product
to access UNIX file system files or MVS data sets, communicate with other systems
running TCP/IP, or establish communication with and request services from a
workstation system acting as an X Windows server.
Note: For UNIX file system file access to TCP/IP, the TCP/IP socket API calls must
be used instead of the POSIX file access functions to preserve the uniqueness of
file descriptors in the UNIX file system.
Before you attempt to code your application program to use TCP/IP APIs, you
should understand the X Windows protocol running on the workstations that will be
used as application clients. You will also need to know how to invoke X Windows to
create a connection to the server on the workstation or z/OS system.
Note: The data set prefix for each of the previous files must match the name used
at your installation. CEE is the default for z/OS Language Environment.
Note: The data set prefix for each of these files must match the name used at your
installation. CEE is the default for the z/OS XL C library.
You must compile your application program using all include files in order to access
the entire z/OS UNIX socket API. To compile a program written using a particular
API, you must include certain files specific to that API even though your program
may not require all of them.
See z/OS XL C/C++ Run-Time Library Reference, which lists the header files that
must be included for each type API. They may be different for Berkeley Sockets
and X/Open sockets.
The following list describes the files that each z/OS UNIX socket application
program must have access to in order to bind:
v CEE.SCEELKED contains stub routines in the link library that are used to resolve
external references to z/OS XL C and z/OS UNIX socket APIs.
v CEE.SCEELKEX contains LONGNAME stub routine object modules for a large
portion of the Language Environment function library, including the z/OS C and
z/OS UNIX socket APIs. When you IPA Link your application program, place the
SCEELKEX library ahead of the SCEELKED Load Module library in the search
order. This preserves long run-time function names in the object module and
listings generated by IPA Link. When you bind your application program, place
the SCEELKEX library ahead of the SCEELKED Load Module library in the
search order. This preserves long run-time function names in the executable
module and listings generated by the binder.
v CEE.SCEERUN contains the z/OS XL C and z/OS UNIX socket run-time
libraries.
Note: If you are planning on developing your application as a C++ application and
use sockets, you must use XOpen Sockets for your application. See section
Compiling under MVS batch for X/Open sockets on page 449 for more
information.
You must make changes to the cataloged procedure, which is supplied with z/OS
XL C/C++ Compiler. After you select the procedure you want to use from those
available in the XL C/C++ supplied data set, CBC.SCCNPRC, you modify it. For
example, if you choose EDCC then you modify it as follows:
1. Change the CPARM parameters to:
CPARM=DEF(MVS,_OE_SOCKETS,_POSIX1_SOURCE=1),RENT,LO,
The z/OS XL C/C++ Run-Time Library Reference identifies the POSIX z/OS XL C
functions, in the standards information at the beginning of each function description.
For a complete discussion of compiling and binding z/OS UNIX sockets with
TCP/IP, see z/OS Communications Server: IP Programmer's Guide and Reference.
For more information about compiling and binding, see z/OS XL C/C++ User's
Guide.
Note: Because you are now required to compile with the RENT and LONGNAME
options, you must bind your sockets application with the z/OS binder.
2. To run your program under TSO/E, type the following:
CALL USER.MYPROG.LOAD(PROGRAM1) POSIX(ON)/
To use the POSIX z/OS XL C functions, you must either specify the run-time
option POSIX(ON), or include the following statement in your C source program:
#pragma runopts(POSIX(ON))
Although all transport-layer protocols support these characteristics, they vary in their
level of support and their interpretation of format.
Transport endpoints
A transport endpoint specifies a communication path between a transport user
and a specific transport provider, which is identified by a local file descriptor (fd).
When a user opens a transport endpoint, a local file descriptor fd is returned which
identifies the endpoint. A transport provider is defined to be the transport protocol
that provides the services of the transport layer. All requests to the transport
provider must pass through a transport endpoint. The file descriptor fd is returned
by the function t_open() and is used as an argument to the subsequent functions to
identify the transport endpoint. A transport endpoint can support only one
established transport connection at a time.
Currently, the only valid value for the identifier parameter for the t_open() function
is /dev/tcp, indicating the TCP transport provider. Even though no device with this
pathname actually exists, the library uses this value to determine which transport
provider to use.
Message queues
XPG4 provides a set of C functions that allow processes to communicate through
one or more message queues in an operating system's kernel. A process can
create, read from, or write to a message queue. Each message is identified with a
type number, a length value, and data (if the length is greater than 0).
A message can be read from a queue based on its type rather than on its order of
arrival. Multiple processes can share the same queue. For example, a server
process can handle messages from a number of client processes and associate a
particular message type with a particular client process. Or the message type can
be used to assign a priority in which a message should be dequeued and handled.
Create the inbound queue to the server with ipc_SndTypePID and the outbound
queue from the server with ipc_RcvTypePID. This arrangement guarantees that the
server knows the process ID of the client, and that the client is the only process
that can receive the server's returned message. The server can also issue msgrcv()
with TYPE=0 to see if any messages belong to process IDs that have gone away.
Security checks on clients are not needed, since clients are unable to receive
messages intended for another process.
A semaphore can have a single value or a set of values; each value can be binary
(0 or 1) or a larger value, depending on the implementation. For each value in a
set, the kernel keeps track of the process ID that did the last operation on that
value, the number of processes waiting for the value to increase, and the number of
processes waiting for the value to become 0.
If you define a semaphore set without any special flags, semop() processing obtains
a kernel latch to serialize the semaphore set for each semop() or semctl() call. The
more semaphores you define in the semaphore set, the higher the probability that
you will experience contention on the semaphore latch. One alternative is to define
multiple semaphore sets with fewer semaphores in each set. To get the least
amount of latch contention, define a single semaphore in each semaphore set.
z/OS has added the __IPC_BINSEM option to semget(). The __IPC_BINSEM option
provides significant performance improvement on semop() processing. __IPC_BINSEM
can only be specified if you use the semaphore as a binary semaphore and do not
specify UNDO on any semop() calls. __IPC_BINSEM also allows semop() to use special
hardware instructions to further reduce contention. With __IPC_BINSEM, you can
define many semaphores in a semaphore set without impacting performance.
Shared memory
Shared memory provides an efficient way for multiple processes to share data (for
example, control information that all processes require access to). Commonly, the
processes use semaphores to take turns getting access to the shared memory. For
example, a server process can use a semaphore to lock a shared memory area,
then update the area with new control information, use a semaphore to unlock the
shared memory area, and then notify sharing processes. Each client process
sharing the information can then use a semaphore to lock the area, read it, and
then unlock it again for access by other sharing processes.
Processes can also use shared mutexes and shared read-write locks to
communicate. For more information on mutexes and read-write locks see
Synchronization primitives on page 355.
Memory mapping
In z/OS, a programmer can arrange to transparently map into a UNIX file system
file process storage.
The use of memory mapping can reduce the number of disk accesses required
when randomly accessing a file.
The related mmap(), mprotect(), msync(), and munmap() functions that provide
memory mapping are part of the X/OPEN CAE Specification.
Within an application, you can instantiate the same template multiple times with the
same arguments or with different arguments. If you use the same arguments, the
repeated instantiations are redundant. These redundant instantiations increase
compilation time, increase the size of the executable, and deliver no benefit.
TEMPINC example
This section contains example files and compilation code examples that show how
to use the TEMPINC compiler option. The following types of files are shown:
v Two source files: stackadd.cpp and stackops.cpp
v A template declaration file: stack.h
v The corresponding template definition file: stack.c
v A function prototype: stackops.h
Figure 139 on page 459 shows the first source file, stackadd.cpp.
main() {
Stack<int, 50> s; // create a stack of ints
int left=10, right=20;
int sum;
cout << "The sum of: " << left << " and: " << right << " is: " << sum << endl;
return(0);
}
Figure 141 on page 460 shows stack.h, which is the template declaration file.
//stack.c
template <class Item, int size>
void Stack<Item,size>::push(Item item) {
if (top >= size) throw size;
stack[top++] = item;
}
template <class Item, int size>
Item Stack<Item,size>::pop() {
if (top <= 0) throw size;
Item item = stack[--top];
return(item);
}
The stackops.h file (Figure 143) contains the prototype for the add function, which
is used in both stackadd.cpp and stackops.cpp.
Figure 144 on page 461 contains the JCL to compile the source files; this JCL does
the following:
1. Compiles both compilation units and creates the TEMPINC destination, which is
a sequential file with the following data set nameMYUSERID.TEMPINC
2. Compiles the template instantiation file in the TEMPINC destination.
Figure 145 shows the syntax of how to compile the program within the z/OS shell.
export _CXX_CXXSUFFIX=cpp
c++ stackadd.cpp stackops.cpp
As you develop your program, you may remove template function references or
reorganize your program so that the template instantiation files become obsolete.
You can periodicaly delete the TEMPINC destination and recompile your program.
Under MVS or z/OS UNIX System Services, you can easily assign a separate
tempinc PDS or directory for each application.
The instantiation information is stored in a template registry file. You must use the
same template registry file for the entire program. Two programs cannot share a
template registry file.
The default file name for the template registry file is templreg in the UNIX file
system and TEMPLREG in batch (a sequential file), but you can specify any other valid
file name to override this default. When cleaning your program build environment
before starting a fresh or scratch build, you must delete the registry file along with
the old object files.
Note: This does not limit the behavior for functions implicitly generated by the
compiler. Implicitly declared special members such as the default constructor,
copy constructor, destructor and copy assignment operator are inline and the
compiler may instantiate them. In particular, out-of-line copies may be
generated.
3. Degradation of the amount of inlining achieved on functions that are not "inline"
and are subject to explicit instantiation declarations may occur.
4. When a non-pure virtual member function is subject to an explicit instantiation
declaration, either directly or through its class, the virtual member function must
be subject to an explicit instantiation definition somewhere in the entire program
or an unresolved symbol error may result at link time.
5. When implicit instantiation of a class template specialization is allowed, the user
program must be written as if a use requiring the implicit instantiation of all
virtual member functions of that class specialization occurs or an unresolved
symbol error for a virtual member function may result at link time.
6. When implicit instantiation of a class template specialization is allowed and the
specialization is subject to explicit instantiation declaration, the class template
specialization must be subject to an explicit instantiation definition somewhere in
the user program or an unresolved symbol error may result at link time.
sample1.h:
template <typename T, T val>
union A {
T foo();
};
sample1a.C:
#include "sample1.h"
sample1b.C:
#include "sample1.h"
int main(void) {
return A<int, 55>().foo();
}
Figure 147 on page 465 shows an erroneous case. That is, an explicit instantiation
declaration of virtual member function foo() is present; but, the explicit instantiation
sample2.C:
template <typename T, T val>
struct A {
virtual T foo();
virtual T bar();
};
int main(void) {
return A<int, 55>().bar();
}
The following environment variables affect the z/OS XL C/C++ environment if they
are on when an application program runs. The variables that begin with _EDC_ and
_CEE_ are described in detail in Environment variables specific to the z/OS XL
C/C++ library on page 477. See Locale source files on page 796 for more
information on the locale-related environment variables.
Note: The settings of these variables affect your environment even if you are using
the C++ I/O stream classes. For more detailed information on I/O streaming and the
Standard C++ I/O stream classes, see Standard C++ Library Reference. For
information on environment variables used in z/OS UNIX System Services, see
z/OS UNIX System Services Command Reference and z/OS UNIX System Services
User's Guide.
_BIDIATTR
Used to specify the attributes which will determine the way the bidirectional
layout transformation takes place, as shown in the following example. If
_BIDIATTR is not specified or contains erroneous values, the default values
will be used. For a detailed description of the bidirectional layout
transformation, see Chapter 62, Bidirectional language support, on page
903.
export _BIDIATTR="@ls typeoftext=visual:implicit, orientation=ltr:ltr,
numerals=nominal:national"
_BIDION
Used to specify if iconv will perform bidirectional layout transformation
beside the basic main function (code page conversion). The value of this
variable is either set to TRUE to activate the bidirectional layout
transformation, or FALSE to prevent the bidirectional layout transformation.
If this variable is not defined in the environment it defaults to FALSE.
_BPXK_AUTOCVT
Activates or deactivates automatic text conversion of tagged UNIX file
system files. The value of this environment variable is interrogated during
initialization of the C main(), and at each pthread initialization in order to set
the autoconversion state for the thread. The autoconversion state for the
thread is looked at by the logical file system (LFS) when determining if
automatic text conversion should be performed during read/write operations
to tagged UNIX file system files.
The default autoconversion state is unset, meaning that the LFS must look
to the BPXPRMxx AUTOCVT parameter, which is either ON or OFF. When
set to a valid value, this environment variable overrides the BPXPRMxx
AUTOCVT parameter.
Restriction: Automatic conversion can only take place between IBM-1047
and ISO8859-1 code sets. Other CCSID pairs are not supported for
automatic text conversion.
During main() initialization, the following behavior is defined for this
environment variable:
Note: Changing the value of this environment variable using any other
mechanism is ignored, although getenv() might show otherwise. You can
use setenv() with a value of NULL to delete an environment variable.
_BPXK_SIGDANGER
Set to either YES or NO, this variable modifies the process termination
mechanism used during UNIX System Services Shutdown. During
Shutdown the kernel sends a signal to each non-permanent non-blocking
process. If _BPXK_SIGDANGER is not in the environment, or if its value is
not YES, then SIGTERM is sent to these processes. If
_BPXK_SIGDANGER is present in the environment and has the value YES
then signal SIGDANGER will be sent instead of SIGTERM. The default
action for SIGTERM is to terminate the process, but the default action for
SIGDANGER is to ignore the signal. The application may register a
SIGDANGER signal catcher function to handle shutdowns. If the process
does not end in a short while after being sent the first signal, the kernel will
send SIGKILL to the process. If the process does not end in a short while
after the second signal is sent, the process will be brought down using
CALLRTM ABTERM=YES.
Note: The program should not use the environ external variable to put this
or any other "_BPXK_" environment variable into its own environment. The
Kernel will not be told about the environment variable setting when it is
added to the environment this way. The program should use an environ
pointer to put this variable into the environment of a new process created
with spawn() or exec(). In this case the kernel will notice _BPXK_
environment variables being created for a new program image. In addition,
the kernel will correctly detect _BPXK_ environment variables generated
into child processes created via fork() and spawn().
Note: XPLINK locales have an .xplink suffix added to the end of the
locale name. For more information about XPLINK locale names, see
Locale naming conventions on page 828
PATH The set of UNIX file system directories that some z/OS XL C/C++ functions,
such as EXECVP, use in trying to locate an executable. The directories are
separated by a colon (:) delimiter. If the pathname contains a slash, the
PATH environment variable will not be used.
__POSIX_SYSTEM
Determines the behavior of the system() function when the POSIX(ON)
run-time option has been specified. If __POSIX_SYSTEM=NO, then system()
behaves as in Language Environment/370 1.2: it creates a nested enclave
within the same process as the invoker (allowing such things as sharing of
memory files). Otherwise, system() performs a fork() and exec(), and the
target program runs in a separate process (preventing such things as
sharing of memory files).
Restriction:__POSIX_SYSTEM=NO is not supported in AMODE 64 applications.
__POSIX_TMPNAM
Determines the behavior of the tmpnam() function when the POSIX(ON)
run-time option has been specified. If the __POSIX_TMPNAM environment
variable is set to NO, tmpnam() behaves as if it was called under
POSIX(OFF). Otherwise, tmpnam() generates a unique file name in the UNIX
file system.
STEPLIB
Determines the STEPLIB environment that is created for an executable file. It
can be a sequence of MVS data set names separated by a colon (:), or can
contain the value CURRENT or NONE. If you do not want a STEPLIB
environment propagated to the environment of the executable file, specify
NONE. The STEPLIB environment variable defaults to the value CURRENT,
which will propagate your current environment to that of the executable file.
See z/OS UNIX System Services Command Reference for more information
on the use of the STEPLIB variable and changing the search order for z/OS
programs.
TZ or _TZ
Time zone information. The TZ and _TZ environment variables are typically
set when you start a shell session, either through /etc/profile or .profile
in your home directory. For more information, see Chapter 58, Customizing
a time zone, on page 847.
The setenv() function adds, changes, and deletes environment variables in the
environment variable table. The getenv() function retrieves the values from the
table. If it does not find an environment variable, getenv() returns NULL. The
clearenv() function clears the environment variable table, and resets to default
behavior the actions affected by z/OS XL C/C++-specific environment variables. The
unsetenv() function deletes environment variables from the table.
The __getenv() function behaves almost the same as getenv() except getenv()
returns the address of the environment variable value string that has been copied
into a buffer, whereas __getenv() returns the address of the actual value string in
the environment variable array. Because the value is not buffered, __getenv()
cannot be used in a multithreaded application or in a single threaded application
where the function setenv() changes the value of the variables.
The putenv() function provides a subset of the function of setenv() and is provided
for convenience in porting UNIX applications. putenv(env_var) is the same as
setenv(var_name, var_value, i) where env_var represents the string
var_name=var_value.
Environment variables may be set any time in an application program or user exit.
You can use the exit routine CEEBINT to set environment variables through calls to
setenv(). For more information on the z/OS Language Environment user exit
CEEBINT, refer to Using run-time user exits in z/OS Language Environment on
page 667. You can also set environment variables by using the ENVAR run-time
option. The syntax for this option is as follows:
ENVAR("1st_var=1st_value", "2nd_var=2nd_value")
For more information on this run-time option, refer to z/OS Language Environment
Programming Reference.
Environment variables set with the setenv() function exist only for the life of the
program, and are not saved before program termination. Child programs are
initialized with the environment variables of the parent. However, environment
variables set by a child program are not propagated back to the parent upon
termination of the child program.
When a parent process invokes a child process by using system(), using the ANSI
form of the system function, the child receives its environment variables from the
value of the ENVAR run-time option specified on the invocation of system(). For
example:
system("PGM=CHILD,PARM=ENVAR(ABC=5)/");)
Naming conventions
Avoid the following when creating names for environment variables:
= Not valid and will generate an error message.
_CBC_ Reserved for z/OS XL C/C++ specific environment variables.
_CCN_ Reserved for z/OS XL C/C++ specific environment variables.
_EDC_ Reserved for z/OS XL C/C++ specific environment variables.
_CEE_ Reserved for z/OS XL C/C++ specific environment variables used
with z/OS Language Environment. See Environment variables
specific to the z/OS XL C/C++ library on page 477 for more
information.
_BPX_ Reserved for z/OS XL C/C++ specific environment variables used in
the kernel. See the spawn callable service in z/OS UNIX System
Services Programming: Assembler Callable Services Reference for
more information.
DBCS characters
Multibyte and DBCS characters should not be used in environment
variable names. Their use can result in unpredictable behavior.
Multibyte and DBCS characters are allowed in environment variable
values; however, the values are not validated, and redundant shifts
are not removed.
white space Blank spaces are valid characters and should be used carefully in
environment variable names and values. For example, setenv(" my
name"," David ",1) sets the environment variable
<space>my<space>name to <space><space>David. A call to getenv("my
name"); returns NULL indicating that the variable was not found. You
must specifically query getenv(" my name") to retrieve the value of
" David".
The environment variable names are case-sensitive. The empty string is a valid
environment variable name.
Note: In general, it is a good idea to avoid special characters, and to use portable
names containing just upper and lower case alphabetics, numerics, and underscore
characters. Environment variable names containing certain special characters, such
as slash (/), are not propagated by the z/OS UNIX shells. Therefore, these variable
names are not available to a program called using the POSIX system() function.
The z/OS XL C/C++ specific environment variables may be set with the setenv()
function.
_CEE_DLLLOAD_XPCOMPAT
Used to indicate if certain 31-bit XPLINK DLL application initialization compatibility
behaviors should be disabled.
This environment variable should only be used for applications that do not run
properly when migrating from one release to another. While the correct run-time
behavior is in the current release, this environment variable provides compatibility
support for existing programs. The need to use these settings indicates incorrect
programming within the application (for example, reliance on a particular order of
C++ static construction across all DLLs that comprise the application). When
possible, you should correct the application rather than use this environment
variable.
0 Always the most current behavior (e.g. no compatibility behavior enabled).
This is identical to the behavior when _CEE_DLLLOAD_XPCOMPAT is not
set.
1 Disable static initialization prerequisite XPLINK DLL load ordering
introduced in z/OS V1R6.
2 Disable non-XPLINK to XPLINK DLL function pointer compatibility
introduced in z/OS V1R8.
3 Disable both static initialization prerequisite XPLINK DLL load ordering, and
non-XPLINK to XPLINK DLL function pointer compatibility. (Disables both
behaviors 1 and 2.)
z/OS Language Environment converts the specified string value to a signed integer,
and interprets this value as a bit mask to determine which functions to use in
compatibility mode. This allows any combination of compatibility behaviors to be
specified.
Here are some examples of how you might set this environment variable:
v z/OS UNIX: export _CEE_DLLLOAD_XPCOMPAT=1 Disable behavior 1
v Batch/TSO command line: ENVAR("_CEE_DLLLOAD_XPCOMPAT=3") Disable behaviors
1 and 2
_CEE_DMPTARG
You can use this variable in two ways:
1. To specify the directory in which Language Environment dumps (CEEDUMPs)
are written for applications that are running as the result of a fork, exec, or
spawn.
_CEE_ENVFILE
Enables a list of environment variables to be set from a specified file. This
environment variable only takes effect when it is set through the run-time option
ENVAR on initialization of a parent program. When _CEE_ENVFILE is defined under
these conditions, its value is taken as the name of the file to be used. For example,
to read the ddname MYVARS, you would call your program with the ENVAR run-time
option, as follows:
ENVAR("_CEE_ENVFILE=DD:MYVARS")
When you set the environment variables with a file in the UNIX file system, you
need to use the absolute path to specify the file. For example, if the absolute path
of the file is /u/DPGROSS/ootest/tsthello/ENV, you would call your program with the
ENVAR run-time option as follows:
ENVAR("_CEE_ENVFILE=/u/DPGROSS/ootest/tsthello/ENV")
The specified file is opened as a variable length record file. For an MVS data set,
the data set must be allocated with RECFM=V. RECFM=VBS must not be used because
environment variables may not be contained in spanned records. RECFM=F is not
suggested because RECFM=F enables padding with blanks, and the blanks are
counted when calculating the size of the line. Each record consists of NAME=VALUE.
For example, a file with the following two records:
_EDC_RRDS_HIDE_KEY=Y
World_Champions=New_York_Yankees
would set the environment variable _EDC_RRDS_HIDE_KEY to the value Y, and the
environment variable World_Champions to the value New_York_Yankees.
will result in the environment variable FRED being set to $FRED:BAMBAM, rather
than to WILMA:BAMBAM as would be the case if the same statements were
processed by a UNIX shell.
_CEE_ENVFILE_COMMENT
Defines the comment character to be checked for when subsequent records are
read from the file. _CEE_ENVFILE_COMMENT is defined within the file specified by the
_CEE_ENVFILE or _CEE_ENVFILE_S environment variable. The comment character
used is the first character after the = and it must not be a space character, as
determined by the isspace() macro.
In the following example, the comment character is defined as *. With this in place,
any subsequent line that begins with * in column one is treated as a comment and
processing will skip to the next line.
_CEE_ENVFILE_COMMENT=*
* This is a comment
NAME1=VALUE1
Notes:
1. Comments cannot be placed within a set of continuation lines.
2. If _CEE_ENVFILE_COMMENT is encountered when the file is read, it is only used to
define the comment character; the keyword is not added to the environment.
_CEE_ENVFILE_CONTINUATION
Defines the continuation character to be checked for when subsequent records are
read from the file. _CEE_ENVFILE_CONTINUATION is defined within the file specified by
the _CEE_ENVFILE or _CEE_ENVFILE_S environment variable. The continuation
character used is the first character after the = and it must not be a space
character, as determined by the isspace() macro.
_CEE_ENVFILE_S
Enables a list of environment variables to be set from a specified file, stripping
trailing white space from each NAME=VALUE line read.. This environment variable only
takes effect when it is set through the run-time option ENVAR on initialization of a
parent program.
When _CEE_ENVFILE_S is defined under this condition, its value specifies the name
of the file to be used. For example, to read the ddname MYVARS, you would call your
program with the ENVAR run-time option as follows:
ENVAR("_CEE_ENVFILE_S=DD:MYVARS")
When you set the environment variables with a file in the UNIX file system, you
need to use the absolute path to specify the file. For example, if the absolute path
of the file is /u/DPGROSS/ootest/tsthello/ENV, you would call your program with the
ENVAR run-time option as follows:
ENVAR("_CEE_ENVFILE_S=/u/DPGROSS/ootest/tsthello/ENV")
For an MVS data set, the data set can be allocated with any record format except
RECFM=VBS, because environment variables may not be contained in spanned
records. Each record consists of NAME=VALUE. For example, a file with the
following two records:
_EDC_RRDS_HIDE_KEY=Y
World_Champions=New_York_Yankees
would set the environment variable _EDC_RRDS_HIDE_KEY to the value Y, and the
environment variable World_Champions to the value New_York_Yankees.
Notes:
1. Using _CEE_ENVFILE_S to set environment variables through a file is not
supported under CICS.
2. z/OS Language Environment searches for an equal sign to delimit the
environment variable from its value. If an equal sign is not found, the
environment variable is skipped and the rest of the text is treated as comments.
3. Both environment variables _CEE_ENVFILE and _CEE_ENVFILE_S can be specified.
_CEE_ENVFILE_S takes precedence, meaning it is processed second in
sequence.
4. Each record of the file is processed independently from any other record in the
file. Data within a record is used exactly as input with no substitution (other than
trailing white space is ignored). A file containing:
FRED=WILMA
FRED=$FRED:BAMBAM
_CEE_HEAP_MANAGER
Specifies the name of the Vendor Heap Manager (VHM) DLL that will be used to
manage the user heap. You set the environment variable as follows:
_CEE_HEAP_MANAGER=dllname
This environment variable must be set using one of the following mechanisms:
v ENVAR run-time option
v Inside the file specified by the _CEE_ENVFILE or _CEE_ENVFILE_S environment
variable.
Either of these mechanisms is before any user code gets control. This means prior
to the HLL user exit, static constructors, and/or main getting control. Setting of this
environment variable once the user code has begun execution will not activate the
VHM, but the value of the environment variable will be updated.
See z/OS Language Environment Vendor Interfaces for more information on the
Vendor Heap Manager support.
_CEE_REALLOC_CONTROL
_CEE_REALLOC_CONTROL has two parameters. The first parameter specifies the lower
bound for the tolerance percentage to be applied. This variable reflects the number
of bytes that will cause the realloc() control feature to be activated. For instance,
if an application issues a malloc() to request storage and a subsequent realloc()
to change the size of that storage allocation, this parameter determines whether the
request will be increased - with the intent that subsequent reallocations will not
require additional storage be obtained and data copied.
The second parameter specifies the percentage that the storage request will be
increased if the request is greater than or equal to the lower bound specified in the
first parameter.
Note: The following examples use storage sizes that are for illustration purposes
only. The sizes are examples and do not reflect any storage rounding that might
occur.
The following example shows this control feature being used within a loop and how
an allocation of a new storage element can be eliminated:
_CEE_ REALLOC_CONTROL=100,20
Because the realloc() request is greater than the lower bound, the first pass
through the first loop results in a new buffer with the same contents as before but
within a storage element of size 132 (110+(110*.20)) and buffsize=110. All the
data in the first buffer (100 bytes) is copied to the second (new) buffer.
The second and third pass through the first loop issue the same realloc, but result
in no action being taken because the new buffsize of 120 and then 130 allows the
requested storage to remain within the current allocation of 132 bytes, even if both
requests are greater than the lower bound. Therefore, allocation of new storage
elements and copies of data are eliminated.
Additionally, the first two paths through the second loop also result in no action
because they result in a buffsize less than the current allocation and can also fit
within the current allocation.
The last path through the second loop results in a new buffer of buffsize 100.
Although this request is also less than the current allocation and fits in the current
allocation, the assumption is that no tolerance ever occurred because the requested
size plus the increase have resulted in a storage allocation less than the current
allocation.
_CEE_RUNOPTS
Used to specify invocation Language Environment run-time options for programs
invoked using one of the exec family of functions. Mechanisms for setting the value
of the _CEE_RUNOPTS environment variable include using the export command within
the z/OS UNIX shell, or using the setenv() or putenv() functions within a C/C++
Note: For this description, the exec family of functions includes the spawn family of
functions.
For example, you could specify the following to set the value of the environment
variable within the z/OS UNIX shell.
export _CEE_RUNOPTS="stack(,,any,) termthdact(dump)"
At the time of the exec, any active invocation command run-time option settings, not
already explicitly part of the _CEE_RUNOPTS environment variable, are added to its
value. This new value for the _CEE_RUNOPTS environment variable is passed to the
exec target to be used as invocation Language Environment run-time options for the
invoked program. Thus, all invocation run-time options, those specified with the
_CEE_RUNOPTS environment variable and those already active, are propagated across
the exec.
When the _CEE_RUNOPTS environment variable is not defined at the time of the exec,
but there are other active invocation command run-time options, it will be re-created
with its value set to represent the active invocation command run-time option
settings. This unique behavior, where the _CEE_RUNOPTS environment variable is
added to, or re-created, across an exec, can cause unexpected results when the
user attempts to unset (clear) the environment variable, or modify its value.
Figure 148 on page 485 demonstrates this behavior. We enter the z/OS UNIX shell
through OMVS, and a sub-shell is created using one of the exec family of functions.
The propagation of the _CEE_RUNOPTS environment variable takes place across
creation of the sub-shell.
Notes:
1. The current value of the _CEE_RUNOPTS environment variable happens to be
POSIX(ON).
2. Using /bin/sh to create a sub-shell will go through the process where the
_CEE_RUNOPTS environment variable is added to, or re-created, across the exec.
3. Displaying the value of the _CEE_RUNOPTS environment variable using echo in the
sub-shell shows that no other invocation command run-time options were in
effect at the time of the exec, since the value of the environment variable is
unchanged (there were no run-time options to add).
4. Using unset to clear the _CEE_RUNOPTS environment variable does remove it from
the sub-shell environment, as shown with the echo command, but it does not
change the fact that POSIX(ON) is the active invocation command run-time
option in the sub-shell.
5. To see this, we use the env | grep _CEE_RUNOPTS command. The env is the
target of an exec. We know that the _CEE_RUNOPTS environment variable is
re-created across the exec from the active invocation command run-time
options. And as you can see, the value shows as POS(ON). During re-creation,
Language Environment uses the minimum abbreviations for the run-time options
when re-creating or adding to the _CEE_RUNOPTS environment variable.
6. When the env returns, the _CEE_RUNOPTS environment variable is still unset in the
sub-shell as seen using the echo command.
7. We now use export to set a different value for the _CEE_RUNOPTS environment
variable in the sub-shell. We see the value using the echo command.
8. Using the env | grep _CEE_RUNOPTS command again, we see the behavior where
the active invocation command run-time options are added to the current value
of the _CEE_RUNOPTS environment variable.
_EDC_ADD_ERRNO2
Controls whether or not errno2 is appended to the output of perror(), strerror(),
and strerror_r(). The errno2 might be set by the z/OS XL C/C++ run-time library,
z/OS UNIX callable services, or other callable services. The errno2 is intended for
diagnostic display purposes only and it is not a programming interface.
It is suggested that applications run with _EDC_ADD_ERRNO2 not being set. This
causes errno2 to be added only to perror() messages.
Note: Not all functions set errno2 when errno is set. In the cases where errno2 is
not set, the errno2 might be a residual value. You might use the __err2ad()
function to clear errno2 to reduce the possibility of a residual value being returned.
_EDC_ANSI_OPEN_DEFAULT
Affects the characteristics of MVS text files opened with the default attributes.
Issuing the following command causes text files opened with the default
characteristics to be opened with a record format of FIXED and a logical record
length of 254 in accordance with the ANSI standard for C.
setenv("_EDC_ANSI_OPEN_DEFAULT","Y",1);
When this environment variable is not specified and a text file is created without its
record format or LRECL defined, then the default is a variable record format.
_EDC_AUTOCVT_BINARY
If automatic file conversion is enabled (_BPXK_AUTOCVT=ON and running with
FILETAG(AUTOCVT) run-time option), this environment variable activates or
deactivates automatic conversion of untagged UNIX file system files opened in
binary mode and not opened for record I/O.
The value of this environment variable is checked every time a UNIX file system file
is opened. If automatic file conversion is enabled and _EDC_AUTOCVT_BINARY=YES, an
untagged file opened in binary mode will trigger the file to be automatically
_EDC_AUTOCVT_BINARY can be set to the following values to set the conversion state
for binary files.
NO (default) If automatic file conversion is enabled, an untagged file opened in
binary mode will not trigger the file to be automatically converted
from the program CCSID to the EBCDIC CCSID as specified by the
_BPXK_CCSIDS environment variable. If _BPXK_CCSIDS is not set, a
default CCSID pair is used. See _BPXK_CCSIDS environment variable
for additional details. An untagged file opened in text mode will not
be affected.
YES If automatic file conversion is enabled, an untagged file opened in
binary mode and not opened for record I/O will trigger the file to be
automatically converted from the program CCSID to the EBCDIC
CCSID as specified by the _BPXK_CCSIDS environment variable. If
_BPXK_CCSIDS is not set, a default CCSID pair is used. See
_BPXK_CCSIDS environment variable for additional details.
Note: If this environment variable is not set, the default behavior is chosen, which
is the same as _EDC_AUTOCVT_BINARY=NO. Because this environment variable is
checked on every file open, an application can pick up the changes to this
environment variable by closing and then re-opening the file at execution time. The
application itself does not need to be restarted.
_EDC_BYTE_SEEK
Indicates to z/OS XL C/C++ that, for all binary files, ftell() should return relative
byte offsets, and fseek() should use relative byte offsets as input. The default
behavior is for only binary files with a fixed record format to support relative byte
offsets. _EDC_BYTE_SEEK is set with the command:
setenv("_EDC_BYTE_SEEK","Y",1);
_EDC_CLEAR_SCREEN
Applies to output text terminal files. _EDC_CLEAR_SCREEN is set with the command:
setenv("_EDC_CLEAR_SCREEN","Y",1);
_EDC_COMPAT
Indicates to z/OS XL C/C++ that it should use old functional behavior for various
items in code ported from old releases of C/370. These functional items are
specified by the value of the environment variable. _EDC_COMPAT is set with the
following command, where x is an integer:
setenv("_EDC_COMPAT","x",1);
For this release, calls to fseek() with an offset of SEEK_CUR, fgetpos(), and
fflush() take into account characters pushed back with the ungetc() library
function. You must set the _EDC_COMPAT environment variable for ungetc() if you
want these functions to ignore ungetc() characters as they did in old C/370 code.
For ftell(), z/OS XL C/C++ uses an encoding scheme that varies according to the
attributes of the underlying data set. You must set the _EDC_COMPAT environment
variable for ftell() if you want to use encoded ftell() values generated in old
C/370 code.
You can set _EDC_COMPAT to indicate that fclose() should not unallocate the
SYSOUT=* data set when it is closing "*" data sets created under batch. This is to
ensure that such data sets can be concatenated with the Job Log, if their attributes
are compatible.
_EDC_CONTEXT_GUARD
Allows the user to control the method used to handle the guard page for AMODE
64 user context stacks.
When the value of _EDC_CONTEXT_GUARD is set to ACTIVE, the guard page for a user
context stack is guarded each time the context is given control and unguarded each
time the context gives up control. This is the default behavior when the value of
_EDC_CONTEXT_GUARD is not set.
When the value of _EDC_CONTEXT_GUARD is set to INUSE, the guard page for a user
context stack is guarded the first time the context is given control and unguarded
when the context has run to completion, that is, when the function specified on the
call to makecontext() returns or exits. This method of handling the guard page
might provide better performance but comes with the following restrictions:
v The storage for user context stacks must be allocated from the heap.
v The storage for a user context stack cannot be reused or freed until the context
runs to completion.
_EDC_C99_NAN
Sets the binary floating-point representation of infinite value and Not a Number for
the printf family of functions as follows:
v When the value of _EDC_C99_NAN is set to YES, then the printf family of functions
use C99 compliant behavior. C99 defines the representation of infinity and Not a
Number as INF, and NAN (for E, F, G, and A conversion specifiers) or inf and
nan (for e, f, g, and a conversion specifiers). In C99 compliant behavior, the
case of the string will be the same as the case of the conversion specifier that
was used.
v When the value of _EDC_C99_NAN is not set, or set to a value other than YES, then
the representation of infinity and Not a Number is INF and NaN.
_EDC_DLL_DIAG
Indicates if additional DLL diagnostic information should be generated upon failure
for the following DLL functions: dllload(), dlopen(), dllqueryfn(), dllqueryvar(),
dlsym(), dllfree(), and dlclose() . _EDC_DLL_DIAG has no effect on implicit
DLLs. If _EDC_DLL_DIAG is not set by the user, it will default to QUIET.
_EDC_EOVERFLOW
Sets the behavior of the ftell(), fseek(), fstat(), lstat(), stat(), and mmap()
functions. By default these functions will not check for the EOVERFLOW error
condition. Setting _EDC_EOVERFLOW to YES enables testing for this condition,
and, if overflow is detected, setting errno to EOVERFLOW and returning an error.
The _EDC_EOVERFLOW environment variable can be set with the function:
setenv("_EDC_EOVERFLOW,"YES", 1);
Value Description
YES Check for EOVERFLOW error conditions.
<other> Ignore setting of EOVERFLOW; this is the default. Equivalent to
unsetting the environment variable.
_EDC_ERRNO_DIAG
Indicates if additional diagnostic information should be generated, when the
perror() or strerror() functions are called to produce an error message. This
environment variable also controls how much additional information is produced.
_EDC_ERRNO_DIAG is set with the following command, where x is an integer and
y is a list of integer errno values, for which additional diagnostic information is
desired.
setenv("_EDC_ERRNO_DIAG","x,y",1);
The list of errno values must be separated by commas. If the y value is omitted,
then additional diagnostic information is generated for all errno values. If a
non-numeric errno value is found in y, it is treated as 0. Acceptable values for x are
as follows:
0 No additional diagnostic information is generated (This is the default if
_EDC_ERRNO_DIAG is not set).
1 The ctrace() function is called to generate additional diagnostic
information.
2 The csnap() function is called to generate additional diagnostic information.
3 The cdump() function is called to generate additional diagnostic information.
See z/OS XL C/C++ Run-Time Library Reference for details on the level of
diagnostic information provided by the above functions.
_EDC_FLUSH_STDOUT_PIPE
Instructs the C Run-Time Library to flush the stdout stream when the stdin stream
is being read from. Both stdin and stdout must be pipes. _EDC_FLUSH_STDOUT_PIPE
is set with the command:
setenv("_EDC_FLUSH_STDOUT_PIPE","YES",1);
Note: The parent process must do a read by using read() from the pipe so that
it can receive whatever data might be there without having to wait for a specific
number of bytes or a newline character. Functions like fread() and fgets() will
hang unless the child process wrote enough bytes or the newline character to
stdout.
_EDC_FLUSH_STDOUT_SOCKET
Instructs the C Run-Time Library to flush the stdout stream when the stdin stream
is being read from. Both stdin and stdout must be sockets.
_EDC_FLUSH_STDOUT_SOCKET is set with the command:
setenv("_EDC_FLUSH_STDOUT_SOCKET","YES",1);
Note: The parent process must do a read by using read() from the socket so
that it can receive whatever data might be there without having to wait for a
specific number of bytes or a newline character. Functions like fread() and
fgets() will hang unless the child wrote enough bytes or the newline character to
stdout.
_EDC_GLOBAL_STREAMS
Used during initialization of the first C main in the environment to allow the C
standard streams stdin, stdout, and stderr to have global behavior. The
environment variable settings and standard streams using the global behavior, are
as follows:
Setting Standard streams using global behavior
0 none
1 stderr
2 stdout
3 stderr,stdout
4 stdin
5 stderr,stdin
6 stdout,stdin
7 stderr,stdout,stdin
Note: The first C main would include any Pre-Init Compatibility Interface
initialization.
You can use one of the following methods to set the environment variable
_EDC_GLOBAL_STREAMS:
v CEEBXITA assembler user exit
You can modify the sample CSECT and assemble and link with the application.
The run-time options specified in the CEEBXITA assembler user exit override all
other sources of run-time options except those that are specified as NONOVR in
the installation default run-time options. These options are honored only during
initialization of the first enclave.
v ENVAR(_EDC_GLOBAL_STREAMS=<setting>)
_EDC_IEEEV1_COMPATIBILITY_ENV
In 1999, the C/C++ Run-Time Library provided IEEE754 floating-point arithmetic
support in support of IBMs Java group. The Java language had a bit-wise
requirement for its math library, meaning that all platforms needed to produce the
same results as Sun Microsystems fdlibm (Freely Distributed LIBM) library.
Therefore, Sun Microsystems fdlibm code was ported to the C/C++ Run-Time
Library to provide IEEE754 floating-point arithmetic support. Subsequent to the
C/C++ Run-Time Librarys 1999 release of IEEE754 floating-point math support,
IBMs Java group provided their own support of IEEE754 floating point arithmetic
and no longer use the C/C++ Run-Time Library for this support.
Beginning in z/OS V1R9, a subset of the original fdlibm functions are being
replaced by new versions that are designed to provide improved performance and
accuracy. The new versions of these functions are replaced at the existing entry
points. However, as a migration aid, IBM has provided new entry points for the
original fdlibm versions. Applications that take no action will automatically use the
updated functions. There are two methods for accessing the original functions.
The first method is through an environment variable, described here, that can be
used by applications that do one of the following:
v Do not include <math.h>.
v Include <math.h> and define the _FP_MODE_VARIABLE feature test macro.
Either of the above will cause the application to be running in what is called
"variable" mode with respect to floating-point math functions called within the
compile unit.
If the application conforms to the rules of the first method, then this environment
variable can be used to access the original fdlibm versions of the functions shown
in Table 86 on page 494.
This environment variable will only take effect if the application is running in
"variable" mode. The following list shows the acceptable values of the environment
variable and the behavior for each value:
ON Original versions of fdlibm functions are used.
other values The new versions of the functions are used. This is the default.
_EDC_IO_ABEND
When an abend condition arises during OS I/O processing, the zOS XL C/C++
run-time library ignores the condition, if possible. When the abend condition cannot
be ignored, the abend is issued. This environment variable controls if the run-time
library should attempt to recover from an abend issued during OS I/O processing.
The acceptable values for the environment variable are as follows:
ABEND Specifies that the run-time library is to ignore abend conditions that can be
ignored and that the run-time library should not attempt to recover from an
abend issued during OS I/O processing. When an abend is issued during
OS I/O processing, Language Environment condition handling semantics
take effect. The only methods available for the application to attempt to
recover are to write a Language Environment condition handler or a
SIGABND signal handler. If this environment value is not set or if a value
other than ABEND or RECOVER is specified, this is the default behavior.
RECOVER
Specifies that the run-time library is to ignore abend conditions that can be
ignored and also that the run-time library should attempt to recover from an
abend issued during OS I/O processing. If the library can recover, then
control will be returned to the application as a failing return value, with errno
set to 92 and diagnostic information in the __amrc structure. If the library
cannot recover, Language Environment condition handling semantics take
effect.
Notes:
1. The value is not case sensitive.
2. When a stream is opened, the current setting of the environment variable
defines the behavior for the life of the open stream, unless overridden by the
abend keyword specified in the modestring on the fopen() or freopen() call.
3. Changes to the environment variable do not affect existing open streams.
4. This environment variable has no effect for SPC applications.
For more information about error handling during I/O operations, refer to
Chapter 10, Performing OS I/O operations, on page 81.
The following example show one method to set this environment variable.
setenv(_EDC_IO_ABEND, RECOVER, 1);
The three values (Filter, Detail, Buffer Size) must be surrounded by parenthesis and
delimited by commas. Values that are left blank use the default setting for that
value.
Value Description
Filter Indicates which files to trace.
//DD:filter
Trace will include the DD names matching the specified filter string.
//filter
Trace will include the MVS data sets matching the specified filter
string. Member names of partitioned data sets cannot be matched
without the use of a wildcard.
filter
Trace will include the Unix files matching the specified filter string.
//DD:*
Trace will include all DD names.
//* Trace will include all MVS data sets. This is the default setting.
/* Trace will include all Unix files.
* Trace will include all MVS data sets and Unix files.
Detail Indicates the level of detail provided by the trace.
0 No tracing will be performed. This is the default setting.
1 First level tracing will be performed. The trace includes the following
information:
v The file being traced.
v The trace detail level and buffer size.
v Details describing how the file was opened (the function called and
parameters passed).
v Formatted file data returned from fldata().
v The file pointer address.
v The DD name, if applicable.
v The function flow details for entry to externally documented file I/O
functions.
2 Second level tracing will be performed. The trace includes everything
that the first level tracing includes, except that the function flow details
will be for entry to externally documented and internal slot, exit, OS,
and open file I/O functions.
Buffer Size
Indicates the buffer size to use for each file's function flow details.
sizeK Specifies the size of each files trace buffer, where size is a number
specified in kilobytes. The default buffer size is 16KB.
The following examples show different ways you can use this environment variable.
v The following examples demonstrate two different ways to trace the default of all
MVS data sets, using level 1 tracing and the default trace table size:
export _EDC_IO_TRACE=(,1,)
setenv("_EDC_IO_TRACE","(,1,)",1);
v The following examples demonstrate two different ways to trace the UNIX file
named posix.data, using level 1 tracing and the default trace table size:
export _EDC_IO_TRACE=(posix.data,1,)
setenv("_EDC_IO_TRACE","(posix.data,1,)",1);
v The following examples demonstrate two different ways to trace all MVS data
sets with names that begin with POSIX.DATA, using level 1 tracing and the
default trace table size:
export _EDC_IO_TRACE=(//POSIX.DATA*,1,)
setenv("_EDC_IO_TRACE","(//POSIX.DATA*,1,)",1);
v The following examples demonstrate two different ways to trace all MVS data
sets with names that begin with POSIX.DATA, using level 1 tracing and size 24K
trace tables:
export _EDC_IO_TRACE=(//POSIX.DATA*,1,24K)
setenv("_EDC_IO_TRACE","(//POSIX.DATA*,1,24K)",1);
_EDC_POPEN
Sets the behavior of the popen() function. When the value of _EDC_POPEN is set to
FORK, popen() uses fork() to create the child process. When the value of
_EDC_POPEN is set to SPAWN, popen() uses spawn() to create the child process. If the
value of _EDC_POPEN is not set, the default behavior is for popen() to use fork() to
create the child process.
_EDC_PTHREAD_YIELD
Used to control when pthread_yield() and sched_yield() will allow a thread to
give up control of a processor so that another thread may have the opportunity to
run. Possible values for _EDC_PTHREAD_YIELD:
0 Control of the processor is released immediately.
-1 Use an internal timing algorithm to determine if the processor should be
released. This is the default.
-2 Take the machine speed into account when determining if the processor
should be released.
_EDC_PTHREAD_YIELD_MAX
This environment variable allows a user program to define the max yield (wait) time
for a particular thread. It is used to configure the speed at which the pthread_yield()
and sched_yield() functions release a processor to enable another thread to run. In
some cases, such as in highly-threaded applications, improved performance may
result by using this environment variable to reduce the default max wait time.
Value Description
positive value
An integer value to set the maximum yield time allowable for a
pthread to wait. This value represents microseconds (1/1000 of a
millisecond).
Note: Values above 32000 (which is the current max default) and
values less than or equal to zero will be ignored.
_EDC_RRDS_HIDE_KEY
Applies to VSAM RRDS files opened in record mode. When this environment
variable is set, you can call fread() with a pointer to a character string, and the
Relative Record Number is not appended to the beginning of the record. The
_EDC_RRDS_HIDE_KEY environment variable is set with the command
setenv("_EDC_RRDS_HIDE_KEY","Y",1);
By default, when you open a VSAM record in record mode, the fread() function is
called with the RRDS record structure, and the record is preceded by the Relative
Record Number.
_EDC_STOR_INCREMENT
Sets the size of increments to the internal library storage subpool acquired above
the 16M line. By default, when the storage subpool is filled, its size is incremented
by 8K. When _EDC_STOR_INCREMENT is set, its value string is translated to its decimal
integer equivalent. This integer is then the new setting of the subpool storage
increment size. The setting of this environment variable is only effective if it is done
before the first I/O in the enclave.
The _EDC_STOR_INCREMENT value must be greater than zero, and must be a multiple
of 4K. If the value is less than zero, the default setting of 8K is used. If the value is
not a multiple of 4K, then it is rounded up to the next 4K interval. If
_EDC_STOR_INCREMENT is set to an invalid value that must be modified internally to be
divisible by 4K, this modification is not reflected in the character string that appears
in the environment variable table.
Internally, the storage subpool increment value is set to 12288 (that is, 12K).
However, the following subsequent call returns "9000", as set by the call to
setenv().
getenv("_EDC_STOR_INCREMENT");
_EDC_STOR_INCREMENT_B
Sets the increment size of an internal library storage subpool acquired below the
16M line. By default, when the below the line storage subpool is filled, its size is
incremented by 4K. When _EDC_STOR_INCREMENT_B is set, its value string is
translated to the decimal equivalent. These integers are then used as the new
settings of the below subpool storage increment sizes. The setting of this
environment variable is only effective if it is done before the first I/O in the enclave.
Consider the case where setenv() is called from CEEBINT (with the CEEBINT user
exit linked to the application) as follows:
setenv("_EDC_STOR_INCREMENT_B","1000",1);
Internally, the storage subpool acquired from 24-bit storage will be 4096 (or 4K).
However, the following subsequent call returns "1000", as set by the setenv()call.
getenv("_EDC_STOR_INCREMENT_B");
_EDC_STOR_INITIAL
Sets the initial size of the internal library storage subpool acquired above the line.
The default subpool storage size is 12K. When _EDC_STORE_INITIAL is set, its value
string is translated to its decimal integer equivalent. This integer is then the new
setting of the subpool storage increment size. The setting of this environment
variable is only effective if it is done before the first I/O in the enclave.
The _EDC_STORE_INITIAL value must be greater than zero, and must be a multiple
of 4K. If the value is less than zero, the default setting of 12K is used. If the value
is not a multiple of 4K, then it is rounded up to the next 4K interval. If
_EDC_STORE_INITIAL is set to an invalid value that must be modified internally to be
divisible by 4K, this modification is not reflected in the character string that appears
in the environment variable table.
Consider the case where setenv() is called from CEEBINT as follows, and the
CEEBINT user exit linked to the application:
setenv("_EDC_STORE_INITIAL","16000",1);
Internally, the storage subpool is initialized to 16384 (that is, 16K). However, the
subsequent call, shown in the following example, returns "16000", as set by the
setenv() call:
getenv("_EDC_STORE_INITIAL");
_EDC_STOR_INITIAL_B
Sets the initial size of an internal library storage subpool acquired below the 16M
line. The default below the line subpool storage size is 4K When
_EDC_STOR_INITIAL_B is set, its value string is translated to the decimal integer
equivalent. This integer is then used as the new setting of the above the line
subpool storage initial size. The setting of this environment variable is only effective
if it is done before the first I/O in the enclave.
Consider the case where setenv() is called from CEEBINT as follows, and with the
CEEBINT user exit linked to the application.
setenv("_EDC_STOR_INITIAL_B","1000",1);
Internally, the storage subpool acquired from 24-bit storage will be set to 4096 (that
is, 4K). However, the subsequent call getenv("_EDC_STOR_INITIAL_B"); returns
"1000", as set by the setenv() call.
_EDC_SUSV3
Indicates behavioral changes that are provided for SUSV3 compliance in an error
path. The affected interfaces are typically setting errno to values that were not used
before and, in some cases, returning failure for conditions that had not been tested
before SUSV3. By default the affected interfaces will not check for these conditions.
When the value of _EDC_SUSV3 is set to 1, the SUSV3 behavior is enabled.
_EDC_UMASK_DFLT
Allows the user to control how the C library sets the default umask used when the
program runs. If z/OS UNIX services are available, the possible values of the
_EDC_UMASK_DFLT environment variable are:
v NO - the library will not change the value
v a valid octal value - the library sets this as the default
v any other value - the library uses 022 octal as the value.
This environment variable has no effect on streams based on UNIX file system files.
You can always read and write zero-byte records in UNIX file system files.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *x;
return(0);
}
Figure 150 on page 502 is another sample program (CCNGEV2) to show how
environment variables are propagated.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *x;
return(0);
}
A built-in function is inline code that is generated in place of an actual function call.
The hardware built-in functions send requests to the compiler to use instructions
that are not typically generated by the compiler. Extra instructions are generated to
load the parameters for the operation and to store the result. These functions
require that the LANGLVL not be set to ANSI. For more information about a given
instruction, refer to the z/Architecture Principles of Operation.
Notes:
1. Using a built-in hardware instruction does not guarantee that a hardware
instruction will be generated. The compiler can decide that it is not necessary to
generate the code.
2. In some cases, the instruction will be generated as data before it is executed
via an EX instruction. This occurs whenever a parameter:
v Must be put in a mask or displacement field.
v Is specified as a non-literal instead of a literal.
For examples, see Table 96 on page 527.
General instructions
General hardware built-in functions are intended to provide access to general
purpose instructions that are not normally generated by the compiler. For more
information on these instructions, see chapter 7 of the z/Architecture Principles of
Operation.
Note: Before you use any of the instructions listed in Table 88 on page 505 in your
program, you must include the builtins.h header file (unless the instructions are
otherwise specified) and compile the program with the LANGLVL(EXTENDED)
option or the LANGLVL(LIBEXT) option.
Table 87. Standard general-instruction prototypes
PROTOTYPE and Notes Sample Pseudo Assembly MIN ARCH
int __cds1(void* Op1, void* Op2, void* Op3) CDS Op1,Op3,Op2D(Op2B) ARCH(0)
Note: The user must include stdlib.h to use this built-in
function. It is similar to cds() but does not explicitly set the type
to be swapped in the prototype.
int __cdsg(void* Op1, void* Op2, void* Op3) CDSG Op1,Op3,Op2D(Op2B) ARCH(5) with
Note: The user must include stdlib.h to use this built-in LP64
function. It is similar to cdsg() but does not explicitly set the type
to be swapped in the prototype.
int __cs1(void* Op1, void* Op2, void* Op3) CS Op1,Op3,Op2D(Op2B) ARCH(0)
Note: The user must include stdlib.h to use this built-in
function. It is similar to cs() but does not explicitly set the type to
be swapped in the prototype.
int __csg(void* Op1, void* Op2, void* Op3) CSG Op1,Op3,Op2D(Op2B) ARCH(5) with
Note: The user must include stdlib.h to use this built-in LP64
function. It is similar to csg() but does not explicitly set the type
to be swapped in the prototype.
Operands:
v op1 and op1_len represent the first operand in the hardware
instruction.
v op3 and op3_len represent the third operand in the hardware
instruction.
v op2 specifies the number of bytes to pad the shorter operand
on the right.
Operands:
v op1 and op1_len represent the first operand in the hardware
instruction.
v op2 specifies the number of bytes to pad the first operand on
the right, in the event that it is shorter than the third operand.
v op3 and op3_len represent the third operand in the hardware
instruction.
Conditions:
v If the LP64 compiler option is in effect, the op1_len and
op3_len operands are 64-bit unsigned integers. Otherwise
they are 32-bit unsigned integers.
v If the operand values are odd numbers, a specification
exception will be triggered by the hardware.
The return value is the condition code set by the CLCLU
instruction.
Note: When the condition code is "3", the condition is handled
by the compiler-generated code.
int __cu12(unsigned short *op1, L R2, Op1 ARCH(7)
unsigned long op1_len, L R3, Op1_len
char *op2, L R4, Op2
unsigned long op2_len, L R5, Op2_len
char **invalid_utf8, CU12 R2, R4, Mask
unsigned char mask);
Operands:
v op1 and op1_len represent the first operand in the hardware
instruction. op1 points to the storage location for receiving the
converted UTF-16 characters.
v op2 and op2_len represent the second operand in the
hardware instruction. op2 points to the source UTF-8
characters.
v invalid_utf8 points to a pointer field for receiving the address
of the invalid UTF-8 character in the source when the
condition code is "2".
v mask specifies the mask encoded in the machine instruction; it
must be a literal value of either 0 or 1.
Note: If option LP64 is specified, both op1_len and op2_len are
64-bit unsigned integers. Otherwise they are 32-bit unsigned
integers.
Operands:
v op1 and op1_len represent the first operand in the hardware
instruction. op1 points to the storage location for receiving the
converted UTF-32 characters.
v op2 and op2_len represent the second operand in the
hardware instruction. op2 points to the source UTF-8
characters.
v invalid_utf8 points to a pointer field for receiving the address
of the invalid UTF-8 character in the source when the
condition code is "2".
v mask specifies the mask encoded in the machine instruction; it
must be a literal value of either 0 or 1.
Note: If option LP64 is specified, both op1_len and op2_len are
64-bit unsigned integers. Otherwise they are 32-bit unsigned
integers.
Operands:
v op1 and op1_len represent the first operand in the hardware
instruction. op1 points to the storage location for receiving the
converted UTF-8 characters.
v op2 and op2_len represent the second operand in the
hardware instruction. op2 points to the source 2-byte Unicode
characters.
v mask specifies the mask encoded in the machine instruction; it
must be a literal value of either 0 or 1.
Note: If option LP64 is specified, both op1_len and op2_len are
64-bit unsigned integers. Otherwise they are 32-bit unsigned
integers.
Operands:
v op1 and op1_len represent the first operand in the hardware
instruction. op1 points to the storage location for receiving the
converted UTF-32 characters.
v op2 and op2_len represent the second operand in the
hardware instruction. op2 points to the source UTF-16
characters.
v mask specifies the mask encoded in the machine instruction; it
must be a literal value of either 0 or 1.
Note: If option LP64 is specified, both op1_len and op2_len are
64-bit unsigned integers. Otherwise they are 32-bit unsigned
integers.
Operands:
v op1 is a 64-bit signed binary integer value that gets converted
into a packed-decimal value.
v op2 points to a 16-byte storage area that receives the
converted packed-decimal value.
int __lad(int* op1, int op3, int* op2) L R3, Op3 ARCH(9)
Note: LAA R1, R3, Op2D(Op2B)
ST R1, *Op1
v Return value corresponds to the condition code set by LAA.
v The location pointed to by op2 must be word aligned for
__lad. Otherwise, a specification exception is recognized.
Operands:
v op1 and op1_len represent the first operand in the hardware
instruction.
v op2 specifies padding the first operand with 2 bytes if it is
shorter than the third operand.
v op3 and op3_len represent the third operand in the hardware
instruction.
Notes:
1. If the operand values are odd numbers, a specification
exception will be triggered by the hardware.
2. If the LP64 compiler option is in effect, the op1_len and
op3_len operands are 64-bit unsigned integers. Otherwise
they are 32-bit unsigned integers.
Operands:
v Each operand is processed left to right. When the operands
overlap, the result is obtained as if the operands were
processed one byte at a time and each result byte were
stored immediately after fetching the necessary operand
bytes.
v len specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the first
operand).
Operands:
v Each operand is processed left to right. When the operands
overlap, the result is obtained as if the operands were
processed one byte at a time and each result byte were
stored immediately after fetching the necessary operand
bytes.
v len specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the first
operand).
Operands:
v The format of op2 is changed from zoned to
signed-packed-decimal, and the result is placed at op1
location.
v op2 is treated as having the zoned format. The numeric bits of
each byte are treated as a digit. The zone bits are ignored,
except the zone bits in the rightmost byte, which are treated
as a sign.
v The sign and digits are moved unchanged to op1 and are not
checked for valid codes. The sign is placed in the rightmost
four bit positions of the rightmost byte of the result field, and
the digits are placed adjacent to the sign and to each other in
the remainder of the result field.
v The result is obtained as if the operands were processed right
to left. When necessary, op2 is considered to be extended on
the left with zeros. If op1 field is too short to contain all digits
of op2, the remaining leftmost portion of op2 is ignored. Access
exceptions for the unused portion of op2 may or may not be
indicated.
v len1 specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the first
operand).
v len2 specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the
second operand).
void __pka(char *op1, char *op2, unsigned char op2_len); PKA Op1D(Op1B), ARCH(6)
v op1 points to a 16-byte storage area. The packed string is Op2D(Op2_len, Op2B)
stored in the storage addressed by op1.
v op2 points to an ASCII string to be packed by the operation.
v op2_len specifies the length encoded in the machine
instruction (that is, the number of additional bytes to the right
of the second operand).
Notes:
1. If op2_len is not between 0 and 31, a specification
exception will be triggered by the hardware.
2. If op2_len is not a literal, the compiler will issue an EX
instruction that executes a target PKA instruction with
op2_len encoded in the register used by the EX
instruction.
Operands:
v op1 represents the first operand in the hardware instruction, it
points at the first 2-byte character after the end of the second
operand.
v op2 represents the second operand in the hardware
instruction, it points at the start of a 2-byte character string.
v pattern is the 2-byte character to be searched for.
v found_char points to a pointer field for receiving the address
of the 2-byte character that was found in the second operand.
The return value is the condition code set by the SRSTU
instruction.
Note: When the condition code is "3", the condition is handled
by the compiler-generated code.
int __stck(unsigned long long *Op1) STCK Op1D(Op1B) ARCH(0)
Operands:
v The bytes of op1 are used as eight-bit arguments to reference
a list designated by the address of op2. Each function byte
selected from the list replaces the corresponding argument in
op1.
v len specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the left of the first
operand used in the machine instruction.
v The bytes of op1 are selected one by one for translation,
proceeding left to right. Each argument byte is added to the
initial op2 address. The addition is performed following the
rules for address arithmetic, with the argument byte treated as
an eight-bit unsigned binary integer and extended with zeros
on the left. The sum is used as the address of the function
byte, which then replaces the original argument byte.
v The operation proceeds until the op1 field is exhausted. The
list is not altered unless an overlap occurs.
v When the operands overlap, the result is obtained as if each
result byte were stored immediately after fetching the
corresponding function byte.
int __tre(char *op1, TRE R1, Op2 ARCH(5)
unsigned long op1_len,
char *op2,
unsigned char test_char);
Operands:
v op1 represents the first operand in the hardware instruction. It
points to the byte string that needs to be translated.
v op1_len specifies the length of the first operand.
Note: If the LP64 compiler option is in effect, the op1_len
operand is a 64-bit unsigned integer. Otherwise it is a 32-bit
unsigned integer.
v op2 represents the second operand in the hardware
instruction. It points to a 256-byte translation table.
v test_char specifies the terminating character in the first
operand for stopping the operation.
The return value is the condition code set by the TRE instruction.
Note: When the condition code is "3", the condition is handled
by the compiler-generated code.
Operands:
v op1 represents the first operand in the hardware instruction.
v op2 and op2_len represent the second operand in the
hardware instruction.
Note: If option LP64 is specified, op2_len is a 64-bit unsigned
integer and the length of the first operand is considered the
same as that of the second operand. If option LP64 is not
specified, both operands are 32-bit unsigned integers.
v tr_table points to a 256-byte translation table on a
double-word boundary.
Note: It is the user's responsibility to provide a double-word
aligned translation table.
v test_char specifies a 1-byte function character that can be
coded in the translation table for stopping the operation.
v mask specifies the mask encoded in the machine instruction; it
must be a literal value of either 0 or 1.
The return value is the condition code set by the TROO
instruction.
Note: When the condition code is "3", the condition is handled
by the compiler-generated code.
int __trot(unsigned short *op1, char *op2, L GR0, test_char ARCH(7)
unsigned long op2_len, L GR1, tr_table
char *tr_table, L R2, Op1
unsigned short test_char, L R3, Op2_len
unsigned char mask); TROT R2, Op2, Mask
Operands:
v op1 represents the first operand in the hardware instruction.
v op2 and op2_len represent the second operand in the
hardware instruction.
Note: If option LP64 is specified, op2_len is a 64-bit unsigned
integer and the length of the first operand is considered the
same as that of the second operand. Otherwise, both
operands are 32-bit unsigned integers.
v tr_table points to a 512-byte translation table on a
double-word boundary.
Note: It is the user's responsibility to provide a double-word
aligned translation table.
v test_char specifies a 2-byte function character that can be
coded in the translation table for stopping the operation.
v mask specifies the mask encoded in the machine instruction; it
must be a literal value of either 0 or 1.
The return value is the condition code set by the TROT
instruction.
Note: When the condition code is "3", the condition is handled
by the compiler-generated code.
Operands:
v op1 represents the first operand in the hardware instruction.
v op2 and op2_len represent the second operand in the
hardware instruction.
v tr_table points to a 64-KB translation table on a double-word
boundary.
Note: It is the user's responsibility to provide a double-word
aligned translation table.
v test_char specifies a 1-byte function character, that can be
coded in the translation table, for stopping the operation.
v mask specifies the mask encoded in the machine instruction; it
must be a literal value of either 0 or 1.
Note: If option LP64 is specified, both op1_len and op2_len are
64-bit unsigned integers. Otherwise they are 32-bit unsigned
integers.
Operands:
v The bytes of op1 are used as eight-bit arguments to select
function bytes from a list designated by the address of op2.
The first nonzero function byte is inserted in general register
2, and the related argument address in general register 1.
v len specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the left of the first
operand used in the machine instruction.
v The bytes of op1 are selected one by one for translation,
proceeding left to right. op1 remains unchanged in storage.
Calculation of the address of the function byte is performed as
in the __tr instruction. The function byte retrieved from the list
is inspected for a value of zero.
v When the function byte is zero, the operation proceeds with
the next byte of op1.
v When the function byte is nonzero, the operation is completed
by inserting the function byte in general register 2 and the
related argument address in general register 1. Either
condition code 1 or 2 is set, depending on whether the
argument byte is the rightmost byte of op1. Condition code 1 is
set if one or more argument bytes remain to be translated.
Condition code 2 is set if no more argument bytes remain.
Operands:
v op1 represents the first operand in the hardware instruction; it
points to the last byte of the byte string to be translated and
tested.
v op2 represents the second operand in the hardware
instruction; it points to a 256-byte table.
v length specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the left of the first
operand used in the machine instruction; the value is between
0 and 255).
Note: When length is not specified as a literal, an EX
instruction is generated to execute a target TRTR instruction
with length encoded in the register used by the EX
instruction.
v R2 points to a one-byte storage for receiving the function byte
in GPR 2 when the condition code is nonzero.
v R1 points to a pointer field for receiving the address in GPR 1
when the condition code is nonzero.
The return value is the condition code set by the TRTR
instruction.
int __trtt(unsigned short *op1, L GR0, test_char ARCH(7)
unsigned short *op2, L GR1, tr_table
unsigned long op2_len, L R2, Op1
char*tr_table, L R3, Op2_len
unsigned short test_char, TRTT R2, Op2, Mask
unsigned char mask);
Operands:
v op1 represents the first operand in the hardware instruction.
v op2 and op2_len represent the second operand in the
hardware instruction.
Note: If option LP64 is specified, op2_len is a 64-bit unsigned
integer and the length of the first operand is considered the
same as that of the second operand. Otherwise, both
operands are 32-bit unsigned integers.
v tr_table points to a 128-KB translation table on a
double-word boundary.
Note: It is the user's responsibility to provide a double-word
aligned translation table.
v test_char specifies a 2-byte function character that can be
coded in the translation table for stopping the operation.
v mask specifies the mask encoded in the machine instruction; it
must be a literal value of either 0 or 1.
The return value is the condition code set by the TRTT
instruction.
Note: When the condition code is "3", the condition is handled
by the compiler-generated code.
Operands:
v The format of op2 is changed from signed-packed-decimal to
zoned, and the result is placed at op1 location.
v op2 is treated as having the signed-packed-decimal format. Its
digits and sign are placed unchanged in op1 location, using
the zoned format. Zone bits with coding of 1111 are supplied
for all bytes except the rightmost byte, the zone of which
receives the sign of op2. The sign and digits are not checked
for valid codes.
v The result is obtained as if the operands were processed right
to left. When necessary, op2 is considered to be extended on
the left with zeros. If op1 field is too short to contain all digits
of op2, the remaining leftmost portion of op2 is ignored. Access
exceptions for the unused portion of op2 may or may not be
indicated.
v len1 specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the first
operand).
v len2 specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the
second operand).
int __unpka(char *op1, unsigned char op1_len, char *op2); UNPKA Op1D(Op1_len, Op1B), ARCH(6)
Op2D(Op2B)
Operands:
v op1 points to a maximum 32-byte storage area to receive the
unpacked data from the second operand.
v op1_len specifies the length encoded in the machine
instruction (that is, the number of additional bytes to the right
of the first operand).
Note: If op1_len is not a literal, the compiler will issue an EX
instruction that executes a target UNPKA instruction with
op1_len encoded in the register used by the EX instruction.
v op2 points to a 16-byte data string that represents 31 digits
and a sign.
The return value is the condition code set by the UNPKA
instruction.
Operands:
v op1 points to a maximum 64-byte storage area to receive the
unpacked data from the second operand.
v op1_len specifies the length encoded in the machine
instruction (that is, the number of additional bytes to the right
of the first operand).
Notes:
1. If op1_len is not a literal, the compiler will issue an EX
instruction that executes a target UNPKU instruction with
op1_len encoded in the register used by the EX
instruction.
2. If op1_len is not an odd number between 0 and 63, a
specification exception will be triggered by the hardware.
v op2 points to a 16-byte data string that represents 31 digits
and a sign.
Operands:
v Each operand is processed left to right. When the operands
overlap, the result is obtained as if the operands were
processed one byte at a time and each result byte were
stored immediately after fetching the necessary operand
bytes.
v len specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the first
operand).
The function prototypes, associated types, and helper macros will be declared in
builtins.h header file. The argument names and order in the function prototypes
attempt to reflect the description of the hardware instructions in z/Architecture
Principles of Operation. A brief description is provided for each function prototype,
data types, and helper macros.
Note: For every 8-byte PLO operation, there are two interfaces, for example,
__plo_DSCG and __plo_DCSGR. The distinction between these two prototypes is
that the former uses a parameter list to receive all its arguments.
Note: There is no AR mode support. You need to enable support for the unsigned
long long type to use the PLO interface. You also need to enable 64 bit mode
compilation when using PLO built-ins that take 64-bit or 128-bit operands.
Decimal instructions
These hardware built-in functions are intended to provide access to decimal
instructions that are not normally generated by the compiler. For more information
about these instructions, see chapter 8 of the z/Architecture Principles of Operation.
If you want to use any of the following functions, your program must include
builtins.h and be compiled with either the LANGLVL(EXTENDED) option or the
LANGLVL(LIBEXT) options.
Operands:
v op2 (the source), which normally contains one or more decimal
numbers in the signed-packed-decimal or
unsigned-packed-decimal format, is changed to the zoned
format and modified under the control of op1 (the pattern). The
edited result replaces op1.
v len specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the first
operand).
v The length of op2 is determined by the operation according to
the contents of the pattern. The leftmost four bits of each
source byte must specify a decimal-digit code (0000-1001); a
sign code (1010-1111) is recognized as a data exception. The
rightmost four bits may specify either a sign code or a
decimal-digit code. Access and data exceptions are
recognized only for those bytes in op2 which are actually
required.
Operands:
v op2 (the source), which normally contains one or more decimal
numbers in the signed-packed-decimal or
unsigned-packed-decimal format, is changed to the zoned
format and modified under the control of op1 (the pattern). The
edited result replaces op1.
v len specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the right of the first
operand).
v __edmk is identical to __ed except for the additional function of
inserting the address of the result byte in general register 1 if
the result byte is a zoned source digit and the significance
indicator was off before the examination. If no result byte
meets the criteria, general register 1 remains unchanged; if
more than one result byte meets the criteria, the address of
the rightmost such result byte is inserted.
v In the 24-bit addressing mode, the address replaces bits 40-63
of general register 1, and bits 0-39 of the register are not
changed. In the 31-bit addressing mode, the address replaces
bits 33-63 of general register 1, bit 32 of the register is set to
zero, and bits 0-31 of the register remain unchanged. In the
64-bit addressing mode, the address replaces bits 0-63 of
general register 1.
Operands:
v op1 points to a byte string to be tested for a valid
packed-decimal value.
v op1_len specifies the length encoded in the machine
instruction (than is, the number of additional bytes to the left of
the first operand used in the machine instruction); the value is
between 0 and 15.
Note: When op1_len is not specified as a literal, an EX
instruction is generated to execute a target TP instruction with
op1_len encoded in the register used by the EX instruction.
Operands:
v op1 represents the first operand in the hardware instruction, it
points to the location to receive the result.
v len1 specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the left of the sign
byte of the first operand). The value is between 0 and 15.
Note: When len1 is not specified as a literal, an EX
instruction is generated to execute a target ZAP instruction
with len1 encoded in the register used by the EX instruction.
v op2 represents the second operand in the hardware
instruction, it points to the start location.
v len2 specifies the length encoded in the machine instruction
(that is, the number of additional bytes to the left of the sign
byte of the second operand). The value is between 0 and 15.
Note: When len2 is not specified as a literal, an EX
instruction is generated to execute a target ZAP instruction
with len2 encoded in the register used by the EX instruction.
The return value is the condition code set by the ZAP instruction.
If you want to use any of the following instructions, your program must include the
builtins.h header file and be compiled with LANGLVL(EXTENDED) or
LANGLVL(LIBEXT).
Table 97. Floating-point instruction prototypes
PROTOTYPE and Notes Sample Pseudo Assembly MIN ARCH
int __tbdr(double *Op1, int M3, double Op2) TBDR F1,M3,Op2 ARCH(3)
LDR *Op1,F1
The return value is the condition code.
Note: Also see functions that return the negative absolute value and functions
that return the negative absolute value.
_Decimal32 __d32_copysign These functions return the
(_Decimal32 exponent_and_fraction, _Decimal32 sign); absolute value of the first
parameter, with the sign of the
_Decimal64 __d64_copysign second parameter.
(_Decimal64 exponent_and_fraction, _Decimal64 sign);
_Decimal128 __d128_copysign
(_Decimal128 exponent_and_fraction, _Decimal128 sign);
_Decimal32 __d32_sNaN (void); These functions create quiet or
_Decimal64 __d64_sNaN (void); signaling NaNs of the specified
_Decimal128 __d128_sNaN (void); precision, with positive signs and
zero payloads.
_Decimal32 __d32_qNaN (void);
_Decimal64 __d64_qNaN (void);
_Decimal128 __d128_qNaN (void);
All these functions set the instruction M4 bit 20 to 0. If the input is a signaling NaN
it is converted to a quiet NaN.
_Decimal64 __d64_quantize These functions return the
(_Decimal64, _Decimal64, long round_mode); arithmetic value of the first
parameter, with the exponent
_Decimal128 __d128_quantize adjusted to match the second
(_Decimal128, _Decimal128, long round_mode); parameter. They can temporarily
override the current rounding
The round_mode parameter must be a compile-time constant expression. Use mode and use the specified
either of the following: rounding mode.
v DFP_ROUND_USING_CURRENT_MODE (8) to use the current rounding
mode.
v One of the values that can be set by __dfp_set_round_mode to temporarily
override the current rounding mode. See Definitions that support FPC
register-rounding macros on page 536.
bool __d64_same_quantum (_Decimal64, _Decimal64); These functions compare the
bool __d128_same_quantum (_Decimal128, _Decimal128); exponents of two parameters. If
the exponents are the same, the
functions return "true".
long __d64_compare_signaling (_Decimal64, _Decimal64); These functions compare two
long __d128_compare_signaling (_Decimal128, _Decimal128); decimal floating-point values.
Unlike a comparison using
These functions normally return <0, ==0 or >0 to indicate the relation. If either standard equality or relational
value is a NaN, they return "-2" (unordered). operators, they also raise an
Invalid Operation exception
when either operand is either a
quiet Nan or a signaling NaN.
Note: Also see functions that return the absolute value and functions that return
the absolute value of the first parameter with the sign of the second parameter.
long long __d32_to_gpr (_Decimal32); These functions transfer a value
long long __d64_to_gpr (_Decimal64); from an FPR or FPR pair to a
void __d128_to_gprs (_Decimal128, long long *upper, long long *lower); GPR, GPR pair, or four GPRs.
The signs 0xA, 0xC, 0xE, and 0xF will be treated as positive, and 0xB and 0xD as
negative.
These functions:
v Determine the exponent type (zero, subnormal, normal, infinity, quiet NaN or
signaling NaN) and sign of the value.
v Return a long integer that indicates whether the exponent matches the mask
specifications. If there is a match, the function returns "1"; if there is no match,
the function returns "0".
Note: The mask must be a constant expression at compile time. See Test
Data Class masks on page 537.
Also see test data group functions.
These functions:
v Determine the exponent type (safe zero, subnormal, normal with no leading
zero, or an infinity or NaN), as well as the sign and first digit of the parameter.
Notes:
1. A "safe zero" has leading zero digits and a non-extreme exponent.
2. A "subnormal" can appear as either an extreme non-zero or a safe
non-zero.
v Return a long integer that indicates whether the exponent matches the mask
specifications. If there is a match, the function returns "1"; if there is no match,
the function returns "0".
Note: The mask must be a constant expression at compile time. For the
statements that define these masks, see Test Data Group masks on page 537.
Also see the test data class functions.
long __d64_biased_exponent (_Decimal64); These functions return the
long __d128_biased_exponent (_Decimal128); exponent of the parameter as an
integer.
Notes:
1. Also see functions that return the digits and sign of the first parameter with the
biased exponent of the second parameter.
2. See Biased exponent definitions on page 536.
unsigned long long __d64_to_unsigned_BCD (_Decimal64); These functions convert the
lower digits of the parameter to
void __d128_to_unsigned_BCD (_Decimal128, unsigned packed format.
bool CorF,
unsigned long long *upper,
unsigned long long *lower);
Positive values will be given the sign 0xC if CorF is false or 0xF if it is true.
Negative values will be given the sign 0xD.
If both exponents are finite, these return "<0", "==0" or ">0" to indicate the relation
between the exponents.
If one exponent is infinite and the other is finite, they return "-2" (unordered).
Exceptions:
v When the input is a zero, the
return value is "0".
v When the input is an infinity,
the return value is "-1".
v When the input is a quiet
NaN, the return value is "-2".
v When the input is a signaling
NaN, the return value is "-3".
void __SFASR (unsigned long); This function modifies the
Floating Point Control (FCP)
Note: See Definitions that support FPC register-rounding macros. register, and could raise an
exception.
#define DFP_ROUND_TO_NEAREST_WITH_TIES_TO_EVEN 0
#define DFP_ROUND_TOWARD_ZERO 1
#define DFP_ROUND_TOWARD_POSITIVE_INFINITY 2
#define DFP_ROUND_TOWARD_NEGATIVE_INFINITY 3
#define DFP_ROUND_TO_NEAREST_WITH_TIES_AWAY_FROM_ZERO 4
#define DFP_ROUND_TO_NEAREST_WITH_TIES_TOWARD_ZERO 5
#define DFP_ROUND_AWAY_FROM_ZERO 6
#define DFP_ROUND_TO_PREPARE_FOR_SHORTER_PRECISION 7
#define DFP_ROUND_USING_CURRENT_MODE 8
DFP_Z_DATA_CLASS_POSITIVE_ZERO
DFP_Z_DATA_CLASS_NEGATIVE_ZERO
DFP_Z_DATA_CLASS_POSITIVE_SUBNORMAL
DFP_Z_DATA_CLASS_NEGATIVE_SUBNORMAL
DFP_Z_DATA_CLASS_POSITIVE_NORMAL
DFP_Z_DATA_CLASS_NEGATIVE_NORMAL
DFP_Z_DATA_CLASS_POSITIVE_INFINITY
DFP_Z_DATA_CLASS_NEGATIVE_INFINITY
DFP_Z_DATA_CLASS_POSITIVE_QUIET_NAN
DFP_Z_DATA_CLASS_NEGATIVE_QUIET_NAN
DFP_Z_DATA_CLASS_POSITIVE_SIGNALING_NAN
DFP_Z_DATA_CLASS_NEGATIVE_SIGNALING_NAN
To get a Test Data Class function to perform a desired test more efficiently, OR
several of supplied masks together. For example, to determine if the exponent of a
parameter is any positive value, OR the following masks together:
v DFP_Z_DATA_CLASS_POSITIVE_ZERO
v DFP_Z_DATA_CLASS_POSITIVE_SUBNORMAL
v DFP_Z_DATA_CLASS_POSITIVE_NORMAL
v DFP_Z_DATA_CLASS_POSITIVE_INFINITY
v DFP_Z_DATA_CLASS_POSITIVE_QUIET_NAN
v DFP_Z_DATA_CLASS_POSITIVE_SIGNALING_NAN
To get a Test Group Class function to perform a desired test more efficiently, OR
several of supplied masks together. For example, to determine if a parameter is an
extreme exponent, OR the following masks together:
v DFP_Z_DATA_GROUP_POSITIVE_ZERO_WITH_EXTREME_EXPONENT
v DFP_Z_DATA_GROUP_NEGATIVE_ZERO_WITH_EXTREME_EXPONENT
If you want to use any of the functions in Table 101, your program must include
builtins.h and be compiled with either the LANGLVL(EXTENDED) option or the
LANGLVL(LIBEXT) and FLOAT(HEX) options.
Note: Some of these instructions also require that the ARCH option is set to a
minimum level.
Table 101. Hexadecimal floating-point instruction prototypes
PROTOTYPE and Notes Sample Pseudo Assembly MIN ARCH
int __cfer(int *Op1, int M3, float Op2) CFER R2,M3,Op2 ARCH(3)
LR *Op3,R2
The return value is the condition code.
int __cfdr(int *Op1, int M3, double Op2) CFDR R2,M3,Op2 ARCH(3)
LR *Op3,R2
The return value is the condition code.
int __cfxr(int *Op1, int M3, long double Op2) CFXR R2,M3,Op2 ARCH(3)
LR *Op3,R2
The return value is the condition code.
float __fier(float Op2) FIER F1,Op2 ARCH(3)
If you want to use any of the functions in Table 102, your program must include
builtins.h and be compiled with either the LANGLVL(EXTENDED) option or the
LANGLVL(LIBEXT) and FLOAT(IEEE) options.
Table 102. Binary floating-point instruction prototypes
PROTOTYPE and Notes Sample Pseudo Assembly MIN ARCH
int __cfdbr(int *Op1, int M3, double Op2) CFDBR R2,M3,Op2 ARCH(3)
LR *Op3,R2
The return value is the condition code.
int __cfebr(int *Op1, int M3, float Op2) CFEBR R2,M3,Op2 ARCH(3)
LR *Op3,R2
The return value is the condition code.
int __cfxbr(int *Op1, int M3, long double Op2) CFXBR R2,M3,Op2 ARCH(3)
LR *Op3,R2
The return value is the condition code.
The compiler language additions for C99 do not apply to C++ applications because
the C++ standard does not mandate support for C99.
When you want to obtain C99 extended support, do either of the following:
v Use the c89 utility with the LANGLVL(EXTC99) option.
v Use the c99 command with the LANGLVL(EXTENDED) option.
You can also obtain C99 behavior with the XL C++ compiler by using the following
KEYWORD and LANGLVL suboptions:
v KEYWORD(RESTRICT) or LANGLVL(EXTENDED), which enable the restrict
qualifier for improved aliasing information.
v LANGLVL(UCS), which enables support for valid universal character name
ranges.
v LANGLVL(C99__FUNC__) or LANGLVL(EXTENDED), which enable the __func__
identifier for debugging assistance.
C++ applications can also access C99 run-time library functions by using feature
test macros. See Feature test macros that control C99 interfaces in XL C++
applications.
To expose C99 interfaces, C++ applications can define the appropriate feature test
macros before including the identified header:
XL C++ applications that need C99 interfaces must use the required feature macros
or, when ambiguous definitions exist, global namespace syntax (when ambiguous
definitions exist).
Figure 156 on page 547 is an example of code that requires the global namespace
syntax. In this example, std:: is not allowed for C99 interfaces.
Figure 156. Example of code that requires the global namespace syntax
For complete details about the normative references and base documents that
underlie Single UNIX Specification, Version 3, see the introduction to the Base
Definitions volume of IEEE Std 1003.1-2001.
In z/OS V1R9, the XL C/C++ Run-Time Library provides a high degree of support
for the Single UNIX Specification, Version 3. With the exception of the list of known
non-compliances, library users may expect most conforming SUSv3 applications to
compile and run on the z/OS platform in conformance with the standard.
Before z/OS V1R9, other feature test macros enabled subsets of SUSv3
functionality. The _UNIX03_SOURCE macro has been used to expose a number of
SUSv3 functions and constants missing from the XL C/C++ Run-Time Library,
before the more general implementation of SUSv3 in z/OS V1R9. The macro is
additive, in that for a given target release, the compiler exposes all symbols
exposed by _UNIX03_SOURCE for the target and any prior release. Given that any
symbol it exposes is part of XSI, the _UNIX03_SOURCE macro is subsumed by
_XOPEN_SOURCE 600, and is redundant when the latter is defined.
Program developers have the option of writing SUSv3 applications that still use the
old threads behavior. An application may override the implicit XSI threads behavior
by defining both _OPEN_THREADS and _XOPEN_SOURCE 600, if there is a
reason to maintain the previous POSIX.4a, draft 6 behavior. On the other hand,
concurrent definition of the _UNIX03_THREADS and _OPEN_THREADS macros is
not allowed and will generate a compile-time error message.
In addition to the feature test macros controlling that symbols are exposed in the
system headers, two new environment variables determine behaviors at run time. In
both cases, these variables impact error handling, enabling paths to provide errno
information and fail a function for errors that were not previously detected. Default
behavior for affected functions is unchanged. The new behavior must be explicitly
enabled through a new setting of the environment variable.
v _EDC_SUSV3 - Default is 0. For new behavior, set to 1.
v _EDC_EOVERFLOW - Default is NO. For new behavior, set to YES.
Beyond these obvious differences in the library, there are other behavioral
differences. One of the more notable differences is the change in the return value of
most threads functions. The POSIX.4a, draft 6 threads behavior indicates a return
of -1 on failure with the error code set in errno. In SUSv3, the majority of these
functions now return the error code on failure rather than a value of -1. With the
exception of pthread_getspecific(), the z/OS implementation will continue to set
errno in addition to returning the error code.
For complete details about syntactical differences and special behavior of functions,
see the individual function descriptions in z/OS XL C/C++ Run-Time Library
Reference.
Chapter 35. Writing applications for Single UNIX Specification, Version 3 551
Symbols withdrawn in SUSv3
Functions, headers, and external variables that comprised the Legacy Feature
Group in Single UNIX Specification, Version 2 are removed and not part of SUSv3.
Also, any symbols that were marked obsolescent in Version 2 have been removed.
Legacy Option bcmp(), bcopy(), bzero(), ecvt(), fcvt(), ftime(), gcvt(), getwd(),
index(), mktemp(), rindex(), utimes(), wcswcs()
Implementation compliance
IBM makes no claim that the z/OS platform complies with Single UNIX
Specification, Version 3 or that the z/OS XL C/C++ Run-Time Library contains a
complete implementation of the C programming interfaces and headers found in the
Base Definitions of this standard. While the library implementation comes close, a
number of known discrepancies remain in z/OS R9. The following summary lists
those discrepancies from SUSv3 behavior that have been identified.
Chapter 35. Writing applications for Single UNIX Specification, Version 3 553
554 z/OS V1R13.0 XL C/C++ Programming Guide
Chapter 36. Saved compile-time options information
Following a successful compilation, the application executable file will always
include compile-time options information in a compact form. This information
supports determination of run-time problems. Saved compile-time options
information includes:
v Fixed subset of compilation options for each source file compiled.
v Source file name for each source file compiled.
The source file name of the compilation unit for which the options are saved is
the first entry in the source file and component version information block.
For names longer than 252 characters, only the last 252 bytes of the source
file name are provided.
The name does not include path information for UNIX files and only the
member name is provided for partitioned data sets.
A dummy name "IPA Link" is provided for programs optimized with IPA.
v Version information for each compiler component that is active during the
compilation.
You can use the version information to determine the compile-time
maintenance level. If the maintenance level is not the most current, there
might be an update available that solves the problem.
This version information will be the same as the information produced using
the PHASEID compiler option. For further information on the PHASEID
compiler option, see z/OS XL C/C++ User's Guide.
Although information about the debug writer is not included because the
debug writer runs after the code generation, that information is available
inside the .dbg file.
A compilation flag in the Program Prolog Area-2 (PPA2) indicates the presence of
saved options information. If the service string is specified, the saved option string
follows it. Otherwise the saved options information follows the time stamp string.
For more information on PPA2, see z/OS Language Environment Vendor Interfaces.
/* offset: 4 */
/* offset: 8 */
/* offset: 12 */
/* offset: 16 */
/* offset: 20 */
/* offset: 24 */
} SOS_t;
You may also find useful information in the IBM Redbook Tuning Large C/C++
Applications on z/OS UNIX System Services. This Redbook is available on the web
at:
http://www.redbooks.ibm.com/abstracts/sg245606.html.
If you follow the guidelines in this information, you will create code that performs
well on execution and can be compiled efficiently.
Be aware that in C++, more than in C, certain coding constructs can lead to n-to-1,
m-to-1 or even z-to-1 code expansion. You can create well-performing code with
these constructs, but you must use them carefully and appropriately, especially
when you are writing critical-path or high-frequency code.
When writing performance-critical C++ programs, ensure that you understand why
problems might occur and what you can do about them if you use any of the
following high-level language constructs:
Note: You can ensure that all memory and storage requests are
properly optimized by following the instructions given in Chapter 40,
Improving performance with compiler options, on page 589.
Note: The compiler expects that the source code conforms to the ANSI aliasing
rules when the ANSIALIAS option is used. This option is on by default.
The ANSI aliasing rules are part of the ISO C Standard, and state that a pointer can
be dereferenced only to an object of the same type or compatible type. Because
the z/OS XL C/C++ compiler follows these rules during optimization, the developer
must create code that conforms to the rules.
Conversely, your code breaks the aliasing rules if it casts a float to an int and
then assigns it to the int pointer.
You can cast and mix data types as long as you are careful how you intermix
values and their pointers in your code. The compiler follows the ANSI aliasing rules
to determine:
v Which variables must be stored into memory before you read a value through a
pointer
v Which variables must be updated from memory after you have updated a value
through a pointer
When you use the NOANSIALIAS option, the compiler generates code to
accommodate worst-case assumptions (for example, that any variable could have
been updated by the store through a pointer). This means that every variable (local
and global) must be stored in memory to ensure that any value can be read through
a pointer. This severely limits the potential for optimization.
int ei1;
float ef1;
int *eip1;
float *efp1;
float exmp1 ()
{
ef1 = 3.0;
ei1=5;
*efp1 = ef1;
*eip1 = ei1;
return *efp1;
}
Table 107 on page 569 shows the difference between code generated with, and
without, ANSI aliasing.
* { * {
* ef1 = 3.0; * ef1 = 3.0;
L r4,=A(@CONSTANT_AREA)(,r3,94) L r2,=A(@CONSTANT_AREA)(,r3,110)
L r2,=Q(EF1)(,r3,98) L r14,_CEECAA_(,r12,500)
LD f0,+CONSTANT_AREA(,r4,0) L r4,=Q(EF1)(,r3,114)
L r14,_CEECAA_(,r12,500) L r15,=Q(EFP1)(,r3,118)
L r15,=Q(EFP1)(,r3,102) LD f0,+CONSTANT_AREA(,r2,0)
L r4,=Q(EIP1)(,r3,106)
L r1,#retvalptr_1(,r1,0)
STE f0,ef1(r2,r14,0)
L r15,efp1(r15,r14,0)
* ei1=5; * ei1=5;
L r2,=Q(EI1)(,r3,110) L r2,=Q(EI1)(,r3,122)
LA r0, STE f0,ef1(r4,r14,0)
L r4,eip1(r4,r14,0)
v Whenever their values cannot change, qualify pointers and their targets as
constants, ensuring that you mark the appropriate part as const.
If only the pointer is constant, you can use a statement that is similar to the
following:
If only the target is constant, use a statement similar to either of the following:
If both the target integer and the pointer are constants, use a statement
similar to either of the following:
v Use the ROCONST compiler option. The ROCONST option works with both C
and C++. This option causes the compiler to treat variables that are defined as
const as if they are read-only. In some cases, these variables will be stored in
read-only memory. For more information, see ROCONST on page 593.
v For global variables initialized to large read-only arrays or strings: Use a
#pragma variable to ensure that they are implemented as read-only csects. This
prevents them from being initialized at load time.
Example: For large initialized arrays
# pragma variable (arrayname, norent)
v In a read-only situation: If you are using the value through a pointer, use a
temporary automatic variable. The difference in the source code is significant, as
shown in the following table:
Using variables
When choosing variables and data structures for your application, keep the
following guidelines in mind:
v Use local variables, preferably automatic variables, as often as possible.
The compiler can accurately analyze the use of local variables, while it has to
make several worst-case assumptions about global variables, which hinders
optimizations. For example, if you code a function that uses external variables,
and calls several external functions, the compiler assumes that every call to an
external function could change the value of every external variable.
v If none of the function calls affect the global variables being used and you have
to read them frequently with function calls interspersed, copy the global variables
to local variables and use these local variables to help the compiler perform
optimizations that otherwise would not be done.
Using IPA can improve the performance of code written using global variables,
because it coalesces global variables. IPA puts global variables into one or more
structures and accesses them using offsets from the beginning of the structures.
For more information, see Using the IPA option on page 598.
v If you need to share variables only between functions within the same
compilation unit, use static variables instead of external variables. Because static
variables are visible only in the current source file, they might not have to be
reloaded if a call is made to a function in another source file.
Organize your source code so references to a given set of externally defined
variables occur only in one source file, and then use static variables instead of
external variables.
In a file with several related functions and static variables, the compiler can
group the variables and functions together to improve locality of reference.
Use a local static variable instead of an external variable or a variable defined
outside the scope of a function.
The #pragma isolated_call preprocessor directive can improve the run-time
performance of optimized code by allowing the compiler to make fewer
assumptions about the references to external and static variables. For more
information, see isolated_call in z/OS XL C/C++ Language Reference.
Coalescing global variables causes variables that are frequently used together to
be mapped close together in memory. This strategy improves performance in the
same way that changing external variables to static variables does.
v Group external data into structures (all elements of an external structure use the
same base address) or arrays wherever it makes sense to do so.
The #pragma isolated_call preprocessor directive lists functions that do not modify
global storage. You can use it to improve the run-time performance of optimized
code. For more information, see isolated_call in z/OS XL C/C++ Language
Reference.
As the following example shows, you can declare a function without providing
information about the number and types of its parameters.
Because the function declaration has no parameter information, the compiler is not
required to diagnose parameter mismatch. You can call this function, passing it any
number of arguments of any type, but the compilation will not be guaranteed to
work if the function is not defined to receive the arguments as passed, due to
differences in linkage conventions. In the worse case, when the z/OS XL C/C++
compiler attempts inlining of such ill-formed function calls, it may get into an
unrecoverable condition and the compilation is halted.
Note: Such a mismatch may sometimes turn out not to be an issue, depending on
the ABI; for example, if the ABI happens to allow both pointers and integers passed
using general purpose registers. Even in this case, there is no guarantee that the
optimized code would work as expected due to ambiguous information received by
the compiler.
Coding expressions
When coding expressions, consider the following recommendations:
v When components of an expression are duplicate expressions, code them either
at the left end of the expression or within parentheses, as shown in the following
example.
The compiler can recognize x*y*z and x + y as duplicate expressions when they
are coded in parentheses or coded at the left end of the expression.
It is the best practice to avoid using pointers as much as possible within
high-usage or other performance-critical code.
Note: The compiler might not be able to optimize duplicate expressions if either
of the following are true:
Coding conversions
Avoid forcing the compiler to convert numbers between integer and floating-point
internal representations. Conversions require several instructions, including some
double-precision floating-point arithmetic. When you must use mixed-mode
arithmetic, code the integral, floating-point, and decimal arithmetic in separate
computations wherever possible. Figure 158 shows an example.
int main(void)
{
int i;
float array[10]={1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0}
float x = 1.0;
for (i = 0; i < 10; i++)
{
array[i] = array[i]*x; /* No conversions needed */
x = x + 1.0;
}
return(0);
}
Arithmetical considerations
Wherever possible, use multiplication rather than division. For example,
x*(1.0/3.0); /* 1.0/3.0 is evaluated at compile time */
If you divide many values by the same number in your code: Assign the divisors
reciprocal to a temporary variable and then multiply by that variable.
enum animals {
ant
cat,
dog,
robin,
last_animal = INT_MAX;
};
For if statements:
v Order the if conditions efficiently; put the most decisive tests first and the most
expensive tests last.
By performing the most common tests first, you increase the efficiency of your
code; fewer tests are required to meet the test conditions.
if (command.is_classg &&
command.len == 6 &&
!strcmp (command.str, "LOGON")) /* call to strcmp() most expensive */
logon ();
Table 109 on page 576 lists analogous data types and shows which data types are
more expensive to reference.
. if (b.xval == 3)
.
.
if (b.xmany + 5 == x) /* inefficient because it does not */
. /* fall on a byte boundary */
.
.
. if (b.xbool)
.
.
Note: At NOOPT the compiler might not expand all built-in functions.
v You can use the following macros (rather than their equivalent functions), if you
include the ctype.h header file.
v If you are using the __cs1 or __cds1 function with arguments other than the ones
declared in the prototypes in stdlib.h, the compiler might not be able to
generate correct code at OPT. In this case, use the NOANSIALIAS option.
Note: As of z/OS V1R2, the new forms for cs() and cds() are __cs1 and
__cds1, respectively. For more information, see Chapter 33, Using hardware
built-in functions, on page 503.
v Typically, arrays are compared element-by-element, using a loop. When you
compare two arrays for equality, replace the loop with the memcmp() library
function. This could result in the execution of many machine instructions being
replaced by the execution of a only a few machine instructions.
if (i == 1000)
/* arrays are equal */
v Neither the C nor the C++ language allows structure comparison, because
structures might contain padding bytes with undefined values. In cases where
you know that no padding bytes exist, use memcmp() to compare structures. The
z/OS AGGREGATE compiler option for C is used to obtain a structure and union
map.
v The memset() library function should be used to initialize a character buffer and
to initialize an array to a repetitive byte pattern (such as zeros).
v Use memset() to clear structs, unions, arrays or character buffers as follows:
char c[10];
v Use the alloca() function to automatically allocate memory from the stack. This
function frees memory at the end of a function call when z/OS XL C/C++
collapses the stack. For more information, see alloca in z/OS XL C/C++
Run-Time Library Reference.
v When using strlen(), do not hide size information. Less code is needed for
strlen() when the upper bound is known at compile time.
char small_str_array[100];
char
. *small_str_ptr;
.
.
x = strlen(small_str_ptr); /* unknown upper bound */
x = strlen(small_str_array); /* better */
If you try to replace all strcmp() calls with a memcmp() call taking a strlen()
value of one of the strings, the result might be an attempt to access protected
storage which follows the shorter string. Such an attempt could cause an
exception because memcmp() does not stop comparing strings when it encounters
a null in one of the strings.
v Whenever possible, replace wcsxxx() functions with their corresponding
wmemxxx() functions, because wmemxxx() functions are more efficient. You can
minimize the execution cost of a wcsxxx() function by using fixed-length wide
character buffers to save the length of incoming wide character strings (including
null terminators) for subsequent calls to wmemcpy() and wmemcmp().
If you are using C, consider calling other C modules with fetch() or DLLs instead
of system(). A system() call does full environment initialization and termination, but
a fetched module and a DLL share the environment of the calling routine. If you are
using C++, consider using DLLs.
Use of DLLs requires more overhead than use of statically-bound function calls. You
can test your code to determine whether you can afford this extra overhead. First,
write the code so that it can be built to implement either a single module or a DLL.
Next build your application both ways, and time both applications to see if you can
handle the difference in execution time. For best DLL performance, structure the
code so that once a function in the DLL is called, it does all it needs to do in the
DLL before it returns control to the caller.
You can also choose how to implement DLLs. If you are using C, you can choose
between:
v The XPLINK compiler option
v The DLL compiler option (which is used with the NOXPLINK option)
Note: In C++, DLL is not an option, but a default. When you use the XPLINK
option, the compiler loads and accesses DLLs faster than it would if you used the
DLL option.
Note: DLL names are case sensitive in the UNIX file system.
v When you are using IPA, export only those subprograms (functions and C++
methods) or variables that you need for the interface to the final DLL.
If you export subprograms or variables unnecessarily (for example, by using the
EXPORTALL option), you severely limit IPA optimization. In this case, global
variable coalescing and pruning of unreachable or 100% inlined code does not
occur. Before it can be processed by IPA, DLLs must contain at least one
subprogram. Any attempt to process a data-only DLL will result in a compilation
error.
v The suboption NOCALLBACKANY of the compiler option DLL is more efficient
than the CALLBACKANY suboption.
The CALLBACKANY option calls a Language Environment routine at run time.
This run-time service enables a C or C++ NOXPLINK DLL routine to call a C
NOXPLINK NODLL routine, which use function pointers that point to actual
function entry points rather than function descriptors.
Note: Compiling source with the DLL option will often cause a degradation in
performance when compared against a statically bound application compiled
without that option.
The option_override pragma can be also used to change the spill size for a function. If
the compiler requests that you to increase the spill size for a specific function, you
should use the option_override pragma instead of the SPILL compiler option, which
increases the spill size for all functions in the compile unit and can have a negative
performance impact on the generated code.
Note: The spill size should not be increased unless requested by a compiler message.
#pragma reachable Declares that the point in the program after the specified function can be the target of a
branch from some unknown location. That is, you can reach the instruction after the
specified function from a point in your program other than the return statement in the
named function. This directive provides information to the compiler that enables it to
explore additional opportunities for optimization.
#pragma strings Indicates if strings should be placed in read-only memory or read/write memory. You can
reduce the memory requirements for DLLs by specifying #pragma strings(readonly),
so that string literals are not placed in the writable static area. Alternatively, you can also
use the ROSTRING compiler option (the default), which informs the compiler that string
literals are read-only.
#pragma unroll Informs the compiler how to perform loop unrolling on the loop body that immediately
follows it. The directive works in conjunction with the UNROLL compiler option to provide
you with some control over the application of this optimization techique. The pragma
directive overrides the UNROLL on page 594 or NOUNROLL compiler option in effect
for the designated loop.
You can reduce the memory requirements for DLLs by specifying #pragma
variable(var_name,NORENT), so that constant variables are not placed in the writable
static area.
Alternatively, you can use the ROCONST compiler option to inform the compiler that
constant variables are not to be placed in the writable static area.
The built-in functions described in this chapter behave exactly the same as those in
the C library. The compiler will generate inline code for these functions if the
appropriate header file is included in the source. For more information, see built-in
functions in z/OS XL C/C++ Run-Time Library Reference.
If you have included the header files but you want to call either the library version of
the function or your own version, enclose the function name in parentheses when
you make the call. For example, if you wanted to call only memcpy from the header
file and use the built-in functions for other memory-related functions, code the
function call as follows:
(memcpy)(buf1, buf2, len)
Table 111. C-library built-in functions
Built-In Function Header File
abs() stdlib.h
alloca() stdlib.h
ceil() math.h
ceilf() math.h
ceill() math.h
Note: The compiler only attempts to generate inline code for ceil(), ceilf(), and ceill()
when the OPTIMIZE(2) compiler option is used.
decabs() decimal.h
decchk() decimal.h
decfix() decimal.h
fabs() math.h
Note: The compiler only attempts to generate inline code for fabs() when the OPTIMIZE(2)
compiler option is used.
floor() math.h
floorf() math.h
floorl() math.h
Note: The compiler only attempts to generate inline code for floor(), floorf(), and
floorl() when the OPTIMIZE(2) compiler option is used.
fortrc() stdlib.h
memchr() string.h
memcpy() string.h
memcmp() string.h
memset() string.h
strcat() string.h
strchr() string.h
strcmp() string.h
strcpy() string.h
strlen() string.h
Platform-specific functions
The built-in functions in this section are related to C-library functions that are z/OS
specific. The full description of each function can be found in z/OS XL C/C++
Run-Time Library Reference.
Table 112. Platform-specific built-in functions
Built-In Function Header File
cds() stdlib.h
cs() stdlib.h
Note: cds() and cs() are masking macros. The system header expands them to the __cds
and __cs. It is advisable to use the hardware functions instead of the library functions
whenever possible. For more information, see Table 87 on page 503.
When you include the header file stdio.h, macros are defined for getc(), putc(),
getchar(), and putchar(). To use the function calls instead of the macro calls, use
#undef after the stdio.h header file is included. If you are working with a threaded
application, these macros are automatically undefined forcing the application to use
function calls, which are thread safe. The feature test macro _ALL_SOURCE causes
these four macros to be undefined. However, if you require _ALL_SOURCE, and want
these macros to be used in a non multi-threaded application, you can use feature
test macro _ALL_SOURCE_NOTHREADS.
When using one of the z/OS UNIX shells, an MVS memory file may or may not
make an efficient temporary file. This depends on whether your z/OS UNIX XL
C/C++ application program uses fork() and exec() functions to call another
program to run in a child process. The child process does not inherit MVS memory
files after an exec() function. For more information, see Accessing MVS data sets
on page 585.
One example of a subtle coding error is to type cast a pointer variable incorrectly.
The compiler assumes ISO conformance when doing optimization. If your program
does not conform, you may receive undefined results. For more information, see
ANSI aliasing rules on page 567 and Using ANSI aliasing rules on page 569.
OPTIMIZE(3) may place instructions onto execution paths where they will be
executed when they may not have been according to the actual semantics of the
program. For example, a loop-invariant floating-point computation that is found on
The same is true for moving loads. Although a load through a pointer is never
moved, loads off the static or stack base register are considered movable using
OPTIMIZE(3). Loads in general are not considered to be absolutely safe using
OPTIMIZE(2) because a program can contain a declaration of a static array a of 10
elements and load a[60000000003], which could cause a segmentation violation.
The same concepts apply to scheduling. In Figure 159, using OPTIMIZE(2), the
computation of b+c is not moved out of the loop for two reasons:
v It is considered dangerous because it is a floating-point operation
v It does not occur on every path through the loop
.
.
.
int i;
float a[100], b, c;
for (i=0; i < 100; i++)
{
if (a[i] < a[i+11])
a[i] = b + c;
. }
.
.
ANSIALIAS
The ANSIALIAS option specifies whether type-based aliasing is to be used during
optimization. Type-based aliasing will improve optimization. For more information
about ANSI aliasing, see ANSI aliasing rules on page 567 and Using ANSI
aliasing rules on page 569.
COMPRESS
Use the COMPRESS option to suppress the generation of function names in the
function control block to reduce the size of your application's load module. The
COMPACT
When the COMPACT option is active, the compiler favors optimizations that tend to
limit the growth of the code. Depending on your specific program, the object size
may increase or decrease and the execution time may increase or decrease. Any
time you change your program, or change the release of the compiler, you should
re-evaluate your use of the COMPACT option.
EXPORTALL
Use the EXPORTALL option only if you want to export all external functions and
variables in the source file so that a DLL application can use them. If you only need
to export some externally defined functions and variables, use the #pragma export
directive or the _Export C++ keyword instead of EXPORTALL.
If you use EXPORTALL, you can severely limit IPA optimization, and can cause
your modules and WSA to be larger than necessary.
IGNERRNO
The IGNERRNO option informs the compiler that the program is not using errno.
This allows the compiler more freedom to explore optimization opportunities for
certain library functions (for example, sqrt). You need to include the system header
files to get the full benefit of the IGNERRNO option.
IPA
The IPA option specifies that the compiler should use interprocedural analysis when
optimizing this module. This can lead to significant performance improvements. For
more information, see Using the IPA option on page 598.
LIBANSI
The LIBANSI option specifies whether or not all functions with the name of an ANSI
C library function are in fact the ANSI functions. This allows the compiler to
generate code based on existing knowledge concerning the behavior of the
function. For example, the compiler will determine whether any side effects are
associated with a particular library function. LIBANSI can provide additional benefits
when used in conjunction with IGNERRNO.
The OBJECTMODEL compiler option has the following suboptions to set the type of
object model, either COMPAT or IBM.
COMPAT uses the object model compatible with previous versions of the
compiler. The COMPAT object model is not available when the
LP64 compiler option has been specified.
IBM uses the new object model and should be selected if you want
improved performance. This is especially true for class hierarchies
with many virtual base classes. The size of the derived class is
considerably smaller and access to the virtual function table is
faster.
All classes in the same inheritance hierarchy must have the same object model.
ROCONST
The ROCONST option specifies that the const qualifier is respected by the
program. Variables that are defined with the const keyword are not overridden by a
casting operation. When you use this option in C with the DLL option, you must
ensure that no const global variables (static or external) are initialized with the
address of an entity from another compile unit.
ROSTRING
The ROSTRING option specifies that strings are placed in read-only memory. It has
the same effect as the #pragma strings(readonly) directive.
RTTI
If you are not using RTTI/dynamic casts in your program, compile with the NORTTI
option.
SPILL
When you specify a very large spill size, you can force the compiler to generate
less than optimal code. For this reason, you might not want to specify the large spill
size for an entire application. For example, either you can specify the large spill size
for only the specific compilation unit that needs it or you can use the #pragma
option_override directive.
STRICT_INDUCTION
With strict induction, induction (loop counter) variables are not optimized. This
guards against problems that can occur if an optimized induction variable overflows.
UNROLL
The UNROLL option gives the user the ability to control the amount of loop unrolling
done by the compiler. Loop unrolling exposes instruction level parallelism for
instruction scheduling and software pipelining and thus can improve a program's
performance. It should be used in conjunction with 581.
Inlining
Inlining replaces certain function calls with the actual code of the function and is
performed before all other optimizations. Not only does inlining eliminate the linkage
overhead, it also exposes the entire called function to the caller, which enables the
compiler to better optimize your code.
Note: See Inlining under IPA on page 597 for information on differences in inlining
under IPA.
Consider the C examples CCNGOP1 and CCNGOP2, shown in Table 113 on page
595. CCNGOP1 specifies the #pragma inline directive for the function
which_group(). If you use the OPTIMIZE option when you compile CCNGOP1, the
compiler determines that CCNGOP1 is equivalent to CCNGOP2.
j = which_group (7);
return(j);
}
Selective mode enables you to specify, in your source code, the functions that you
do, and do not, want inlined.
If you know which functions are frequently invoked from within a compilation unit,
you can mark them for inlining:
v For a C program, add the appropriate #pragma inline directives in your source
and compile with INLINE (NOAUTO,REPORT,,).
v For a C++ program, add inline keywords to your source and compile with
INLINE (NOAUTO,REPORT,,).
If your code contains complex macros, the macros can be made into static routines
that are marked to be inlined at no execution-time cost. All static routines that are
interfaces to a data object can be placed in a header file.
Note: When functions become too large, run-time performance can degrade.
Under the z/OS UNIX shell, to provide assistance in choosing which routines to
inline, use the c89 -W command to pass the INLRPT option to the z/OS XL C/C++
compiler. At NOOPT, you will also need to specify the INLINE option. The default at
NOOPT is NOINLINE.
You can get the same value at OPT for a C program passing the INLRPT option to
the z/OS XL C/C++ compiler as follows:
c89 -2 -W "0,inlrpt"
Note: Inlining debugging functions or functions that are rarely invoked can degrade
performance. Use the #pragma noinline directive to instruct the automatic inliner to
not inline these types of functions. The #pragma inline and the #pragma noinline
directives and the inline keyword are honored by automatic inlining regardless of
the limit and threshold you have specified. For more information, see inline in
z/OS XL C/C++ Language Reference.
For more information about IPA, see Using the IPA option on page 598.
The only compiler that currently supports the XPLINK compiler option is the z/OS
C/C++ compiler. All COBOL and PL/I programs are non-XPLINK. Calls between
COBOL or PL/I and XPLINK-compiled C/C++ are cross-linkage calls and will incur
the stack swapping overhead.
For more information on making ILC calls with XPLINK, refer to z/OS Language
Environment Writing Interlanguage Communication Applications.
Applications that use Language Environment facilities that are not supported in an
XPLINK environment, or that use products that are not supported in an XPLINK
environment (for example, CICS), can not be recompiled as XPLINK applications.
IPA also supports Program-directed feedback (PDF). The PDF suboptions allow the
compiler to use information from training runs when optimizing the code. The
compiler can then focus its optimizations on the most executed parts of the code
and move low-priority code out of the critical path.
Interprocedural analysis through the IPA compiler option improves upon the limited
interprocedural analysis described above. When you invoke interprocedural analysis
through the IPA option, the compiler performs optimizations across the entire
program. It also performs optimizations not otherwise available with the C/C++
compiler. The types of optimizations performed include:
Inlining across compilation units
Inlining replaces certain function calls with the actual code of the function.
Inlining not only eliminates the linkage overhead but also exposes the entire
function to the caller and thus enables the compiler to better optimize your
code.
Program partitioning
Program partitioning improves performance by reordering functions to
exploit locality of reference. Functions that call each other frequently will be
closer together in memory.
Coalescing of global variables
The compiler puts global variables into one or more structures and
accesses the variables by calculating the offsets from the beginning of the
structures. This lowers the cost of variable access and exploits data locality.
Code straightening
Code straightening streamlines the flow of your program.
Unreachable code elimination
Unreachable code elimination removes unreachable code within a function.
Call graph pruning of unreachable functions
Call graph pruning of unreachable functions removes code that is 100%
inlined or never referenced.
Intraprocedural constant and set propagation
IPA propagates floating point and integer constants to their uses and
computes constant expressions at compile time. Also, variable uses that are
known to be one of several constants can result in the folding of
conditionals and switches.
Intraprocedural pointer alias analysis
IPA tracks pointer definitions to their uses, resulting in more refined
information about memory locations that a pointer dereference may use or
define. This enables other parts of the compiler to better optimize code
around such dereferences. IPA tracks data and function pointer definitions.
When a pointer dereference can only refer to a single memory location or
function, the dereference is rewritten to be an explicit reference to the
memory location or function.
The execution time for code optimized using IPA (IPA compile and link) is normally
faster than for code optimized using interprocedural analysis (IPA compile only) or
the OPT compiler option. Please note that not all applications are suited for IPA
optimization and the performance gains realized from using IPA will vary.
Note: For additional information about using the IPA(LINK) option, see IPA(LINK)
option and exploitation of 64-bit virtual memory on page 332.
Program-directed feedback
IPA uses program-directed feedback (PDF) to organize the code and to focus
optimization on the frequently-used portions of the code. This can result in
significant performance gains. Using PDF is a two-step process, that first gathers
training data, then optimizes code during compile time.
Training data is gathered by running an application that was built using the PDF
suboptions. When the application is run it collects information about itself. This
information is the training data. The application should be run in a normal manner
with accurate and varied input in order to gather as much valid training data as
possible.
The second IPA build uses the training data when optimizing. This training data
gives IPA information on:
v The most common paths
v The critical paths
v The least-used parts of the code
As of z/OS V1R12 XL C/C++ compiler, stale profiling data can be used in the
second stage of the PDF process, if minor changes are made to the source file in
the first PDF stage. As a result of this change to the behavior of the PDF process, it
will be possible to run both stages of PDF under different compilation options. The
compiler will issue a list of warnings but will not terminate. During the link step, TPO
will print a message identifying any functions that have been detected to change
from the first stage of PDF process.
Invocation parameters
Compiler
Source file(s)
Analysis phase Listing sections
Messages
Object module(s)
Code generation
Listing sections
phase
Messages
Note: If you want to get the maximum benefit from IPA, run both the IPA Compile
and IPA Link steps.
You can invoke the IPA Compile step in the same environments that you use for a
regular compilation. You can invoke the IPA Link step only in MVS batch mode or in
one of the z/OS UNIX shell environments through the c89 utility.
This information describes the flow of IPA processing under MVS batch. The flow of
processing with the c89 utility is the same, but there are differences in how you
invoke IPA.
IPA Compile step processing: You invoke the IPA Compile step by specifying the
IPA(NOLINK) compiler option, as shown in Figure 161 on page 602. (NOLINK is the
default suboption). During the IPA Compile step, the compiler creates optimized
objects. These objects contain information that the IPA Link step can use for further
optimization.
Compiler
Source file(s)
Analysis phase Listing sections
Messages
IPA compile
Messages
optimization phase
The following processing takes place for each compilation unit that you specify for
the IPA Compile step:
1. The compiler determines the final suboptions for the IPA option, based upon the
compiler options and IPA suboptions that you specified. This is necessary
because the compiler does not support some combinations of compiler options
and IPA suboptions. The compiler issues a warning message if it finds
unsupported combinations.
2. The compiler promotes some IPA suboptions based upon the presence of
related compiler options and issues informational messages if it does so. For
more information, see interactions in z/OS XL C/C++ User's Guide.
3. The compiler generates an IPA object file. This object file contains control
information for a compilation unit required for the IPA Link step.
The IPA object module produced by IPA (NOLINK,NOOBJECT) has the same
structure as a regular object module. It should not be used as input to the
prelinker, linker, or binder.
Each IPA object contains a CSECT that includes the ESD name @@IPAOBJ.
4. If you specify the OBJECT suboption of the IPA option, the compiler produces a
combined IPA and conventional object file. The IPA object connection occurs
through the conventional object through END records. While the conventional
object file is not required by the IPA Link step, creating it permits you to bind
this file to create an executable module without IPA optimization. It is difficult to
debug IPA optimized code. You can use an executable module that is not
optimized to debug your program.
During the IPA Compile step, the compiler generates information that allows you to
create object libraries with the C370LIB utility or to create z/OS UNIX archives with
IPA Link step processing: You invoke the IPA Link step by specifying the
IPA(LINK) compiler option, as shown in Figure 162. During this step, the compiler
links the IPA objects that were produced by the IPA Compile step (along with
non-IPA object files and load modules, if specified), does partitioning, performs
optimizations, and generates the final object code.
Invocation parameters
(IPA(LINK, CONTROL(dsn))
(other IPA suboptions may be
specified)
Compiler
An exception to this is the IPA object files produced by the OS/390 Release 2 C IPA
Compile. These must be recompiled from the program source using a compiler that
is version OS/390 Release 3 or later before attempting to process them with the
current IPA Link.
If LPAs or LIBPACKS do not have enough space for the Language Environment
Library, then you can place it into a library lookaside (LLA). This reduces library I/O
activity by keeping selected directory entries in storage.
Similarly, if your application uses C++ class libraries, then application performance
may be increased by placing specific libraries in the LPA or the dynamic link pack
area (DLPA). For example:
v If the application is a heavy user of the C++ ANSI Standard Libraries, then place
the 31-bit CEE.SCEERUN2(C128) or 64-bit CEE.SCEERUN2(C64) Language
Environment run-time library in the DLPA.
v If the application is using the non-XPLINK C++ standard library, then place the
CEE.SCEERUN(C128N) Language Environment run-time library in an LPA.
v If the application is a heavy user of the USL IOSTREAM libraries, then place the
CBC.SCLBDLL Language Environment run-time library in an LPA (for
non-XPLINK applications) or the CBC.SCLBDLL2 Language Environment
run-time library in a DLPA (for XPLINK applications).
The RPTSTG(ON) option should not be used in the final build or run because it is
resource-intensive, which adversely affects the performance of the application. The
__heaprpt() function, which does not require the RPTSTG(ON) option, obtains a
summary heap storage report while your application is running. For more
information, see __heaprpt() in z/OS XL C/C++ Run-Time Library Reference.
You can also tune I/O storage by using the _EDC_STOR_INITIAL and
_EDC_STOR_INCREMENT environment variables. The I/O storage usage is not in the
storage report.
The HEAPPOOLS run-time option might increase storage use, but will improve the
performance of the application. This option is effective if:
v The application is multi-threaded
v The application often uses:
new()
delete()
new[]()
delete[]()
malloc()
__malloc31()
realloc()
calloc()
free()
Note: If you are not sure which settings of ALL31 and HEAPPOOLS are in effect, use
the Language Environment run-time option RPTOPTS. RPTOPTS(ON) generates a report
of run-time options and their settings that are in use by the currently-running
application. Because this option diminishes the performance of the application, it
should be used for diagnosis purposes only.
IMS and CICS both have similar methods to allow you to preload a frequently used
module.
Library lookasides
The library lookaside facility (LLA) reduces the amount of I/O activity necessary to
locate and fetch modules and program objects from storage. In addition, LLA can
work with virtual lookasides to quickly fetch modules from virtual storage instead of
from a direct access storage device (DASD).
Virtual lookasides
The virtual lookaside facility (VLF) is used to cache various items to reduce I/O,
reduce CPU time, and increase response time. For example, you can cache the
user IDs (UIDs) and group IDs (GIDs), which will reduce the DASD I/O overhead for
Resource Access Control Facility (RACF) calls.
General tips
The following list contains suggestions to support your efforts to debug programs,
and reduce compilation time, and improve application performance.
v All builds for testing or production should be compiled with the optimization level
at which you intend to ship the final product.
v Even if you compile with opt(0) and debug on a regular basis, you should also
do some testing at higher optimization levels to ensure that no aliasing rules or
ANSI rules have been broken, which would cause the code to be optimized
incorrectly.
v You can ensure the cleanest possible optimized compilations, as well as reduce
the number of bugs that occur only at high optimization levels, by reviewing
every warning issued by the compiler.
Note: Warnings are often a sign that the compiler is not sure how to interpret the
code. If the compiler is not sure how to interpret code at Opt(0), the code could
cause an error at higher optimization levels or contribute to longer compilation
times.
v The simpler the code is, the more easily the compiler can understand it and the
faster it will compile. For more information, see Chapter 37, Improving program
performance, on page 565.
v The CHECKOUT (for C) or INFO(for C++) option can be used to look for certain
common problems (such as unprototyped functions and uninitialized variables)
that can increase both compilation time and execution time.
v Generate production builds each week throughout the project cycle. This makes
it easier to determine when problems entered the code base. Waiting until the
end of a cycle to generate a build with high optimization can make it more
difficult to find errors caused by coding that does not confirm to ANSI aliasing
rules.
v Set up a build so that you can customize options for any source file, if necessary.
For example, use a makefile for a UNIX System Services-based build with a
default rule for compilation. You can then customize targets for source files that
require different options. Similarly, use the OPTFILE compiler option for a
JCL-based build. A build script can then use a project-level option file for all
source files in a module or DLL. You can specify either of the following:
Both a project-level option file and additional specific options for a source file
A source-specific option file in the option list that follows the options file name
v Set up build scripts so that they can be used for both development and
production builds to:
Programmer tips
v You can add code to the beginning and end of a header file to ensure that it is
not processed unnecessarily during compilation.
The following example contains code that is included in a header file called
myheader.
#ifndef __myheader
#ifdef __COMPILER_VER__
#pragma filetag ("IBM-1047")
#endif
#define __myheader 1
.
.
. /* header file contents */
#endif
You must ensure that the filetag statement, if used, appears before the first
statement or directive (except for any conditional compilation directives). The
ifndef statement is the first non-comment statement in the header file (the actual
token used after the ifndef statement is your choice). The define statement
must follow; it cannot appear before the filetag statement, but it must appear
before any other preprocessor statement (other than comments).
Note that the header can contain comment statements in any location. Using this
format of header-file blocking will improve compilation time for programs where a
header file is included more than once.
v Use the system header files from UNIX file system instead of partitioned data
sets to improve compilation time. Specify the following compiler options to do
this:
For C++
NOSEARCH SEARCH(/usr/include/, /usr/lpp/cbclib/include/)
For C NOSEARCH SEARCH(/usr/include/)
v With the MEMORY compiler option (the default), the compiler uses a hiperspace or
memory file in place of a work file (if possible). This option increases compilation
speed, but you might require additional memory to use it. If the compilation fails
because of a storage error, either increase your storage size or recompile your
program using the NOMEMORY option.
v If your file has many recursive tempate definitions and you want to use the
TEMPINC option, the FASTTEMPINC compiler option might reduce the compilation
time.
Note: This option defers generating object code until the final versions of all
template definitions have been determined. Then, a single compilation pass
generates the final object code. Time is not wasted generating object code that
will be discarded and generated again.
However, you can use the dbx debugger utility to help you determine problems. One
method is to set the stop location at the point where your program detects an error
situation, or detects a severe condition, which the code cannot handle. This method
has the following limitations:
v The point at which you want to allow dbx to take control must be determined prior
to compile time.
v You can use the dbx stepi subcommand to step through the code at the
instruction level only.
v No source or symbolic debug information is available, which means that the
debugger cannot execute any instructions that require debug information, such
as relating the execution to the source file or examining the values of variables.
main.c
When z/OS XL C applications are compiled, many routines are needed to support
the z/OS XL C environment that are not included in your executable. These
routines, which are in z/OS Language Environment, are dynamically loaded at run
time. This reduces the size of the program to its practical minimum and provides for
the sharing of z/OS XL C library code by allowing its placement in Extended Link
Pack Areas.
Note: Using the decimal data type and its related functions (decabs(), decchk(),
and decfix()) without z/OS Language Environment is not supported.
The built-in versions of these functions are available only if the appropriate
header file (string.h, wchar.h, math.h, or stdlib.h) is included in the source file.
The use of these functions is described in z/OS XL C/C++ Run-Time Library
Reference.
v The memory management functions, including complete support for:
The malloc() function
The calloc() function
The realloc() function
The free() function
The HEAP run-time option
v The exit() function
v The sprintf() function.
Storage allocated by these functions is not part of the heap, so freeing it is your
responsibility. You can use the free() function to free the storage before the
environment is terminated. Storage allocated using these functions is not
automatically freed when the environment is terminated.
When you do not use the System Programming C Facilities, the compiler generates
a CEESTART CSECT (control section) whenever a main() or fetchable function is
encountered in the source file. With the NOSTART compiler option, described in the
z/OS XL C/C++ User's Guide, you can suppress the generation of CEESTART for
source files that contain a main() function where this is required. In a system
programming C environment, you must compile using the NOSTART option. The
object modules created will then be suitable for inclusion in applications that use the
alternative initialization routines described in this section.
//SYSLIN DD *
INCLUDE SYSLIB(EDCXSTRT)
ENTRY EDCXSTRT
INCLUDE OBJECT(main-function)
/*
The value returned to the host system will be the return value from main().
The value returned to the host system will be the return value from main().
Applications initialized with this routine will run in any environment supported by
z/OS Language Environment.
The parameters (argc and argv) passed to the main() function are undefined. There
is no argument parsing (argc and argv) or redirection of standard streams.
If the z/OS XL C library functions are required, the routine EDCXABRT must be
explicitly included during the link edit. This routine enables exception handling for
EDCXSTRX. If it is not explicitly included, abend code 2107 with reason code 7206
will terminate the program.
The RENT compiler option is supported in this environment only if the z/OS XL C
library functions are used.
int __xisa(void);
int main(void) {
puts("Hello, World");
return 3999;
}
This routine is compiled normally and link edited using control statements shown in
Figure 165 on page 626. The CEE.SCEERUN load library must be available at run
time because it contains the C library function puts().
Figure 165. Link edit control statements used to build a freestanding z/OS routine
Figure 166 shows how to compile and link a freestanding program using the
cataloged procedure EDCCL.
Figure 168 on page 627 shows the JCL required to build and execute the routine in
Figure 167.
1 The z/OS Language Environment prelinker must be used for modules
compiled with the RENT compiler option.
2 This is the object module created by compiling the sample module with the
RENT and NOSTART compiler options.
3 The output from the prelinker is made available to the linkage editor.
4 The alternative initialization routine (EDCXSTRT in this example) must be
included explicitly in the module. If this is not the first CSECT in the module, it
must be explicitly named as the module entry point.
5 The prelinked output is included in the load module.
6 EDCXEXIT must be explicitly included if the exit() function is used in the
application.
7 The routine EDCRCINT must be explicitly included in the module if the RENT
compiler option is used. No error will be detected at load time if this routine
is not explicitly included. At execution time, abend 2106, reason code 7205,
will result if EDCRCINT is required but not included.
Notes:
1. This module must be explicitly included in the program using the binder INCLUDE control statement.
2. This module will normally be included by automatic call.
3. This module must be explicitly included if you want to use the system programming version of the function.
4. Including EDCXABRT requires the system programmer C environment to be library enabled
There is no requirement on the name of the entry point (that is, it does not have to
be main()), so several different entry points, with names specified by the calling
environment, can be combined in the same program.
Routines that do not require the z/OS XL C environment should specify one of
these two pragma forms:
v #pragma environment(function-name), if the library is required, or
v #pragma environment(function-name,nolib), if no library is required.
This pragma causes the compiler to generate a different prolog for the specified
function. The prolog contains the instructions at the beginning of the routine that
perform the housekeeping necessary for the function to run, including allocation of
the function's automatic storage. This prolog will set up a C environment sufficient
for both the function in which it is specified and any function that may be called.
The RENT compiler option is not supported in this environment; if you require
reentrant system exit routines, the routine must be naturally reentrant. See z/OS
Language Environment Programming Guide for more information about reentrancy.
System exit routines can be linked with their callers or dynamically loaded and
invoked.
#define REVERSE 0
#define FLIPCHR 1
/* Valid commands */
static char *cmds[] =
{
"SYSXTREV", "SYSXTFLIP" 2
};
void revstring( P_ENT *p11, P_ENT *p12 );
void flipstring( P_ENT *p11, P_ENT *p12 );
int IKJCT44B() {
int **parme;
struct parmentry *e7, *e10, *e11, *e12, *e13;
/* Get the parameter entry values for those relevant for CLISTs */
e7 = (struct parmentry *)parme[ 6]; /* exit return */
e10 = (struct parmentry *)parme[ 9]; 4
e11 = (struct parmentry *)parme[10];
e12 = (struct parmentry *)parme[11];
e13 = (struct parmentry *)parme[12];
/* flipstring() ... */
/* - flip the first and last characters in the string */
void flipstring( P_ENT *p11, P_ENT *p12 ) {
char t;
t = p11->pt[p11->len-1];
memcpy( p12->pt, p11->pt, p11->len );
p12->pt[p11->len-1] = p12->pt[0];
p12->pt[0] = t;
p12->len = p11->len;
}
1 The #pragma environment directive sets up an entry point IKJCT44B other
than main().
2 This is the list of user-specific subroutines that are available in this system
exit.
3 The function __xregs() is used to retrieve the parameters available to the
system exit in R1 from the operating system.
4 The parameters are parameter entries passed from TSO to this system exit
and are used for the following reasons:
e7 Exit reason code
e10 Name of subroutine
e11 Arguments
e12 Result
5 The list of user-specific subroutines is checked and if the unknown CLIST
subroutine is recognized, the subroutine is called. Otherwise, the function
returns in error.
Table 115 on page 632 lists the parts used by the routines, and their function and
location in MVS. The SYSLIB specified is CEE.SCEESPC.
Notes:
1. This module must be explicitly included in the program using the binder INCLUDE
control statement.
2. This module will normally be included by automatic call.
3. This module must be explicitly included if you want to use the system programming
version of the function.
The functions that act as entry points for these routines are __xhotc(), __xhotl(),
__xhotu(), and __xhott(), respectively. For more information on these four
functions, refer to Chapter 45, Library functions for system programming C, on
page 661.
As an alternative to the persistent environments, you can also create and retain a C
environment using the preinitialized programming interface. This interface supports
the RENT compiler option, but is less versatile in other respects. z/OS Language
Environment provides a callable service for preinitialization called CEEPIPI. This is
described in z/OS Language Environment Programming Guide. You may also find
information in Retaining the C environment using preinitialization on page 257
helpful.
If any C library function is required by any routine called in this environment, the
stub routines library CEE.SCEELKED should be made available at link time after
CEE.SCEESPC.
endptr=memchr(p2,@,INSIZE);
if (NULL==endptr)
i=INSIZE; /* no ender? use max */
else
i=endptr-p2; /* length of stuff before it */
The structure of the assembler caller (CCNGSP5) is shown in Figure 171 on page
635.
1 This routine is entered with standard linkage conventions. It saves the
registers in the save area pointed to by register 13, acquires a dynamic
storage area for its own use, and chains the save areas together.
2 A C environment that includes support for the z/OS XL C library is created
by calling EDCXHOTL. The parameter list for this call is the address of the
handle (for the persistent C environment created), the address of a word
containing the initial stack size, and the address of a word containing the
initial stack location (0 for below the 16MB line and 1 for above). This
parameter list uses the normal OS linkage format.
3 The routine loops 10 times calling the C function crtn twice each time
through the loop.
4 The parameter list for the first call is the address of the handle, the address
of a word pointing to the function, and the parameters to be received by the
function. EDCXHOTU is called. This causes the specified C function, crtn() to
be given control with register 1 pointing to the remaining parameters,
LOOPCTR and FMTSTR1.
5 The C function is called again, this time with FMTSTR2 as the second
parameter.
6 When the loop ends, EDCXHOTT is called to terminate the environment
created at 2
7 The routine terminates by freeing its dynamic storage area and returning to
its caller.
Table 116 on page 637 lists the parts used by persistent environments and their
function and location. The SYSLIB is CEE.SCEESPC.
Notes:
1. This module must be explicitly included in the program using the binder INCLUDE
control statement.
2. This module will normally be included by automatic call.
3. This module must be explicitly included if you want to use the system programming
version of the function.
Note: Memory files cannot be shared between the user routines and the server.
Once the user has initialized the server, it uses other server-supplied stub routines
to send requests (messages) to the server for action. One of the parameters to this
routine will be the handle returned by the initialize call. These request stubs would
typically return a feedback code to indicate success or failure as well as any other
information requested. The server defines the parameter list to be passed and the
feedback codes to be given to the user.
When the user is finished with the server, it calls yet another stub routine to
terminate the server. This structure is illustrated in a sample user routine
(CCNGSP6) shown in Figure 172 on page 639.
C Define the variable that will hold the handle for the server
INTEGER*4 HANDLE 1
C Define the variable that well use to get the strings back
CHARACTER*100 CH
INTEGER*4 CHLEN
C Go home
STOP
END
1 The user routine sets up a variable that will be used to hold the handle
returned by the server. The form taken by this handle is up to the supplier
of the service, but a fullword (4 bytes) should be regarded as typical.
2 The user routine calls the initialize routine to set up the connection between
the user routine and the server.
3 The user routine adds three strings to the queue. In this example, the first
character of the string indicates the order in which the user expects to
retrieve the strings.
4 The user enters a loop in which the strings are retrieved from the queue.
5 The user routine prints out the strings passed back by the call to the server.
If there is no string remaining in the queue a null string (zero length) is
returned.
6 Before ending, the user routine closes down the server.
This routine is linked normally with the server-supplied stub routines (described in
Constructing user-server stub routines on page 652).
int retcode=0;
struct { 5
int code;
union info *plist;
} *req;
for(;;) { 8
union info *info;
int length;
char *string;
struct queue_entry *ent;
switch(req->code) { 11
}
} 18
return(0);
}
You must specify EDCXSTRT, QMGSERV, EDCXMEM and EDCXEXIT when you
link edit.
Many choices are available in the design of the API and how single calls in the user
are mapped. For example, the initialize call could accept parameters governing the
behavior of the session being established and pass them to the server as
commands once the server has been initialized. In the example the interactions are
straight forward, the initialize only starts up the server, and the message calls send
single messages, untouched and unexamined, to the server.
There are two kinds of stubs: the initialization stub and the message stubs.
Termination is a special case of a message stub. These stubs are most
appropriately written in assembler so that they can run in any language environment
with minimal performance cost.
The initialization stub is responsible for loading and calling the server. It can use the
low-level storage management and contents supervision routines supplied in
SCEESPC. These routines are described in Tailoring the system programming C
environment on page 653. The structure of an initialization stub is shown in
Figure 174 on page 644.
1 Stub routines are presumed to have a save area available at the location
pointed to by register 13.
2 The parameter list passed to stub routines is OS linkage; that is, register 1
points to a list of addresses. In this example, the initialization stub receives
only one parameter, the handle, that gets the address of a control block
representing the environment.
3 For efficiency, this routine gets a work area that will be used by all the stub
routines. The low level storage management routine EDCXGET, (described in
Getting storage on page 654) is available for this purpose. This area will
be the DSA for this and all other stub routines. It begins with an 18-word
save area for use by routines called by this stub. It will be freed by the
terminate stub.
4 When a save area is available, EDCXLOAD (described in Loading a module
on page 656) is called to load the server.
Message stubs are responsible for passing requests from the user application to the
service application. Like the initialization stub, they are free to use the low-level
storage management and contents supervision routines supplied with the system
programming facilities. Example message stubs are shown in Figure 175 on page
646, Figure 176 on page 647, Figure 177 on page 649, and Figure 178 on page
650.
1 Like the initialize stub, the QMGLIFO message stub expects a standard
save area pointed to by register 13. The parameters are passed with
standard OS linkage (register 1 pointing to a list of addresses).
2 The handle contains the value that was placed there by the initialization
stub at 8 in Figure 174 on page 644. This is the address of the control
block that is used to manage the interface between the user application and
the server.
3 Recover the address of the stub work area for use as a Dynamic Storage
Area (DSA). This value was saved here by the initialization stub at The
save area back chain field is set according to usual conventions.
4 A parameter list consisting of the handle (as returned by EDCXSRVI at 5 in
Figure 174 on page 644 in the initialization stub), code for LIFO, and the
address of the remaining parameters.
5 Call EDCXSRVN to re-awaken the server. This causes the server to resume
The routine in Figure 176 uses functions supplied in SCEESPC to load or locate the
server code and initialize its environment.
1 Like the initialize stub, the QMGFIFO message stub expects a standard
save area pointed to by register 13. The parameters are passed with
standard OS linkage (register 1 pointing to a list of addresses).
The routine in Figure 177 on page 649 uses functions supplied in SCEESPC to load
or locate the server code and initialize its environment.
1 Like the initialize stub, the QMGGET message stub expects a standard
save area pointed to by register 13. The parameters are passed with
standard OS linkage (register 1 pointing to a list of addresses).
2 The handle contains the value that was placed there by the initialization
stub at 8 Figure 174 on page 644. This is the address of the control block
that is used to manage the interface between the user application and the
server.
3 Recover the address of the stub work area for use as a Dynamic Storage
Area (DSA). This value was saved here by the initialization stub at 7
Figure 174 on page 644. The save area back chain field is set according to
usual conventions.
The routine in Figure 178 uses functions supplied in SCEESPC to load or locate the
server code and initialize its environment.
The routines in the following section are used to create and use a persistent C
environment for a server co-routine, written using z/OS XL C and EDCXSTRT, or
EDCXSTRL and callable by a user application written in any language.
As with the persistent C environment, the initialization call returns a handle that is
used by EDCXSRVN for further communication with the created environment. EDCXSRVN
suspends the execution of the calling routine and sends a message to the waiting
server. When the server completes the function called for by the message its
execution is suspended and the caller of EDCXSRVN resumes.
Upon return, R15 will contain the return code supplied by the server (as the
parameter to EDCXSACC) for this service.
For more information on EDCXSACC, see __xsacc() Accept Request for Service
on page 664.
There are no special considerations for building user applications. The automatic
call facility will cause the correct routines from CEE.SCEESPC to be included.
Notes:
1. This module must be explicitly included in the program using the binder INCLUDE
control statement.
2. This module will normally be included by automatic call.
3. This module must be explicitly included if you want to use the system programming
version of the function.
Generating abends
The EDCXABND routine is called to generate an abend if there is an internal error
during initialization or termination of a system programming C environment. This
module must have the entry point name of @@XABND. It uses the following parameter:
R1 The address of the abend code and reason code
This routine is not provided with a save area. In addition to the linkage registers,
this routine may freely alter registers 2 and 4. Figure 179 on page 654 shows an
example.
Getting storage
The EDCXGET routine is called to get storage from the operating system. The entry
point name for this routine must be @@XGET; see Figure 180 on page 655 for an
example. It uses the following parameter:
R0 The requested length, in bytes. If the high-order bit is zero or if the request
was made in 24-bit addressing mode, the storage will be allocated below
the 16M line. If the high-order bit is on and the request is made in 31-bit
addressing mode, storage will be allocated anywhere with a preference for
storage above the 16M line if available.
This routine is not provided with a save area. In addition to the linkage registers,
this routine may freely alter registers 2 and 4.
If you provide your own EDCXGET routine, it will be used when C library functions
explicitly get storage. Whenever the library functions invoke operating system
services, there may be implicit requests for storage that cannot be tailored.
This routine is not provided with a save area. In addition to the linkage registers,
this routine may freely alter registers 2 and 4.
This routine is not provided with a save area. In addition to the linkage registers,
this routine may freely alter registers 2 and 4.
If you provide your own EDCXFREE routine, it will be used when C library functions
explicitly free storage. Whenever the library functions invoke operating-system
services, there may be implicit requests to free storage that cannot be tailored.
Loading a module
The EDCXLOAD routine is called to load a named module into storage. Its entry
point must be @@XLOAD. It has the following parameter:
R1 Points to the name of the routine to be loaded
This routine is provided with a save area. Apart from the linkage registers, it must
save and restore all registers used.
This routine is provided with a save area. Apart from the linkage registers, it must
save and restore all registers used.
If one of these message routines is not included and an exception occurs, the
program could terminate without displaying a message. These error messages are
directed to stderr. Refer to z/OS Language Environment Debugging Guide for
more information.
Table 118 contains the abend codes and reason codes specific to the system
programming facilities.
Table 118. Abend and reason codes specific to system programming environments
Code Type Code Description
Abend 2100 No storage abend code
2101 Error freeing storage
2102 Error finding stack seg home
2103 Error loading library
2104 Error with heap allocation
2105 Error with system level command
2106 Error initializing statics
2107 Error establishing error handler for EDCXSTRX
2108 Error cleaning up heap for EDCXSTRX
4000 Error when handling abend
Purpose
The function creates a persistent C environment that does not require the dynamic
library facilities of z/OS Language Environment at run time.
For an extensive example of the use of __xhotc(), see Creating and using
persistent C environments on page 632.
Format
#include <spc.h>
Returned value
__xhotc() returns a token (or handle) which is used in subsequent calls to
__xhotu() and __xhott() to use or terminate a persistent C environment. This
handle is found in both the first parameter passed and R15.
The RENT compiler option is not supported for routines called using this
environment.
Purpose
The function creates a persistent C environment that will use the dynamic z/OS XL
C/C++ library functions. All library facilities are available in this environment except:
v The RENT compiler option is not supported in the persistent environment
described in this chapter.
v Exception handling is not supported in persistent C environments.
For an extensive example of the use of __xhotl(), see Creating and using
persistent C environments on page 632.
Format
#include <spc.h>
Returned value
This routine returns a token (or handle) which is used in subsequent calls to
__xhotu() and __xhott() to use or terminate a persistent C environment. This
handle is found in both the first parameter passed and R15.
Purpose
This function terminates a persistent C environment created by __xhotc() or
__xhotl(). __xhott() is specific to SP C. It is part of the group serving the
persistent C environment. (The function is also available under the name EDCXHOTT.)
For an extensive example of the use of __xhott(), see Creating and using
persistent C environments on page 632.
#include <spc.h>
__xhotu()
Purpose
This function is used to run a function in a persistent C environment. The function is
also available under the name EDCXHOTU.
This routine, and the C function being called, must use OS linkage. As a result, you
cannot make direct use of z/OS XL C/C++ Library functions with this function. C
functions being invoked using __xhotu() must be compiled with #pragma
linkage(func_name,OS).
For an extensive example of the use of __xhotu(), see Creating and using
persistent C environments on page 632.
Format
#include <spc.h>
Returned value
The returned value from __xhotu() is the returned value from the function run in the
persistent C environment.
Purpose
This routine finds the value a specified register had on entry to EDCXSTRT,
EDCXSTRL, EDCXSTRX, or the main routine of an exit routine compiled with
#pragma environment(...).
Format
#include <spc.h>
Returned value
__xregs() returns the value found.
Purpose
This routine operates in the server part of a user-server application. It is used to
indicate acceptance or rejection of the last-requested service. The function is also
available under the name EDCXSACC.
Calls to __xsacc are optional but, if made, should be when the request is validated
and all server references to user-owned storage are complete. __xsacc does not
cause a return of control to the user; its sole purpose is to indicate that user-owned
storage is no longer required by the application server.
In the case of a request that cannot be processed, possibly because the user's
command is not recognized by the server or the parameter format is invalid, the call
to __xsacc should be omitted.
Format
#include <spc.h>
Returned value
The return code for the last-requested service, zero indicating that the request was
accepted and will be processed.
Purpose
This routine operates in the server part of a user-server application. It is used to
indicate completion of the last-requested service and to get the information required
for the next service to be performed. The function is also available under the name
EDCXSRVC.
Format
#include <spc.h>
Purpose
The __xusr() and __xusr2() functions are also available under the names EDCXUSR
and EDCXUSR2, respectively. Two words in an internal control block are available for
customer use. These words have an initial value of zero (that is, all bits are 0), but
are otherwise ignored by compiled code, and by the z/OS XL C/C++-specific
Library. The values in these words may be freely queried or set by application code
using the pointers returned by these functions.
Format
#include <spc.h>
void *__xusr(void);
void *__xusr2(void);
Returned value
__xusr() and __xusr2() return the addresses of these user words. The words, and
__xusr() and __xusr2() themselves, are available in any environment, not only the
system programming environments.
Purpose
This function performs in the same manner as malloc except that it allocates
storage below the 16MB line in XA or ESA systems, even when the run-time option
HEAP(ANYWHERE) is specified. Storage allocated by this function is not part of the
heap, so you must free this storage explicitly using the free() function before this
Format
#include <spc.h>
Purpose
This function performs in the same manner as malloc(), except that it allocates
page-aligned storage. Storage allocated by this function is not part of the heap, so
you must free this storage explicitly using the free() function before this
environment is terminated. Storage allocated using __4kmalc() is not automatically
freed when the environment is terminated.
Format
#include <spc.h>
This section is provided here for your convenience. For further information on using
run-time user exits in the z/OS Language Environment environment, refer to z/OS
Language Environment Programming Guide.
Note: You cannot code either the CEEBXITA user exit or the CEEBINT user exit as an
XPLINK application.
In most cases, you do not need to modify any user exit to run your application.
Instead, you can accept the IBM-supplied default versions of the exits, or the
defaults as defined by your installation. To do so, run your application normally and
the default versions of the exits are invoked. You may also want to read the
sections User exits supported under z/OS Language Environment on page 668
and Order of processing of user exits on page 668, which provide an overview of
the user exits and describe when they are invoked.
If you plan to modify either of the user exits to perform some specific function, you
must link the modified exit to your application before running, as described in Using
installation-wide or application-specific user exits on page 669. In addition, the
sections Using the Assembler user exit on page 670 and High level language
user exit interface on page 681 describe the respective user exit interfaces to
which you must adhere to change an assembler or HLL user exit.
INITIALIZATION
PROCESSING Assembler User Exit
(CEEBINT)
In Figure 182, run-time user exits are invoked in the following sequence:
1. Assembler user exit is invoked for enclave initialization.
The assembler user exit (CEEBXITA) is invoked very early during the initialization
process, before the enclave initialization is complete. Early invocation of the
assembler exit allows the enclave initialization code to benefit from any changes
that might be contained in the exit. If run-time options are provided in the
assembler exit, the enclave initialization code is aware of the new options.
2. Environment is established.
3. HLL user exit is invoked.
Although both the assembler and HLL exits are invoked for initialization, they do not
perform exactly the same functions. See CEEBXITA behavior during enclave
initialization on page 670 and High level language user exit interface on page 681
for a detailed description of each exit.
z/OS Language Environment provides the CEEBXITA assembler user exit for
termination but does not provide a corresponding HLL termination user exit.
Finally, you can customize CEEBXITA or CEEBINT yourself for use on your application.
When CEEBXITA or CEEBINT is linked in your program, it functions as an
application-specific user exit. The application-specific exit is used only when you run
that application. The installation-wide assembler user exit is not executed.
To obtain an application-specific user exit, you must explicitly include it at bind time
in the application using a binder INCLUDE control statement. Any time that the
application-specific exit is modified, it must be relinked with the application.
Notes:
1. CEEBXITA and CEECXITA are the defaults on your system for MVS and CICS, if z/OS
Language Environment is installed at your site without modification.
2. The source code for CEEBXITA, CEEBXITC, CEEDXITA, and CEEBX05A can be found on MVS
in the sample library SCEESAMP.
3. CEEBX05A is an example user exit program for COBOL applications on z/OS.
CEEBXITA performs no special tasks other than to return control to z/OS Language
Environment initialization.
The assembler user exits allow you to request an abend. Under z/OS (as well as
TSO and CICS), you can also request a dump to assist in problem diagnosis. Note
that termination activities have not yet begun when the user exit is invoked. Thus,
the majority of storage has not been modified when the dump is produced.
It is possible to request an abend and dump in the enclave termination user exit for
all enclave-terminating events.
Example code that shows how to request an abend and dump when there is an
unhandled condition of severity 2 or greater can be found in the member CEEBX05A
in the sample library.
This allows you to free files at this time, and it presents another opportunity to
request an abend.
The IBM-supplied CEEBXITA performs no special tasks other than to return control to
z/OS Language Environment termination.
When TRAP(ON) is in effect, and the abend code is in the CEEAUE_A_AB_CODES list,
z/OS Language Environment percolates the abend. Normal z/OS Language
Environment condition handling is never invoked to handle these abends. This
feature is useful when you do not want z/OS Language Environment condition
handling to intervene for some abends, for example, when IMS issues abend code
777.
When TRAP(OFF) is specified, the condition handler is not invoked for any abends or
program interrupts. The use of TRAP(OFF) is not recommended; refer to z/OS
Language Environment Programming Reference for more information.
Any errors occurring during the enclave termination user exit lead to abnormal
termination (through an abend) of the z/OS Language Environment environment.
If a program check occurs during the enclave termination user exit and TRAP(ON) is
in effect, the application ends abnormally with ABEND code 4044 and reason code
2. If a program check occurs during the enclave termination exit and "TRAP(OFF)"
has been specified, the application ends abnormally without additional error
checking support. z/OS Language Environment provides no condition handling;
error handling is performed by the operating system. The use of TRAP(OFF) is not
recommended; refer to z/OS Language Environment Programming Guide for more
information.
z/OS Language Environment takes the same actions as described above for
program checks during the process termination user exit.
If a user exit is modified, you are responsible for conforming to the interface shown
in Figure 183 on page 673. This user exit must be written in assembler.
When the user exit is called, register 1 (R1) points to a word that contains the
address of the CXIT control block. The high order bit is on. The CXIT control block
contains the following fullwords:
CEEAUE_LEN (input parameter)
A fullword integer that specifies the total length of this control block. For z/OS
Language Environment, the length is 48 bytes.
CEEAUE_FUNC (input parameter)
A fullword integer that specifies the function code. In z/OS Language
Environment, the following function codes are supported:
1 initialization of the first enclave within a process
2 termination of the first enclave within a process
3 nested enclave initialization
4 nested enclave termination
5 process termination
The user exit should ignore function codes other than those numbered from 1
through 5.
CEEAUE_RETC (input/output parameter)
A fullword integer that specifies the return or abend code. CEEAUE_RETC has
different meanings depending on the flag CEEAUE_ABND:
v As an input parameter, this fullword is the enclave return code.
Process terminationentry
CEEAUE_LEN 48
CEEAUE_FUNC 5 (process termination function).
CEEAUE_RETC Return code presented to the invoking system in
Process terminationreturn
CEEAUE_RETC If CEEAUE_ABND = 0, the return code from the
process.
If CEEAUE_ABND = 1, the abend code.
CEEAUE_RSNC If CEEAUE_ABND = 0, the reason code for CEEAUE_RETC
from the process.
If CEEAUE_ABND = 1, reason code for the
CEEAUE_RETC abend reason code.
CEEAUE_FLAGS CEEAUE_ABND = 1 if an abend is requested, or 0 if
the enclave should continue with termination
processing.
CEEAUE_DUMP = 1 if the abend should request a
dump.
CEEAUE_STEPS = 1 if the abend should abend the
step, or 0 if the abend should abend the task.
CEEAUE_USERWD The value of CEEAUE_USERWD for all subsequent
exits.
Default versions of the above exits are not supplied under z/OS Language
Environment; instead, z/OS Language Environment supplies a default version of
CEEBXITA. Table 122 describes the order of precedence if the IBMBXITA and
IBMFXITA user exits are found in the same root program with CEEBXITA.
Table 122. Interaction of Assembler user exits
CEEBXITA IBMBXITA Present under MVS Batch, Exit Driven
Present IBMFXITA Present under CICS
No No Default version of CEEBXITA
Yes No CEEBXITA
No Yes IBMBXITA under MVS Batch;
IBMFXITA under CICS
Yes Yes CEEBXITA
The HLL enclave initialization exit is invoked after the enclave has been
established, after the Debug Tool initial command string has been processed, and
prior to the invocation of compiled code. When invoked, it is passed a parameter list
that conforms to the z/OS Language Environment definition. The parameters are all
fullwords and are defined as follows:
Number of arguments in parameter list (input)
A fullword binary integer.
v On entry: Contains 7.
v On exit: Not applicable.
Return code (output)
A fullword binary integer.
v On entry: 0.
v On exit: Able to be set by the exit, but not interrogated by z/OS Language
Environment.
As supplied, CEEBINT has only one exit defined that you can establish: the hook exit
described by the Hook_exit control block. This exit gains control when hooks
generated by the PL/I compile-time TEST option are executed. You can establish
this exit by setting appropriate pointers (A_Exits to Exit_list to Hook_exit).
Figure 185 on page 683 illustrates the Exit_list and Hook_exit control blocks.
0(0) Exit_list_len
4(4) Exit_list_hooks
Hook_exit
0(0) Hook_exit_len
4(4) Hook_exit_rtn
8(8) Hook_exit_fnccode
12(C) Hook_exit_retcode
16(10) Hook_exit_rsncode
20(14) Hook_exit_userwd
24(18) Hook_exit_ptr
28(1C) Hook_exit_reserved
32(20) Hook_exit_dsa
36(24) Hook_exit_addr
The control block for the hook exit must contain the following fields:
Hook_exit_len
The length of the control block.
Hook_exit_rtn
The address of a routine you want invoked for the exit. When the routine is
invoked, it is passed the address of this control block. Because this routine is
invoked only if the address you specify is nonzero, you can turn the exit on and
off.
Hook_exit_fnccode
The function code with which the exit is invoked. This is always 1.
Hook_exit_retcode
The return code set by the exit. You must ensure it conforms to the following
specifications:
0 Requests that Debug Tool be invoked next
4 Requests that the program resume immediately
Usage requirements
1. The user exit must not be a main-designated routine. For example, it cannot be
a z/OS XL C or a z/OS XL C++ main() function.
2. The HLL exit routines must be linked with compiled code. If you do not provide
an initialization user exit, an IBM-supplied default, which returns control to your
application, is linked with the compiled code.
3. The exit cannot be written in COBOL/370.
4. The exit should be coded so that it returns for all unknown function codes.
5. z/OS XL C constructs such as the exit(), abort(), raise(SIGTERM), and
raise(SIGABRT) functions terminate the enclave.
6. A PL/I EXIT or STOP statement terminates the enclave.
7. Use the callable service IBMHKS to turn hooks on and off. For more information
about IBMHKS, see PL/I for MVS & VM Compiler and Run-Time Migration Guide.
8. When CEEBINT is written in C/C++, the following information must be coded so
that SMP/E can maintain the CSECT and properly link the intended user exit:
#pragma map(CEEBINT,"CEEBINT")
MTF is a facility available under z/OS that can be used by application programs to
improve turnaround time on multiprocessor and attached-processor configurations.
When a program uses MTF on such a system, the elapsed time required to run the
program can be reduced. You can run tasks, which can run independently of each
other, simultaneously.
MTF is easy to use and requires very little knowledge of the multitasking
capabilities upon which it depends. From the programmers perspective,
multitasking facilities are available through the library functions of z/OS XL C.
Because of this simplicity, it is easy to introduce MTF to existing applications and
code new MTF applications to gain the benefits of multitasking.
Notes:
1. Except for a few differences, the MTF support for z/OS XL C is the same as for
the equivalent FORTRAN multitasking facilities. MTF is not supported under
CICS, IMS, DB2, C++, or z/OS UNIX. In addition, IPA is not supported in an
MTF environment.
2. XPLINK is not supported in an MTF environment.
3. AMODE 64 applications are not supported in an MTF environment.
When a program is organized in this manner, the main task runs the part of the
program that controls the overall processing. This part is referred to as the main
task program throughout this manual.
The subtasks run the portions of the program that can run independently of the
main task program and of each other. These portions of the program are referred to
as parallel functions. The library functions provided by MTF allow the main task
program to schedule parallel functions and allow them to run independently. Parallel
functions are queued for execution on the next available subtask. Scheduling a
parallel function does not require that there be a free subtask at the time of the
scheduling. MTF allows the main task program to schedule more parallel functions
than there are actual MVS subtasks.
MTF applications are link-edited as two separate load modules: a main task load
module (containing the main task program) and a parallel load module (containing
all parallel functions).
z/OS XL C provides the following MTF functions (for details, refer to z/OS XL C/C++
Run-Time Library Reference):
v tinit() to initialize the MTF environment
v tsched() to schedule parallel functions to run
v tsyncro() to synchronize the completion of parallel functions
v tterm() to terminate all executing parallel functions.
z/OS XL C also provides the header file mtf.h, which must be included in your main
task program if you are going to use the MTF facilities. The mtf.h header file
contains the macros MTF_ANY and MTF_ALL, as well as the error-return codes and
prototypes for library functions.
Your application may not have computational independence along the same
subscript axis of K, as in this picture. The divisions might have been along one of
the other subscript axes, I or J. Also, the computational independence in your
application may not fall into neat, box-like divisions.
For example, as Figure 187 shows, without multitasking, the z/OS XL C program
and all its functions can only use one processor. While running, your program may
be switched back and forth between the processors, but it can only run on one
processor at a time.
Processor 1 Processor 2
Your C program
Function suba()
Function subb()
...
Function subn()
Your C program
Function suba()
Function subb()
...
Function subn()
Each example provides an illustration of how the processors are used and how the
program is organized to accomplish the particular use of the processors.
Processor use
In Figure 188 on page 689, only the function suba has computations that can be
done independently of the main task program, which includes the C main program
plus its functions.Note that the arrows to Processor 1 and Processor 2 are for
illustration only. The main task program could have run on Processor 2 and the
parallel function, suba, on Processor 1; in fact, while they run, they may be switched
between the processors.
C main
Function suba()
task program
Function subb()
Parallel Function
...
Function subn()
Sample program
With the appropriate MTF request, the parallel function, suba, is scheduled to run in
a subtask. As Figure 189 on page 690 shows, the MTF functions perform the
following tasks:
1 tinit() names the parallel load module plmod and specifies one subtask.
2 tsched() schedules the parallel function suba to run. suba is
computationally-independent of the main task.
3 At this point, tsyncro() makes the main task program wait until suba is
finished before the main task program continues.
Function subb()
...
Function subn()
Processor use
In Figure 190, functions suba and subc are independent of each other and of the
main task program. The arrows to Processors 1, 2, and 3 are for illustration only.
The main task program and the parallel functions could run on any of the
processors.
C main
Function suba() Function subc()
task program
Function subb()
Parallel Functions
(One Parallel Module)
...
#include <mtf.h>
...
tinit("plmod",2); 1
...
tsched(MTF_ANY, "suba", arglist1); 2
Function suba()
...
Function subb()
...
1 tinit() names the parallel load module plmod and specifies two subtasks.
2 Each call to tsched() schedules one of the parallel functions, passing
different data to each for processing. suba and subc are
computationally-independent parallel functions.
3 At this point, tsyncro() makes the main task program wait until both suba
and subc are finished before the main task program continues its
processing.
Processor use
In Figure 192 on page 692, parallel function suba has data you can divide, so two
instances of suba run independently of the main task program and of each other.
C main
Function suba() Function suba()
task program
Function subb()
Parallel Functions
(One Parallel Module)
...
Figure 192. Processor use with multiple instances of the same parallel function
Sample program
As Figure 193 on page 693 shows, the MTF functions perform the following tasks:
1 tinit() names the parallel load module plmod and specifies two subtasks.
2 Each call to tsched() schedules one instance of the parallel function to run
and supplies separate data to be processed by that instance of suba. The
data to be processed by each instance of the parallel function could be two
different sections of the same array. Both instances of suba are
computationally-independent of the main task program and each other,
because each instance of suba processes different data.
3 At this point, tsyncro() makes the main task program wait until all
instances of suba finish before the main task program continues.
Function subb()
...
Figure 193. Sample program using multiple instances of the same parallel function
New programs can be designed to use MTF, and existing programs can be
reconstructed.
Parallel functions
v A parallel function must be written only in C.
v The return value of a parallel function must be void. If a parallel function
attempts to return a value, the behavior will be undefined.
v External parallel function names must be 8 characters or shorter in length and
will be uppercased.
C MTF
Library
tinit, tsched
tsyncro, tterm
Notes:
1. Each task has private and separate storage structure that leads to most of the
parallel function idiosyncrasies:
v All file operations from same task.
v Storage must be malloc() or free()d from same task.
v Independent signal handling environments.
2. MTF library functions are only operational in the main task.
3. call/return used for invocation within a task.
4. MTF only supports parallel load modules in a PDS. Parallel load modules in a
PDSE are NOT supported.
Passing data
v A parallel function is always invoked in its last-used state. If, for example, a
parallel function has defined a static variable with an initializer, then the variable
has that value the first time the parallel function executes on a given task. Should
the value be modified, the modification is available the next time that parallel
function is run only if the function is scheduled to the same task. If you don't
Input/Output
v File pointers must not be shared across subtasks. A given file pointer must only
be used (for file access and closing) on the same task on that it was created
{(using fopen())}. File pointers must be utilized as a serial resource. z/OS XL C
does not protect against misuse, and a program will have unpredictable behavior
if this rule is not enforced.
v Each parallel function updates (writes or changes) a file as if it had complete
control over the file; therefore, there should be no simultaneous read or update of
a given file while any function on any task is updating that file (even if separate
file pointers are used).
v Memory files cannot be shared across subtasks.
Exception/Signal handling
v The parallel functions on the subtasks run with TRAP(ON) run-time option, and
each has a signal handling environment entirely independent from that of each
other task. All signals are initialized to default handling on each task, and can be
modified for a given task only through a signal statement from a parallel function
on that task.
v All signal interrupts are eligible to be raised from the operating system or by the
raise() function during execution of parallel functions. All signals, however,
require special handling in the case of parallel functions because of the
requirement that parallel functions always return normally. Signals must either be
ignored or a handler must be established that does not terminate the program. If
these signals are left to default handling or a handler is established that
terminates the program, MTF will treat this as an abnormal termination of the
parallel function.
Function termination
v Parallel functions run as called functions (from EDCMTFS, the z/OS XL C library
supplied main function for parallel modules) and must terminate by simple return
(to EDCMTFS). For more information on EDCMTFS, see Creating the parallel
functions load module on page 703.
v Termination with exit() and abort() calls is invalid because these functions
interfere with EDCMTFS operation and they are treated by MTF as abnormal
terminations.
v On the first valid call to MTF (tsched(), tsyncro(), tterm()) from the main task
program after a parallel function has abnormally terminated (via exit()/abort()
or otherwise) MTF will:
Abort all parallel functions scheduled or in progress
Remove the MTF environment
Return ETASKABND on that MTF call
The following items must not be used as the arguments supplied to the parallel
function using tsched():
v Function pointers
v A pointer to data or storage that will be modified or released before a tsyncro().
After inserting calls to the parallel functions, insert a call to tsyncro() wherever the
program requires that any subtask, one particular subtask, or all of the subtasks
have finished executing the parallel functions previously scheduled to them. As the
last MTF call, insert a call to tterm() before to exit/return from the main task
program to remove the MTF environment.
To properly use MTF from the main task program it is necessary to include the
mtf.h header file before to the first MTF call in your program. MTF calls themselves
can be issued from non-main as well as main functions within the main task
program, subject only to the restrictions already described above. MTF calls,
however, can only be issued from C functions and not from functions written in any
other language.
The next sections show examples of how to change existing C programs to use
MTF following the steps just outlined.
Example 1
Figure 195 on page 698 shows a computation of the dot product on two long
one-dimensional arrays of data. The processing within the loop structure may be
separated so that the dot product is not a result of serial calculations but a result of
parallel calculations. This is because the first part of the array is not dependent on
return(res);
}
void pdotprod(double *a, double *b, int len, int m, int n, double *pres)
{
int i, from, to;
*pres = 0;
The variables to and from are used to determine on which part of the array the
parallel function is to perform.
/*Add all the partial results to determine the final dot product*/
for (i=0;i < n; ++i)
res += pres[i];
return(res);
}
Also, within the main task program, the subtasks must be initialized and eventually
terminated as shown in Figure 198.
#include <mtf.h>
int main(void)
{
.
.
.
/* other code */
/* Attach and initialize a subtask */
tinit(load_sub_name, n);
.
.
.
result = dotprod(vector1,vector2,len);
.
.
.
/* Terminate subtasks */
tterm();
/* more code */
}
Example 2
Not all application programs contain parallelism within the iterations of a loop
structure. The following example illustrates parallel computations that appear as
different segments of code in the original program. Also illustrated is the use of
pointer arguments for passing data, and I/O operations to files in parallel functions.
/* MTF example 2 */
#include <stdio.h>
while (1)
{
res1 = fscanf(file1, "%lf", &val1);
res1 += fscanf(file2, "%lf", &val2);
if (res1 != 2)
break;
result += val1 * val2;
}
if (res1 == 1)
printf("Error: Files of unequal length\n");
else
printf("Result: %lf\n", result);
}
int main(void)
{
fdotprod("a.input", "b.input");
fdotprod("c.input", "d.input");
return(0);
}
#include <stdio.h>
#include <mtf.h>
int main(void)
{
tinit("plmod", 2);
tsched(MTF_ANY, "fdotprod", "a.input", "b.input");
tsched(MTF_ANY, "fdotprod", "c.input", "d.input");
tsyncro(MTF_ALL);
tterm();
return(0);
}
while(1)
{
res1 = fscanf(file1, "%lf", &val1);
res1 += fscanf(file2, "%lf", &val2);
if (res1 != 2)
break;
result += val1 * val2;
}
if (res1 == 1)
printf("Error: Files of unequal length\n");
else
printf("Result: %lf\n", result);
}
while(1)
{
res1 = fscanf(file1, "%lf", &val1);
res1 += fscanf(file2, "%lf", &val2);
if (res1 != 2)
break;
result += val1 * val2;
}
if (res1 == 1)
printf("Error: Files of unequal length\n");
else
printf("Result: %lf-n", result);
}
The procedures that you usually use to compile and link-edit a z/OS XL C program
can be used to create the main task program load module. For example, the
following JCL sequence (see Figure 202 on page 703) uses the standard z/OS XL
C cataloged procedure EDCCL to compile and link-edit the C source for the main
task program (stored in data set USERPGM.C(MTASKPGM)) and create a main task
program load module named MTASKPGM in data set USERPGM.LOAD.
Figure 202. Sample JCL to compile and link main task program
Note: The executable module for parallel function program must be a load module
(in a PDS data set), created using the linkage editor (and prelinker if required due
to the presence of C++ code or C code compiled with the RENT option). The MTF
library functions used to access the parallel functions are not compatible with a
program object executable module (in a PDSE data set).
The procedures that you usually use to compile and link-edit a z/OS XL C program
must be modified such that the library module CEESTART will be the entry point of the
parallel functions load module.
When you link-edit this load module, include the following linkage editor control
statements:
INCLUDE SYSLIB(EDCMTFS)
ENTRY CEESTART
For example, the JCL sequence in Figure 203 uses the standard z/OS XL C
cataloged procedure EDCCL to compile and link-edit the C source for the parallel
functions and create a parallel functions load module named PLMOD in data set
USERPGM.LOAD. This load module contains the module EDCMTFS, and has EDCMTFS as
the load modules entry point.
Note: First, we have a step that compiles and link-edits the main task program.
/*********************************************************************/
/* Modify the isa/isainc/heap subparameters in the following line */
/* as required to meet your needs. Ensure that your version (compiled*/
/* and linked) is then accessed in your link-edit of the parallel */
/* module in place of the prebuilt EDCMTFS found in SCEELKED. */
/*********************************************************************/
#pragma runopts(STACK(8K,4K,ANY,FREE),HEAP(4K,4K,ANY,FREE))
/*********************************************************************/
/* The following lines must remain unmodified to ensure proper */
/* operation of MTF. */
/*********************************************************************/
#pragma runopts(TRAP(ON),RPTSTG(OFF),\
(STAE,SPIE,NOREPORT,NOTEST,\
ARGPARSE,REDIR,NOEXECOPS)
int main(int argc, char **argv) { return tsetsubt(argc,argv); }
You can also add a #pragma runopts statement with the LIBRARY and VERSION
options to EDCMTFS, if required.
STEPLIB DD statement
You must ensure that the library containing the load modules is specified on the
STEPLIB DD statement in your JCL, as well as the other libraries usually specified,
as follows:
//STEPLIB DD DSN=user.dsn,DISP=SHR
user.dsn
name of the load module library that contains the parallel functions load
module. The parallel functions load module (parallel_loadmod_name),
specified on the call to tinit(), must be in this data set. You must allocate
the ddname EDCMTF to the user.dsn data set as well as adding user.dsn to
the STEPLIB concatenation list.
Because these files are automatically allocated while the program is running, you
need not supply DD statements for them unless you wish to override the default
device type or other file characteristics. The default device type is a terminal in TSO
or SYSOUT=* in batch.
Example of JCL
An example of the run-time JCL to run a program that uses MTF is shown in
Figure 205. This figure shows the JCL that is unique to running MTF, as well as the
other JCL the program would typically require. (Some programs might require
additional DD statements.)
MTASKPGM is the name of the main task program load module, and is the load
module that gets control when MVS first starts running the program. In this
example, this load module is contained in data set USERPGM.LOAD, which is referred
to by the STEPLIB DD statement. USERPGM.LOAD also contains the parallel functions.
The STDIN01 DD statement specifies the data set that contains the programs input
data for the first task. The STDOUT02 DD statement specifies that printed output aside
from run-time error messages from the second subtask is to be written to SYSOUT
class S and that the record format is to be fixed-length. These DD statements are
necessary only if you do not want to accept the defaults.
Note: When opening files under MTF, you incur additional overhead when
fopen() and freopen() are called. This overhead would normally be
performed at the first read or write to the stream and will not affect the
performance of a program that does indeed perform at least one read or write
to the stream.
fetch()/release() must only be issued from the same task.
free() must be issued on the same task as the malloc()/calloc()/realloc()
functions were issued. Note also that a realloc() must be issued in the same
task as the malloc().
signal()/raise() also identified earlier under the rules for parallel functions in
Designing and coding applications for MTF on page 693. Basically, each
task has its own distinct interrupt environment. Thus signal()/raise() issued
from one task have no effect on the operation of any other task.
PL/I and COBOL interlanguage calls must not be made from parallel
functions.
For information on using CSP/AD or CSP/AE under CICS, see Chapter 49, Using
Cross System Product (CSP), on page 735.
Notes:
1. AMODE 64 applications are not supported in a CICS TS environment.
2. As of this publication, the standalone CICS translator does not recognize the C
compiler's support for alternative locales and coded character sets. Therefore,
you should write all your CICS C code in coded character set IBM-1047 (APL
293).
3. XPLINK applications are not supported under CICS prior to CICS TS 3.1.
4. As of V1R2, a non-XPLINK Standard C++ Library DLL allows support for the
Standard C++ Library in the CICS subsystem. For further information, see
"Binding z/OS C/C++ Programs" in z/OS XL C/C++ User's Guide.
After CICS TS has been installed on your system, you must perform the following
tasks:
v Create a CICS TS environment if one does not already exist. This involves
creating a CICS System Definition (CSD), journals, and a Global Catalog Set
(GCD).
v Copy CEECCICS from SCEERUN to an Authorized Program Facility (APF) data set.
The data set should be concatenated in the STEPLIB when CICS is cold started.
v Create the CESO and CESE Transient Data Queues. Sample Destination Control
Table (DCT) definitions are supplied in SCEESAMP(CEECDCT).
v Add required definitions to the CSD. Sample CSD definitions are provided in
SCEESAMP(CEECCSD). These sample definitions create a group called CEE, which
must be added to the installation LIST.
The C run-time event handler module CEEEV003 is required for CICS TS support (in
addition to the z/OS Language Environment interface modules). CEEEV003 must be
link-edited as AMODE=31, RMODE=ANY, and loaded above the 16M line.
If you will be using the I/O stream library, complex mathematics, collection, or
Application Support Class DLLs provided with the z/OS XL C++ compiler, you must
define these DLLs in the CSD, and the CBC.SCLBDLL library must be added to the
DFHRPL concatenation. Sample CICS CSD definitions can be found in
CBC.SCLBJCL(CLB3YCSD).
In the following CICS command, the function is SEND TEXT. This function has 4
options: FROM, LENGTH, RESP and RESP2. In this case, each of the options takes one
argument.
For further information on the EXEC CICS interface and a list of available CICS TS
functions, refer to CICS documentation, which is available at:
http://www-01.ibm.com/software/htp/cics/cics-library/
When you are designing and coding your CICS TS application, remember the
following:
v The EXEC CICS command and options should be in uppercase. The arguments
follow general C or C++ conventions.
v Before any EXEC CICS command is issued, the EXEC Interface Block (EIB) must be
addressed by the EXEC CICS ADDRESS EIB command.
v z/OS XL C/C++ does not support the use of EXEC CICS commands in macros.
The example program in Figure 206 on page 714 (CCNGCI1) shows the use of
several EXEC CICS commands to perform various tasks.
1 Initialize the CICS interface
2 Access the storage passed from the caller
Chapter 48. Using the CICS Transaction Server (CICS TS) 713
/* program : GETSTAT */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FILE_LEN 40
struct com_struct {
unsigned int quiet ;
} *commarea ;
DFHEIBLK *dfheiptr ;
main ()
{
long int vsamrrn;
signed short int vsamlen;
unsigned char status_record[41];
signed long int myresp;
signed long int myresp2;
vsamrrn = 1;
vsamlen = FILE_LEN;
/* read the status record from the file*/
EXEC CICS READ FILE("STATFILE") 4
UPDATE
INTO(status_record)
RIDFLD(vsamrrn)
RRN
LENGTH(vsamlen)
RESP(myresp)
RESP2(myresp2);
/* check cics response */
/* -- non 0 implies a problem */
if (myresp != DFHRESP(NORMAL))
unexpected_prob("Unable to read from file",61);
if (memcmp(status_record,"DOWNTME ",8) == 0)
check_4_down_status(status_record);
if (commarea->quiet != 1)
sendmsg(status_record);
exit(11);
}
Figure 206. Example illustrating how to use EXEC CICS commands (Part 1 of 3)
strncpy((status_record+8),update,8);
strncpy((status_record+16),uptime,8);
update[8] =\0;
uptime[8] =\0;
if (dnresp != DFHRESP(NORMAL))
unexpected_prob("Unexpected prob with ASKTIME",dnresp);
if (dnresp != DFHRESP(NORMAL))
unexpected_prob("Unexpected prob with FORMATTIME",dnresp);
curdate[8] =\0;
curtime[8] =\0;
vsmrrn = 1;
vsmlen = FILE_LEN;
if (dnresp != DFHRESP(NORMAL)) {
printf("The dnresp from REWRITE = %d\n", dnresp) ;
printf("The dnresp2 from REWRITE = %d\n", dnresp2) ;
unexpected_prob("Unexpected prob with WRITE",dnresp);
}
Figure 206. Example illustrating how to use EXEC CICS commands (Part 2 of 3)
Chapter 48. Using the CICS Transaction Server (CICS TS) 715
printf("%s %s Changed status from DOWNTME to OK\n",curdate,
curtime);
}
}
if (memcmp(status_record,"OK ",3)==0)
strcpy(outmsg,"The system is available.");
else if (memcmp(status_record,"DOWNTME ",8)==0)
strcpy(outmsg,"The system is down for regular backups.");
else
strcpy(outmsg,"SYSTEM PROBLEM -- call help line for details.");
printf("%s\n",outmsg);
outlen=strlen(outmsg);
if (msgresp != DFHRESP(NORMAL))
unexpected_prob("Message output failed from sendmsg",71);
msglen = strlen(desc);
fprintf(stderr,"%s\n",desc);
if (msgresp != DFHRESP(NORMAL))
exit(99);
else
exit(rc);}
Figure 206. Example illustrating how to use EXEC CICS commands (Part 3 of 3)
Note: You can set up a SIGIOERR handler to catch read or write system errors. See
Chapter 18, Debugging I/O programs, on page 221 for more information.
stdout and stderr are assigned to transient data destinations (queues). The type of
queue, intrapartition or extrapartition, is determined during CICS initialization.
Intrapartition queues are used for queueing messages and data within a CICS
region. Extrapartition queues are used to send data outside the CICS region or to
receive data from outside the CICS region.
The transient data queues associated with stdout and stderr are CESO and CESE
respectively. z/OS XL C/C++ supports VA and VBA queues with an lrecl of at least
137 bytes.
Records sent to the transient data queues associated with stdout and stderr take
the form of a message. The entire message record can be preceded by an ASA
Standard control character. Figure 207 illustrates the recommended message
format.
1 4 4 1 14 1 108
The following are sample messages of data written to a CICS data queue:
Standard streams can only be redirected to, or from, memory files. Because only
one transient data queue can be associated with each of stdout and stderr, these
queues can contain output written in chronological order from many C and C++
programs. This output must be sorted as necessary into the desired sequence.
Chapter 48. Using the CICS Transaction Server (CICS TS) 717
If you are using C++, you can also use the I/O stream library to create and access
memory files. Hiperspace memory files are not supported.
Arguments to C or main()
When a z/OS XL C/C++ program is running under CICS TS, you cannot pass
command line arguments to it. The values for argc and argv have the following
settings:
argc 1
argv[0] 4-character CICS transaction ID
Run-time options
Command line run-time options cannot be passed in CICS. To specify run-time
options in XL C/C++, you must include the #pragma runopts directive in the code.
Figure 206 on page 714 shows how to do this. See z/OS Language Environment
Programming Guide for information on other ways to supply run-time options when
you are running under CICS TS.
Note: The z/OS XL C++ compiler does not support packed decimal data. Any
program using the C or C++ character data type to handle packed decimal data
must have its own functions for the manipulation of this data.
Locales
All locale functions are supported for locales that have been defined in the CSD.
CSD definitions for the IBM-supplied locales are provided in SCEESAMP(CEECCSD).
setlocale() returns NULL if the locales are not defined.
POSIX
There is no support for POSIX functions that are not already defined as part of
ANSI/ISO. z/OS UNIX is not supported under CICS.
Multitasking facility
MTF functions are not supported under CICS TS.
IMS
There is no support for the ctdli() function under CICS TS. If you call ctdli()
under CICS TS, the return value is -1. For information about the CICS TS method
to access IMS, refer the CICS documentation at:
http://www-01.ibm.com/software/htp/cics/cics-library/
Dump functions
The dump functions csnap(), cdump(), and ctrace() are supported under CICS TS.
The output is sent to the CESE transient data queue. The dump can not be written if
the queue does not have a sufficient LRECL. An LRECL of at least 161 is
recommended.
fetch()
The fetch() function is supported under CICS TS. Modules to be fetched must be
defined to the CSD and installed in the PPT.
release()
The release() function is supported under CICS TS.
system()
The system() function is not supported under CICS TS. However, there are two
EXEC CICS commands that give you similar functionality:
EXEC CICS LINK
This command enables you to transfer control to another program and
return to the calling program later. See Figure 208 on page 723.
EXEC CICS XCTL
This command enables you to transfer control to another program. Control
does not return to the caller after completion of the called program.
Time functions
All time functions are supported except the clock() function, which returns the
value (time_t)(-1) if it is used under CICS TS.
iscics()
The iscics() function is an extension to the C library. It returns a non-zero value if
your program is currently running under CICS. If your program is not running under
CICS, iscics() returns the value 0. The following example shows how to use
iscics() in your C or C++ program to specify non-CICS or CICS specific behavior.
Chapter 48. Using the CICS Transaction Server (CICS TS) 719
if (iscics() == 0)
<non-CICS behavior>
else
<CICS-specific behavior>
Program termination
A C or C++ program running under CICS will terminate when:
v An exit() function call or a return statement is issued in the C or C++ program.
The atexit() list of functions is run when the C or C++ program terminates.
Storage management
A z/OS XL C/C++ program can acquire storage from and release storage to CICS
TS either implicitly or explicitly.
Storage is acquired and released explicitly by the user with the C library functions
malloc(), calloc(), realloc(), or free(), with z/OS Language Environment
Callable Services (refer to z/OS Language Environment Programming Guide), with
the C++ new and delete operators, or with the EXEC CICS commands EXEC CICS
GETMAIN, or EXEC CICS FREEMAIN.
v If you request the storage by using the C functions malloc(), realloc(), or
calloc() you must deallocate it by using C functions as well.
v If you request the storage by using z/OS Language Environment Callable
Services, you must deallocate it by using z/OS Language Environment Callable
Services.
v If you request the storage by using EXEC CICS GETMAIN, you must deallocate it by
using EXEC CICS FREEMAIN.
v If you request storage using the C++ new operator, you must deallocate it by
using the C++ delete operator.
Partial deallocations are not supported. All storage allocated at a given time must
be deallocated at the same time.
The z/OS XL C/C++ library functions acquire all storage from the Extended
Dynamic Storage Area (EDSA) unless you specify otherwise using the ANYHEAP,
BELOWHEAP, HEAP, STACK, or LIBSTACK run-time options.
Storage that is acquired with the EXEC CICS GETMAIN command exists for the
duration of the CICS task.
Exception handling
You can use three different kinds of exception handlers when running C programs
in a CICS TS environment: CICS exception handlers, z/OS Language Environment
abend handlers, and C exception handlers. If you are using C++, you can use any
of these three, or the C++ exception handling approach using try, throw, and
catch. When a CICS condition is not handled under C++, the behavior of
constructors and destructors for objects is undefined.
If the CICS command EXEC CICS HANDLE ABEND PROGRAM(name) was specified in the
application, it will be called for any program exception that occurs (such as an
operation exception or a protection exception) as well as for any EXEC CICS ABEND
ABCODE(...) command that is run.
In CICS TS, the C error handling facilities have almost the same behavior as
discussed in Chapter 28, Handling error conditions, exceptions, and signals, on
page 403. A signal raised with the raise() function is handled by its corresponding
signal handler or the default actions if no handler is installed. If a program exception
such as a protection exception occurs, it is handled by the appropriate C handler if
no CICS or z/OS Language Environment handler is present.
The following chart shows the process for handling abends in CICS TS.
Chapter 48. Using the CICS Transaction Server (CICS TS) 721
MAP 0050: Error handling in CICS
001
002
003
Continue at Step 005.
004
Call z/OS XL C/C++-CICS interface for termination of program. CICS turns off
signal and runs program in handler.
005
006
007
008
Default handling the program check and percolate to next stack
frame.
009
Run C or C++ handler.
010
Run z/OS Language Environment user handler. See z/OS Language
Environment Programming Guide for more details.
011
Resume at the next instruction.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#define FILE_LEN 40
struct com_struct {
int quiet;
} com_reg;
if (strcmp(argv[0],"CHST") !=0) {
printf("argv[0] = %s\n", argv[0]) ;
com_reg.quiet = 1;
}
else
com_reg.quiet = 0;
if (myresp2 != 11)
unexpected_prob("Unexpected rc from GETSTAT\n",myresp2);
vsamrrn = 1;
vsamlen = FILE_LEN;
Chapter 48. Using the CICS Transaction Server (CICS TS) 723
/* following READ for UPDATE is for test purpose only. */
EXEC CICS READ FILE("STATFILE")
UPDATE
INTO(status_record)
RIDFLD(vsamrrn)
RRN
LENGTH(vsamlen)
RESP(myresp)
RESP2(myresp2);
if (myresp != DFHRESP(NORMAL)) {
printf("The dnresp from REWRITE = %d\n", myresp) ;
printf("The dnresp2 from REWRITE = %d\n", myresp2) ;
unexpected_prob("Unexpected prob with WRITE",myresp);
}
if (memcmp(status_record,"OK ",3) != 0)
raise(SIGUSR1);
exit(11);
}
msglen = strlen(desc);
fprintf(stderr,"%s\n",desc);
if (msgresp != DFHRESP(NORMAL))
exit(99);
else
exit(rc);
}
Note: The handler mentioned here is not a catch clause. It is a C signal handler
exception registered by a C++ routine.
v If you do an EXEC CICS RETURN out of an atexit() routine, the resulting return
code (RESP2) is undefined.
Chapter 48. Using the CICS Transaction Server (CICS TS) 725
z/OS XL C/C++ integrated CICS translator
If you are using CICS Transaction Server 3.1 or later, you can compile XL C/C++
source code with embedded CICS commands and keywords without using the
CICS TS language translation utility if you use the CICS compiler option. You can
embed comments and macros within the embedded CICS commands.
When you use the z/OS XL C/C++ integrated CICS translator, you might experience
the following benefits:
v More seamless operation of C/C++ applications that run in the CICS
environment, especially under UNIX System Services
v Improved program readability
v Easier application maintenance
v Tighter coupling between the translation and compilation phases
v A more unified development approach across z/OS XL C, z/OS XL C++, COBOL,
and PL/I
In general, source code that can be processed successfully by the standalone CICS
translator will be compatible with the integrated CICS translator.
Exception: The standalone CICS translator does not recognize C/C++ macros. For
this reason, a CICS command that is processed with the integrated CICS translator
can either fail to translate or change semantically if it (coincidentally) contains an
identifier that is identical to a macro that is active within the scope of the CICS
command.
Note: If you are using C++, you must use the CPP translator option to indicate to
the compiler that you are using the C++ language, rather than the C language. The
use of the CPP parameter specifies that the translator is to translate z/OS XL C++
programs. Code translated without the CPP option or with a translator released
before version 4.1 of CICS is not supported by the z/OS XL C++ compiler and will
not compile.
The standalone CICS translator supplies a control block (DFHEIBLK) for passing
information between CICS TS and the application program. C or C++ function
references for the EXEC CICS commands are generated. The translation step is not
required if you do not use EXEC CICS statements.
The standalone CICS translator does not evaluate preprocessor directives such as
#include or #define. You should ensure that all EXEC CICS statements are
translated.
Translating example
The samples in this section are valid for both the integrated CICS translator and the
standalone CICS translator. Figure 209 on page 727 (CCNGCI3) shows pieces of C
and C++ code before they are translated with the standalone CICS translator.
Figure 210 on page 728 shows the corresponding programs after translation.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct com_struct {
unsigned int quiet ;
} *commarea ;
main () {
Figure 210 on page 728 shows how the programs appear after they are translated.
Chapter 48. Using the CICS Transaction Server (CICS TS) 727
#ifndef __dfheitab
#define __dfheitab 1
char *dfhldver = "LD TABLE DFHEITAB 320." ;
unsigned short int dfheib0 = 0 ;
char *dfheid0 = "\x00\x00\x00\x0c" ;
char *dfheicb = " " ;
typedef struct { 3
unsigned char eibtime [4] ;
unsigned char eibdate [4] ;
unsigned char eibtrnid [4] ;
unsigned char eibtaskn [4] ;
unsigned char eibtrmid [4] ;
signed short int eibfil01 ;
signed short int eibcposn ;
signed short int eibcalen ;
unsigned char eibaid ;
unsigned char eibfn [2] ;
unsigned char eibrcode [6] ;
unsigned char eibds [8] ;
unsigned char eibreqid [8] ;
unsigned char eibrsrce [8] ;
unsigned char eibsync ;
unsigned char eibfree ;
unsigned char eibrecv ;
unsigned char eibfil02 ;
unsigned char eibatt ;
unsigned char eibeoc ;
unsigned char eibfmh ;
unsigned char eibcompl ;
unsigned char eibsig ;
unsigned char eibconf ;
unsigned char eiberr ;
unsigned char eiberrcd [4] ;
unsigned char eibsynrb ;
unsigned char eibnodat ;
signed long int eibresp ;
signed long int eibresp2 ;
unsigned char eibrldbk ;
} DFHEIBLK;
DFHEIBLK *dfheiptr;
#endif
#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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
if (memcmp(status_record,"OK ",3)==0)
strcpy(outmsg,"The system is available.");
else if (memcmp(status_record,"DOWNTME ",8)==0)
strcpy(outmsg,"The system is down for regular backups.");
else
strcpy(outmsg,"SYSTEM PROBLEM -- call help line for details.");
outlen=strlen(outmsg);
if (msgresp != 0 )
unexpected_prob("Message output failed from sendmsg",71);
}
void unexpected_prob( char* desc, int rc)
{
long int msgresp, msgresp2;
int msglen;
msglen = strlen(desc);
Chapter 48. Using the CICS Transaction Server (CICS TS) 729
{
dfhb0020 = msglen;
dfhexec("\x18\x06\x60\x00\x2F\x00\x00\x00\x00\x00\x20\x04\x00\x00\x20\xF0\xF0\
\xF0\xF0\xF4\xF1\xF0\xF0",dfhdummy,desc,dfhbp020 ); 6
msgresp = dfheiptr->eibresp;
msgresp2 = dfheiptr->eibresp2;
}
fprintf(stderr,"%s\n",desc);
if (msgresp != 0)
exit(99);
else
exit(rc);
}
3 This structure, DFHEIBLK, is used for passing information between CICS and
the application program.
4 This is the CICS command that was interpreted by the translator. The
translator comments out the EXEC CICS commands.
5 The translator inserts this call to the function dfhexec and comments out the
EXEC CICS commands for further processing by the z/OS XL C/C++
compiler. The values msgresp and msgresp2 are set from the values in the
DFHEIBLK structure.
6 This EXEC CICS command is similar in format to the one discussed in 4.
However, you should note that the generated call to dfhexec is different. For
this reason it is important that EXEC CICS commands are not imbedded in
macros.
For both C and C++, this means that if your program is naturally reentrant and has
not been translated, you can compile and link it just as you would a non-CICS
program.
Figure 212 shows an example of JCL to translate and compile a C++ program.
//*--------------------------------------------------------------------
//* Translate a C++-CICS program
//*--------------------------------------------------------------------
//*--------------------------------------------------------------------
//* Translate C++ program for CICS
//*--------------------------------------------------------------------
//TRANSTEP EXEC PGM=DFHEDP1$,
// REGION=2048K,
// PARM=MAR(1,80,0),OM(1,80,0),NOS,CPP
//STEPLIB DD DSN=CICS.SDFHLOAD,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSPUNCH DD DSN=&&SYSCIN,DISP=(,PASS),UNIT=VIO,
// DCB=BLKSIZE=400,SPACE=(400,(400,100))
//SYSIN DD DSN=MYID.CHKSTAT.C,DISP=SHR
//*--------------------------------------------------------------------
//* Compile the translated C++ source.
//*--------------------------------------------------------------------
//C0010308 EXEC CBCC,
// OUTFILE=MYID.OBJECT(CHKSTAT),DISP=SHR,
// CPARM=NOSEQ NOMAR RENT ,
// SYSOUT6=*
//SYSIN DD DSN=*.TRANSTEP.SYSPUNCH,DISP=(OLD,DELETE)
Chapter 48. Using the CICS Transaction Server (CICS TS) 731
Prelinking and linking all object modules
If you are using C++, or if you have compiled your C source with the RENT
compile-time option, you must prelink all of the object modules together. The
prelinker accepts one or more object modules, combines them, and generates a
single output object module which can then be linked. For more information, see
z/OS XL C/C++ User's Guide.
When prelinking for CICS, you should expect some unresolved external references
and a return code of 4. These unresolved references should be resolved at link
time.
CICS provides a stub called DFHELII, which must be link-edited with the load
module. For your convenience, the linkage editor commands required for CICS are
provided with CICS in the DFHEILID member of the SDFHC370 data set. The DFHEILID
member must be reblocked before it is passed to the linkage editor. A name card
should also be passed to the linkage editor. All applications must run AMODE=31. It is
recommended that the object module is linked with AMODE(31) and RMODE(ANY).
CICS does not require any other linkage editor options.
If you are using C, and your program will reside in one of the DFHRPL libraries, you
do not need to link-edit the module with the RENT option. However, if the program is
to be installed in one of the link pack areas, STEPLIBs, or data sets in the system
link list, you should link-edit the module with the RENT option.
Figure 213 on page 733 shows an example of how to prelink and link C and C++
modules.
Program processing
In a CICS environment, a single copy of a program is used by several transactions
concurrently. One section of a program can process a transaction and then be
suspended (usually as a result of an EXEC CICS command). Another transaction can
then start or resume processing the same or any other section of the same
application program. This behavior requires that the program be reentrant.
Chapter 48. Using the CICS Transaction Server (CICS TS) 733
However, if the program is to be installed in one of the link pack areas, STEPLIBs, or
data sets in the system link list, the module should be link-edited with the RENT
option.
CSD considerations
Before you can run a program, you must define it in the CICS CSD. When defining
a program to CICS, you should use LANGUAGE(LE). However, if the program is in C
and does not use ILC support, you can use LANGUAGE(C).
If you use a copy of a reentrant C or C++ application program that was installed in
the link pack area, you must specify USELPACOPY(YES) in the resource definition
when you define the program in the CSD. You can use the CICS-supplied
procedure DFYEITDL to translate, compile, prelink, and link-edit C or C++ programs.
For C programs, you may have to change the compile step of this procedure. You
will have to change the compile step to use it with the C++ compiler.
Passing control
You can pass control between CSP and z/OS XL C as follows:
CALL Calls another application or subroutine to be run. When execution is
completed, control is returned to the statement following the CALL
statement in the original application.
XFER|DXFR Transfers control and initiates execution of a CSP application or
non-CSP program or transaction. The current application is
terminated when the transfer statement is executed.
Under CICS, XFER is used to transfer control to another CICS
transaction, while DXFR is used to transfer control to an application
or program. If the target name is an application, control remains in
CSP and the application is initiated immediately. If the target name
is a program, CSP issues CICS XCTL to the program name.
Note: From a z/OS XL C program, you can pass control to a CSP application but
you cannot pass control to another z/OS Language Environment-enabled language
(COBOL, PL/I) from that CSP application. Only one z/OS Language
Environment-enabled language can be in the chain of calls.
Example programs
The following example program (CCNGCP1 in Figure 215) CALLs a CSP application
in the z/OS environment. You must receive a structure.
Note: CSP cannot pass the DXFR statement to z/OS XL C under TSO.
#include <stdlib.h>
#include <math.h>
#pragma linkage(DCGCALL,OS)
int rc = 0;
char module [ 8] = {"DCGCALL " } ;
struct tag_a6progc {
char alfx [ 8];
char applx [ 8];
} ;
a6_rec.a6xbc = base;
a6_rec.a6ybc = power;
a6_rec.a6zbc = (int) pow((double) a6_rec.a6xbc,
(double) a6_rec.a6ybc);
Figure 216 on page 738 shows example program CCNGCP2, which uses an XFER
command to transfer control to a CSP application. You must pass a structure.
#include <stdlib.h>
#include <math.h>
#pragma linkage(DCGXFER,OS)
struct tag_a5ws {
short length ;
char filler [ 8];
char a5ct [ 4];
char a5lan [ 4];
char fil1 [ 8]; /* packed fields for PLI */
char fil2 [ 8]; /* packed fields for PLI */
char fil3 [ 8]; /* packed fields for PLI */
int a5xbc;
int a5ybc;
int a5zbc;
};
struct tag_a5progx {
char alfx [ 8];
char applx [ 8];
};
struct {
char s_parm [ 240];
} s_parms = {"ALF=C "};
struct tag_a5progx a5_progx = {"FZERSAM.","R924A5 "} ;
_Packed struct tag_a5ws a5_ws = { 54,
"CCNGCP2",
"XFER" ,
"C " ,
"0000110C",
"0000220C",
"0000330C",
12, 2, 0
};
base = atoi(argv[1]) ;
power= atoi(argv[2]) ;
a5_ws.a5xbc = base;
a5_ws.a5ybc = power;
a5_ws.a5zbc = (int) pow((double) a5_ws.a5xbc,
(double) a5_ws.a5ybc);
if ((fetch_ptr = (ASM_VOID *) fetch(module)) == NULL ) {
printf (" failed on fetch of CSP %8s module \n", module);
}
Figure 216. z/OS XL Ctransferring control to CSP under TSO using the XFER/DXFR
statement (Part 1 of 2)
Figure 216. z/OS XL Ctransferring control to CSP under TSO using the XFER/DXFR
statement (Part 2 of 2)
Example programs
Figure 217 on page 740 shows example program CCNGCP3, which shows how
parameters are received from a CSP application that uses a CALL statement to
transfer control. You must pass three parameters:
v An int
v A string
v A struct
void main()
{
struct date {
char yy[2];
char mm[2];
char dd[2];
} ;
int *parm1_ptr ;
char *parm2_ptr ;
struct date * parm3_ptr ;
parm1_ptr = (int *) __csplist[0]; /* get 1st parm */
parm2_ptr = (char *) __csplist[1]; /* get 2nd parm */
parm3_ptr = (struct date *) __csplist[2]; /* get 3rd parm */
Figure 218 on page 741 shows example program CCNGCP4, which shows how
parameters are received from a CSP application that uses an XFER/DXFR statement
to transfer control. You must pass a structure.
Notes:
1. Under TSO, CSP/AD cannot use the XFER statement to transfer control to z/OS
XL C.
2. Under TSO, you cannot use the DXFR statement to transfer control to CSP.
#pragma linkage(DCGXFER,OS)
#pragma linkage(DCGCALL,OS)
struct tag_a3ws {
short length ;
char filler [ 8];
char a3ct [ 4];
char a3lan [ 4];
char fil1 [ 8]; /* packed fields for PLI */
char fil2 [ 8]; /* packed fields for PLI */
char fil3 [ 8]; /* packed fields for PLI */
int a3xbc;
int a3ybc;
int a3zbc;
};
struct tag_a3progx {
char alfx [ 8];
char applx [ 8];
};
void main()
{
_Packed struct tag_a3ws *parm1 ;
_Packed struct tag_a3ws a3_ws ;
Figure 218. CSP transferring control to z/OS XL C under TSO using the XFER statement
(Part 1 of 3)
Figure 218. CSP transferring control to z/OS XL C under TSO using the XFER statement
(Part 2 of 3)
Figure 218. CSP transferring control to z/OS XL C under TSO using the XFER statement
(Part 3 of 3)
Example programs
Figure 219 on page 744 shows example program CCNGCP5, which shows how
parameters are received from a CSP application that uses a CALL statement to
transfer control. The z/OS XL C program is expecting to receive an int as a
parameter.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
main()
{
struct tag_commarea { /* commarea passed to z/OS C from R924A1 */
int *ptr1 ;
int *ptr2 ;
int *ptr3 ;
} * ca_ptr ; /* commarea ptr */
int *parm1_ptr ;
int *parm2_ptr ;
int *parm3_ptr ;
/* addressability to EIB control block */
/* and COMMUNICATION AREA */
EXEC CICS ADDRESS EIB(dfheiptr) COMMAREA(ca_ptr) ;
parm1_ptr = ca_ptr->ptr1 ;
parm2_ptr = ca_ptr->ptr2 ;
parm3_ptr = ca_ptr->ptr3 ;
Figure 220 on page 745 (example program CCNGCP6) shows how parameters are
received from a CSP application that uses an XFER statement to transfer control.
#include <math.h>
#include <string.h>
/* structure passed to R924A6*/
void main()
{
struct {
char *appl_ptr;
_Packed struct tag_a3rec *rec3_ptr ;
} parm_ptr ;
/* Structure received R924A3*/
struct tag_a3rec {
char a3ct [ 4];
char a3lan [ 4];
char fil1 [ 8]; /* packed fields for PLI */
char fil2 [ 8]; /* packed fields for PLI */
char fil3 [ 8]; /* packed fields for PLI */
int a3xbc; /* int field 1 for z/OS C */
int a3ybc; /* int field 2 for z/OS C */
int a3zbc; /* int field 3 for z/OS C */
}
Figure 220. CSP transferring control to z/OS XL C under CICS using the XFER statement
(Part 1 of 2)
struct tag_a3progx {
char alfx [ 8];
char applx [ 8];
};
_Packed struct tag_a3progx a3progx = {"USR5ALF.","R924A6 "} ;
short length_a3rec = sizeof(a3rec) ;
char * pa3rec ;
short i ;
if (dfheiptr->eibresp2 != 0) {
printf("CCNGCP6: EXEC CICS LINK returned non zero \n");
printf(" return code. eibresp2 =%d\n",
dfheiptr->eibresp2);
}
/*----- end of C calling CSP under CICS ------------------------*/
EXEC CICS RETURN ;
}
Figure 220. CSP transferring control to z/OS XL C under CICS using the XFER statement
(Part 2 of 2)
Figure 221 on page 747 (example program CCNGCP7) The following example
program shows how parameters are received from a CSP application that uses a
DXFR statement to transfer control. You must receive a structure.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
Figure 221. CSP Transferring Control to z/OS XL C under CICS Using the DXFR Statement
(Part 1 of 2)
struct tag_a5progc {
char alfc [ 8] ;
char applc [ 8] ;
struct tag_a3rec a3rec;
} a5progc = {"USR5ALF.","R924A5 "};
if (dfheiptr->eibcalen == length_a3rec ) {
memcpy(&a5progc.a3rec, ca_ptr , length_a3rec);
if (dfheiptr->eibresp2 != DFHRESP(NORMAL)) {
printf ("CCNGCP7: failed on xctl call to DCBINIT\n");
printf (" \n");
}
}
else {
printf ("CCNGCP7:length of COMMAREA is different from expected\n");
printf (" expected %d, actual %d\n",
length_a3rec, dfheiptr->eibcalen);
printf (" \n");
EXEC CICS RETURN;
}
748 Figure
z/OS V1R13.0 XL C/C++ 221. CSP Transferring
Programming Guide Control to z/OS XL C under CICS Using the DXFR Statement
(Part 2 of 2)
Chapter 49. Using Cross System Product (CSP) 749
750 z/OS V1R13.0 XL C/C++ Programming Guide
Chapter 50. Using Data Window Services (DWS)
Data Window Services (DWS) is part of the CSL (Callable Services Library). DWS
gives your C or C++ program the ability to manipulate data objects (temporary data
objects known as TEMPSPACE, and VSAM linear data sets).
Notes:
1. XPLINK is not supported with DWS.
2. AMODE 64 applications are not supported with DWS.
To use DWS functions with C code, you do not have to specify a linkage pragma or
add any specialized code. Code the DWS function call directly inside your z/OS XL
C program just as you would a call to a C or C++ library function and then link-edit
the DWS module containing the function you want (such as CSRIDAC, CSRVIEW,
CSRSCOT, CSRSAVE or CSRREFR) with your C or C++ program.
To use DWS functions with C++ code, you must specify C linkage for any DWS
function that you use. For example, if you wished to use CSRIDAC, you would use a
code fragment as shown in Figure 222.
extern "C" {
void csridac( char*, char*, char*, char*, char*,
char*, long int*, char*, long int*,
long int*, long int*);
}
int main(void)
{
/* Set up the parameters that will be used by CSRIDAC. */
At link-edit time, you should link-edit the DWS module containing the function you
want, just as you would for a C program.
int main(void)
{
/* Set up the parameters that will be used by CSRIDAC. */
return 0;
}
Any errors that occur during database processing are handled by the database
product. If a program is terminated during DB2 processing, DB2 takes appropriate
action, depending on the nature of termination. For information about handling SQL
error return codes, refer to DB2 Application Programming and SQL Guide.
To ensure that you are using compatible releases of z/OS XL C/C++ and DB2, see
z/OS Program Directory.
Refer to the both in z/OS XL C/C++ User's Guide and DB2 Application
Programming and SQL Guide whenever your application performs the following
operations:
v Declares global host variables.
v Declares host variables inside functions.
v Includes a header found in SYSLIB or in the LSEARCH path.
v Puts comments at the end of selected lines in the middle of a multiline SQL
statement.
v Inserts, updates, or retrieves data using a host variable.
v Embeds SQL statements in template functions or classes.
The following are advantages of using the XL C/C++ DB2 coprocessor instead of
the DB2 C/C++ precompiler:
v Host variable names follow the same lexical scoping rules as C/C++ variables.
An advantage of using the DB2 C/C++ precompiler instead of the XL C/C++ DB2
coprocessor is that you can obtain a more useful message listing by preprocessing,
precompiling, and then compiling source code with embedded SQL statements.
Compiler diagnostics refer to line numbers of the translated output from the DB2
C/C++ precompiler, not to the line numbers of your source code. This means that
you need both the DB2 C/C++ precompiler listing and the compiler listing to work
through the compilation errors. Run-time troubleshooting tools also refer to
coordinates of the DB2 C/C++ precompiler output.
When you embed DB2 stored procedures in a program that will be compiled with
XPLINK, each CREATE PROCEDURE statement must include a RUN OPTIONS
clause that specifies XPLINK(ON).
#include <string.h>
#include <stdio.h>
int main(void)
{
if (CreaTab() == 1)
{
printf("Test Failed in table-creation.\n");
exit(1);
}
if (DropTab() == 1)
{
printf("Test Failed in table-dropping.\n");
exit(1);
}
printf("Test Successful.\n");
return(0);
}
/*
* This routine creates the table CTAB1 and inserts some values
* into it
*/
int CreaTab(void)
{
if (sqlca.sqlcode != 0)
{
printf("ERROR - SQL code returned non-zero for "
"creation of CTAB1, received %d\n",sqlca.sqlcode);
return(1);
}
if (sqlca.sqlcode != 0)
{
printf("ERROR - SQL code returned non-zero for "
"insert into tables, received %d\n",sqlca.sqlcode);
return(1);
}
return(0);
}
/*
* This routine will drop the table.
*/
int DropTab(void)
{
EXEC SQL DROP TABLE CTAB1;
if (sqlca.sqlcode != 0)
{
printf("ERROR - SQL code returned non-zero for "
"drop of CTAB1 received %d??\n",sqlca.sqlcode);
return(1);
}
EXEC SQL COMMIT WORK;
return(0);
}
Figure 225 on page 758 is a C++ code example with embedded SQL statements.
The sample code creates, populates, updates, and drops a table called CTAB1V.
You can use this example either by compiling the program with the SQL option in
effect or by running the program through the DB2 C/C++ precompiler, and then
compiling the generated code with the NOSQL option in effect.
#define NUM_ROWS 3
#define IN_VALUE {A, B, C}
#define OUT_VALUE {D, E, F}
class SqlTestTable {
public:
// The constructor and destructor create and drop the test table
SqlTestTable() {
EXEC SQL CREATE TABLE CTAB1V (
ID INTEGER NOT NULL,
TESTVAR CHAR(1) NOT NULL
) IN DATABASE DSNUCOMP;
if (sqlca.sqlcode != 0) {
std::cout << "ERROR - SQL code returned " << sqlca.sqlcode
<< " for creation of CTAB1V.\n";
}
}
~SqlTestTable() {
EXEC SQL DROP TABLE CTAB1V; // Clean up the database
if (sqlca.sqlcode != 0) {
std::cout << "ERROR - SQL code returned " << sqlca.sqlcode
<< " for drop of CTAB1V.\n";
}
EXEC SQL COMMIT WORK;
}
if (sqlca.sqlcode != 0) {
std::cout << "ERROR - SQL code returned " << sqlca.sqlcode
<< " for insert into tables.\n";
returnValue = 66; // Not returned immediately in case cleanup is needed
}
return returnValue;
}
if (sqlca.sqlcode != 0) {
std::cout << "ERROR - SQL code returned "
<< sqlca.sqlcode << " for update in tables.\n";
returnValue = 66; // Not returned immediately in case cleanup is needed
}
return returnValue;
}
if (sqlca.sqlcode != 0) {
std::cout << "ERROR - SQL code returned "
<< sqlca.sqlcode << " for SELECT of the data.\n";
return 66; // Return immediately since no cleanup; nothing else to be done
}
if (check_var != value) {
std::cout << "ERROR - Value in table
" << check_var << " is not the expected value " << value << ".\n";
returnValue = 66; // Not returned immediately in case cleanup is needed
}
return returnValue;
}
};
// SQL Declares Not needed. Added to see what happens if not used as SQL vars.
EXEC SQL BEGIN DECLARE SECTION;
TestType inValue;
TestType outValue;
EXEC SQL END DECLARE SECTION;
if (returnValue != 55) {
return returnValue;
}
}
// Check to see if the insert went OK using host variables as function parms
for (i = 0; i < NUM_ROWS; i++) {
inValue = aLongVariableName[i];
returnValue = testTable.checkTable(i, inValue);
if (returnValue != 55) {
return returnValue;
}
}
if (returnValue != 55) {
return returnValue;
}
}
// Check to see if the update went OK using non-host variables as function parms
for (i = 0; i < NUM_ROWS; i++) {
returnValue = testTable.checkTable(i, expectedResults[i]);
if (returnValue != 55) {
return returnValue;
}
}
Because GDDM uses OS-style linkage, calls from C to GDDM require the #pragma
linkage pragma, as in the following example:
#pragma linkage(identifier, OS)
In C++ code, calls to and from GDDM require that any GDDM functions you use be
prototyped as extern "OS", as shown in the following example:
extern "OS" {
ASREAD( int *type, int *num, int *count );
CHAATT( int num, int *attrib );
CHHATT( int num, int *attrib );
}
Because C++ does not support #pragma linkage, any existing C code that you are
moving to C++ should use the extern "OS" specification instead.
When linking a GDDM application, you must add the GDDM library to your SYSLIB
concatenation.
Notes:
1. XPLINK is not supported by GDDM.
2. AMODE 64 applications are not supported by GDDM.
Examples
The following examples demonstrate the interface between C and GDDM by
drawing a polar chart to compare the characteristics of two cars.
Figure 226 on page 762 shows a sample program (CCNGGD1) using GDDM and
C.
float x_data[8] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 };
float y_data[16] = {
14190.0, 260.0, 0.21, 0.066, 83.3, 6.0, 19.1, 14190.0,
12986.0, 290.0, 0.23, 0.066, 95.6, 5.0, 16.2, 12986.0 };
float maxvals[16] = {
15000.0, 300.0, 0.25, 0.070, 100.0, 6.0, 20.0, 15000.0,
15000.0, 300.0, 0.25, 0.070, 100.0, 6.0, 20.0, 15000.0 };
int main(void)
{
fsinit();
chhatt( 4, h_attrs);
chhead( 40,"TWO CARS COMPARED USING SEVEN PARAMETERS");
chaatt( 2,a_attrs);
chxtic( 1.0, 0.0);
chxlat( 1, xl_attrs);
chxlab( 7, 31,
float x_data[8] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 };
float y_data[16] = {
14190.0, 260.0, 0.21, 0.066, 83.3, 6.0, 19.1, 14190.0,
12986.0, 290.0, 0.23, 0.066, 95.6, 5.0, 16.2, 12986.0 };
float maxvals[16] = {
15000.0, 300.0, 0.25, 0.070, 100.0, 6.0, 20.0, 15000.0,
15000.0, 300.0, 0.25, 0.070, 100.0, 6.0, 20.0, 15000.0 };
int main(void)
{
fsinit();
chhatt( 4, h_attrs);
chhead( 40,"TWO CARS COMPARED USING SEVEN PARAMETERS");
chaatt( 2,a_attrs);
chxtic( 1.0, 0.0);
chxlat( 1, xl_attrs);
chxlab( 7, 31,
"PURCHASE PRICE ; $15,000 INSURANCE ;$300/YEAR "
"$0.25/MILE ;SERVICING $0.070/MILE ;FUEL "
" 100 BHP/TON; POWER/WT RATIO 6; SEATS"
" BAGGAGE SPACE; 20 CU FT");
chyrng ( 0.5,1.0);
chyset( "NOAXIS");
chyset( "NOLABEL");
chyset( "PLAIN");
chset( "KBOX");
chkatt( 1,k_attrs);
chkey( 2, 5, "CAR ACAR B");
for(i=0; i<16; ++i)
y_data[i] = y_data[i] / maxvals[i];
chpolr(2, 8, x_data, y_data);
chnatt( 4, n_attrs);
chnoff( 0.0, 0.53);
chnote( "Z2", 1, "+");
chset("BNOTE");
n_attrs[3] = 75;
chnatt(4,n_attrs);
chnoff(0.0, 0.60);
chnote("Z2", 12, "CENTER VALUE");
chnoff(0.0, 0.55);
chnote("Z2", 23, "= 1/2 X PERIMETER VALUE");
/*************************************************************
** Issue a screen read. When any interrupt is generated **
** by the terminal operator, the program terminates. **
*************************************************************/
asread( &type, &num, &count);
fsterm();
exit(0);
}
z/OS XL C/C++ provides the ctdli() C library function to invoke IMS facilities (see
z/OS XL C/C++ Run-Time Library Reference for more information).
You can also invoke IMS facilities with the callable service CEETDLI which is
provided by the z/OS Language Environment. The CEETDLI interface performs
essentially the same functions as ctdli(), but it offers some advantages,
particularly if you plan to run an ILC application in IMS. If you use the CEETDLI
interface instead of ctdli(), condition handling is improved because of the
coordination between z/OS Language Environment and IMS condition handling
facilities. For complete information on the CEETDLI interface, see z/OS Language
Environment Programming Guide.
For a description of writing IMS batch and online programs in C or C++, see the
appropriate book listed in IMS/ESA on page 1026.
To use IMS from z/OS XL C/C++, you must keep the following in mind:
v The file <ims.h> must be included in the program.
v PLIST(OS) and TARGET(IMS) must be used to compile IMS z/OS XL C/C++
application programs. PLIST(OS) establishes the correct parameter list format
when invoked under IMS and TARGET(IMS) establishes the correct operating
environment. These compile-time options can alternatively be specified using
#pragma runopts. The PLIST(OS) compiler option is equivalent to
#pragma runopts(ENV(IMS)). The descriptions that follow use the compile-time
options, but the #pragma runopts equivalents can be used instead.
v TARGET(IMS) is mandatory, as it establishes the correct operating environment.
PLIST(OS) must also be used if the program is the initial main() program called
under IMS. Programs in nested enclaves do not need to be compiled with
PLIST(OS).
v When you specify PLIST(OS) the argument count (argc) will be set to one (1),
and the first element in the argument vector (argv[0]) will contain a NULL string.
v IMS provides a language interface module (DFSLI000) that gives a common
interface to IMS and DL/I. This module must be link-edited with the application
program.
The rest of this chapter is based on the assumption that you are using the ctdli()
interface.
Notes:
1. AMODE 64 applications are not supported in an IMS environment.
2. As of V1R2, a non-XPLINK Standard C++ Library DLL allows support for the
Standard C++ Library in the IMS subsystem. For further information, see binding
programs in z/OS XL C/C++ User's Guide.
3. XPLINK applications are supported under the IMS environment.
z/OS XL C/C++ provides extensive error-handling facilities for the programmer, but
special steps are required to coordinate IMS and C or C++ error handling so that
IMS can do its database rollbacks when a program fails.
Any program that invokes IMS by way of some other IMS interface should be
executed with TRAP(OFF). You should be sure that the program contains code to
issue a rollback call to IMS before terminating after an error. Refer to z/OS
Language Environment Programming Reference for more information about the
limitations of using TRAP(OFF).
Other considerations
A program communication block (PCB) is a control block used by IMS to describe
results of a DL/I call (DB PCB) or the results of a message retrieval or insertion (I/O
PCB) made by your program. A valid PCB is one that has been correctly initialized
by IMS and passed to you through your C or C++ program. For details on PCBs,
refer to the IMS/ESA on page 1026. See also the sample C-IMS and C++-IMS
programs in z/OS XL C/C++ Run-Time Library Reference.
For more information on the run-time options ENV and PLIST, see z/OS Language
Environment Programming Reference.
If you are running a C or C++ program under TSO or IMS, be aware of the effects
of specifying compiler options PLIST(OS), TARGET(IMS), and their combinations.
Table 125 shows the combinations of PLIST(OS) and TARGET(IMS) and the resulting
PCB generated under each of the environments.
Table 125. PCB generated for C or C++ program under TSO and IMS
Combination Running under TSO Running under IMS
TARGET(IMS) only Invalid PCB Valid PCB
PLIST(OS) only Null PCB Null PCB
TARGET(IMS) and PLIST(OS) Invalid PCB Valid PCB
For both C and C++, specifying PLIST(OS) under either TSO or IMS results in an
argc value of 1 (one), and argv[0] = NULL. For more information on the compiler
options TARGET(IMS) and PLIST(OS), see z/OS XL C/C++ User's Guide.
Examples
The sample C++ program CCNGIM1 (Figure 228) makes an IMS call and checks
the return code status of the call in IMS batch. Header file CCNGIM3 (Figure 230
on page 773) is included by this program.
#pragma runopts(env(ims),plist(os))
#include <ims.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ccngim3.h"
int main(void) {
/*******************************************************************/
/* Declare the database pointer control blocks for each database */
/*******************************************************************/
PCB_STRUCT_8_TYPE *locdb_ptr,*orddb_ptr;
int rc;
int failed = 0; /* Indicate if any part of test case failed. */
/*******************************************************************/
/* Get the pointers to the databases from the parameter list */
/*******************************************************************/
locdb_ptr = (__pcblist[1]);
orddb_ptr = (__pcblist[2]);
/*******************************************************************/
/* Make some calls to the database and change its contents */
/*******************************************************************/
/*******************************************************************/
/* Issue a DL/I call with arguments below the line (using CTDLI) */
/*******************************************************************/
/********************************************************************/
/* The first parameter for ctdli is an int specifying the number of */
/* arguments-this parameter was optional under C but is mandatory */
/* under C++ */
/********************************************************************/
rc = ctdli(six,gu,orddb_ptr,&aio_area,qual0,qual1,qual2);
return(0);
}
#pragma runopts(env(ims),plist(os))
#include <ims.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ccngim3.h"
int main(void) {
/*******************************************************************/
/* Declare the database pointer control blocks for each database */
/*******************************************************************/
PCB_STRUCT_8_TYPE *locdb_ptr,*orddb_ptr;
/*******************************************************************/
/* IO areas used for DL/I calls */
/*******************************************************************/
/*******************************************************************/
/* SSAs for DL/I calls */
/*******************************************************************/
/*******************************************************************/
/* Get the pointers to the databases from the parameter list */
/*******************************************************************/
locdb_ptr = (__pcblist[1]);
orddb_ptr = (__pcblist[2]);
/*******************************************************************/
/* Make some calls to the database and change its contents */
/*******************************************************************/
io_area = malloc(sizeof(IOA2));
rc = ctdli(six,gu,orddb_ptr,&aio_area,qual0,qual1,qual2);
return(0);
}
Figure 230 on page 773 shows the header file (CCNGIM3) that is used by both the
C and the C++ examples in Figure 228 on page 769 and Figure 229 on page 771,
respectively.
/*------------------*/
/* DB PCB */
/*------------------*/
typedef struct {
char db_name[8];
char seg_level[2];
char stat_code[2];
char proc_opt[4];
int dli;
char seg_name[8];
int len_kfb;
int no_senseg;
char key_fb[2];
} DB_PCB;
/*------------------*/
/* IO PCB */
/*------------------*/
typedef struct {
char term[8];
char ims_res[2];
char stat_code[2];
char date[4];
char time[4];
int input_seq;
char output_mess[8];
char mod_nme[8];
char user_id[8];
} IO_AREA;
typedef struct {
char item[40];
} IOA2;
The z/OS XL C++ compiler itself does not support QMF. However, QMF can be
accessed through C code that is statically or dynamically called from C++.
You must include the header file DSQCOMMC.H (provided with the QMF application),
which contains the function and structure definitions necessary to use the QMF
interface.
For information on how to write your z/OS XL C/C++ applications with the QMF
interface, see the appropriate QMF manual listed in QMF on page 1027.
Notes:
1. AMODE 64 applications are not supported by QMF.
2. XPLINK is not supported by QMF.
Example programs
Figure 231 is a sample program (CCNGQM1) that demonstrates the interface
between the QMF facility and the z/OS XL C/C++ compiler.
/* this example shows how to use the interface between QMF and C */
#include <string.h>
#include <stdlib.h>
#include <DSQCOMMC.H> /* QMF header file */
int main(void)
{
struct dsqcomm communication_area; /* found in DSQCOMMC */
/********************************************************************/
/* Query interface command length and commands */
/********************************************************************/
signed long command_length;
static char start_query_interface [] = "START";
static char set_global_variables [] = "SET GLOBAL";
static char run_query [] = "RUN QUERY Q1";
static char print_report [] = "PRINT REPORT (FORM=F1)";
static char end_query_interface [] = "EXIT";
/********************************************************************/
/* Query command extension, number of parameters and lengths */
/********************************************************************/
signed long number_of_parameters;
signed long keyword_lengths[10];
signed long data_lengths[10];
/********************************************************************/
/* Keyword parameter and value for START command */
/********************************************************************/
static char start_keywords[] = "DSQSCMD";
static char start_keyword_values[] = "USERCMD1";
/********************************************************************/
/* Keyword parameter and value for SET command */
/********************************************************************/
#define SIZE_VAL 8
char set_keywords[3][SIZE_VAL];
signed long set_values[3];
/********************************************************************/
/* Start a Query Interface Session */
/********************************************************************/
number_of_parameters = 1;
command_length = sizeof(start_query_interface);
keyword_lengths[0] = sizeof (start_keywords);
data_lengths[0] = sizeof(start_keyword_values);
dsqcice(&communication_area,
&command_length,
START_query_interface[0],
&number_of_parameters,
&keyword_lengths[0],
START_keywords[0],
&data_lengths[0],
START_keyword_values[0],
char_data_type[0]);
/********************************************************************/
/* Set numeric values into query using SET command */
/********************************************************************/
number_of_parameters = 3;
command_length = sizeof(set_global_variables);
strcpy(set_keywords[0],"MYVAR01");
strcpy(set_keywords[1],"SHORT");
strcpy(set_keywords[2],"MYVAR03");
keyword_lengths[0] = SIZE_VAL;
keyword_lengths[1] = SIZE_VAL;
keyword_lengths[2] = SIZE_VAL;
data_lengths[0] = sizeof(long);
data_lengths[1] = sizeof(long);
data_lengths[2] = sizeof(long);
set_values[0] = 20;
set_values[1] = 40;
set_values[2] = 84;
dsqcice(&communication_area,
&command_length,
&set_global_variables[0],
&number_of_parameters,
&keyword_lengths[0],
&set_keywords[0],
&data_lengths[0],
&set_values[0],
&int_data_type[0]);
/********************************************************************/
/* Print the results of the query */
/********************************************************************/
command_length = sizeof(print_report);
dsqcic(&communication_area, &command_length,
&print_report[0]);
/********************************************************************/
/* End the query interface session */
/********************************************************************/
command_length = sizeof(end_query_interface);
dsqcic(&communication_area, &command_length,
&end_query_interface[0]);
return 0;
}
Figure 232 on page 778 is a sample program (CCNGQM2) that demonstrates how
a C++ program may call a C program (see Figure 233 on page 779) that accesses
QMF.
extern "C" {
int Gen_Report(void);
}
int main( int argc, char *argv[])
{
int cmd;
if (argc < 2 )
{
printf("ERROR - program takes at least one parm");
}
else
{
cmd=argv[1][0];
cmd=toupper(cmd);
switch (cmd)
{
case R:
{
Gen_Report();
break;
}
default:
printf("%d is an invalid option.\n");
}
}
}
Sample program CCNGQM3 (Figure 233 on page 779) is called from the C
program shown in Figure 232.
#include <string.h>
#include <stdlib.h>
#include <DSQCOMMC.H> /* QMF header file */
int Gen_Report(void)
{
struct dsqcomm communication_area; /* found in DSQCOMMC */
/********************************************************************/
/* Query interface command length and commands */
/********************************************************************/
signed long command_length;
static char start_query_interface [] = "START";
static char set_global_variables [] = "SET GLOBAL";
static char run_query [] = "RUN QUERY Q1";
static char print_report [] = "PRINT REPORT (FORM=F1)";
static char end_query_interface [] = "EXIT";
/********************************************************************/
/* Query command extension, number of parameters and lengths */
/********************************************************************/
signed long number_of_parameters;
signed long keyword_lengths[10];
signed long data_lengths[10];
/********************************************************************/
/* Variable data type constants */
/********************************************************************/
static char char_data_type[] = DSQ_VARIABLE_CHAR;
static char int_data_type[] = DSQ_VARIABLE_FINT;
/********************************************************************/
/* Keyword parameter and value for START command */
/********************************************************************/
static char start_keywords[] = "DSQSCMD";
static char start_keyword_values[] = "USERCMD1";
/********************************************************************/
/* Keyword parameter and value for SET command */
/********************************************************************/
#define SIZE_VAL 8
char set_keywords[3][SIZE_VAL];
signed long set_values[3];
/********************************************************************/
/* Start a Query Interface Session */
/********************************************************************/
number_of_parameters = 1;
command_length = sizeof(start_query_interface);
keyword_lengths[0] = sizeof (start_keywords);
data_lengths[0] = sizeof(start_keyword_values);
dsqcice(&communication_area,
&command_length,
&start_query_interface[0],
&number_of_parameters,
&keyword_lengths[0],
&start_keywords[0],
&data_lengths[0],
&start_keyword_values[0],
&char_data_type[0]);
/********************************************************************/
/* Print the results of the query */
/********************************************************************/
command_length = sizeof(print_report);
dsqcic(&communication_area, &command_length,
&print_report[0]);
/********************************************************************/
/* End the query interface session */
/********************************************************************/
command_length = sizeof(end_query_interface);
dsqcic(&communication_area, &command_length,
&end_query_interface[0]);
exit(0);
}
Elements of internationalization
The typical elements of cultural environment are as follows:
Native language
The text that the executing program uses to communicate with a user or
environment, that is, the natural language of the end user.
Character sets and coded character sets
Map an alphabet, the characters used in a particular language, onto the set
of hexadecimal values (code points) that uniquely identify each character.
This mapping creates the coded character set, which is uniquely identified
by the character set it encodes, the set of code point values, and the
mapping between these two.
For example IBM-273, also known as the German Code Page, and
IBM-297, also known as the French Code Page, are two coded character
sets which assign different EBCDIC encodings in the hexadecimal range 40
to FE to the same Latin Alphabet Number 1. IBM S/390 systems in
Germany and France both use this Latin 1 alphabet, which is specified by
International Standard ISO/IEC 8859-1. However, systems in Germany are
configured for encodings of this alphabet given by IBM-273; whereas,
systems in France are configured for encodings of this alphabet given by
IBM-297.
IBM-1027, Japanese Latin Code Page, is another example of a coded
character set. It assigns EBCDIC encodings in the hexadecimal range 40 to
FE to characters specified by Japanese Industrial Standard JIS X 201-1978
plus encodings for a few more Latin characters selected by IBM. The
resulting alphabet defined by IBM-1027 consists of some characters found
in Latin Alphabet Number 1 and some Katakana characters. IBM S/390
systems in Japan are configured for encodings of this alphabet assigned by
IBM-1027.
Collating and ordering
The relative ordering of characters used for sorting.
Character classification
Determines the type of character (alphabetic, numeric, and so forth)
represented by a code point.
Locale-sensitive interfaces
The z/OS XL C/C++ run-time library provides many interfaces to manipulate and
access locales. You can use these interfaces to write internationalized C programs.
The following list summarizes all the z/OS XL C/C++ library functions which affect
or are affected by the current locale.
Selecting locale
Changing the characteristics of the user's cultural environment by changing
the current locale: setlocale()
Querying locale
Retrieving the locale information that characterizes the user's cultural
environment:
Monetary and numeric formatting conventions:
localeconv()
Date and time formatting conventions:
localdtconv()
User-specified information:
nl_langinfo()
Encoding of the variant part of the portable character set:
getsyntx()
Character set identifier:
csid(), wcsid()
Classification of characters:
The locale source file is processed by the locale compilation tool, called the
localedef tool.
To enhance portability of the locale source files, certain information related to the
character sets can be encoded using the symbolic names of characters. The
mapping between the symbolic names and the characters they represent and its
associated hexadecimal value is defined in the character set description file or
charmap file. See Appendix E, Charmap files supplied with z/OS XL C/C++, on
page 953 for a list of the charmap files shipped with your product.
Figure 234 shows the conceptual model of the locale build process.
(Optional)
LOCALEDEF tool ASCII method
code
compiled object
Compiled locale used by the
C/C++ interfaces
Each charmap file must contain at least the definition of the portable character set
and the character symbolic names associated with each character. The characters
in the portable character set and the corresponding symbolic names, and optional
alternate symbolic names, are defined in Table 126.
Table 126. Characters in portable character set and corresponding symbolic names
Symbolic Name Alternate Character Hex Value Hex Value
Name (EBCDIC) (ASCII)
<NUL> 00 00
<tab> <SE10> 05 09
<vertical-tab> <SE12> 0b 0b
<form-feed> <SE13> 0c 0c
<carriage-return> <SE14> 0d 0d
<newline> <SE11> 15 0a
<backspace> <SE09> 16 08
<alert> <SE08> 2f 07
<space> <SP01> 40 20
<period> <SP11> . 4b 2e
<less-than-sign> <SA03> < 4c 3c
<left-parenthesis> <SP06> ( 4d 28
<plus-sign> <SA01> + 4e 2b
The portable character set is the basis for the syntactic and semantic processing of
the localedef tool, and for most of the utilities and functions that access the locale
object files. Therefore the portable character set must always be defined. It is
conceptually divided into two parts:
Invariant Characters for which encoding must be constant among all charmap
files. The required encoded values are specified in Table 126 on
page 788. If any of these values change, the behavior of any
utilities and functions on z/OS XL C/C++ is unpredictable. For
example, if you are using charmaps such as Turkish IBM-1026 or
Japanese IBM-290, where the characters encoded vary from the
encoding in Table 126 on page 788, you may get unpredictable
results with the utilities and functions.
Variant Characters for which encoding may vary from one EBCDIC charmap
file to another. Only the following characters are allowed in this
group:
The following definitions can precede the two sections listed above. Each consists
of the symbol shown in the following list, starting in column 1, including the
surrounding brackets, followed by one or more <blank>s, followed by the value to
be assigned to the symbol.
<code_set_name>
The string literal containing the name of the coded character set name
(IBM-1047, IBM-273, etc.)
<mb_cur_max>
the maximum number of bytes in a multibyte character which can be set to
a value between 1 and 4. EBCDIC locales have mb_cur_max settings of
either 1 or 4. ASCII locales have mb_cur_max settings of 1, 2 or 3.
If it is 1, each character in the character set defined in this charmap is
encoded by a one-byte value. If it is 4, each character in the character set
defined in this charmap is encoded by a one-, two-, three-, or four-byte
value. If it is not specified, the default value of 1 is assumed. If a value of
other than 1 or 4 is specified for an EBCDIC locale, a warning message is
issued and the default value of 1 is assumed.
For ASCII locales mb_cur_max is defined as 1, 2 or 3. The value 1 means
the same as for EBCDIC locales, while the values 2 and 3 mean 2 and 3
bytes per character respectively.
<mb_cur_min>
The minimum number of bytes in a multibyte character. Can be set to 1
only. If a value of other than 1 is specified, a warning message is issued
and the default value of 1 is assumed.
<escape_char>
Specifies the escape character that is used to specify hexadecimal or octal
notation for numeric values. It defaults to the hexadecimal value 0xe0,
which represents the \ character in the coded character set IBM-1047. For
portability among the EBCDIC based systems, the escape character has
been redefined to the / or <slash> character in all IBM-supplied charmap
files, with the following statement:
Additional characters can be defined by the user with symbolic character names.
The CHARMAP section starts with the line containing the keyword CHARMAP, and ends
with the line containing the keywords END CHARMAP. CHARMAP and END CHARMAP must
both start in column one.
The character set mapping definitions are all the lines between the first and last
lines of the CHARMAP section. The formats of the character set mappings for this
section are as follows:
The first format defines a single symbolic name and a corresponding encoding. A
symbolic name is one or more characters with visible glyphs, enclosed between
angle brackets.
For reasons of portability, a symbolic name should include only the characters from
the invariant part of the portable character set. If you use variant characters or
decimal or hexadecimal notation in a symbolic name, the symbolic name will not be
portable. A character following an escape character is interpreted as itself; for
example, the sequence <\\\>> represents the symbolic name \> enclosed within
angle brackets, where the backslash \ is the escape character. If / is the escape
character, the sequence <///>> represents the symbolic name />. In the supplied
charmap files, the escape character has been redefined to the forward slash /.
The number can be written using octal, decimal, or hexadecimal notation. Decimal
numbers are written as a d followed by 2 or 3 decimal digits. Hexadecimal
numbers are written as an x followed by 2 hexadecimal digits. An octal number is
written with 2 or 3 octal digits. As an example, the single byte value x1F could be
written as \37, \x1F, or \d31.
In lines defining ranges of symbolic names, the encoded value is the value for the
first symbolic name in the range (the symbolic name preceding the ellipsis).
Subsequent names defined by the range have encoding values in increasing order.
When constants are concatenated for multibyte character values, they must be of
the same type, and are interpreted in byte order from first to last with the least
significant byte of the multibyte character specified by the last constant. Each value
is then prepended by the byte value of <shift_out> and appended with the byte
value of <shift_in>. Such a string represents one EBCDIC multibyte character, as
the following example shows:
<escape_char> /
<comment_char> %
<mb_cur_max> 4
<mb_cur_min> 1
<shift-out> /x0e
<shift-in> /x0f
CHARMAP
% many definition lines
<j0101>...<j0104> /d129/d254
%many definition lines
END CHARMAP
is interpreted as:
<j0101> /d129/d254
<j0102> /d129/d255
<j0103> /d130/d0
<j0104> /d130/d1
Note: The two functions csid() and wcsid() query the locales and return the
character set identifier for a given character. This information is not currently used
by any other library function.
The CHARSETID section starts with a line containing the keyword CHARSETID, and
ends with the line containing the keywords END CHARSETID. Both CHARSETID and END
CHARSETID must begin in column 1. The lines between the first and last lines of the
CHARSETID section define the character set identifier for the defined coded character
set.
The individual characters are specified by the symbolic name or the value. The
group of characters are specified by two symbolic names or by two numeric values
(or combination) separated by an ellipsis (...). The interpretation of ranges of values
is the same as specified in the CHARMAP section. The character set identifier is
specified by a numeric value.
%
% CHARMAP
%
CHARMAP
...
<j0110> /x42/x5a
<j0111>...<j0112> /x43/xbe
<judc2001>...<judc2094> /x72/x8d
...
END CHARMAP
%
% CHARSETID
%
CHARSETID
...
<j0110> 1
<j0111>...<j0112> 1
<judc2001>...<judc2094> 3
...
END CHARSETID
ASCII locales must be specified using only the characters from the portable
character set, and all character references must be symbolic names, not explicit
code point values.
The definition file is composed of an optional definition section for the escape and
comment characters to be used, followed by the category source definitions.
Comment lines and blank lines can appear anywhere in the locale definition file. If
the escape and comment characters are not defined, default code points are used
(xE0 for the escape character and x7B for the comment character, respectively). The
definition section consists of the following optional lines, where <character> in both
cases is a single-byte character to be used:
escape_char <character>
comment_char <character>
For example, the following statement defines the escape character in this file to be
/ (the <slash> character).
Locale definition files passed to the localedef utility are assumed to be in coded
character set IBM-1047.
To ensure portability among EBCDIC systems, you should redefine these characters
to characters from the invariant part of the portable character set. The suggested
redefinition is:
escape_char /
comment_char %
This suggested redefinition is used in all locale definition files supplied by IBM. For
reasons of portability, you should use the suggested redefinition in all your
customized locale definition files. See Chapter 57, Customizing a locale, on page
839 for information about customizing locales. These two redefinitions should be
placed in the first lines of the locale definition source file, before any of the
redefined characters are used.
Each category source definition consists of a category header, a category body, and
a category trailer, in that order.
category header
consists of the keyword naming the category. Each category name starts
with the characters LC_. The following category names are supported:
LC_CTYPE, LC_COLLATE, LC_NUMERIC, LC_MONETARY, LC_TIME, LC_MESSAGES,
LC_TOD, and LC_SYNTAX.
The LC_TOD and LC_SYNTAX categories, if present, must be the last two
categories in the locale definition file.
category body
consists of one or more lines describing the components of the category.
Each component line has the following format:
<identifier> <operand1>
<identifier> <operand1>;<operand2>;...;<operandN>
Figure 235 on page 798 is an example of locale source containing the header,
body, and trailer.
Figure 235. Example locale source containing header, body, and trailer
You do not have to define each category. Where category definitions are absent
from the locale source, default definitions are used.
In each category, the keyword copy followed by a string specifies the name of an
existing locale to be used as the source for the definition of this category.
If the locale is not found, an error is reported and no locale output is created.
For the batch (EDC(X)LDEF proc) and TSO (LOCALDEF) commands, the name must
be the member name of a partitioned data set allocated to the EDCLOCL DD
statement. For the UNIX System Services localedef command, the copy keyword
specifies the path name of the source file.
You can continue a line in a locale definition file by placing an escape character as
the last character on the line. This continuation character is discarded from the
input. Even though there is no limitation on the length of each line, for portability
reasons it is suggested that each line be no longer than 2048 characters (bytes).
There is no limit on the accumulated length of a continued line. You cannot continue
comment lines on a subsequent line by using an escaped <newline>.
For multibyte characters, the entire encoding sequence, including the shift-out and
shift-in characters, must be present. Otherwise, the sequence of bytes not enclosed
between the shift-out and shift-in characters are interpreted as a sequence of single
byte characters.
LC_CTYPE category
This category defines character classification, case conversion, and other character
attributes. In this category, you can represent a series of characters by using three
adjacent periods as an ellipsis symbol (...). An ellipsis is interpreted as including
all characters with an encoded value higher than the encoded value of the
character preceding the ellipsis and lower than the encoded value following the
ellipsis.
The keywords recognized in the LC_CTYPE category are listed below. In the
descriptions, the term "automatically included" means that it is not an error either to
include or omit any of the referenced characters; they are assumed by default even
if the entire keyword is missing and accepted if present. If a keyword is specified
without any arguments, the default characters are assumed.
You may define additional character classes using your own keywords. A maximum
of 31 classes are supported in total: the 12 standard classes, and up to 19
user-defined classes. The defined classes affect the behavior of wctype() and
iswctype() functions.
escape_char /
comment_char %
%%%%%%%%%%%%%
LC_CTYPE
%%%%%%%%%%%%%
% upper letters are A-Z by default plus the three defined below
upper <A-acute.>;<A-grave.>;<C-acute.>
% lower case letters are a-z by default plus the three defined below
lower <a-acute>;<a_grave><c-acute>
% space characters are default 6 characters plus the one defined below
space <hyphen-minus>
cntrl <alert>;<backspace>;<tab>;<newline>;<vertical-tab>;/
<form-feed>;<carriage-return>;<NUL>;/
<SO>;<SI>
END LC_CTYPE
Note: This is an IBM extension; therefore, locales that use it may not be
portable to localedef tools developed by other vendors.
6. Equivalence class definition. Two or more collating elements have the same
collation value (primary weight).
7. Ordering by weights. When two strings are compared to determine their
relative order, the two strings are first broken up into a series of collating
elements. Each successive pair of elements is compared according to the
relative primary weights for the elements. If they are equal, and more than one
weight is assigned, then the pairs of collating elements are compared again
according to the relative subsequent weights, until either two collating elements
are not equal or the weights are exhausted.
Collating rules
Collation rules consist of an ordered list of collating order statements, ordered from
lowest to highest. The <NULL> character is considered lower than any other
character. The ellipsis symbol ("...") is a special collation order statement. It
specifies that a sequence of characters collate according to their encoded character
values. It causes all characters with values higher than the value of the <collating
identifier> in the preceding line, and lower than the value for the <collating
identifier> on the following line, to be placed in the character collation order
between the previous and the following collation order statements in ascending
order according to their encoded character values.
The use of the ellipsis symbol ties the definition to a specific coded character set
and may preclude the definition from being portable among implementations.
The ellipsis symbol can precede or succeed the ellipsis symbol and may also have
weights on the same line.
A <collating-symbol> can define a position in the relative order for use in weights.
The special symbol IGNORE as a weight indicates that when strings are compared
using the weights at the level where IGNORE is specified, the collating element
should be ignored, as if the string did not contain the collating element. In regular
expressions and pattern matching, all characters that are IGNOREd in their primary
weight form an equivalence class.
All characters specified by an ellipsis are assigned unique weights, equal to the
relative order of the characters. Characters specified by an explicit or implicit
UNDEFINED special symbol are assigned the same primary weight (they belong to the
same equivalence class).
is equivalent to
<a>
Collating keywords
The following keywords are recognized in a collation sequence definition.
copy Specifies the name of an existing locale to be used as the source
for the definition of this category. If this keyword is specified, no
other keyword shall be present in this category. If the locale is not
found, an error is reported and no locale output is created. The
copy keyword cannot specify a locale that also specifies the copy
keyword for the same category.
collating-element
Defines a collating-element symbol representing a multicharacter
collating element. This keyword is optional. In addition to the
collating elements in the character set, the collating-element
keyword can be used to define multicharacter collating elements.
The syntax is:
"collating-element %s from \%s\"", <collating-element>, <string>
% collating elements
1 collating-element <ch> from "<c><h>"
collating-element <Ch> from "<C><h>"
collating-element <eszet> from "<s><z>"
collating-symbol <LOW>
2 collating-symbol <UPPER-CASE>
collating-symbol <LOWER-CASE>
collating-symbol <NONE>
<space>
6 ....
<quotation-mark>
7 <a> <a>;<NONE>;<LOWER-CASE>
10 <a-acute> <a>;<a-acute>;<LOWER-CASE>
11 <a-grave> <a>;<a-grave>;<LOWER-CASE>
8 <A> <a>;<NONE>;<UPPER-CASE>
11 <A-acute> <a>;<a-acute>;<UPPER-CASE>
11 <A-grave> <a>;<a-grave>;<UPPER-CASE>
11 <ch> <ch>;<NONE>;<LOWER-CASE>
11 <Ch> <ch>;<NONE>;<UPPER-CASE>
9 <s> <s>;<s>;<LOWER-CASE>
12 <eszet> "<s><s>";"<eszet><s>";<LOWER-CASE>
9 <z> <z>;<NONE>;<LOWER-CASE>
order_end
Comparison of strings
Compare the strings s1="aAch" and s2="AaCh" using the above LC_COLLATE
definition:
1. s1=> "aA<ch>", and s2=> "Aa<Ch>"
2. first pass:
a. substitute the elements of the strings with their primary weights: s1=>
"<a><a><ch>", s2=> "<a><a><ch>"
b. compare the two strings starting with the first element they are equal.
3. second pass:
a. substitute the elements of the strings with their secondary weights: s1=>
"<NONE><NONE><NONE>", s2=>"<NONE><NONE><NONE>"
b. compare the two strings from the last element to the first they are equal.
4. third pass:
a. substitute the elements of the strings with their third level weights:
s1=> "<LOWER-CASE><UPPER-CASE><LOWER-CASE>",
s2=> "<UPPER-CASE><LOWER-CASE><UPPER-CASE>",
b. compare the two strings starting from the beginning of the strings: s2
compares lower than s1, because <UPPER-CASE> is before <LOWER-CASE>.
LC_MONETARY category
This category defines the rules and symbols used to format monetary quantities.
The operands are strings or integers. The following keywords are supported:
copy Specifies the name of an existing locale to be used as the source
for the definition of this category. If this keyword is specified, no
other keyword should be present in this category. If the locale is not
found, an error is reported and no locale output is created. The
copy keyword cannot specify a locale that also specifies the copy
keyword for the same category.
int_curr_symbol
Specifies the international currency symbol. The operand is a
four-character string, with the first three characters containing the
alphabetic international currency symbol in accordance with those
specified in ISO4217 Codes for the Representation of Currency and
Funds. The fourth character is the character used to separate the
international currency symbol from the monetary quantity.
The following value may also be specified, though it is not If not
defined, it defaults to the empty string ("").
currency_symbol
Specifies the string used as the local currency symbol. If not
defined, it defaults to the empty string ("").
mon_decimal_point
The string used as a decimal delimiter to format monetary
quantities. If not defined it defaults to the empty string ("").
mon_thousands_sep
Specifies the string used as a separator for groups of digits to the
left of the decimal delimiter in formatted monetary quantities. If not
defined, it defaults to the empty string ("").
mon_grouping Defines the size of each group of digits in formatted monetary
quantities. The operand is a sequence of integers separated by
semicolons. Also, for compatibility, it may be a string of integers
separated by semicolons. Each integer specifies the number of
digits in each group, with the initial integer defining the size of the
group immediately preceding the decimal delimiter, and the
following integers defining the preceding groups. If the last integer
is not 1, then the size of the previous group (if any) is used
repeatedly for the rest of the digits. If the last integer is 1, then no
further grouping is performed. If not defined, mon_grouping defaults
to 1 which indicates that no grouping. An empty string is
interpreted as 1.
Figure 238 on page 814 is an example of the definition of the LC_MONETARY category.
%%%%%%%%%%%%%
LC_MONETARY
%%%%%%%%%%%%%
int_curr_symbol "<J><P><Y><space>"
currency_symbol "<yen>"
mon_decimal_point "<period>"
mon_thousands_sep "<comma>"
mon_grouping 3
positive_sign ""
negative_sign "<hyphen-minus>"
int_frac_digits 0
frac_digits 0
p_cs_precedes 1
p_sep_by_space 0
n_cs_precedes 1
n_sep_by_space 0
p_sign_posn 1
n_sign_posn 1
debit_sign "<D><B>"
credit_sign "<C><R>"
left_parenthesis "<left-parenthesis>"
right_parenthesis "<right-parenthesis>"
int_p_cs_precedes -1
int_n_cs_precedes -1
int_p_sep_by_space -1
int_n_sep_by_space -1
int_p_sign_posn -1
int_n_sign_posn -1
END LC_MONETARY
LC_NUMERIC category
This category defines the rules and symbols used to format non-monetary numeric
information. The operands are strings. The following keywords are recognized:
copy Specifies the name of an existing locale to be used as the source
for the definition of this category. If this keyword is specified, no
other keyword should be present in this category. If the locale is not
found, an error is reported and no locale output is created. The
copy keyword cannot specify a locale that also specifies the copy
keyword for the same category.
decimal_point Specifies a string used as the decimal delimiter in numeric,
non-monetary formatted quantities. This keyword cannot be omitted
and cannot be set to the empty string.
thousands_sep Specifies a string containing the symbol that is used as a separator
for groups of digits to the left of the decimal delimiter in numeric,
non-monetary, formatted quantities.
grouping Defines the size of each group of digits in formatted non-monetary
quantities. The operand is a sequence of integers separated by
semicolons. Also, for compatibility, it may be a string of integers
separated by semicolons. Each integer specifies the number of
escape_char /
comment_char %
%%%%%%%%%%%%%
LC_NUMERIC
%%%%%%%%%%%%%
decimal_point "<comma>"
thousands_sep "<space>"
grouping 3
END LC_NUMERIC
LC_TIME category
The LC_TIME category defines the interpretation of the field descriptors used for
parsing, then formatting, the date and time. The descriptors identify the replacement
portion of the string, while the rest of a string is constant. The definition of
descriptors is included in z/OS XL C/C++ Run-Time Library Reference. All these
descriptors can be used in the format specifier in the time formatting functions
strftime().
For the definitions of the time formatting descriptors, see the description of the
strftime() function in z/OS XL C/C++ Run-Time Library Reference.
LC_MESSAGES category
The LC_MESSAGES category defines the format and values for positive and negative
responses. The following keywords are recognized:
copy Specifies the name of an existing locale to be used as the source
for the definition of this category. If you specify this keyword, no
other keyword should be present in this category. If the locale is not
found, an error is reported and no locale output is created. The
copy keyword cannot specify a locale that also specifies the copy
keyword for the same category.
yesexpr The operand consists of an extended regular expression that
describes the acceptable affirmative response to a question that
expects an affirmative or negative response.
noexpr The operand consists of an extended regular expression that
describes the acceptable negative response to a question that
expects an affirmative or negative response.
yestr The operand consists of an fixed string (not a regular expression)
that can be used by an application for composition of a message
that lists an acceptable affirmative response, such as in a prompt.
%%%%%%%%%%%%%
LC_MESSAGES
%%%%%%%%%%%%%
% yes expression is a string that starts with
% "SI", "Si" "sI" "si" "s" or "S"
yesexpr "<circumflex><left-parenthesis><left-square-bracket><s><S>/
<right-square-bracket><left-square-bracket><i><I><right-square-bracket>/
<vertical-line><left-square-bracket><s><S><right-square-bracket>/
<right-parenthesis>"
END LC_MESSAGES
LC_TOD category
The LC_TOD category defines the rules used to define the beginning, end, and
duration of daylight savings time, and the difference between local time and
Greenwich Mean time. This is an IBM extension.
Note: LC_TOD and LC_SYNTAX are not supported for ASCII locales (a locale
specification can not contain a definition for these categories). However, for
consistency with EBCDIC locales, localedef generates default values for these
categories in ASCII locale objects (the values generated for the C locale but with
ASCII code points).
escape_char /
comment-char %
%%%%%%%%%%%%%
LC_TOD
%%%%%%%%%%%%%
% the time zone difference is 8hrs; the name of the daylight saving
% time is PDT, and it starts on the first Sunday of April at 2&00AM
% and ends on the second Sunday of October at 2&00AM
timezone_difference +480
timezone_name "<P><S><T>"
daylight_name "<P><D><T>"
start_month 4
end_month 10
start_week 1
end_week 2
start_day 1
end_day 30
start_time 7200
end_time 3600
shift 3600
END LC_TOD
LC_SYNTAX category
The LC_SYNTAX category defines the variant characters from the portable character
set. LC_SYNTAX is an IBM-specific extension. This category can be queried by the C
library function getsyntx() to determine the encoding of a variant character if
needed.
The operands for the characters in the LC_SYNTAX category accept the single byte
character specification in the form of a symbolic name, the character itself, or the
decimal, octal, or hexadecimal constant. The characters must be specified in the
LC_CTYPE category as a punct character. The values for the LC_SYNTAX characters
must be unique. If symbolic names are used to define the encoding, only the
symbolic names listed for each character should be used.
The code points for the LC_SYNTAX characters are set to the code points specified.
Otherwise, they default to the code points for the respective characters from the
charmap file, if the file is present, or to the code points of the respective characters
in the IBM-1047 code page.
escape_char /
comment-char %
%%%%%%%%%%%%%
LC_SYNTAX
%%%%%%%%%%%%%
backslash "<backslash>"
right_brace "<right-brace>"
left_brace "<left-brace>"
right_bracket "<right-square-bracket>"
left_bracket "<left-square-bracket>"
circumflex "<circumflex>"
tilde "<tilde>"
exclamation_mark "<exclamation-mark>"
number_sign "<number-sign>"
vertical_line "<vertical-line>"
dollar_sign "<dollar-sign>"
commercial_at "<commercial-at>"
grave_accent "<grave-accent>"
END LC_SYNTAX
Method files
Method files can be used when creating ASCII locales. They specify the method
functions used by the C run-time's locale-sensitive interfaces when the ASCII locale
is activated.
IBM ships the method files used to build its ASCII locales in the /usr/lib/nls/method
directory. These method files support various ASCII Latin 1 and non-Latin 1 single
byte encodings, ASCII SJIS and EUC multibyte encodings and UTF-8 multibyte
encodings.
By replacing the CHARMAP related method functions in a method file, users can
create a locale which supports a user-defined code page. For each replaced
Each user provided method must follow the standard interface defined for the API it
implements and add an argument of type _LC_charmap_objhdl_t as the first
argument. The _LC_charmap_objhdl_t is defined in the localdef.h header file.
Users can provide these CHARMAP methods via a DLL side deck, an archive
library or an object file. The user-written method functions are used both by the
locale-sensitive APIs they represent, and also by the localedef utility itself while
generating the method-file based ASCII locale object. This second use by localedef
itself causes a temporary DLL to be created while processing the CHARMAP file
supplied on the -f parameter. The name of the file containing method objects or
side deck information is passed by the localedef utility as a parameter on the c89
command line, so the standard archive/object/side deck suffix naming conventions
apply (for example, .a, .o, .x).
Figure 243 on page 824 shows the expected grammar for a method file.
method_assign :
"csid" meth_name meth_lib_path
"fnmatch" meth_name meth_lib_path
"is_wctype" meth_name meth_lib_path
"mblen" meth_name meth_lib_path
"mbstowcs" meth_name meth_lib_path
"mbtowc" meth_name meth_lib_path
"regcomp" meth_name meth_lib_path
"regerror" meth_name meth_lib_path
"regexec" meth_name meth_lib_path
"regfree" meth_name meth_lib_path
"rpmatch" meth_name meth_lib_path
"strcoll" meth_name meth_lib_path
"strfmon" meth_name meth_lib_path
"strftime" meth_name meth_lib_path
"strptime" meth_name meth_lib_path
"strxfrm" meth_name meth_lib_path
"towlower" meth_name meth_lib_path
"towupper" meth_name meth_lib_path
"wcscoll" meth_name meth_lib_path
"wcsftime" meth_name meth_lib_path
"wcsid" meth_name meth_lib_path
"wcstombs" meth_name meth_lib_path
"wcswidth" meth_name meth_lib_path
"wcsxfrm" meth_name meth_lib_path
"wctomb" meth_name meth_lib_path
"wcwidth" meth_name meth_lib_path
;
meth_name:
global_name
cfunc_name
;
The following additional subroutines are mandatory in AIX method files, but are not
supported on z/OS and if specified are ignored:
mbtopc
mbstopcs
pctomb
pcstombs
Any other method not specified in the method file retains the default. Mixing of
user-written method function names (represented as cfunc_name in the grammar)
and IBM-provided method function names (represented by global_name in the
grammar) is not allowed. A method file should not include both. If the localedef
command encounters both cfunc_name values and global_name values in a
method file, an error is generated and the locale is not created.
It is not mandatory that the METHODS section specify the meth_lib_path name for
all methods. The following is an example of how to specify the meth_lib_path and
what the localedef passes on the c89 command invoking the binder when linking
the method-based ASCII locale object:
METHODS
mblen "__mblen_myuni"
mbstowcs "__mbstowcs_myuni" "/u/my/libmyuni.a"
mbtowc "__mbtowc_myuni"
wcstombs "__wcstombs_myuni" "/u/gen/libgenuni.a"
wcswidth "__wcswidth_myuni"
wctomb "__wctomb_myuni"
wcwidth "__wcwidth_myuni" "./wcwidth.o"
It is also possible to use the -L localedef option to specify the c89 -L library flags
and only reference the library names in the method file following the liblibname.a
convention.
If an individual method does not specify a meth_lib_path name, the method inherits
the most recently specified meth_lib_path name. If no meth_lib_path name is
The method for the mbtowc and wcwidth subroutines should avoid calling other
methods where possible.
Note: AMODE 64 locales are always XPLINK locales, while 31-bit locales may be
XPLINK or non-XPLINK.
The locale DLL object can be loaded by the setlocale() function and then
accessed by the z/OS XL C/C++ functions that are sensitive to the cultural
information, or that can query the locales. For a list of all the library functions
sensitive to locale, see Locale-sensitive interfaces on page 784. For detailed
information on how to invoke localedef, see "localedef Utility" in the z/OS XL C/C++
User's Guide.
The locale DLL object created by localedef must adhere to certain naming
conventions so that the locale can be used by the system. These conventions are
outlined in Locale naming conventions on page 828.
The TSO localedef (LOCALDEF) command and the batch XPLINK localdef
command (EDCXLDEF proc) cannot be used to generate ASCII locales or AMODE
64 locales. Only the UNIX System Services localedef command may be used.
ASCII locales are generated by specifying the -A localedef option on the
command line of the UNIX System Services localedef command. AMODE 64
locales are generated by specifying the -6 option on the command line of the UNIX
System Services localedef command. Specify both -A and -6 to produce locale
The POSIX shell (/bin/sh) UNIX System Services shell, /bin/sh, is an example of a
non-XPLINK application that uses locales. It needs non-XPLINK locales. If the shell
invokes an XPLINK application that uses locales, the application will need an
XPLINK version of the same locale. Usually, both XPLINK and non-XPLINK
versions of a locale are needed whenever an XPLINK application is invoked from
the shell, or when an XPLINK application invokes the shell or any other
non-XPLINK application. Likewise, usually both AMODE 64 and non-XPLINK
versions of a locale are needed whenever a AMODE 64 application is invoked from
the shell, or when a AMODE 64 application invokes the shell or any other
non-XPLINK application. The locale object naming conventions ensure that the
run-time library loads the appropriate version of the locale.
The Codeset parts are optional. If they are not specified, Codeset defaults to
IBM-nnn, where nnn is the default code page, which for EBCDIC locales is shown in
Table 128 on page 830 and for ASCII locales in Table 129 on page 832. (The
modifier portion defaults to nothing.)
For PDS resident locales, the mapping between the descriptive locale name and
the eight-character name of the locale object is performed as follows:
1. The Language-Territory part is mapped into a two-letter LT code.
2. The Codeset part is mapped into a two-letter CC code.
3. The object name is built from a prefix, the two-letter LT code, and the two-letter
CC code. The prefix is one of the following show in Table 127 on page 829.
(Note that the @-sign in the PDS and z/OS UNIX locale names always has
Latin-1/Open Systems encoding; see IBM-1047 CHARMAP.)
Type Mapping
Non-XPLINK Fr_BE.IBM-1148 maps to EDC$FBHO
Fr_BE.IBM-1148@euro maps to EDC@FBHO
Fr_BE.IBM-1148@preeuro maps to EDC3FBHO
XPLINK Fr_BE.IBM-1148 maps to CEH$FBHO
Fr_BE.IBM-1148@euro maps to CEH@FBHO
Fr_BE.IBM-1148@preeuro maps to CEH3FBHO
ASCII Fr_BE.ISO8859-1 maps to CEJ$FBI1
Fr_BE.UTF-8 maps to CEJ$FBU8
AMODE 64 Fr_BE.IBM-1148 maps to CEQ$FBHO
Fr_BE.IBM-1148@euro maps to CEQ@FBHO
Fr_BE.IBM-1148@preeuro maps to CEQ3FBHO
AMODE 64 ASCII Fr_BE.ISO8859-1 maps to CEZ$FBI1
Fr_BE.UTF-8 maps to CEZ$FBU8
For resident locales in the z/OS UNIX file system, the mapping between the
descriptive locale name and the z/OS UNIX file name is performed as follows:
1. The locale object file name starts out the same as the descriptive name.
2. If the locale object is XPLINK, add a suffix of ".xplink" to the end of the object
file name.
3. If the locale object is AMODE 64, add a suffix of ".lp64" to the end of the object
file name.
Type Mapping
Non-XPLINK Fr_BE.IBM-1148 maps to Fr_BE.IBM-1148
Fr_BE.IBM-1148@euro maps to Fr_BE.IBM-1148@euro
Fr_BE.IBM-1148@preeuro maps to Fr_BE.IBM-1148@preeuro
XPLINK Fr_BE.IBM-1148 maps to Fr_BE.IBM-1148.xplink
Fr_BE.IBM-1148@euro maps to Fr_BE.IBM-1148@euro.xplink
Fr_BE.IBM-1148@preeuro maps to Fr_BE.IBM-1148@preeuro.xplink
ASCII Fr_BE.ISO8859-1 maps to Fr_BE.ISO8859-1.xplink
Fr_BE.UTF-8 maps to Fr_BE.UTF-8.xplink
AMODE 64 Fr_BE.IBM-1148 maps to FR_BE.IBM-1148.lp64
Fr_BE.IBM-1148@euro maps to Fr_BE.IBM-1148@euro.lp64
Fr_BE.IBM-1148@preeuro maps to Fr_BE.IBM-1148@preeuro.lp64
AMODE 64 ASCII Fr_BE.ISO8859-1 maps to Fr_BE.ISO8859-1.lp64
Fr_BE.UTF-8 maps to Fr_BE.UTF-8.lp64
You can customize this table by adding new LOCALE name mappings. z/OS XL
C/C++ reserves alphabetic LT codes, but you can use codes containing numeric
values for your own customized names.
The Language-Territory names and their mappings into LT codes that are provided
are shown in Table 128.
Table 128. Supported language-territory names and LT codes for EBCDIC locales
Locale Language Country/Territory EBCDIC 2-Byte
Name Codeset LT Code
Ar_AA Arabic Algeria, Bahrain, Egypt, Iraq, IBM-425 AR
Jordan, Kuwait, Lebanon, Libya,
Morocco, Oman, Qatar, Saudi
Arabia, Syria, Tunisia, U.A.E.,
Yemen
Be_BY Byelorussian Belarus IBM-1025 BB
Bg_BG Bulgarian Bulgaria IBM-1025 BG
C IBM-1047 CC
Ca_ES Catalan Spain IBM-924 CS
Cs_CZ Czech Czech Republic IBM-870 CZ
Da_DK Danish Denmark IBM-1047 DA
De_AT German Austria IBM-924 DT
De_CH German Switzerland IBM-1047 DC
De_DE German Germany IBM-1047 DD
De_LU German Luxembourg IBM-924 DL
El_GR Greek Greece IBM-875 EL
En_AU English Australia IBM-1047 NA
En_BE English Belgium IBM-924 EB
En_CA English Canada IBM-1047 EC
En_GB English United Kingdom IBM-1047 EK
En_HK English China (Hong Kong S.A.R. of IBM-1047 NH
China)
En_IE English Ireland IBM-924 EI
En_IN English India IBM-1047 NI
En_JP English Japan IBM-1027 EJ
Table 129 shows the supported language-territory names and LT codes for ASCII
locales. Note that ASCII locale names can also be coded
<uppercase><lowercase>_<uppercase><uppercase>. For example, both en_US and
En_US are valid ASCII locale names.
Table 129. Supported language-territory names and LT codes for ASCII locales
Locale Language Country/Territory ASCII Codeset 2-Byte LT
Name Code
be_BY Byelorussian Belarus ISO8859-5 BB
bn_IN Bengali India UTF-8 BN
CODESET specifies the name Codeset; CODE specifies the respective CC code.
You can customize this table by adding new CODESET names. The alphabetic codes
in the first byte of each CC name are reserved by IBM for future use, but you can
use codes starting with numeric values for your own customized names.
Table 130 lists the Codeset names and their mappings into CC codes that are
provided.
Table 130. Supported codeset names and CC codes
Codesets Primary Country or Territory 2-Byte CC code
Big5 Taiwan BT
IBM-037 USA, Canada, Brazil EA
IBM-273 Germany, Austria EB
IBM-274 Belgium EC
IBM-277 Denmark, Norway EE
IBM-278 Finland, Sweden EF
IBM-280 Italy EG
IBM-282 Portugal EI
IBM-284 Spain, Latin America EJ
IBM-285 United Kingdom EK
IBM-290 Japan (Katakana) EL
IBM-297 France EM
IBM-300 Japanese DBCS EN
IBM-420 Algeria, Bahrain, Egypt, Iraq, Jordan, Kuwait, FF
Lebanon, Libya, Morocco, Oman, Qatar, Saudi
Arabia, Syria, Tunisia, U.A.E., Yemen
IBM-424 Israel FB
IBM-425 Algeria, Bahrain, Egypt, Iraq, Jordan, Kuwait, AR
Lebanon, Libya, Morocco, Oman, Qatar, Saudi
Arabia, Syria, Tunisia, U.A.E., Yemen
IBM-500 International EO
IBM-838 Thailand EP
The exceptions to the rule above are the following special locale names, which are
already recognized:
v C (EBCDIC and ASCII)
v POSIX (EBCDIC and ASCII)
v SAA (EBCDIC only)
v S370 (EBCDIC only)
The special names C, POSIX, SAA, and S370 always refer to the built-in locales, which
cannot be modified. The S370 locale and the following names are for locales in an
old format, created with the EDCLOC assembler macro, rather than with the localedef
utility:
v GERM (EBCDIC only)
v FRAN (EBCDIC only)
v UK (EBCDIC only)
v ITAL (EBCDIC only)
v SPAI (EBCDIC only)
v USA (EBCDIC only)
You can use the C macros in Table 131 on page 838, which are defined in the
locale.h header file, as synonyms for these special locale names. These macros
can only be used for EBCDIC locales. The <prefix> in the Compiled locale column
The predefined name for the built-in locale in the old format is S370.
The rest of the special names refer to the EBCDIC locale objects whose names are
built by prepending the letters EDC$ for non-XPLINK locales or CEH$ for XPLINK
locales to the special name, as for EDC$FRAN.
The following example assumes that the target of the generated locale will be a
data set, but locales may also reside in a z/OS UNIX file system (see Locale
naming conventions on page 828 for differences in object names). In this example
you will build a locale named TEXAN using the charmap file representing the
IBM-1047 encoded character set. The locale is derived from the locale representing
the English language and the cultural conventions of the United States. We will
assume that non-XPLINK, XPLINK, and AMODE 64 applications will use the TEXAN
locale. All three versions of the TEXAN locale will be generated.
1. See Locale source files on page 947 to determine the source of the locale you
are going to use. In this case, it is the English language in the United States
locale, the source for which is the member EDC$EUEY of the PDS
CEE.SCEELOCX.
2. Copy the member EDC$EUEY from PDS CEE.SCEELOCX to the data set
hlq.LOCALE.SOURCE which has been pre-allocated with the same attributes as
CEE.SCEELOCX.
3. In your new file, change the locale variables to the desired values. For example,
change
d_t_fmt "%a %b %e %H:%M:%S %Z %Y
to
d_t_fmt "Howdy Pardner %a %b %e %H:%M:%S %Z %Y"
4. This locale's <Language>-<Territory> value is TEXAN. The <Codeset> value is
IBM-1047. TEXAN is not a valid PDS resident locale name in the run-time library,
because it does not appear in the run-time Locale Name Table. You must
modify the table to include the TEXAN locale. Here are the steps to follow.
a. Copy the member EDC$LCNM from PDS CEE.SCEESAMP to the data set
hlq.LOCALE.TABLE which has been pre-allocated with the same attributes
as CEE.SCEESAMP. The z/OS XL C/C++ Library uses this table to map
locale code registry prefixes into two-character codes.
b. For this example, insert a new line into the assembler table before the last
EDCLOCNM TYPE=END entry:
EDCLOCNM TYPE=ENTRY,LOCALE=TEXAN,CODESET=IBM-1047,CODE=1T
5. Now that your locale name table has been modified, you must make it available
to the system. Assemble the EDC$LCNM member and link-edit it into the
hlq.LOCALE.LOADLIB load library with the member name EDC$LCNM. For our
example, this is done as follows:
6. Generate the non-XPLINK, XPLINKand 64bit locale objects into a load library.
Note that both the XPLINK and 64bit locale objects must be placed in a PDSE,
while non-XPLINK locale objects may be in either a PDS or PDSE load library.
a. Determine the correct locale object names, using the locale naming
Conventions outlined in Locale naming conventions on page 828. PDS
resident locale object names are of the form <prefix><LT><CC> .
For this non-XPLINK locale the <prefix> is EDC$, the <LT> code for TEXAN is
1T and the <CC> code for IBM-1047 is EY. The non-XPLINK object name is
therefore EDC$1TEY.
For this XPLINK locale the <prefix> is CEH$. The <LT>and <CC> codes
remain the same. The XPLINK object name is therefore CEH$1TEY.
For this 64bit locale the <prefix> is CEQ$. The <LT> and <CC> codes
remain the same. The 64bit locale object name is, therefore, CEQ$1TEY.
b. Use localedef to generate the locale objects.
v For non-XPLINK:
v For XPLINK:
v For 64bit
The batch and TSO versions of the localedef utility cannot be used to
generate 64bit locales. The UNIX Systems Services utility must be used.
To do this from TSO or batch the BPXBATCH utility can be used. See z/OS
UNIX System Services Command Reference for more information about
BPXBATCH. Here, we will assume we are in a UNIX System Services shell
session:
See z/OS XL C/C++ User's Guide for detailed information about the batch and
TSO versions of localedef utility. The UNIX System Services version of the
localedef utility is also described in z/OS UNIX System Services Command
Reference.
Note: The TEXAN locale uses one of the IBM supplied CHARMAPs. If you need
to customize a CHARMAP, then you must define its two-letter <CC> code in the
Codeset Name table EDCUCSNM. This is similar to defining the locale TEXAN in
EDC$LCNM. The two-letter CHARMAP codes beginning with a number are
reserved for customer use. This is the same as the convention for
customer-supplied Locale Name <LT> codes in the Locale Name table. The <CC>
portion of your locale object names would then change to be the new <CC>
value you added to the Codeset Name table.
For example, assume that the CCNGCL1 program has been compiled with LP64 into a
UNIX file system executable called getlocname. Further assume that you have
generated non-XPLINK, XPLINK and AMODE 64 UNIX file system resident versions
of the TEXAN locale into your current directory. The following commands make TEXAN
available to non-XPLINK, XPLINK and AMODE 64 applications:
$ ls
TEXAN.IBM-1047 TEXAN.IBM-1047.xplink TEXAN.IBM-1047.lp64 getlocname
$ export LOCPATH=$PWD
$ export LC_ALL=TEXAN.IBM-1047
$ getlocname
Default NULL locale = C
Default "" locale = /u/marcw/TEXAN.IBM-1047.lp64
$
If getlocname was compiled non-XPLINK then the output would look like the
following:
$ getlocname
Default NULL locale = C
Default "" locale = /u/marcw/TEXAN.IBM-1047
$
$ getlocname
Default NULL locale = C
Default "" locale = /u/marcw/TEXAN.IBM-1047.xplink
$
Note: You cannot customize the built-in locales, C, POSIX, SAA, or S370. The locale
source files EDC$POSX and EDC$SAAC are provided for reference only.
#include <stdio.h>
#include <time.h>
#include <locale.h>
int main(void){
char dest[80];
int ch;
time_t temp;
struct tm *timeptr;
temp = time(NULL);
timeptr = localtime(&temp);
/* Fetch default locale name */
printf("Default empty_str locale is %s\n",setlocale(LC_ALL,""));
ch = strftime(dest,sizeof(dest)-1,
"Local C datetime is %c", timeptr);
printf("%s\n", dest);
return(0);
}
Compile the program. Before you execute it, ensure the load library containing the
non-XPLINK version of the TEXAN locale and updated table is available. If you
compile your program XPLINK, ensure the load library containing the XPLINK
version of the TEXAN locale and updated Locale Name table is available. If you
compile your program LP64, ensure the load library containing the 64bit version of
the TEXAN locale and updated Locale Name table is available. The output should be
similar to:
Default empty_str locale is S370
Local C datetime is Fri Aug 20 14:58:12 1993
New locale is TEXAN
Texan datetime is Howdy Pardner Fri Aug 20 14:58:12 1993
For programs which are run POSIX(OFF), and which are not 64bit programs, if the
second operand to setlocale() had been NULL, rather than "", the default locale
name returned would have been C.
setlocale(LC_ALL,"") returns "S370"
setlocale(LC_ALL,NULL) returns "C"
#ifdef __cplusplus
extern "C"{
#else
#pragma linkage(CEEBINT,OS)
#endif
#ifdef __cplusplus
}
#endif
#include <locale.h>
#include <stdio.h>
int main(void){
printf("Default NULL locale = %s\n", setlocale(LC_ALL,NULL));
printf("Default \"\" locale = %s\n", setlocale(LC_ALL,""));
}
If the above example is compiled and executed with the TEXAN locale, the results
are as follows:
CEEBINT entry. number = 7
Locale = TEXAN.IBM-1047
Default NULL locale = TEXAN.IBM-1047
Default "" locale = S370
The exit CEEBINT may provide a uniform way of restricting the use of customized
locales across an installation. To do this, a system programmer can compile
CEEBINT separately, and link it with the application program that will use it. The
disadvantage to this approach is that CEEBINT must be link-edited into each user
module explicitly. See Chapter 46, Using run-time user exits, on page 667 for
more information about user exits.
Figure 246 on page 845 shows a sample program (CCNGCL3) that uses
environment variables to select a locale. (For more information about setting
environment variables, see Chapter 32, Using environment variables, on page
467.)
#include <locale.h>
#include <stdio.h>
int main(void){
printf("Default NULL locale = %s\n", setlocale(LC_ALL,NULL));
printf("Default \"\" locale = %s\n", setlocale(LC_ALL,""));
return(0);
}
If you run this program in Figure 246 as is, without calling setenv(), you can expect
the following result (for a 31-bit, POSIX(OFF), program ):
Default NULL locale = C
Default "" locale = S370
On the other hand, if you issue the above setenv() call after main() but before the
first printf() statement, the LC_ALL variable will be set to "TEXAN.IBM-1047" and
you can expect this result instead:
Default NULL locale = C
Default "" locale = TEXAN.IBM-1047
In the example above, the default NULL locale returns C because the value of
LC_ALL does not affect the current locale until the next setlocale(LC_ALL, "") is
done. When this call is made, the LC_ALL environment variable will be used and the
locale will be set to TEXAN.IBM-1047.
The names of the environment variables match the names of the locale categories:
v LC_ALL
v LC_COLLATE
v LC_CTYPE
v LC_MONETARY
v LC_NUMERIC
v LC_TIME
v LC_TOD
v LC_SYNTAX
TZ=standardHH[:MM[:SS]]
[daylight[HH[:MM[:SS:]]]
[,startdate[/starttime],enddate[/endtime]]]
The value of the TZ or _TZ environment variable has the following five fields (two
required and three optional):
standard
An alphabetic abbreviation for the local standard time zone (for example, GMT,
EST, MSEZ).
HH[:MM[:SS]]
The time offset westward from the universal reference time. A leading minus
sign (-) means that the local time zone is east of the universal reference time.
Note: The time zone external variables, tzname, timezone, and daylight,
declarations remain feature test protected in time.h. Definition of these external
variables are only known to the C/C++ run-time library if the z/OS UNIX System
Services C/C++ signature CSECT is link edited with your C/C++ application.
The POSIX definition of the C locale is described below, with the IBM extensions
LC_SYNTAX and LC_TOD showing their default values.
The SAA and S370 definitions of the C locale are different from the POSIX definition;
consistency with previous releases of z/OS XL C/C++ is provided for migration
compatibility. The differences are described in Differences between SAA C and
POSIX C locales on page 858.
The relationship between the POSIX C and SAA C locales is as follows. If you are
running with the run-time option POSIX(OFF):
1. The SAA C locale definition is the default. "C", "SAA", and "S370" are treated as
synonyms for the SAA C locale definition, which is prebuilt into the library.
The source file EDC$SAAC LOCALE is provided for reference, but cannot be used
to alter the definition of this prebuilt locale.
2. Issuing setlocale(category, "") has the following effect:
v First, locale-related environment variables are checked for the locale name to
use in setting the category specified. Querying the locale with
setlocale(category, NULL) returns the name of the locales specified by the
appropriate environment variables.
v If no non-null environment variable is present, then it is the equivalent of
having issued setlocale(category, "S370"). That is, the locale chosen is
the SAA C locale definition, and querying the locale with setlocale(category,
NULL) returns "S370" as the locale name.
3. If no setlocale() function is issued, or setlocale(LC_ALL, "C"), then the locale
chosen is the pre-built SAA C locale, and querying the locale with
setlocale(category, NULL) returns "C" as the locale name.
4. For setlocale(LC_ALL,"SAA"), the locale chosen is the pre-built SAA C locale,
and querying the locale with setlocale(category, NULL) returns "SAA" as the
locale name.
5. For setlocale(LC_ALL,"S370"), the locale chosen is the pre-built SAA C locale,
and querying the locale with setlocale(category, NULL) returns "S370" as the
locale name. AMODE 64 applications do not support the "S370" locale, and
setlocale will fail requests for that name.
6. For setlocale(LC_ALL,"POSIX"), the locale chosen is the pre-built POSIX C
locale, and querying the locale with setlocale(category, NULL) returns "POSIX"
as the locale name.
The setlocale() function supports locales built using the localedef utility, as well as
locales built using the assembler source and produced by the EDCLOC macro.
However, locales built using EDCLOC are not supported when running AMODE 64
applications.
The LC_TOD category for the SAA C and POSIX C locales can be customized during
installation of the library by your system programmer. See Customizing your
installation on page 845 for more information. The supplied default will obtain the
time zone difference from the operating system. However, it will not define the
daylight savings time.
The LC_SYNTAX category for the SAA C and POSIX C locales is set to the IBM-1047
definition of the variant characters. Figure 247 lists other locale categories for the
POSIX C locale.
escape_char /
comment_char %
%%%%%%%%%%%%
LC_CTYPE
%%%%%%%%%%%%
% "alpha" is by default "upper" and "lower"
% "alnum" is by definition "alpha" and "digit"
upper <A>;<B>;<C>;<D>;<E>;<F>;<G>;<H>;<I>;<J>;<K>;<L>;<M>;/
<N>;<O>;<P>;<Q>;<R>;<S>;<T>;<U>;<V>;<W>;<X>;<Y>;<Z>
lower <a>;<b>;<c>;<d>;<e>;<f>;<g>;<h>;<i>;<j>;<k>;<l>;<m>;/
<n>;<o>;<p>;<q>;<r>;<s>;<t>;<u>;<v>;<w>;<x>;<y>;<z>
digit <zero>;<one>;<two>;<three>;<four>;/
<five>;<six>;<seven>;<eight>;<nine>
space <tab>;<newline>;<vertical-tab>;<form-feed>;/
<carriage-return>;<space>
cntrl <alert>;<backspace>;<tab>;<newline>;<vertical-tab>;/
<form-feed>;<carriage-return>;/
<NUL>;<SOH>;<STX>;<ETX>;<EOT>;<ENQ>;<ACK>;<SO>;/
<SI>;<DLE>;<DC1>;<DC2>;<DC3>;<DC4>;<NAK>;<SYN>;/
<ETB>;<CAN>;<EM>;<SUB>;<ESC>;<IS4>;<IS3>;<IS2>;/
<IS1>;<DEL>
punct <exclamation-mark>;<quotation-mark>;<number-sign>;/
<dollar-sign>;<percent-sign>;<ampersand>;<apostrophe>;/
<left-parenthesis>;<right-parenthesis>;<asterisk>;/
<plus-sign>;<comma>;<hyphen>;<period>;<slash>;/
<colon>;<semicolon>;<less-than-sign>;<equals-sign>;/
<greater-than-sign>;<question-mark>;<commercial-at>;/
<left-square-bracket>;<backslash>;<right-square-bracket>;/
<circumflex>;<underscore>;<grave-accent>;/
<left-curly-bracket>;<vertical-line>;<right-curly-bracket>;<tilde>
xdigit <zero>;<one>;<two>;<three>;<four>;/
<five>;<six>;<seven>;<eight>;<nine>;/
<A>;<B>;<C>;<D>;<E>;<F>;/
<a>;<b>;<c>;<d>;<e>;<f>
blank <space>;/
<tab>
toupper (<a>,<A>);(<b>,<B>);(<c>,<C>);(<d>,<D>);(<e>,<E>);/
(<f>,<F>);(<g>,<G>);(<h>,<H>);(<i>,<I>);(<j>,<J>);/
(<k>,<K>);(<l>,<L>);(<m>,<M>);(<n>,<N>);(<o>,<O>);/
(<p>,<P>);(<q>,<Q>);(<r>,<R>);(<s>,<S>);(<t>,<T>);/
(<u>,<U>);(<v>,<V>);(<w>,<W>);(<x>,<X>);(<y>,<Y>);/
(<z>,<Z>)
tolower (<A>,<a>);(<B>,<b>);(<C>,<c>);(<D>,<d>);(<E>,<e>);/
(<F>,<f>);(<G>,<g>);(<H>,<h>);(<I>,<i>);(<J>,<j>);/
(<K>,<k>);(<L>,<l>);(<M>,<m>);(<N>,<n>);(<O>,<o>);/
(<P>,<p>);(<Q>,<q>);(<R>,<r>);(<S>,<s>);(<T>,<t>);/
(<U>,<u>);(<V>,<v>);(<W>,<w>);(<X>,<x>);(<Y>,<y>);/
(<Z>,<z>)
END LC_CTYPE
%%%%%%%%%%%%
LC_COLLATE
%%%%%%%%%%%%
order_start
% ASCII Control characters
<NUL>
<SOH>
<STX>
<ETX>
<EOT>
Chapter 59. Definition of S370 C, SAA C, and POSIX C locales 851
Figure 247. Additional locale categories for POSIX C (Part 2 of 6)
852 z/OS V1R13.0 XL C/C++ Programming Guide
<ENQ>
<ACK>
<alert>
<backspace>
<tab>
<newline>
<vertical-tab>
<form-feed>
<carriage-return>
<SO>
<SI>
<DLE>
<DC1>
<DC2>
<DC3>
<DC4>
<NAK>
<SYN>
<ETB>
<CAN>
<EM>
<SUB>
<ESC>
<IS4>
<IS3>
<IS2>
<IS1>
<space>
<exclamation-mark>
<quotation-mark>
<number-sign>
<dollar-sign>
<percent-sign>
<ampersand>
<apostrophe>
<left-parenthesis>
<right-parenthesis>
<asterisk>
<plus-sign>
<comma>
<hyphen>
<period>
<slash>
<zero>
<one>
<two>
<three>
<four>
<five>
<six>
<seven>
<eight>
<nine>
<colon>
<semicolon>
<less-than-sign>
<equals-sign>
<greater-than-sign>
<question-mark>
<commercial-at>
<A>
<B>
<C>
<D>
<E>
<F>
<G>
Chapter 59. Definition of S370 C, SAA C, and POSIX C locales 853
Figure 247. Additional locale categories for POSIX C (Part 3 of 6)
854 z/OS V1R13.0 XL C/C++ Programming Guide
<H>
<I>
<J>
<K>
<L>
<M>
<N>
<O>
<P>
<Q>
<R>
<S>
<T>
<U>
<V>
<W>
<X>
<Y>
<Z>
<left-square-bracket>
<backslash>
<right-square-bracket>
<circumflex>
<underscore>
<grave-accent>
<a>
<b>
<c>
<d>
<e>
<f>
<g>
<h>
<i>
<j>
<k>
<l>
<m>
<n>
<o>
<p>
<q>
<r>
<s>
<t>
<u>
<v>
<w>
<x>
<y>
<z>
<left-curly-bracket>
<vertical-line>
<right-curly-bracket>
<tilde>
<DEL>
order_end
END LC_COLLATE
%%%%%%%%%%%%
LC_MONETARY
%%%%%%%%%%%%
int_curr_symbol ""
currency_symbol ""
mon_decimal_point ""
mon_thousands_sep "" Chapter 59. Definition of S370 C, SAA C, and POSIX C locales 855
mon_grouping ""
856 z/OS V1R13.0 XL C/C++ Programming Guide
positive_sign ""
negative_sign ""
int_frac_digits -1
frac_digits -1
p_cs_precedes -1
p_sep_by_space -1
n_cs_precedes -1
n_sep_by_space -1
p_sign_posn -1
n_sign_posn -1
END LC_MONETARY
%%%%%%%%%%%%
LC_NUMERIC
%%%%%%%%%%%%
decimal_point "<period>"
thousands_sep ""
grouping ""
END LC_NUMERIC
%%%%%%%%%%%%
LC_TIME
%%%%%%%%%%%%
abday "<S><u><n>";/
"<M><o><n>";/
"<T><u><e>";/
"<W><e><d>";/
"<T><h><u>";/
"<F><r><i>";/
"<S><a><t>"
day "<S><u><n><d><a><y>";/
"<M><o><n><d><a><y>";/
"<T><u><e><s><d><a><y>";/
"<W><e><d><n><e><s><d><a><y>";/
"<T><h><u><r><s><d><a><y>";/
"<F><r><i><d><a><y>";/
"<S><a><t><u><r><d><a><y>"
abmon "<J><a><n>";/
"<F><e><b>";/
"<M><a><r>";/
"<A><p><r>";/
"<M><a><y>";/
"<J><u><n>";/
"<J><u><l>";/
"<A><u><g>";/
"<S><e><p>";/
"<O><c><t>";/
"<N><o><v>";/
"<D><e><c>"
mon "<J><a><n><u><a><r><y>";/
"<F><e><b><r><u><a><r><y>";/
"<M><a><r><c><h>";/
"<A><p><r><i><l>";/
"<M><a><y>";/
"<J><u><n><e>";/
END LC_TIME
%%%%%%%%%%%%
LC_MESSAGES
%%%%%%%%%%%%
yesexpr "<circumflex><left-square-bracket><y><Y><right-square-bracket>"
noexpr "<circumflex><left-square-bracket><n><N><right-square-bracket>"
END LC_MESSAGES
If you are running in a C locale, one way you can determine if the SAA C or the
POSIX locale is in effect is to check if the cent sign ( at X'4A') is defined as a
punctuation character. Under the default POSIX support, the cent sign is not part of
the POSIX portable character set. Figure 248 on page 859 (sample CCNGDL1)
shows how to perform this test.
#include <stdio.h>
#include <ctype.h>
int main(void)
{
if (ispunct(0x4A)) {
printf(" cent sign is punct\n");
printf(" current locale is SAA- or S370-like\n");
}
else {
printf(" cent sign is not punct\n");
printf(" default locale is POSIX-like\n");
}
return(0);
}
Under the SAA or System/370 default locales, the lowercase letters collate before
the uppercase letters; under the POSIX definition, the lowercase letters collate after
the uppercase letters. The locale "" is the same locale as the one obtained from
setlocale(LC_ALL,""). For more detail on these special environment variables, see
Chapter 32, Using environment variables, on page 467. Other differences between
the SAA C locale and the POSIX C locale are as follows:
<mb_cur_max> The POSIX C locale is built using coded character
set IBM-1047, with <mb_cur_max> as 1. The SAA C
locale is built using coded character set IBM-1047,
with <mb_cur_max> as 4.
The cent sign In the default POSIX support, the cent sign () is
not part of the POSIX portable character set; in the
SAA locale, it is defined as a punctuation character.
Collation weight by case In the POSIX definition, the lowercase letters collate
after the uppercase letters; in the SAA or
System/370 default locales, the lowercase letters
collate before the uppercase letters.
LC_CTYPE category The SAA C locale has all the EBCDIC control
characters defined in the cntrl class. The POSIX
C locale has only the ASCII control characters in the
cntrl class. The SAA C locale includes (the cent
character) and (the broken vertical line) as
punct characters. The POSIX C locale does not
group these characters as punct characters.
LC_COLLATE category The default collation for the SAA C locale is the
EBCDIC sequence. The POSIX C locale uses the
ASCII collation sequence; the first 128 ASCII
characters are defined in the collation sequence,
and the remaining EBCDIC characters are at the
end of the collating sequence.
LC_TIME category The SAA C locale uses the date and time format
(d_t_fmt) as "%Y/%M/%D %X"; the POSIX C locale
See z/OS XL C/C++ User's Guide for descriptions of the genxlt and iconv utilities,
z/OS XL C/C++ Run-Time Library Reference for descriptions of the iconv()
functions, and z/OS MVS Program Management: User's Guide and Reference,
SA22-7643 for descriptions of the uconvdef utility.
The name of the conversion programs have the following naming conventions:
v The name starts with a four letter prefix. The prefix is EDCU for non-XPLINK
converters, CEHU for XPLINK converters, and CEQU for AMODE 64 converters.
v The prefix is followed by the two-letter CC code that corresponds to the
CodesetRegistry.CodesetEncoding name of the fromCodeSet defined in the
Table 130 on page 835.
v The first CC code is followed by the two-letter CC code than corresponds to the
CodesetRegistry.CodesetEncoding name of the toCodeSet defined in the
Table 130 on page 835.
To generate your own conversions, you must modify the codeset name table
EDCUCSNM with the macros described in Locale naming conventions on page 828.
For descriptions of the genxlt and iconv utilities, refer to z/OS XL C/C++ User's
Guide. There is also a UNIX System Services iconv utility, which is described in
z/OS UNIX System Services Command Reference.
The iconv utility can also perform bidirectional layout transformation (such as
shaping and reordering) while converting from fromCodeSet to toCodeSet according
to the value of an environment variable called _BIDION. The value of this variable
is either set to TRUE to activate the BiDi layout transformation or FALSE to prevent
the bidirectional layout transformation. If this variable is not defined in the
environment it defaults to FALSE. The _BIDIATTR environment variable can be
used to contain the bidirectional attributes (for information on bidirectional layout
transformation see Chapter 62, Bidirectional language support, on page 903)
which will determine the way the bidirectional transformation takes place. These two
environment variables are described in Chapter 32, Using environment variables,
on page 467.
The iconv() family of functions has been modified to utilize character conversion
services provided by Unicode Services. The iconv_open(), iconv(), and
iconv_close() function interfaces remain unchanged except for the addition of the
following:
v Four new errno values - ECUNNOENV, ECUNNOCONV, ECUNNOTALIGNED,
and ECUNERR
v Two new environment variables - _ICONV_MODE and _ICONV_TECHNIQUE
For more information about these errno values and environment variables, see the
iconv_open() function description in z/OS XL C/C++ Run-Time Library Reference.
There are differences in externals between the iconv() family of functions and
Unicode Services. However, the differences in externals are managed by the iconv()
family of functions except where noted in the C/C++ Migration Guide for Application
Developers. All conversions listed in Table 133 on page 865 and Table 134 on page
876 will continue to work as they do today. However, Unicode Services supports
conversions between thousands of additional character sets not listed inTable 133
on page 865 and Table 134 on page 876. A complete list of conversions supported
by Unicode Services can be found in EBCDIC Conversion Table, ASCII Conversion
Table, and Unicode Conversion Table in z/OS Unicode Services User's Guide and
Reference. To set up a conversion using iconv_open() for any of the character sets
listed in EBCDIC Conversion Table, ASCII Conversion Table, and Unicode
Conversion Table, use a character string representing the CCSIDs for
fromcode/tocode. For example, to set up a conversion from CCSID 00256 to CCSID
00870 using conversion technique R, you need to set the _ICONV_TECHNIQUE
environment variable to R and call iconv_open() as follows:
cd = iconv_open(00870, 00256);
Conversions:
Latin-1 EBCDIC to/from Latin-1 EBCDIC: RTC
Non-Latin-1 EBCDIC to/from Latin-1 EBCDIC: RTC
Latin-1 ASCII to/from Latin-1 EBCDIC: C-RTC
Non_latin-1 ASCII to/from Latin-1 EBCDIC: C-RTC
IBM-850 IBM-1047
Code Point Code Point
0A <-> 15
DA -> 3F
0A <- 25
The code set converters that are provided as programs are shown in Table 133 on
page 865. The GENXLT source for the code set converters are shipped in the
CEE.SCEEGXLT data set.
Notes:
1. Table 132 shows the <prefix> values that appear in the Program Name column
of Table 133 on page 865.
Table 132. Referencing data types
Converter Prefix
31-bit EDCU
31-bit XPLINK CEHU
AMODE 64 CEQU
CAUTION:
The naming conventions provided for building genxlt conversion tables allow
the iconv interfaces to recognize the converters. All genxlt conversion tables,
whether customized or shipped in z/OS Language Environment, are intended
for use with the C/C++ iconv interfaces or the iconv utility. Direct
programming to these tables is not supported and will produce unpredictable
results.
IBM makes no guarantee that converter binaries or source shipped with z/OS
Language Environment will continue to be shipped in future releases. For a
complete list of names and aliases removed in z/OS V1R9, go to the following
URL: http://www-03.ibm.com/systems/z/os/zos/features/lang_environment/
assist/support/pk65279.html
Starting in z/OS V1R12, the C/C++ Run-time Library will not ship the genxlt
source for character conversions performed by Unicode Services. However, if
you require the affected genxlt converters and plan to build them by creating
your own source or by migrating source from a prior release, you must
continue to name them as shown in Table 133. For more details, refer to The
genxlt utility on page 861.
Table 133. Coded character set conversion tables
FromCode ToCode GENXLT source shipped Program Name
IBM-858 IBM-1047 Yes <prefix>AIEY
IBM-858 IBM-1140 Yes <prefix>AIHA
IBM-858 IBM-1141 Yes <prefix>AIHB
IBM-858 IBM-1142 Yes <prefix>AIHE
IBM-858 IBM-1143 Yes <prefix>AIHF
IBM-858 IBM-1144 Yes <prefix>AIHG
IBM-858 IBM-1145 Yes <prefix>AIHJ
IBM-858 IBM-1146 Yes <prefix>AIHK
IBM-858 IBM-1147 Yes <prefix>AIHM
IBM-858 IBM-1148 Yes <prefix>AIHO
IBM-858 IBM-1149 Yes <prefix>AIHR
IBM-037 IBM-924 Yes <prefix>EAEZ
IBM-273 IBM-924 Yes <prefix>EBEZ
IBM-278 IBM-924 Yes <prefix>EFEZ
IBM-280 IBM-924 Yes <prefix>EGEZ
IBM-284 IBM-924 Yes <prefix>EJEZ
IBM-285 IBM-924 Yes <prefix>EKEZ
IBM-297 IBM-924 Yes <prefix>EMEZ
IBM-500 IBM-924 Yes <prefix>EOEZ
You can also use the name UTF-8 to request setup for conversion to and from
Transform Format 8, UTF-8, specified in Unicode Standard, Version 2.1,
Appendices A-7 and A-8. For example, iconv_open("UTF-8", "IBM-1047") requests
setup for conversion from IBM-1047 character encoding to UTF-8 character
encoding.
Before z/OS V1R12, source for UCS-2 converters was in a data set named
installation-prefix.SCEEUMAP, where the installation prefix for z/OS XL C/C++
data sets defaults to CEE. UCS-2 source was also installed in the z/OS UNIX file
system directory /usr/lib/nls/locale/ucmap. Starting in z/OS V1R12, IBM will no
longer ship UCS-2 source with the C/C++ Run-time Library.
The following notes apply only when you create your own converters:
v The iconv() family of functions uses Unicode Services to perform character
conversion to or from UCS-2. Therefore, IBM no longer ships uconvTable
binaries in either the installation-prefix.SCEEUTBL data set or the z/OS UNIX
file system directory /usr/lib/nls/locale/uconvTable. Both the installation-
prefix.SCEEUTBL data set and the /usr/lib/nls/locale/uconvTable directory have
been removed. Users who create their own uconvTable converters need to create
the installation-prefix.SCEEUTBL data set, the /usr/lib/nls/locale/uconvTable
directory, or both to hold the converters. The installation-prefix.SCEEUTBL data
set needs to be created with a fixed block record format and lrecl of 80.
v If your installation uses an installation-prefix different from CEE for z/OS XL
C/C++ data sets, you must use the environment variable _ICONV_UCS2_PREFIX to
specify the value of your installation-prefix before using iconv_open() to set up
UCS-2 converters. Otherwise, iconv_open() cannot find your z/OS XL C/C++
uconvTable binary data set. One way to do this is to use the ENVAR run-time
option when you start your application. For example, ENVAR(...,
_ICONV_UCS2_PREFIX=YOUR.PREFIX, ...) has iconv_open() search for uconvTable
binaries it requires in the data set YOUR.PREFIX.SCEEUTBL.
v If uconvTable binaries are installed in both the z/OS UNIX file system directory
named /usr/lib/nls/locale/uconvTable and installation-prefix.SCEEUTBL data
set, the iconv_open() function searches for uconvTable binaries in the z/OS
UNIX file system before searching in the z/OS XL C/C++ UCS-2 data set.
v You can use the LOCPATH environment variable to give iconv_open() a
colon-separated list of pathname prefixes to use instead of /usr/lib/nls/locale/ to
find uconvTable directories in your z/OS UNIX file system.
v If you have created your own conversion tables and want the iconv() family of
functions to use them, you need to set the _ICONV_MODE environment variable to
C.
v If you want to create customized conversion tables with any of the CCSIDs
related to the conversion table source that is no longer shipped, create
Note: IBM makes no guarantee that the uconvdef or genxlt utilities will continue
to be supported in future releases.
Members in the UCS-2 source data sets have names of the form EDCUUccU, where
cc is the CC-id associated with a particular coded character set name. Table 134 on
page 876 shows the CC-id and member name associated with each coded
character set name for which UCS-2 source is provided. The UCS-2 source is in a
data set named installation-prefix.SCEEUMAP. The default value of the
installation-prefix is CEE.
CAUTION:
UCS-2 converter binaries added to the SCEEUTBL data set or the uconvTable
directory must follow the EDCUUccU naming convention that allows iconv
interfaces to recognize a UCS-2 converter.
All UCS-2 tables are intended for the use with the C/C++ iconv interfaces or
the iconv utility. Direct programming to these tables is not supported and will
produce unpredictable results.
Starting in z/OS V1R12, IBM will not ship conversion table source in either the
installation-prefix.SCEEUMAP data set or the /usr/lib/nls/locale/ucmap
directory. However, if you choose to migrate the conversion tables to your
own installation-prefix.SCEEUTBL data set, you need to continue to name
them as listed in Table 134 on page 876.
In addition to the code set mappings, directives are interpreted by the uconvdef
command to produce the compiled table. These directives must precede the code
set mapping section. They consist of the following keywords surrounded by <>
(angle brackets), starting in column 1, followed by white space and the value to be
assigned to the symbol:
This type is used to direct uconvdef on the type of table to build. It is also stored in
the table to indicate the type of processing algorithm in the UCS conversion
methods.
<locale> Specifies the default locale name to be used if locale information is
needed.
<subchar> Specifies the encoding of the default substitute character in the
multibyte code set.
Symbolic character names in mapping lines must follow the pattern specified in the
<char_name_mask>, except for the reserved symbolic name, <unassigned>, that
indicates the associated code points are unassigned.
is interpreted as:
<U3003> \x81\x56
<U3004> \x81\x57
<U3005> \x81\x58
<U3006> \x81\x59
3. This format defines a range of one or more unassigned encodings.
"<unassigned>"%s...%s %s/n",<encoding>,<comments>
For example, the line
<unassigned> \x9b...\x9c
is interpreted as:
<unassigned> \x9b <unassigned> \x9c
There is wide variation among coded character sets; many glyphs do not appear in
all coded character sets, and hexadecimal encodings for some glyphs differ from
one coded character set to another. You may encounter problems when exporting a
file from a system running in one coded character set, to a system running in
another. For example, a left bracket ([) entered under the APL-293 or Open
Systems IBM-1047 coded character set will appear as the capitalized Y-acute ().
This occurs in such common coded character sets as International 500, France
297, Germany 273, and US or Canada 037.
These facilities cause the compiler to respect your code page. Thus, you can enter
source code with what appears to you to be the correct characters, and the
compiler will recognize those characters.
The rest of this chapter discusses other ways to work efficiently in different locales.
Table 135 on page 886 lists these 13 characters. It also displays their appearance
when the Open Systems coded character set IBM-1047 hexadecimal values are
entered on systems where different Country Extended Coded Character Sets are
installed. These hex values are the ones expected by z/OS XL C/C++, and are
consistent with the use of the APL-293 coded character set.
Table 136 lists the hexadecimal values assigned across some of the EBCDIC coded
character sets for the 13 variant characters from the PPCS. Appendix C, z/OS XL
C/C++ code point mappings, on page 925 gives more information about the
mapping of glyphs and Appendix A, POSIX character set, on page 915 lists the full
PPCS.
Table 136. Mappings of Hex encoding of 13 PPCS variant characters
Character Glyph GCGID Open APL Inter- France Germany US/Can
Name Systems IBM-293 national 297 view 273 view 037 view
IBM-1047 view 500 view
view
left bracket [ SM060000 AD AD 4A 90 63 BA
right bracket ] SM080000 BD BD 5A B5 FC BB
left brace { SM110000 C0 C0 C0 51 43 C0
right brace } SM140000 D0 D0 D0 54 DC D0
backslash \ SM070000 E0 E0 E0 48 EC E0
circumflex ^ SD150000 5F 5F 5F 5F 5F B0
tilde ~ SD190000 A1 A1 A1 BD 59 A1
exclamation ! SP020000 5A 5A 4F 4F 4F 5A
mark
pound (number) # SM010000 7B 7B 7B B1 7B 7B
sign
vertical bar | SM130000 4F 4F BB BB BB 4F
accent grave ` SD130000 79 79 79 A0 79 79
dollar sign $ SC030000 5B 5B 5B 5B 5B 5B
commercial "at" @ SM050000 7C 7C 7C 44 B5 7C
Although the official current coded character set for z/OS XL C/C++ is now coded
character set IBM-1047 (Open Systems), the coded character set IBM-293 syntax
points are still valid. Those points are the ones with syntactic relevance to the z/OS
XL C/C++ compiler. Refer to Table 135 on page 886 and Table 136 on page 886 for
more information.
You can continue coding in the local coded character set, writing the syntax as if it
were in coded character set IBM-1047. This solution uses the existing behavior of
the compiler, but this method is not ideal for the following reasons; Figure 250 on
page 888 illustrates these difficulties.
v The code can be difficult to read and may not even look like C code anymore.
v There may be ambiguities in the code.
v Exporting code to another site can be difficult because the mapping between the
hybrid characters used and the target coded character set may not be exact.
Chapter 61. Coded character set considerations with locale functions 887
/* this has strings in codepage 273 with APL 293 syntax, and is a */
/* pre-locale source file for a user in Germany */
&hash273;define MAX_NAMES 20
&hash273;define MAX_NAME_LEN 80
&hash273;define STR(num) &hash273;num
&hash273;define SCAN_FORMAT(len) "%"STR(len)"s %"STR(len)"s"
The code points in Figure 250, which have different glyphs in character code set
IBM-273 and APL-293, are described below:
1 code point for the { character. In coded character set 273, this is the
character .
2 code point for the [ character. In coded character set 273, this is the
character .
Chapter 61. Coded character set considerations with locale functions 889
2 1
Source Set up
Converter
4 5
Compiler Runtime
The following example tag uses the German coded character set IBM-273:
??=pragma filetag("IBM-273")
Chapter 61. Coded character set considerations with locale functions 891
Because the # character is variant in different coded character sets, you must use
the trigraph ??= for the #pragma filetag directive.
The #pragma filetag directive specifies the coded character set in which the
source or data was entered. The coded character set specified in the #pragma
filetag directive is in effect for the entire source file, but not for any other source
file. This also applies to header files and data files.
The #pragma filetag directive can only appear once in each file, and it must
appear before the first statement in a program. If encountered elsewhere, a warning
appears and the directive does not change. If a comment contains variant
characters and appears before the directive, the comment does not translate.
Attention: If you wish to use the iconv utility on a file that is tagged with the ??=
#pragma filetag directive, you must update the file manually to change the filetag
to the correct converted coded character set. iconv does not update the pragma in
source files.
The value of this macro is defined per source file. If no #pragma filetag
directive is present, the macro is undefined.
__CODESET__
This macro expands to a string literal representing the character coded
character set of the LOCALE compiler option. The value of this macro is
defined per compilation. If a value is not supplied, the macro is undefined.
Figure 252 on page 893 shows an example program (CCNGCC2) that uses the
__CODESET__ macro.
iconv_t convInfo;
int main() {
#ifdef __CODESET__
char *run-timeCodeSet;
setlocale(LC_ALL, ""); /* set locale to default locale */
run-timeCodeSet = nl_langinfo(CODESET);
convInfo = iconv_open(run-timeCodeSet, __CODESET__);
#endif
char intro[] = "Welcome to my variant world!\n";
char nlIntro[sizeof(intro)];
convstr(convInfo, intro, sizeof(intro),
nlIntro, sizeof(nlIntro));
puts(nlIntro); /* string will print appropriately */
#ifdef __CODESET__
iconv_close(convInfo);
#endif
return(0);
}
Figure 253 on page 894 shows the values that these macros will take on,
emphasizing that for __FILETAG__, a value is assigned for each source file, but for
__LOCALE__ and __CODESET__, a value is assigned for a compilation.
Chapter 61. Coded character set considerations with locale functions 893
Assuming: Compiled source file with LOCALE("De_DE.IBM-273")
Using setlocale()
You can change the run-time locale to any one of the other predefined locales
listed in Table 139 on page 928. To use a defined locale, refer to it by its
setlocale() parameter. To define a new locale, copy the source file provided, edit
it, then assemble it (see Chapter 57, Customizing a locale, on page 839).
For example, if you used an ASCII client machine to write code that uses string
literals, and then upload this to an EBCDIC server such as MVS, your string literals
would be converted to EBCDIC. However, if you specified "CONVLIT(ISO8859-1)"
when you compiled your code, your string literals would have been converted to an
ASCII code page.
/* header.h */
char *text="Hello World";
/* test.c */
#pragma convlit(suspend)
#pragma comment (user, "A user comment")
#include <stdio.h>
#include "header.h"
#pragma convlit(resume)
main (){
char *text2 ="Hi There!";
}
To use the LOCALE option, you must supply a locale name value. The locale name is
a string that represents the locale you want to compile source with; this will
determine the characteristics of output, including the coded character set used for
variant characters in the source. Usually, a locale name is of the format territory
name.coded character set. For example, the German locale for coded character set
273 is De_DE.IBM-273. The territory name is De_DE and the coded character set is
IBM-273. To determine the coded character set of the current locale, use the
function nl_langinfo(CODESET).
The special locale name "" gives you the default locale, which can be set using
environment variables. The locale name "C" specifies the C default locale. Full
details about the C locale are found in Chapter 59, Definition of S370 C, SAA C,
and POSIX C locales, on page 849.
You can create your own locales by using the localedef utility. See Locale source
files on page 796 for details.
Chapter 61. Coded character set considerations with locale functions 895
Examples: To compile a sample file, userid.SORTNAME.C, enter:
CC userid.SORTNAME.C (LOCALE("De_DE.IBM-273")
To generate a preprocessed file that can be sent to other sites, that use different
coded character sets, enter:
CC userid.SORTNAME.C (LOCALE("De_DE.IBM-273") PPONLY
The compiler will insert the #pragma filetag directive at the start of the
preprocessed file, using the coded character set specified in the LOCALE option. In
this example, ??=pragma filetag("IBM-273") is inserted.
Since the preprocessed file has been tagged, it can be compiled using the z/OS XL
C/C++ compiler at any site, regardless of the locale used.
Object modules and output listings: The compiler respects the locale specified
by the LOCALE compiler option when it generates the listing. If the locale option is
specified, the object module is generated in the coded character set of your current
locale. Otherwise, the object module is generated in the coded character set
IBM-1047.
Code will run correctly if the run-time locale is the same as the locale of the object
module.
For information about exporting code to other sites, see Exporting source code to
other sites on page 900.
You can use the LOCALE compiler option to ensure that listings are sensitive to a
specified locale.
Figure 255 on page 898 shows the result from compiling source file hello273.c
with:
xlc -F:c89 -o hello273 -qso -qlocale="De_DE.IBM-273" -qxplink -qgoff hello273.c
Chapter 61. Coded character set considerations with locale functions 897
15694A01 V1.10 z/OS XL C ./hello273.c 02.04.08 13:38:36 1 Page 1
* * * * * P R O L O G * * * * *
* * * * * E N D O F P R O L O G * * * * *
* * * * * S O U R C E * * * * *
* * * * * I N C L U D E S * * * * *
1 TSCTEST.CEEZ1A0.SCEEH.H(STDIO)
2 TSCTEST.CEEZ1A0.SCEEH.H(FEATURES)
3 TSCTEST.CEEZ1A0.SCEEH.SYS.H(TYPES)
* * * * * E N D O F I N C L U D E S * * * * *
15694A01 V1.10 z/OS XL C ./hello273.c 24.10.07 09:05:53 Page 4
* * * * * M E S S A G E S U M M A R Y * * * * *
0 0 0 0 0
* * * * * E N D O F M E S S A G E S U M M A R Y * * * * *
* * * * * E N D O F C O M P I L A T I O N * * * * *
For example, if you use an ASCII client machine to write code with string literals
and upload it to an EBCDIC server, then your string literals will be converted to
EBCDIC. However, if you add the pragma convert("ISO8859-1") directive to your
source code, then your string literals will be converted to an ASCII code page.
For example, consider the program in Figure 256 on page 900. When this program
is compiled, the string "Hello World" will be converted to an ASCII string, but the
string "Hi There!" will not be converted.
Chapter 61. Coded character set considerations with locale functions 899
/* header.h */
#pragma convert("ISO8859-1")
char *text="Hello World";
#pragma convert(pop)
/* test.c */
#pragma comment (user, "A user comment")
#include "header.h"
main () {
char *text2 ="Hi There!";
}
First, even though z/OS XL C/C++ provides support for multiple coded character
sets, other tools may not do so. Tools such as CICS and DB2 may not support
source code in any coded character set other than the default coded character set,
IBM-1047. If you are using these tools, and you write your code in a code page
other than IBM-1047, you will need to use the z/OS XL C/C++ iconv utility to
convert your code to coded character set IBM-1047 before you can use the tool.
Second, older versions of the C/370 product do not support source in coded
character sets other than IBM-1047. This makes it difficult to share code with a site
using an older compiler.
To export code, use the iconv() utility to convert each source file, header file, and
data file to the target coded character set. You can then send all files to the target
location for compilation.
Note: You must ensure that your code runs in the same locale that it was compiled
under before running it with any other locales.
1. Use the #pragma filetag directive to tag each source file, header file, and data
file.
2. Use message files for all external strings, such as prompts, help screens, and
error messages. To write truly portable code, convert these strings to the
run-time coded character set in your application code.
3. Use the setlocale() function so that the library functions are sensitive to the
run-time coded character set.
Ensure that locale-sensitive information, such as decimal points, are displayed
appropriately. Use either nl_langinfo() or localeconv() to obtain this
information.
If you specify locale("locale-name"), your code will run correctly with libraries
running in the same coded character set. However, if you compile with a different
locale than you run under, you have to ensure that your code has no internal data,
and also that all libraries you use are run-time locale sensitive.
For example, consider the following code fragment. If you compile with
locale("De_DE.IBM-273"), the square brackets are converted to the hex values
X'63' and X'FC'. If the default locale you then run under is not "De_DE.IBM-273",
but instead "En_US.IBM-1047", and you have not used setlocale(), the square
brackets will be interpreted as and , and the call to scanf() will not do what you
intended.
int main() {
setlocale(LC_ALL, "");
.
.
.
rc = scanf("%[1234567890abcdefABCDEF]", hexNum);
.
.
.
}
If you only need to run your code locally or export it to a site that has your locale
environment, you can solve this problem by using the following coding. This
ensures that your code runs with the same locale it was compiled under. Library
functions such as printf(), scanf(), strfmon(), and regcomp() are sensitive to the
current coded character set. The __LOCALE__ macro is described in Using
predefined macros on page 892.
int main() {
setlocale(LC_ALL, __LOCALE__);
.
.
.
rc = scanf("%[1234567890abcdefABCDEF]", hexNum);
.
.
.
}
If you are generating code to export to a site that may not have your locale
environment, you should write your code in IBM-1047.
Chapter 61. Coded character set considerations with locale functions 901
v Code your new source in one coded character set, preferably IBM-1047. Tag all
new source files to make them more portable by putting the #pragma filetag
directive at the top of each one.
v If you need to interact with existing code, compile your new code using the locale
in which the existing code was written.
v If you want to write code in a coded character set that does not have a
one-to-one mapping to coded character set IBM-1047 (that is, a coded character
set that is not Latin-1), create your own conversion table and compile it with the
genxlt utility. Use your own conversion table with the iconv utility to convert your
source code to coded character set IBM-1047.
Since the following tools scan source code, they may be affected:
v The Debug Tool does not support code written in any coded character set other
than IBM-1047.
v Translators such as CICS and DB2 read source files and generate new source
files. If they do not, then follow these steps:
1. Convert the source file to coded character set IBM-1047 using the iconv
utility.
2. Remove the #pragma filetag directive from the source file, or change it to
??=pragma filetag("IBM-1047"). Run the source that is in the IBM-1047
coded character set through the appropriate translator, if needed.
Bidirectional languages
Bidirectional languages are languages such as Arabic and Hebrew, that are written
and read mainly from right to left, but some portions of the text, such as numbers
and embedded Latin languages (e.g. English) are written and read left to right.
Additional characteristics of bidirectional languages include:
v visual order versus logical order
v symmetric swapping
v number formats
v cursive (shaping) versus non-cursive
In bidirectional text, it is important to note the difference between the logical order in
which the text is processed or read, and the visual order in which the text is
displayed. Bidirectional text is usually stored in logical order. For example, assume
that the following text is Arabic, then the logical storage would contain:
maple street 25 entrance b
and the visual display would be (if read from right to left):
b ecnartne 25 teerts elpam
Arabic numerals (Latin digits) are those numerals used with Latin text, while Hindi
numerals are used within Arabic text, in some of the Arabian countries, like Egypt.
However, the Implicit algorithm states the number storage should use Arabic
numerals (Latin digit), and be displayed according to the user's settings.
Note that even though the text in the example is displayed right to left, the number
"25" is still written left to right. That is because Arabic/Hebrew numbers are written
and read left to right.
Arabic is a cursive language. Arabic characters are connected together, and each
character has different shapes depending on its location within the word: initial,
middle, final or isolated. Cursive languages are suited to handwriting rather than
printing. Arabic is always cursive, whether in books, newspapers, signs or
Note that Hebrew letters do not use shaping, and numbers used with Hebrew text
are always displayed with the same digits as used for English.
Legacy operating systems like MVS used to store Arabic and Hebrew data in their
visual format. Sometimes for specific needs, data might be stored in a specific
shape, for example initial shape. Currently, most applications store text in its
unshaped form in logical order. Reordering and shaping are done at display time.
Storing text in its unshaped form in logical order makes it easier to process the data
(sorting, comparison).
Those functions can be used to convert text from logical (implicit) unshaped forms
to visual (display) shaped forms and vice versa. The layout functions also handle
conversion of numerals.
A full list of attributes and values is available in X/Open Portable Layout Services:
Context-dependent and Directional Text. Some attributes listed in Table 137 are
specific to the z/OS implementation and are noted with an asterisk (*) symbol.
m_create_layout( )
This function creates a LayoutObject associated with the locale identified by
attrobj. The LayoutObject is an opaque object containing all the data and methods
necessary to perform the layout operations on context-dependent or directional
characters of the locale identified by the attrobj. The memory for the LayoutObject
is allocated by m_create_layout( ) . The LayoutObject created has default layout
values. (If the modifier argument is not NULL, the layout values specified by the
modifier overwrite the default layout values associated with the locale).
#include <sys/layout.h>
LayoutObject m_create_layout(const AttrObject attrobj,const char* modifier);
attrobj argument
Is or may be an amalgam of many opaque objects. A locale object is just one
example of the type of object that can be attached to an attribute object. The
attrobj argument specifies a name that is usually associated with a locale
category.
modifier argument
Can be used to announce a set of layout values when the LayoutObject is
created.
m_setvalues_layout( )
This function is used to change the layout values of a LayoutObject.
layout_object argument
Specifies a LayoutObject returned by the m_create_layout() function.
values argument
Specifies the list of layout values that are to be changed. The values are written
into the LayoutObject and may affect the behavior of subsequent layout
functions.
m_getvalues_layout( )
This function is used to query the current settings of the layout values within a
Layout Object.
#include <sys/layout.h>
int m_getvalues_layout(const LayoutObject layout_object,LayoutValues values,
int *index_returned);
layout_object argument
Specifies a Layout Object returned by the m_create_layout( ) function.
values argument
Specifies the list of layout values that are to be queried. Each value element of
a LayoutValueRec must point to a location where the layout value is stored. That
is, if the layout value is of type T , the argument must be of type *T . The
values are queried from the Layout Object and represent its current setting. It is
the user's responsibility to manage the memory allocation for the layout values
queried. If the layout value name has QueryValueSize ORed to it, instead of the
setting of the layout value, only its size is returned. This option can be used by
the caller to determine the amount of memory needed to be allocated for the
layout values queried.
m_transform_layout ( )
This function performs layout transformations (reordering and shaping), or it may
provide additional information needed for layout transformation (such as the
expected size of the transformed layout, the nesting level of different segments in
the text and cross references between the locations of the corresponding elements
before and after the layout transformation). Both the input text and output text are
character strings. The m_transform_layout( ) function transforms the input text in
InpBuf according to the current layout values in layout_object. Any layout value
whose value type is LayoutTextDescriptor describes the attributes of the InpBuf
and OutBuf arguments. If the attributes are the same for both InpBuf and OutBuf, a
null transformation is performed with respect to that specific layout value. The
InpBuf argument specifies the source text to be processed. The InpSize argument
is the number of bytes within InpBuf to be processed by the transformation. Its
value will not change after return from the transformation.
LayoutObject argument
Specifies the Layout Object returned by m_create_layout().
InpBuf argument
Corresponds to the input string that the layout functions will process.
InpSize argument
Gives the input size of the input string specified by the InpBuf argument.
Note: If you need to pass 1 as a value for InpSize, you must cast it using
(size_t)-1.
OutBuf argument
Any transformed data is stored here. This buffer will contain the data after
converting it to the specified layout values and output code page.
Outsize argument
Gives the number of bytes in the Output Buffer.
InpToOut mapping argument
A cross-reference from each InpBuf code element to the transformed data. The
cross-reference relates to the data in InpBuf starting with the first element that
InpBufIndex points to (and not necessarily starting from the beginning of the
InpBuf).
OutToInp mapping argument
A cross-reference to each InpBuf code element from the transformed data. The
cross-reference relates to the data in InpBuf starting with the first element that
InpBufIndex points to (and not necessarily starting from the beginning of the
InpBuf).
Property argument
A weighted value that represents peculiar input string transformation properties
with different connotations. If this argument is not a NULL pointer, it represents
an array of values with the same number of elements as the source sub string
text before the transformation. Each byte will contain relevant ''property''
information of the corresponding element in InpBuf starting from the element
pointed by InpBufIndex.
InpBufIndex argument
InpBufIndex is an offset value to the location of the transformed text. When
m_transform_layout( ) is called, InpBufIndex contains the offset to the element
in InpBuf that will be transformed first. (Note that this is not necessarily the first
element in InpBuf). At the return from the transformation, InpBufIndex contains
the offset to the first element in the InpBuf that has not been transformed. If the
entire sub string has been transformed successfully, InpBufIndex will be
incremented by the amount defined by InpSize.
#include <sys/layout.h>
int m_wtransform_layout(LayoutObject layout_object,
const wchar_t *InpBuf,
const size_t InpSize, void *OutBuf,
size_t *Outsize,
size_t *InpToOut, size_t *OutToInp,
unsigned char *Property,
size_t *InpBufIndex );
m_destroy_layout( )
This function destroys the layout object and frees up the allocated memory used by
the layout object.
#include <sys/layout.h>
int m_destroy_layout(const LayoutObject layoutobject);
The example in Figure 257 sets the option using a layout string modifier.
Figure 258 demonstrates how to use the m_setvalues_layout() function to set the
option.
#include <sys/layout.h>
LayoutObject plh;
int error = 0, index;
size_t insize = 9, outsize;
LayoutValues layout;
LayoutTextDescriptor set_desc;
char *inbuffer;
char *outbuffer;
char *inShape;
char *outShape;
char *myModifier=
"@lstypeoftext=implicit:visual,shaping=nominal:shaped,orientation=ltr:rtl";
In the first line, declare a LayoutObject called "plh". This is the layout object that
m_create_layout() creates later when invoked. index is the index of the returned
error. insize is the size of the input buffer,and outsize is the size of the output
buffer. The four integer variables in the second and third lines will be used later
in the call of m_setvalues_layout( ) and m_transform_layout( ). In the fourth line,
declare a LayoutValues variable called "layout" and in the fifth line declare a
LayoutTextDescriptor called "set_desc". These two variables are very
important. They will be used with m_setvalues_layout() in the form of
input/output pairs to specify new input and output values for each one of the
specified attributes. The next two lines add four strings (char *), that will be
used as the input buffer, output buffer, input code page and, finally, the output
code page. The last line adds a string that specifies the modifier to be used as
specified earlier in the m_create_layout() function to create the layout object.
3. Allocate memory to the declared strings, layout values, layout text descriptor,
and write the contents of the input buffer.
plh = m_create_layout("Ar_AA",myModifier);
In the preceding example, the layout object "plh" is created with the locale
Ar_AA with the modifier myModifier.
5. At this point of the program, there are two options: call m_setvalues_layout() or
call the m_transform_layout() (or m_wtransform_layout()) directly.
Specify the input/output layout values. The first two lines below specify the two
strings used as the input and output code pages. These two strings will be used
by the other functions to specify the input code page for the input buffer and the
output code page for the output buffer.
strcpy(outShape,"ibm-420");
strcpy(inShape,"ibm-425");
set_desc[0].inp = ORIENTATION_LTR;
set_desc[0].out = ORIENTATION_LTR;
set_desc[1].inp = TEXT_IMPLICIT;
set_desc[1].out = TEXT_VISUAL;
set_desc[2].inp = TEXT_NOMINAL;
set_desc[2].out = TEXT_SHAPED;
Add the input/output layout text descriptor pairs. These pairs are in the form of
input descriptor and output descriptor; for example, the first statement specifies
that the input orientation will be "orientation-left-to-right" and the second
statement specifies that the output orientation will be also "orientation-left-to-
right". All the above pairs follow the same rule to define the input/output pairs.
layout[0].name = ShapeCharset;
layout[0].value = (char *)outShape;
layout[1].name = InputCharset;
layout[1].value = (char *)inShape;
layout[2].name = Orientation;
layout[2].value = (LayoutTextDescriptor)&set_desc[0];
layout[3].name = TypeOfText;
layout[3].value = (LayoutTextDescriptor)&set_desc[1];
layout[4].name = TextShaping;
layout[4].value = (LayoutTextDescriptor)&set_desc[2];
layout[5].name = 0;
In the preceding lines, "set_desc" pairs create the new layout values attributes.
Each one of these statements will be in the form of attribute_name/
attribute_value pairs, for example in the fifth and sixth statements "Orientation"
is the attribute name and set_desc[0] (as defined above) is the attribute value.
if((error =m_setvalues_layout(plh,layout,&index)))
printf("\n An error %d occurred in setting the value number %d\n",error,index);
Invoke m_setvalues_layout() using the layout object "plh", the layout values
"layout" and an integer "index". If m_setvalues_layout() could not set any one of
the layout values attributes, it will return -1 in the integer variable called "error",
and also return the index of the layout value that caused the problem.
6. Call the m_transform_layout() function. The m_transform_layout() and
m_wtransform_layout() functions are the same, except that
m_wtransform_layout() is used for wide character (wchar_t). Both functions will
do the actual reordering and shaping of the input buffer using the layout object
(plh) created in step 4.
m_transform_layout(plh,inbuffer,insize,outbuffer,&outsize,NULL,
NULL,NULL,NULL);
m_destroy_layout(plh);
Finally, Figure 259 on page 913 is sample program (CCNGBID1) that shows how
the bidirectional layout API are used.
char *inbuffer=NULL;
char *outbuffer=NULL;
char *inShape=NULL;
char *outShape=NULL;
char
*myModifier="@lstypeoftext=implicit:visual,shaping=nominal:shaped,orientation=ltr:rtl";
layout = (LayoutValues)malloc(6*sizeof(LayoutValueRec));
set_desc = (LayoutTextDescriptor)malloc(3*sizeof(LayoutTextDescriptorRec));
inbuffer[0] = 0xB0; /* These are the HEX code for Arabic characters in the IBM-425 codepage */
inbuffer[1] = 0xB1;
inbuffer[2] = 0xB2;
inbuffer[3] = 0xBF;
inbuffer[4] = 0x40;
inbuffer[5] = 0x9A;
inbuffer[6] = 0x75;
inbuffer[7] = 0x58;
inbuffer[8] = 0xDC;
strcpy(outShape,"ibm-420");
strcpy(inShape,"ibm-425");
set_desc[0].inp = ORIENTATION_LTR;
set_desc[0].out = ORIENTATION_LTR;
set_desc[1].inp = TEXT_IMPLICIT;
set_desc[1].out = TEXT_VISUAL;
set_desc[2].inp = TEXT_NOMINAL;
set_desc[2].out = TEXT_SHAPED;
layout[0].name = ShapeCharset;
layout[0].value = (char *)outShape;
layout[1].name = InputCharset;
layout[1].value = (char *)inShape;
layout[2].name = Orientation;
layout[2].value = (LayoutTextDescriptor)&set_desc[0];
layout[3].name = TypeOfText;
layout[3].value = (LayoutTextDescriptor)&set_desc[1];
layout[4].name = TextShaping;
layout[4].value = (LayoutTextDescriptor)&set_desc[2];
layout[5].name = 0;
if( error=m_setvalues_layout(plh,layout,&index))
printf("\n An error %d occurred in setting the value number %d\n",error,index);
m_transform_layout(plh,inbuffer,insize,outbuffer,&outsize,NULL,NULL,NULL,NULL);
m_destroy_layout(plh);
if(inbuffer)
free(inbuffer);
if(outbuffer)
free(outbuffer);
if(set_desc)
free(set_desc);
if(layout)
free(layout);
if(inShape)
free(inShape);
if(outShape)
free(outShape);
}
With z/OS XL C/C++, the localedef utility uses code page IBM-1047 as the
definition of the code points for the characters in the Portable Character Set.
Therefore, the default values for the escape-char and comment-char are the code
points from the IBM-1047 code page.
??=ifdef __COMPILER_VER__
??=pragma filetag ("codepage")
??=endif
Note: If you are running standard 3270 emulation in the U.S., your workstation
software most likely uses code page 37. You can then use this alternative by
specifying IBM-037 as codepage.
NO
Note: These ten variant characters are selected because they are syntactically
important to the z/OS XL C/C++ compiler.
2. Run the program Figure 261 on page 921 to display the following information:
v Selected hexadecimal values for the variant characters that your current
setup uses:
v The values that the compiler and library expect for mapping the keyboard.
3. Perform the following steps until the hexadecimal values for the variant
characters that your current setup matches the values that the compiler and
library expect for mapping the keyboard.
a. Use the values that the compiler and library expect for mapping the
keyboard to edit the input file MYFILE.DAT.
b. Run the program CCNGMV1 again.
Sample program
CCNGMV1 in Figure 261 on page 921performs the following actions:
v Reads the ten characters from MYFILE.DAT.
#include <stdio.h>
#include <locale.h>
#include <variant.h>
#include <stdlib.h>
num_var_char=sizeof(char_names)/sizeof(char *);
if ((user_char=(char*)calloc(num_var_char, 1)) == NULL)
{
printf("Error: Unable to allocate the storage\n");
exit(99);
}
read_user_data(user_char, num_var_char);
/* managed to read the users characters from the file */
code_set="default IBM-1047";
compiler_char="\xe0\xbd\xad\xd0\xc0\x5f\xa1\x5a\x7b\x4f";
/* standard compiler code page */
Note: If you are using 3279-S3G-1 with ISPF, z/OS batch, or TSO, see Displaying
square brackets when using ISPF on 3279 emulation on page 923.
After you reset the environment by specifying the appropriate code page for the
compiler, follow these steps:
1. Start ISPF and open a C or C++ source file with square brackets.
2. Run CCNGMV2 before editing to convert the compiler recognizable
hexadecimal values of the square brackets to trigraphs.
3. Run CCNGMV2 again to convert the trigraphs to displayable characters.
4. Edit your C or C++ source code.
5. Run the CCNGMV2 macro again to convert the displayable characters back to
the original hexadecimal values.
6. Save and file the C source file.
PROC 0
ISREDIT MACRO
SET RP = &STR())
/* Symbolic values for 6 C language symbols.
/* 1. left bracket, EBCDIC hex value
/* 2. right bracket, EBCDIC hex value
/* 3. left bracket, trigraph
/* 4. right bracket, trigraph
/* 5. left bracket, square
/* 6. right bracket, square
SET LBRACKET_HEX = XAD
SET RBRACKET_HEX = XBD
SET LBRACKET_TRI = &STR(??(
SET RBRACKET_TRI = &STR(??&RP)
SET LBRACKET_SQR = XBA /* LBRACKET_SQR = HEX BA */
SET RBRACKET_SQR = XBB /* RBRACKET_SQR = HEX BB */
Figure 263 shows the Latin-1/Open Systems code point mappings for code page
IBM-1047 .
Compiled locales
The following table lists each setlocale() parameter and its corresponding
language, country/territory, codeset, and actual program name. The S370 C, POSIX C
and SAA C locales do not have locale modules associated with them. They are
built-in locales that cannot be modified, and are always present. Their names
cannot be changed. These locales are based on the coded character set IBM-1047.
The new versions of the POSIX C and SAA C locales can be provided, but to refer to
them, you must specify the full name of the requested locale, including the
CodesetRegistry-CodesetEncoding names. For example, the following refers to the
SAA C locale built from the coded character set IBM-037:
"SAA.IBM-037"
Note: Not all locales listed in Table 139 on page 928 are fully enabled. The
compiler cannot compile source that is coded in Ja_JP.IBM-290, Ja_JP.IBM-930,
Ja_JP.IBM-1390, or Tr_TR.IBM-1026.
The <prefix> in the Load module name column for EBCDIC locales is shown in the
following table:
Table 138. Referencing data types
EBCDIC locale Prefix
31-bit EDC
31-bit XPLINK CEH
AMODE 64 CEQ
Table 141. ASCII locale object names and method files in the z/OS UNIX file system
UNIX file system Locale Object Name Method File
bg_BG.UTF-8 utfmeth.m
ca_ES.UTF-8 utfmeth.m
ca_ES.UTF-8@euro utfmeth.m
ca_ES.UTF-8@preeuro utfmeth.m
cs_CZ.ISO8859-2.xplink sbmeth.m
cs_CZ.UTF-8.xplink utfmeth.m
cs_CZ.UTF-8@euro utfmeth.m
cs_CZ.UTF-8@preeuro utfmeth.m
cy_GB.UTF-8 utfmeth.m
cy_GB.UTF-8@euro utfmeth.m
da_DK.ISO8859-1.xplink iso1meth.m
da_DK.UTF-8.xplink utfmeth.m
da_DK.UTF-8@euro utfmeth.m
de_AT.UTF-8 utfmeth.m
de_AT.UTF-8@euro utfmeth.m
de_AT.UTF-8@preeuro utfmeth.m
de_CH.ISO8859-1.xplink iso1meth.m
The Applicable Codesets column indicates which charmap files can be used with
the source files to build the locales. The values in this column indicate the following:
All The locale source contains only the portable character set and can be used
to build a locale with any of the supplied charmap files.
Latin-1
The locale source contains characters from the Latin-1 character set, and
can be used to build a locale from any of the supplied Latin-1 charmap files.
See Appendix E, Charmap files supplied with z/OS XL C/C++, on page
953 for a list of Latin-1 charmap files.
Other The locale source is specific to the specified coded character set, and can
only be used to build a locale with the specified charmap file.
Table 142. Locale source files supplied with z/OS XL C/C++
Language Country / Territory Source name Applicable Codesets
POSIX (built-in) EDC$POSX All
All of these charmap files are provided with the National Language Resources
feature of z/OS Language Environment. Consult your system programmer to
determine whether they have been installed.
Under MVS, the charmap files are provided in a separate partitioned data set,
CEE.SCEECMAP. The sign is converted to the @ character.
Table 143 lists the coded character set name, which is the same as the name of the
corresponding charmap file, and the national language each code set represents.
The column marked Latin-1 indicates if the charmap file is for a coded character set
that contains the Latin-1 character set.
Table 143. Coded character set names and corresponding primary country/territory
Codeset Primary Country/Territory Latin-1
Big5 Taiwan No
IBM-037 USA, Canada, Brazil Yes
IBM-273 Germany, Austria Yes
IBM-274 Belgium Yes
IBM-277 Denmark, Norway Yes
IBM-278 Finland, Sweden Yes
IBM-280 Italy Yes
IBM-281 Japan (Latin-1) Yes
IBM-282 Portugal Yes
IBM-284 Spain, Latin America Yes
IBM-285 United Kingdom Yes
IBM-290 Japan (Katakana) No
IBM-297 France Yes
IBM-424 Israel No
IBM-425 Algeria, Bahrain, Egypt, Iraq, Jordan, Kuwait, Lebanon, No
Libya, Morocco, Oman, Qatar, Saudi Arabia, Syria, Tunisia,
U.A.E., Yemen
IBM-500 International Yes
IBM-838 Thailand No
IBM-870 Croatia, Czech Republic, Hungary, Poland, Romania, No
Serbia (Latin), Slovakia, Slovenia
IBM-871 Iceland Yes
IBM-875 Greece No
IBM901 Estonia, Latvia, Lithuania No
IBM921 Estonia, Latvia, Lithuania No
IBM-923 Multinational No
IBM-924 Latin 9/Open Systems No
Only the charmap files for IBM-930, IBM-933, IBM-935, IBM-937, IBM-939 and
IBM-1388 specify <mb_cur_max> as 4 and include the definition of the double-byte
characters.
Note: The SAA C locale is built with the charmap IBM-1047, but has <mb_cur_max>
set to 4 to maintain compatibility with old releases of C/370.
Any of these charmaps that represent the same character set, even though they
represent different encoding of the same character sets, can be used with any
locale source that uses the same character set, to build a new locale and charmap
combination. See Chapter 56, Building a locale, on page 787 for information about
building your own locales.
Charmap file
Figure 265 shows the charmap file for the encoded character set IBM-1047.
<code_set_name> "IBM-1047"
<mb_cur_max> 1
<mb_cur_min> 1
<escape_char> /
<comment_char> %
CHARMAP
<NUL> /x00
<SOH> /x01
<STX> /x02
<ETX> /x03
<SEL> /x04
<tab> /x05
<HT> /x05
<RNL> /x06
<DEL> /x07
<GE> /x08
<SPS> /x09
<RPT> /x0a
<vertical-tab> /x0b
<VT> /x0b
<form-feed> /x0c
<FF> /x0c
<carriage-return> /x0d
<CR> /x0d
<SO> /x0e
<SI> /x0f
<DLE> /x10
<DC1> /x11
<DC2> /x12
<DC3> /x13
<RES> /x14
<newline> /x15
<backspace> /x16
<BS> /x16
<POC> /x17
<CAN> /x18
<EM> /x19
<UBS> /x1a
<CU1> /x1b
<IFS> /x1c % file separator
<IS4> /x1c
<FS> /x1c
<IGS> /x1d % group separator
<IS3> /x1d
<GS> /x1d
<IRS> /x1e % record separator
<IS2> /x1e
<RS> /x1e
<IUS> /x1f % unit separator
<IS1> /x1f
958 Figure
z/OS V1R13.0 XL C/C++ 265. Charmap
Programming Guidefile (Part 2 of 6)
Appendix F. Examples of charmap and locale definition source 959
<LE13> /x54
<i-acute> /x55
<LI11> /x55
<i-circumflex> /x56
<LI15> /x56
<i-diaeresis> /x57
<LI17> /x57
<i-grave> /x58
<LI13> /x58
<s-sharp> /x59
<LS61> /x59
<exclamation-mark> /x5a
<SP02> /x5a
<dollar-sign> /x5b
<SC03> /x5b
<asterisk> /x5c
<SM04> /x5c
<right-parenthesis> /x5d
<SP07> /x5d
<semicolon> /x5e
<SP14> /x5e
<circumflex> /x5f
<circumflex-accent> /x5f
<SD15> /x5f
<hyphen> /x60
<hyphen-minus> /x60
<SP10> /x60
<slash> /x61
<SP12> /x61
<A-circumflex> /x62
<LA16> /x62
<A-diaeresis> /x63
<LA18> /x63
<A-grave> /x64
<LA14> /x64
<A-acute> /x65
<LA12> /x65
<A-tilde> /x66
<LA20> /x66
<A-ring> /x67
<LA28> /x67
<C-cedilla> /x68
<LC42> /x68
<N-tilde> /x69
<LN20> /x69
<broken-bar> /x6a
<SM65> /x6a
<comma> /x6b
<SP08> /x6b
<percent-sign> /x6c
<SM02> /x6c
<underscore> /x6d
<SP09> /x6d
<greater-than-sign> /x6e
<SA05> /x6e
<question-mark> /x6f
<SP15> /x6f
<o-slash> /x70
<LO61> /x70
<E-acute> /x71
<LE12> /x71
<E-circumflex> /x72
<LE16> /x72
<E-diaeresis> /x73
<LE18> /x73
<E-grave> /x74
<LE14> /x74
<I-acute> /x75
<LI12> /x75
<I-circumflex> /x76
<LI16> /x76
<I-diaeresis> /x77
<LI18> /x77
<I-grave> /x78
<LI14> /x78
CHARSETID
<NUL>...<SUB> 0
<space>...<U-acute> 1
END CHARSETID
%%%%%%%%%%%%%
LC_CTYPE
%%%%%%%%%%%%%
upper <A>;<B>;<C>;<D>;<E>;<F>;<G>;<H>;<I>;<J>;<K>;<L>;<M>;/
<N>;<O>;<P>;<Q>;<R>;<S>;<T>;<U>;<V>;<W>;<X>;<Y>;<Z>
lower <a>;<b>;<c>;<d>;<e>;<f>;<g>;<h>;<i>;<j>;<k>;<l>;<m>;/
<n>;<o>;<p>;<q>;<r>;<s>;<t>;<u>;<v>;<w>;<x>;<y>;<z>
space <tab>;<newline>;<vertical-tab>;<form-feed>;/
<carriage-return>;<space>
cntrl <alert>;<backspace>;<tab>;<newline>;<vertical-tab>;/
<form-feed>;<carriage-return>;<NUL>;<SOH>;<STX>;/
<ETX>;<SEL>;<RNL>;<DEL>;<GE>;<SPS>;<RPT>;<SI>;<SO>;<DLE>;<DC1>;/
<DC2>;<DC3>;<RES>;<POC>;<CAN>;<EM>;<UBS>;<CU1>;<IFS>;/
<IGS>;<IRS>;<ITB>;<DS>;<SOS>;<fs>;<WUS>;<BYP>;<LF>;/
<ETB>;<ESC>;<SA>;<SM>;<CSP>;<MFA>;<ENQ>;<ACK>;/
<SYN>;<IR>;<PP>;<TRN>;<NBS>;<EOT>;<SBS>;<IT>;<RFF>;/
<CU3>;<DC4>;<NAK>;<SUB>
punct <exclamation-mark>;<quotation-mark>;<number-sign>;<dollar-sign>;/
<percent-sign>;<ampersand>;<apostrophe>;<left-parenthesis>;/
<right-parenthesis>;<asterisk>;<plus-sign>;<comma>;/
<hyphen-minus>;<period>;<slash>;<colon>;<semicolon>;/
<less-than-sign>;<equals-sign>;<greater-than-sign>;/
<question-mark>;<commercial-at>;<left-square-bracket>;/
<backslash>;<right-square-bracket>;<circumflex>;/
<underscore>;<grave-accent>;<left-curly-bracket>;/
<vertical-line>;<right-curly-bracket>;<tilde>
digit <zero>;<one>;<two>;<three>;<four>;/
<five>;<six>;<seven>;<eight>;<nine>
xdigit <zero>;<one>;<two>;<three>;<four>;/
<five>;<six>;<seven>;<eight>;<nine>;/
<A>;<B>;<C>;<D>;<E>;<F>;/
<a>;<b>;<c>;<d>;<e>;<f>
blank <space>;<tab>
END LC_CTYPE
%%%%%%%%%%%%%
LC_COLLATE
%%%%%%%%%%%%%
order_start forward;forward
<NUL>
...
<SUB>
<space>
<exclamation-mark>
<quotation-mark>
<number-sign>
<dollar-sign>
<percent-sign>
END LC_COLLATE
order_start forward;forward
<NUL>
...
<SUB>
<space>
<exclamation-mark>
<quotation-mark>
<number-sign>
<dollar-sign>
<percent-sign>
<ampersand>
<apostrophe>
<left-parenthesis>
<right-parenthesis>
<asterisk>
<plus-sign>
<comma>
<hyphen-minus>
<period>
<slash>
<zero>
...
<nine>
<colon>
<semicolon>
<less-than-sign>
<equals-sign>
<greater-than-sign>
<question-mark>
<commercial-at>
<A> <A>;<A>
<B> <B>;<B>
<C> <C>;<C>
<D> <D>;<D>
<E> <E>;<E>
<F> <F>;<F>
<G> <G>;<G>
<H> <H>;<H>
<I> <I>;<I>
<J> <J>;<J>
<K> <K>;<K>
<L> <L>;<L>
<M> <M>;<M>
<N> <N>;<N>
<O> <O>;<O>
<P> <P>;<P>
<Q> <Q>;<Q>
<R> <R>;<R>
<S> <S>;<S>
<T> <T>;<T>
<U> <U>;<U>
<V> <V>;<V>
<W> <W>;<W>
<X> <X>;<X>
<Y> <Y>;<Y>
<Z> <Z>;<Z>
<left-square-bracket>
<backslash>
<right-square-bracket>
<circumflex>
<underscore>
<grave-accent>
<a> <A>;<a>
<b> <B>;<b>
<c> <C>;<c>
Appendix F. Examples of charmap and locale definition source 971
END LC_COLLATE%%%%%%%%%%%%%
LC_MONETARY
%%%%%%%%%%%%%
int_curr_symbol "<U><S><D><space>"
currency_symbol "<dollar-sign>"
mon_decimal_point "<period>"
mon_thousands_sep "<comma>"
mon_grouping "3;0"
positive_sign ""
negative_sign "<hyphen-minus>"
int_frac_digits 2
frac_digits 2
p_cs_precedes 1
p_sep_by_space 0
n_cs_precedes 1
n_sep_by_space 0
p_sign_posn 2
n_sign_posn 2
debit_sign "<D><B>"
credit_sign "<C><R>"
left_parenthesis "<left-parenthesis>"
right_parenthesis "<right-parenthesis>"
END LC_MONETARY
%%%%%%%%%%%%%
LC_NUMERIC
%%%%%%%%%%%%%
decimal_point "<period>"
thousands_sep "<comma>"
grouping "3;0"
END LC_NUMERIC
day "<S><u><n><d><a><y>";/
"<M><o><n><d><a><y>";/
"<T><u><e><s><d><a><y>";/
"<W><e><d><n><e><s><d><a><y>";/
"<T><h><u><r><s><d><a><y>";/
"<F><r><i><d><a><y>";/
"<S><a><t><u><r><d><a><y>"
abmon "<J><a><n>";/
"<F><e><b>";/
"<M><a><r>";/
"<A><p><r>";/
"<M><a><y>";/
"<J><u><n>";/
"<J><u><l>";/
"<A><u><g>";/
"<S><e><p>";/
"<O><c><t>";/
"<N><o><v>";/
"<D><e><c>"
mon "<J><a><n><u><a><r><y>";/
"<F><e><b><r><u><a><r><y>";/
"<M><a><r><c><h>";/
"<A><p><r><i><l>";/
"<M><a><y>";/
"<J><u><n><e>";/
"<J><u><l><y>";/
"<A><u><g><u><s><t>";/
"<S><e><p><t><e><m><b><e><r>";/
"<O><c><t><o><b><e><r>";/
"<N><o><v><e><m><b><e><r>";/
"<D><e><c><e><m><b><e><r>"
d_fmt "%m//%d//%y"
t_fmt "%H:%M:%S"
am_pm "<A><M>";"<P><M>"
END LC_TIME
%%%%%%%%%%%%%
LC_MESSAGES
%%%%%%%%%%%%%
yesexpr "<circumflex><left-parenthesis><left-square-bracket><y><Y>/
<right-square-bracket><left-square-bracket><e><E><right-square-bracket>/
<left-square-bracket><s><S><right-square-bracket><vertical-line>/
<left-square-bracket><y><Y><right-square-bracket><right-parenthesis>"
noexpr "<circumflex><left-parenthesis><left-square-bracket><n><N>/
<right-square-bracket><left-square-bracket><o><O><right-square-bracket>/
<vertical-line><left-square-bracket><n><N><right-square-bracket>/
<right-parenthesis>"
END LC_MESSAGES
backslash "<backslash>"
right_brace "<right-brace>"
left_brace "<left-brace>"
right_bracket "<right-square-bracket>"
left_bracket "<left-square-bracket>"
circumflex "<circumflex>"
tilde "<tilde>"
exclamation_mark "<exclamation-mark>"
number_sign "<number-sign>"
vertical_line "<vertical-line>"
dollar_sign "<dollar-sign>"
commercial_at "<commercial-at>"
grave_accent "<grave-accent>"
END LC_SYNTAX
%%%%%%%%%%%%%
LC_TOD
%%%%%%%%%%%%%
timezone_difference +480
timezone_name "<P><S><T>"
daylight_name "<P><D><T>"
start_month 0
end_month 0
start_week 0
end_week 0
start_day 0
end_day 0
start_time 0
end_time 0
shift 3600
END LC_TOD
mblen "__mblen_sb_a"
mbtowc "__mbtowc_iso1"
mbstowcs "__mbstowcs_std_a"
wctomb "__wctomb_iso1"
wcstombs "__wcstombs_std_a"
wcwidth "__wcwidth_std_a"
wcswidth "__wcswidth_std_a"
csid "__csid_std_a"
towupper "__towupper_std_a"
towlower "__towlower_std_a"
get_wctype "__get_wctype_std_a"
is_wctype "__is_wctype_std_a"
strcoll "__strcoll_std_a"
strxfrm "__strxfrm_std_a"
wcscoll "__wcscoll_std_a"
wcsxfrm "__wcsxfrm_std_a"
regcomp "__regcomp_std_a"
regexec "__regexec_std_a"
regfree "__regfree_std_a"
regerror "__regerror_std_a"
strfmon "__strfmon_std_a"
strftime "__strftime_std_a"
strptime "__strptime_std_a"
wcsftime "__wcsftime_std_a"
wcsid "__wcsid_std_a"
END METHODS
Sample program
Figure 268 shows the contents of sample program CCNGHCI. The sample program
CCNGHC1 converts all C syntax from code page IBM-1047 to the coded character
set that you specify. Comments, string literals and character constants are left
alone.
Note: Appendix C, z/OS XL C/C++ code point mappings, on page 925 provides
figures that show the first and second nybbles of the hexadecimal digits that
comprise the code point mappings for code page IBM-1047 and the APL code page
293.
/*
* CCNGHC1: Sample code to convert all C syntax from code page 1047
* to the coded character set the user specifies.
* Comments, string literals and character constants are
* left alone. The escape character in an escape sequence
* is changed, since it is variant.
*
* Usage: CCNGHC1 <coded character set>
* The input file is read from stdin and the output is written
* to stdout.
*
* Example: If you want to convert all C syntax, written in coded character set
* 1047, in a file (test1047 c a) to coded character set 500, you can
* use CCNGHC1 by issuing the following command.
*
* ccnghc1 <test1047.c.a >test1047.gen.a IBM-500
*
* The result will store in "test500 gen a" file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <iconv.h>
#include <errno.h>
/*
* CharState - state that the FSM is in. Initial State is CodeState
*/
enum CharState { CodeState, SQuoteState, DQuoteState, CommentState,
DBCSState, EscState, EOFState };
Figure 268. Converting hybrid C syntax from code page IBM-1047 (Part 1 of 8)
#pragma inline(LAST_POS)
#pragma inline(NEXT_TO_LAST_POS)
#pragma inline(LookAhead)
#pragma inline(GetNextChar)
#pragma inline(ConvBuff)
/*
* Initialize the environment, and if everything is ok, convert input
*/
main(int argc, char *argv[]) {
char *codeset = Initialize(argc, argv);
if (codeset == NULL) {
return(8);
}
return(Convert(codeset));
}
/*
* Check that 1 parameter was specified - the coded character set to convert the
* the syntax to.
* Re-open stdin and stdout as binary files for record I/O.
* Return the code set if everything is ok, NULL otherwise
*/
static char *Initialize(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Expected %d argument but got %d\n",
1, argc-1);
return(NULL);
}
Figure 268. Converting hybrid C syntax from code page IBM-1047 (Part 2 of 8)
return(argv[1]);
}
/*
* Return the last position in a record
*/
static int LAST_POS(int recSize) {
return(recSize-1);
}
/*
* Return the next to last position in a record
*/
static int NEXT_TO_LAST_POS(int recSize) {
return(recSize-2);
}
/*
* Convert the stdin file using codeset and write to stdout.
* Set up the translation table.
* Read the first record and copy it into the output buffer.
* Go through the FSM, starting in the Code State and leaving
* when EOFState is reached (End Of File).
* Close the translation table.
*/
static int Convert(char *codeset) {
enum CharVal c;
int recSize;
enum CharState prvState;
int rc;
int codeStartPos = 0;
int curPos = 0;
enum boolean high = FALSE;
enum CharState state = CodeState;
char * inBuff;
char * outBuff;
int maxRecSize;
XlateTable xlateTable;
Figure 268. Converting hybrid C syntax from code page IBM-1047 (Part 3 of 8)
case CommentState:
switch(c) {
case BSlashChar:
curPos = LAST_POS(recSize);
break;
case StarChar:
if (LookAhead(inBuff, outBuff, &recSize,
&curPos, maxRecSize, &codeStartPos,
state, xlateTable)
== SlashChar) {
state = CodeState;
codeStartPos = curPos;
}
break;
}
break;
Figure 268. Converting hybrid C syntax from code page IBM-1047 (Part 4 of 8)
case SQuoteState:
switch(c) {
case SQuoteChar:
state = CodeState;
codeStartPos = curPos;
break;
case SOChar:
prvState = state;
state = DBCSState;
break;
case BSlashChar:
ConvBuff(curPos, curPos, outBuff, xlateTable);
if (curPos != LAST_POS(recSize)) {
prvState = state;
state = EscState;
}
break;
}
break;
case DBCSState:
high = 1; /* TRUE -> FALSE or FALSE -> TRUE */
if (high && (c == SIChar)) {
state = prvState;
high = FALSE;
}
break;
case EscState:
state = prvState; /* really, this is ok */
break;
case EOFState:
break;
default:
fprintf(stderr, "Internal error - ended up in state %d\n",
state);
return(16);
Figure 268. Converting hybrid C syntax from code page IBM-1047 (Part 5 of 8)
/*
* Initialize the translation table and allocate the input and
* output buffers to use.
* Return 0 if successful.
*/
static int InitConv(char **inBuff, char **outBuff, int *maxRecSize,
char *codeset, XlateTable* xlateTable) {
*maxRecSize = info.__maxreclen;
*inBuff = malloc(*maxRecSize);
*outBuff = malloc(*maxRecSize);
return(!inBuff || !outBuff);
}
/*
* Convert the buffer from start to end using the translation table
*/
static void ConvBuff(int start, int end,
char *buff, XlateTable xlateTable) {
int rc;
size_t inleft, outleft, org;
char *inptr, *outptr;
while (1) {
rc = iconv(xlateTable,&inptr,&inleft,&outptr,&outleft);
if (rc == -1) {
switch (errno) {
/* Skip the invalid character */
case EILSEQ: if (--inleft == 0) return;
++inptr;
++outptr;
--outleft;
break;
if (*curPos == LAST_POS(*recSize)) {
if (UpdateAndRead(inBuff, outBuff, recSize, maxRecSize,
*codeStartPos, state, xlateTable)) {
return(EOFChar);
}
*curPos = 0;
*codeStartPos = 0;
}
else {
(*curPos)++;
}
return(inBuff[*curPos]);
}
/*
* Similar to LookAhead(), but return the current character
*/
static enum CharVal GetNextChar(char *inBuff, char *outBuff,
int *recSize, int maxRecSize,
int *curPos, int *codeStartPos,
enum CharState state,
XlateTable xlateTable) {
Figure 268. Converting hybrid C syntax from code page IBM-1047 (Part 7 of 8)
if (state == CodeState) {
ConvBuff(codeStartPos, LAST_POS(*recSize), outBuff, xlateTable);
}
fwrite(outBuff, 1, *recSize, stdout);
*recSize = ReadAndCopy(inBuff, outBuff, maxRecSize);
return((*recSize == 0) ? 1 : 0);
}
/*
* Read in a record from stdin and copy it to the output buffer.
* Return the number of bytes read.
*/
static int ReadAndCopy(char *inBuff, char *outBuff,
int maxRecSize) {
int recSize;
/*
* Free allocated storage and close the translation table.
*/
static int TermConv(char *inBuff,
char *outBuff, XlateTable xlateTable) {
iconv_close(xlateTable);
free(inBuff);
free(outBuff);
return(0);
}
Figure 268. Converting hybrid C syntax from code page IBM-1047 (Part 8 of 8)
Memory Management
If you have ever received an error from overwriting storage created with the
malloc() function, the following code may be of interest. It shows how to use
debuggable versions of malloc()/calloc()/realloc() and free(). You can tailor the
following macros.
Figure 269 shows an example program (CCNGMI1) that uses debuggable versions
of malloc()/calloc()/realloc() and free() macros.
Figure 270 on page 988 shows the main routine (CCNGMI2) that calls the
preceding macros.
/*
* heapVerbose: external variable that controls whether heap
* allocation and free messages are displayed.
*/
int heapVerbose=1;
/*
* mallocHeapID: static variable that is the Heap ID used for allocating
* storage via debug_malloc().
* On the first call to debug_malloc(), a Heap will be created
* and this Heap ID will be set.
* All subsequent calls to debug_malloc will use this Heap ID.
*/
static _INT4 mallocHeapID=0;
/*
* CHARS_PER_LINE/BYTES_PER_LINE: Used by dump() and DumpLine()
* to control the width of a storage dump.
*/
#define CHARS_PER_LINE 40
#define BYTES_PER_LINE 16
/*
* align: Given a value and the alignment desired (in bits), round
* the value to the next largest alignment, unless it is
* already aligned, in which case, just return the value passed.
*/
#pragma inline(align)
if (value % alignment) {
return(((value >> shift) << shift) + alignment);
}
else {
return(value);
}
}
/*
* CEEErr: Given a title string and a feedback code, print the
* title to stderr, then print the message associated
* with the feedback code. If the feedback code message can not
* be printed out, print out the message number and severity.
*/
static void CEEErr(const char* title, _FEEDBACK* fc) {
_FEEDBACK msgFC;
_INT4 dest = 2;
if (!CEEOk(&msgFC)); {
fprintf(stderr, "Message number:%d with severity %d occurred\n",
fc->tok_msgno, fc->tok_sev);
}
}
if (length % 4) length += 4;
if (!mallocHeapID) {
_INT4 heapSize = HEAP_INIT_SIZE;
_INT4 heapInc = HEAP_INCR_SIZE;
_INT4 opts = HEAP_OPTS;
return(0);
}
lenPtr = (long*) address;
*lenPtr= initSize;
start = ((char*) address) + sizeof(long);
end = start + initSize + PADDING_SIZE;
memset(start, PADDING_BYTE, PADDING_SIZE);
memset(end, PADDING_BYTE, PADDING_SIZE);
if (heapVerbose) {
fprintf(stderr, " starting at address %p\n", address);
}
return(start + PADDING_SIZE);
}
/*
* debug_calloc: Call debug_malloc() to allocate the requested amount
* of storage. If the allocation was successful,
* initialize the allocated storage to 0.
* Return the address of the allocated storage (or a NULL
* pointer if debug_malloc returned a NULL pointer).
*/
void* debug_calloc(size_t num, size_t size) {
size_t initSize = num * size;
void* ptr;
ptr = debug_malloc(initSize);
if (ptr) {
memset(ptr, 0, initSize);
}
return(ptr);
}
long oldSize;
long* lenPtr;
char* start;
char* end;
char* msg;
long newSize = initSize;
if (ptr == 0) {
return(debug_malloc(newSize));
}
if (heapVerbose) {
fprintf(stderr, "Re-allocate %d bytes from address %p to ",
newSize, address);
}
/*
* Add the padding size to the total size, then round up to the
* nearest double word
*/
CEEErr(msg, &fc);
dump(address, oldSize + (PADDING_SIZE*2) + sizeof(long));
__ctrace(msg);
return(0);
}
if (heapVerbose) {
fprintf(stderr, "Free address %p\n", address);
}
if (!padding(start, PADDING_SIZE, PADDING_BYTE) ||
!padding(end, PADDING_SIZE, PADDING_BYTE)) {
CEEErr(msg, &fc);
dump(address, size + (PADDING_SIZE*2) + sizeof(long));
__ctrace(msg);
}
}
}
Figure 271 shows sample program CCNGWT1, which performs a WTO call.
********
* R1->ADDRESS OF INTEGER -> LENGTH OF STRING
* ->CHARACTER STRING
EDCPRLG DSALEN=DLEN
USING DSA,13
********
* RANGE CHECK LENGTH
* IGNORE A SINGLE TRAILING NULL CHARACTER
********
* BUILD WTO BUFFER
* COPY LIST FORM OF WTO TO DSA
* EXECUTE WTO
Figure 272 shows the program (CCNGWT2) you would run after you compile the
code shown in Figure 271 on page 997.
int main(void) {
#define msg "my message"
WTO(sizeof msg-1,msg);
}
Note: This information is included to aid you in such a task and is not
programming interface information.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ccngip2.h"
/*
* RECORD: each record of a pds will be read into one of these structures.
* The first 2 bytes is the record length, which is put into count,
* the remaining 254 bytes are put into rest. Each record is 256 bytes long.
*/
typedef struct {
unsigned short int count;
char rest[RECLEN];
} RECORD;
FILE *fp;
int bytes;
NODE_PTR node, last_ptr;
RECORD rec;
int list_end;
char *qual_pds;
node = NULL;
last_ptr = NULL;
/*
* Allocate a new variable, qual_pds, which will be the same as pds, except
* with single quotes around it, i.e. ID.PDS.DATASET ==> ID.PDS.DATA SET
*/
fp = fopen(qual_pds,"rb");
if (fp == NULL)
return(NULL);
do
{ bytes = fread(&rec, 1, sizeof(rec), fp);
if ((bytes != sizeof(rec)) && !feof(fp)) {
perror("FREAD:");
fprintf(stderr,"Failed in %s, line %d\n"
"Expected to read %d bytes but read %d bytes\n",
__FILE__,__LINE__,sizeof(rec), bytes);
exit(-1);
}
/*
* bit 0 of the info-byte is 1 if the member is an alias,
* 0 otherwise. ALIAS_MASK is used to extract this information
*/
#define ALIAS_MASK ((unsigned int) 0x80)
/*
* The number of user data half-words is in bits 3-7 of the info byte.
* SKIP_MASK is used to extract this information. Since this number is
* in half-words, it needs to be double to obtain the number of bytes.
*/
#define SKIP_MASK ((unsigned int) 0x1F)
/*
1000 * 8 hex FFs mark the end of the directory
z/OS V1R13.0 XL C/C++ Programming Guide
*/
char *endmark = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
static int gen_node(NODE_PTR *node, RECORD *rec, NODE_PTR *last_ptr) {
ptr = rec->rest;
/* member name */
name = ptr;
ptr += NAMELEN;
/* ttr */
memcpy(ttr,ptr,TTRLEN);
ptr += TTRLEN;
/* info_byte */
info_byte = (unsigned int) (*ptr);
alias = info_byte & ALIAS_MASK;
if (!alias) add_name(node,name,last_ptr);
skip = (info_byte & SKIP_MASK) * 2 + 1;
ptr += skip;
count += (TTRLEN + NAMELEN + skip);
}
return(list_end);
}
/*
* ADD_NAME: Add a new member name to the linked node. The new member is
* added to the end so that the original ordering is maintained.
*/
NODE_PTR newnode;
/*
* malloc space for the new node
*/
newnode = (NODE_PTR)malloc(sizeof(NODE));
if (newnode == NULL) {
fprintf(stderr,"malloc failed for %d bytes\n",sizeof(NODE));
exit(-1);
}
memcpy(newnode->name,name,NAMELEN);
newnode->name[NAMELEN] = \0;
newnode->next = NULL;
/*
* add the new node to the linked list
*/
if (*last_ptr != NULL) {
(*last_ptr)->next = newnode;
*last_ptr = newnode;
}
else {
*node = newnode;
*last_ptr = newnode;
}
return(newnode->name);
}
/*
* FREE_MEM: This function is not used by pds_mem(), but it should be used
* as soon as you are finished using the linked list. It frees the storage
* allocated by the linked list.
*/
NODE_PTR next_node=node;
Figure 274 on page 1003 (CCNGIP2) shows the associated header file.
Each window on a terminal's display has its own window data structure. This
structure keeps state information about the window such as its size and where it is
located on the display. Curses uses the window data structure to obtain relevant
information it needs to carry out your instructions.
The Curses archive file resides in /usr/lib. The name of the Curses archive file is
libcurses.a; this file is used for all applications: base 31-bit, XPLINK 31-bit, and
64bit. The following is an example of compiling test.c with the Curses archive
using XPLINK:
The following is an example of compiling test.c with the Curses archive for a
64bit application:
For more information about curses, refer to the z/OS C Curses manual.
For a dynamically called DLL module to share access to the POSIX external
variables with its caller, the DLL module must define the _SHARE_EXT_VARS
feature test macro. This is implemented in the current Language Environment
run-time. For more information, see the section on feature test macros in z/OS XL
C/C++ Run-Time Library Reference.
When compiling code with the XPLINK or LP64 compiler options, all access to
these external variables is resolved by dynamic linkage, using IMPORT control
statements in the CELHS003 (CELQS003) member of the SCEELIB library. The
SCEEOBJ library cannot be used when binding XPLINK executable modules.
Because of this, the _SHARE_EXT_VARS (and subordinate) feature test macros
need only be used with XPLINK to access the thread-specific values of these
external variables without the explicit use of the thread-specific functions.
For more information on the header files referred to in the following sections, see
z/OS XL C/C++ Run-Time Library Reference.
errno
When a run-time library function is not successful, the function may do any of the
following to identify the error:
v Set errno to a documented value.
v Set errno to a value that is not documented. You can use strerror() or perror()
to get the message associated with the errno.
v Not set errno.
v Clear errno.
See also errno.h.
daylight
The daylight savings time flag set by tzset(). Note that other time zone sensitive
functions such as ctime(), localtime(), mktime(), and strftime() implicitly call
tzset(). Use the __dlght() function to access the thread-specific value of
daylight. See also time.h.
Any changes to errno are unspecified. Use the __gderr() function to access the
thread-specific value of getdate_err. The getdate64() function affects the same
pointer to the thread-specific value of getdate_err as __gderr() does. The
getdate64() function also uses the same getdate_err values as getdate() does.
See also time.h.
h_errno
An integer that holds the specific error code when the network nameserver
encounters an error. The network nameserver is used by the gethostbyname() and
gethostbyaddr() functions. Use the __h_errno() function to access the
thread-specific value of h_errno. See also netdb.h.
__loc1
A global character pointer that is set by the regex() function to point to the first
matched character in the input string. Use the ____loc1() function to access the
thread-specific value of __loc1. __loc1 is not supported in AMODE 64 applications.
See also libgen.h.
loc1
A pointer to characters matched by regular expressions used by step(). The value
is not propagated across a call to a fetched module. loc1 is not supported in
AMODE 64 applications. See also regexp.h.
loc2
A pointer to characters matched by regular expressions used by step(). The value
is not propagated across a call to a fetched module. loc2 is not supported in
AMODE 64 applications. See also regexp.h.
optarg
Character pointer used by getopt() for options parsing variables. Use the
__optargf() function to access the thread-specific value of optarg. See also
stdio.h and unistd.h.
opterr
Error value used by getopt(). Use the __operrf() function to access the
thread-specific value of opterr. See also stdio.h and unistd.h.
optind
Integer pointer used by getopt() for options parsing variables. Use the __opindf()
function to access the thread-specific value of optind. See also stdio.h and
unistd.h.
optopt
Integer pointer used by getopt() for options parsing variables. Use the __opoptf()
function to access the thread-specific value of optopt. See also stdio.h and
unistd.h.
signgam
Storage for sign of lgamma(). This function defaults to thread specific. See also
math.h.
stdin
Standard Input stream. The external variable will be initialized to point to the
enclave-level stream pointer for the standard input file. There is no multithreaded
function. See also stdio.h.
stderr
Standard Error stream. The external variable will be initialized to point to the
enclave-level stream pointer for the standard error file. There is no multithreaded
function. See also stdio.h.
stdout
Standard Output stream. The external variable will be initialized to point to the
enclave-level stream pointer for the standard output file. There is no multithreaded
function. See also stdio.h.
timezone
Long integer difference from UTC and standard time as set by tzset(). Note that
other time zone sensitive functions such as, ctime(), localtime(), mktime(), and
strftime() implicitly call tzset(). Use the __tzone() function to access the
thread-specific value of timezone. See also time.h.
tzname
Character pointer to unsized array of timezone strings used by tzset() and
ctime(). The *tzname variable contains the Standard and Daylight Savings time
zone names. If the TZ environment variable is present and correct, tzname is set
from TZ. Otherwise tzname is set from the LC_TOD locale category. See the
tzset() function for a description. There is no multithreaded function. See also
time.h.
The way you package your product may have a significant impact on its relationship
with other products, its dependency on libraries, and the way it is eventually
serviced. For this reason, you should make a packaging plan as part of the design
process for your product.
Compiler options
The following options are useful when you compile a program that will be packaged
as a product:
TARGET
If your product will run on multiple releases of z/OS, use the TARGET
compiler option to specify the lowest level of the z/OS Language
Environment that you will support. The compiler will notify you if your
application uses any features that are not supported at this level.
The target must be the same release as the compiler or a previous release.
If the target is a previous release, you must link with the system library of
the target system. You cannot link with libraries from the current release
and run the resulting executable with a previous release of z/OS Language
Environment.
CSECT
Use the CSECT compiler option or #pragma csect to assign names to
CSECTs. This provides you with more control and flexibility when you
service the product.
For more information about these compiler options, see z/OS XL C/C++ User's
Guide.
Libraries
Your product can use various type of libraries:
z/OS Language Environment libraries
Because z/OS Language Environment is upward-compatible, a program
that runs on a lower level of z/OS Language Environment can also run on
higher levels without being relinked or recompiled. You can optionally
recompile your programs, if you want to take advantage of new features
that are introduced to z/OS Language Environment.
Your own libraries
If your program uses your own libraries, you can statically bind the libraries
with the program and consider them an integral part of the product.
Prelinking
You must use the z/OS Language Environment prelinker before linking your
application if the resultant load module will reside in a PDS and any of the following
are true:
v Your application contains C++ code.
v Your application contains C code that is compiled with the RENT, LONGNAME, DLL, or
IPA compiler option.
v Your application is compiled to run under z/OS UNIX System Services.
SMP/E will not invoke the prelinker. If your product needs to be prelinked, you
should usually prelink as part of your product build and ship the prelinker output on
the SMP/E tape.
Linking
There are two ways to ship an application that is statically linked to a library:
v You can use the ++MOD command to build the application, and not perform the
final link to the library until the product is installed. If the customer later installs a
PTF for this library, your application will automatically be relinked.
v You can build the application and link it to the library, and then install it using the
++PROGRAM command. If a PTF is issued for the library, this will have no effect
until you include the updated library in a PTF for your product.
++MOD method
If you want to do the final link-edit step during installation, use the ++MOD
command statement in the MCS. You must compile and then partially link your
program with any libraries that will not exist on the customer's system, and then
produce output in link-edited format. Any references to libraries that will exist on the
customer's system, such as z/OS Language Environment libraries, are unresolved.
Ship this link-edited module on the SMP/E tape.
SMP/E supports the automatic library call facility through the use of SYSLIB DD
statements. This allows you to implicitly include modules without explicitly specifying
them in the JCLIN. This can provide flexibility if the link-edit structure of the
application must change during servicing, for example because new functions are
used.
When you service a ++MOD, you must ship your fixes using a ++PTF command
statement. The SMP/E tape must contain the text deck (object files) in fixed-block
80 format. SMP/E invokes the link-editor to rebind the new text deck with the
existing load module. You must name all of the CSECTs, using the CSECT compiler
option or #pragma csect. (If you do not name the CSECTs, CSECT replacement
To allow rebind, you must also use the EDIT=YES option in the bind step. This is the
default.
++PROGRAM method
You can choose to do the final link step as part of your product build, and ship the
output load module to your customer. The advantage is that the whole build process
is under your control, and you can perform the final testing of the load module in
your own controlled environment.
If your customers have different levels of z/OS Language Environment, you must
target your build to the lowest level and link with system libraries at this level. Your
product will have a prerequisite that the customer must have z/OS Language
Environment at this level or a higher level.
If service is applied to any linked library, this will have no effect on your product
until you include the service in a PTF.
The ++PTF command, which is used for shipping and applying fixes, expects input
in fixed-block 80 format. The output of the link step is not in this format. You can
convert it as follows:
1. UNLOAD - use IEBCOPY to copy the module and its alias (if any) to a
sequential file.
2. Run the SMP/E utility GIMDTS to convert the sequential file to a fixed-block 80
file.
Conceptually, the ++PROGRAM copies the whole load module to your customer's
target dataset with no additional processing. You customer receives the module
exactly as you ship it.
Accessibility features help a user who has a physical disability, such as restricted
mobility or limited vision, to use software products successfully. The major
accessibility features in z/OS enable users to:
v Use assistive technologies such as screen readers and screen magnifier
software
v Operate specific or equivalent features using only the keyboard
v Customize display attributes such as color, contrast, and font size
z/OS information
z/OS information is accessible using screen readers with the BookServer or Library
Server versions of z/OS books in the Internet library at:
http://www.ibm.com/systems/z/os/zos/bkserv/
One exception is command syntax that is published in railroad track format, which
is accessible using screen readers with the Information Center, as described in
Dotted decimal syntax diagrams.
The dotted decimal numbering level denotes the level of nesting. For example, if a
syntax element with dotted decimal number 3 is followed by a series of syntax
elements with dotted decimal number 3.1, all the syntax elements numbered 3.1 are
subordinate to the syntax element numbered 3.
Certain words and symbols are used next to the dotted decimal numbers to add
information about the syntax elements. Occasionally, these words and symbols
might occur at the beginning of the element itself. For ease of identification, if the
word or symbol is a part of the syntax element, it is preceded by the backslash (\)
character. The * symbol can be used next to a dotted decimal number to indicate
that the syntax element repeats. For example, syntax element *FILE with dotted
decimal number 3 is given the format 3 \* FILE. Format 3* FILE indicates that
syntax element FILE repeats. Format 3* \* FILE indicates that syntax element *
FILE repeats.
The following words and symbols are used next to the dotted decimal numbers:
v ? means an optional syntax element. A dotted decimal number followed by the ?
symbol indicates that all the syntax elements with a corresponding dotted
decimal number, and any subordinate syntax elements, are optional. If there is
only one syntax element with a dotted decimal number, the ? symbol is displayed
on the same line as the syntax element, (for example 5? NOTIFY). If there is
more than one syntax element with a dotted decimal number, the ? symbol is
displayed on a line by itself, followed by the syntax elements that are optional.
For example, if you hear the lines 5 ?, 5 NOTIFY, and 5 UPDATE, you know that
syntax elements NOTIFY and UPDATE are optional; that is, you can choose one
or none of them. The ? symbol is equivalent to a bypass line in a railroad
diagram.
v ! means a default syntax element. A dotted decimal number followed by the !
symbol and a syntax element indicate that the syntax element is the default
option for all syntax elements that share the same dotted decimal number. Only
one of the syntax elements that share the same dotted decimal number can
specify a ! symbol. For example, if you hear the lines 2? FILE, 2.1! (KEEP), and
2.1 (DELETE), you know that (KEEP) is the default option for the FILE keyword.
IBM may not offer the products, services, or features discussed in this document in
other countries. Consult your local IBM representative for information on the
products and services currently available in your area. Any reference to an IBM
product, program, or service is not intended to state or imply that only that IBM
product, program, or service may be used. Any functionally equivalent product,
program, or service that does not infringe any IBM intellectual property right may be
used instead. However, it is the user's responsibility to evaluate and verify the
operation of any non-IBM product, program, or service.
IBM may have patents or pending patent applications covering subject matter
described in this document. The furnishing of this document does not give you any
license to these patents. You can send license inquiries, in writing, to:
IBM Director of Licensing
IBM Corporation
North Castle Drive
Armonk, NY 10504-1785
USA
For license inquiries regarding double-byte (DBCS) information, contact the IBM
Intellectual Property Department in your country or send inquiries, in writing, to:
IBM World Trade Asia Corporation
Licensing
2-31 Roppongi 3-chome, Minato-ku
Tokyo 106, Japan
The following paragraph does not apply to the United Kingdom or any other
country where such provisions are inconsistent with local law:
INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS
PUBLICATION AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
PARTICULAR PURPOSE. Some states do not allow disclaimer of express or
implied warranties in certain transactions, therefore, this statement may not apply to
you.
Any references in this information to non-IBM Web sites are provided for
convenience only and do not in any manner serve as an endorsement of those
Web sites. The materials at those Web sites are not part of the materials for this
IBM product and use of those Web sites is at your own risk.
IBM may use or distribute any of the information you supply in any way it believes
appropriate without incurring any obligation to you.
The licensed program described in this information and all licensed material
available for it are provided by IBM under terms of the IBM Customer Agreement,
IBM International Program License Agreement, or any equivalent agreement
between us.
Information concerning non-IBM products was obtained from the suppliers of those
products, their published announcements or other publicly available sources. IBM
has not tested those products and cannot confirm the accuracy of performance
compatibility or any other claims related to non-IBM products. Questions on the
capabilities of non-IBM products should be addressed to the suppliers of those
products.
All statements regarding IBM's future direction or intent are subject to change
without notice, and represent goals and objectives only.
This information contains examples of data and reports used in daily business
operations. To illustrate them as completely as possible, the examples include the
names of individuals, companies, brands, and products. All of these names are
fictitious and any similarity to the names and addresses used by an actual business
enterprise is entirely coincidental.
COPYRIGHT LICENSE:
Permission Notice
This book includes information about certain callable service stub and linkage-assist
(stub) routines contained in specific data sets that are intended to be bound or
link-edited with code and run on z/OS systems. In connection with your authorized
use of z/OS, you may bind or link-edit these stubs into your modules and distribute
your modules with the included stubs for the purposes of developing, using,
marketing and distributing programs conforming to the documented programming
interfaces for z/OS, provided that each stub is included in its entirety, including any
IBM copyright statements. These stubs have not been thoroughly tested under all
conditions. IBM, therefore, cannot guarantee or imply the reliability, serviceability, or
function of these stub programs. The stubs referred to in this book are contained in
one or more of the following data sets:
v CEE.SAFHFORT
v CEE.SCEEBIND
v CEE.SCEEBND2
v CEE.SCEECPP
v CEE.SCEELKED
v CEE.SCEELKEX
v CEE.SCEEOBJ
v CEE.SCEESPC
v CEE.SIBMAM24
v CEE.SIBMCALL
v CEE.SIBMCAL2
v CEE.SIBMMATH
v CEE.SIBMTASK
Notices 1021
Trademarks
IBM, the IBM logo, and ibm.com are trademarks or registered trademarks of
International Business Machines Corp., registered in many jurisdictions worldwide.
Other product and service names might be trademarks of IBM or other companies.
A current list of IBM trademarks is available on the Web at "Copyright and
trademark information" at www.ibm.com/legal/copytrade.shtml.
Java and all Java-based trademarks and logos are trademarks or registered
trademarks of Oracle and/or its affiliates.
UNIX is a registered trademark of The Open Group in the United States and other
countries.
Other company, product, and service names might be trademarks or service marks
of others.
Standards
The following standards are supported in combination with the z/OS Language
Environment:
v The C language is consistent with Programming languages - C (ISO/IEC
9899:1999). This standard has officially replaced American National Standard for
Information Systems-Programming Language C (X3.1591989) and is technically
equivalent to the ANSI C standard. The compiler supports the changes adopted
into the C Standard by ISO/IEC 9899:1990/Amendment 1:1994. For more
information on ISO, visit their web site at http://www.iso.ch/
v The C++ language is consistent with Programming languages - C++ (ISO/IEC
14882:2003) and Programming languages - C++ (ISO/IEC 14882:1998).
The following standards are supported in combination with the z/OS Language
Environment and z/OS UNIX System Services:
v IEEE Std 1003.11990, IEEE Standard Information TechnologyPortable
Operating System Interface (POSIX)Part 1: System Application Program
Interface (API) [C language], copyright 1990 by the Institute of Electrical and
Electronic Engineers, Inc. For more information on IEEE, visit their web site at
http://www.ieee.org/.
v A subset of IEEE P1003.1a Draft 6 July 1991, Draft Revision to Information
TechnologyPortable Operating System Interface (POSIX), Part 1: System
Application Program Interface (API) [C Language], copyright 1992 by the Institute
of Electrical and Electronic Engineers, Inc.
v IEEE Std 1003.21992, IEEE Standard Information TechnologyPortable
Operating System Interface (POSIX)Part 2: Shells and Utilities, copyright 1990
by the Institute of Electrical and Electronic Engineers, Inc.
v A subset of IEEE Std P1003.4a/D61992, IEEE Draft Standard Information
TechnologyPortable Operating System Interface (POSIX)Part 1: System
Portions of this text are reprinted and reproduced in electronic form in z/OS, from
IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- Portable
Operating System Interface (POSIX), The Open Group Base Specifications Issue 6,
copyright 2001-2004 by the Institute of Electrical and Electronics Engineers, Inc and
The Open Group. In the event of any discrepancy between these versions and the
original IEEE and The Open Group Standard, the original IEEE and The Open
Group Standard is the referee document. The original Standard can be obtained
online at http://www.opengroup.org/unix/online.html .
Notices 1023
1024 z/OS V1R13.0 XL C/C++ Programming Guide
Bibliography
This bibliography lists the publications for IBM products that are related to z/OS XL
C/C++. It includes publications covering the application programming task. The
bibliography is not a comprehensive list of the publications for these products,
however, it should be adequate for most z/OS XL C/C++ users. Refer to z/OS
Information Roadmap, SA22-7500, for a complete list of publications belonging to
the z/OS product.
Related publications not listed in this section can be found on the IBM Online
Library Omnibus Edition MVS Collection, SK2T-0710, the z/OS Collection,
SK3T-4271, or on a tape available with z/OS.
z/OS
v z/OS Introduction and Release Guide, GA22-7502
v z/OS Planning for Installation, GA22-7504
v z/OS Summary of Message and Interface Changes, SA22-7505
v z/OS Information Roadmap, SA22-7500
v z/OS Licensed Program Specifications, GA22-7503
v z/OS Migration, GA22-7499
v z/OS Program Directory, GI10-0670
z/OS XL C/C++
v z/OS XL C/C++ Programming Guide, SC09-4765
v z/OS XL C/C++ User's Guide, SC09-4767
v z/OS XL C/C++ Language Reference, SC09-4815
v z/OS XL C/C++ Messages, GC09-4819
v z/OS XL C/C++ Run-Time Library Reference, SA22-7821
v z/OS C Curses, SA22-7820
v z/OS XL C/C++ Compiler and Run-Time Migration Guide for the Application
Programmer, GC09-4913
v Standard C++ Library Reference, SC09-4949
Debug Tool
v Debug Tool documentation, which is available at: www.ibm.com/software/
awdtools/debugtool/library/
Assembler
v HLASM Language Reference, SC26-4940
v HLASM Programmer's Guide, SC26-4941
COBOL
v COBOL documentation, which is available at: http://www.ibm.com/software/
awdtools/cobol/zos/library/
PL/I
v PL/I documentation, which is available at: http://www.ibm.com/software/awdtools/
pli/plizos/library/
VS FORTRAN
v VS FORTRAN documentation, which is available at: http://www.ibm.com/
software/awdtools/fortran/vsfortran/library.html
DB2
v DB2 for z/OS documentation, which is available at: https://www-304.ibm.com/
support/docview.wss?uid=swg27019288&wv=1
IMS/ESA
v IMS documentation, which is available at: http://www.ibm.com/software/data/ims/
library.html
MVS
v z/OS MVS Program Management: User's Guide and Reference, SA22-7643
v z/OS MVS Program Management: Advanced Facilities, SA22-7644
DFSMS
v z/OS DFSMS Introduction, SC26-7397
v z/OS DFSMS Managing Catalogs, SC26-7409
v z/OS DFSMS Using Data Sets, SC26-7410
v z/OS DFSMS Macro Instructions for Data Sets, SC26-7408
v z/OS DFSMS Access Method Services for Catalogs, SC26-7394
Bibliography 1027
1028 z/OS V1R13.0 XL C/C++ Programming Guide
Index
Special characters ] (right square bracket) and [ (left square bracket) 919
| (vertical bar) 919
__abendcode macro, using for debugging 223
& (ampersand)
__amrc structure
using to specify temporary data set names 82
debugging I/O programs 221
# (number sign) 919
example 224
#pragma csect
using with VSAM 150, 173
packaging products 1012
__amrc2 structure
shipping fixes 1012
usage 225
{ (left brace) 919
__csplist() library function 735
} (right brace) 919
__last_op codes for __amrc 225
^ (caret) 919
__rsncode macro 223, 418
~ (tilde) 919
__STDC_CONSTANT_MACROS feature test
macro 546
__STDC_FORMAT_MACROS feature test macro 546
__STDC_LIMIT_MACROS feature test macro 546
Numerics
_24malc() library function 665 24malc() library function 665
_4kmalc() library function 666 32-bit application
_EDC_ERRNO_DIAG environment variable 490 recompiling as 64-bit 327
_EDC_GLOBAL_STREAMS environment variable 492 4kmalc() library function 666
_EDC_IEEEV1_COMPATIBILITY_ENV environment 64 bit offsets 139
variable 493 64-bit
_EDC_IO_ABEND environment variable 494 _LP64 macro 351
_EDC_IO_TRACE environment variable 495 environment 325
_EDC_POPEN environment variable 496 migrating from 32-bit 331
_EDC_PTHREAD_YIELD environment variable 496 pointers 341
_EDC_PTHREAD_YIELD_MAX environment printf 347
variable 497 structure alignment 333
_EDC_PUTENV_COPY environment variable 498 64-bit virtual memory
_EDC_RRDS_HIDE_KEY environment variable 159 IPA(LINK) 332
_ICONV_UCS2 environment variable 880
_ICONV_UCS2_PREFIX environment variable 874
_ISOC99_SOURCE feature test macro 546 A
_LP64 macro abend
64-bit 351 CICS and assembler user exit 675
_TR1_C99 feature test macro 546 codes
_TZ environment variable 847 CEEBXITA, CEEAUE_RETC field 673
_xhotc() library function 661 specifying those to be percolated 676
_xhotl() library function 662 dumps, CEEAUE_DUMP 675
_xhott() library function 662 generating 653
_xhotu() library function 663 percolating 671, 676
_xregs() library function 663 requesting dump 675
_xsacc() library function 664 system 671, 676
_xsrvc() library function 665 TRAP run-time option 672
_xusr() library function 665 user 671, 676
_xusr2() library function 665 ABEND, compiler
! (exclamation mark) 919 insufficient storage 332
// (double slash), part of MVS data set name 82, 153 MEMLIMIT system parameter and IMEMLIM
/* (EOF sequence for text terminal) 191 variable 332
\a (alarm) 106 absolute value, decimal type 390
\b (backspace) 106 acc parameter for fopen()
\f (form feed) 106 memory file I/O 202
\n (newline) 106 terminal I/O 190
\r (carriage return) 106 VSAM data sets 155
\t (horizontal tab) 106 z/OS OS I/O 98
\v (vertical tab) 106 accept(), network example 433
\x0E (DBCS shift out) 106 access control list (ACL) 144
\x0F (DBCS shift in) 107 access method selection 95
Index 1031
CICS (Customer Information Control System) cin (continued)
(continued) predefined stream, usage 21
compiling XL C/C++ programs after CINET 443
preprocessing 730 class libraries
Cross System Product (CSP) 735 optimizing 567
CSD considerations 734 clearenv() library function 475
csnap() library function 719 clearing memory 578
ctdli() library function 719 client perspective 434
ctrace() library function 719 client/server
define and run the program 733 allocation with socket() 433
designing and coding a program 712 conversation 432
developing and XL C/C++ program 711 exchanging data 432
DLL 719 server perspective 433
dump functions 719 clock() library function 719
dynamic allocation 719 clog
EXEC CICS LINK 719 C++ standard error stream 61
EXEC CICS statements predefined stream, usage 21
example 726 closing
EXEC CICS statements and the standalone CICS memory files 209
translator 726 OS I/O files 117
EXEC CICS XCTL 719 terminal files 196
fetch() library function 719 the CELQPIPI MSGRTN file 218
floating point arithmetic 720 VSAM data sets 172
input and output 30, 213 z/OS Language Environment message file 216
interlanguage support 721 z/OS UNIX file system files 131
iscics() library function 719 clrmemf() library function
JCL to translate and compile 730 memory I/O files 209
link considerations 733 COBOL
link load module 732 assembler user exit 670
linking for reentrancy 732 using linkage specifications 237
locale support 718, 902 code
memory file support 717 code point mappings 925
migrating to a newer translation option 726 independence 693
MTF support 718 motion 590
overview 711 code conversions
packed decimal support 718 CCNGHC1 977
POSIX support 718 from IBM-1047 character set 977
prelinking 732 code point mappings
preparing for use with z/OS Language hexadecimal values 925
Environment 711 coded character set
program processing 733 CICS support 711
program termination 720 considerations with locale 885
redirecting standard streams 73 conversion during compile 895
reentrancy 733 conversion utilities 861
release() library function 719 converters supplied 864
requirements 711 IBM-1047
run-time options 718 converting code to 889
SP C support 719 converting to a specific character set 977
standalone CICS translator 726 IBM-1047 vs. IBM-293 887
standard stream support 717 independence 889
storage management 720 related to compile-edit cycle 889
svc99() library function 719 coded character set id 144
system() library function 719 collating sequence difference, SAA and POSIX 859
translating example 726 command
translating options 725 syntax diagrams xxv
using with IMS 719 common expression elimination 590
z/OS UNIX 1005 Common INET 443
z/OS XL C/C++ integrated CICS translator 726 Common Programming Interface (CPI) 775
z/OS XL C/C++ library support 718 communication, network basics 426
cin communications, interprocess
C++ standard input stream 61 asynchronous signal delivery 413
Index 1033
data types DEC_PRECISION decimal constant (continued)
conversions range of values 377
explicit 384 decabs() built-in function 390
decimal decchk() built-in function 389, 394
using in C 377 decchk() library function 394
fixed-point decfix() built-in function 390
using in C 377 decimal data type
referencing bit fields absolute value 390
and optimization 575 assignments 379
datagram constants 378
definition 426 conversions 385
sockets 429 declarations 377
DB2 error messages 394
application programming environment, z/OS exception handling 393
UNIX 1005 fixing sign of 390
codepage 753 operators 379
DB2 C/C++ precompiler 754 printing with library functions 389
host variables 753 SPC restriction 393
example 757 validating 389
invoking DB2 services with z/OS XL C/C++ 754 variables 378
locale support 902 viewing with library functions 389
preprocessor directives 753 decimal data types
stored procedures and XPLINK 754 and variable arguments 389
varable-length source input 753 as variables 377
when NOSQL is the default compiler option 753 using in C 377
with z/OS XL C/C++ 753 decimal floating-point support
examples 755 built-in instructions, hardware 529
XL C/C++ DB2 coprocessor 753 biased exponent definitions 536
DBCS (Double-Byte Character Support) FPC register-rounding macros 536
input and output functions 51 macros 536
reading 52 Test Data Class masks 537
shift in character 107 Test Data Group masks 537
shift out character 106 decimal.h header file 377
writing 54 declarations
DCB (Data Control Block) and optimization
OS I/O 101 referencing bit fields 575
parameter on a DD statement 84 decimal 377
parameters, optimizing code 585 extern, using for linkage to other languages 237
ddname default
creating C locales for POSIX, SAA, and S370 849
description 34 DCB attributes for SYSOUT data set 92
in source code 35 fopen() 32
under MVS batch 34 locales 849, 859
under TSO 34 LRECL, fopen() 32
opening a z/OS UNIX file system I/O file under RECFM 32
MVS 126 definition side-deck 291
opening an OS I/O file under z/OS 83 delete
restriction 35 named module from storage 657
dead code elimination 590 optimizing 567
dead store elimination 590 pipes with z/OS UNIX file system 134
Debug Tool VSAM records 161
CEEBINT and 681 z/OS UNIX file system files 131
debugging I/O programs 221 delimiter in JCL statements 91
DEC_DIG decimal constant delivery, signals
numerical limit 379 ANSI C rules 411
range of values 377 asynchronous 413
DEC_EPSILON decimal constant 379 POSIX rules 411
DEC_MAX decimal constant 379 differences among C, POSIX, and SAA locales 859
DEC_MIN decimal constant 379 digitsof operator 383
DEC_PRECISION decimal constant direct processing 159
numerical limit 379
Index 1035
EDCXSRVC routine 652 environment variables (continued)
EDCXSRVN routine _EDC_ZERO_RECLEN 501
initiating a server request 652 _ICONV_UCS2 880
EDCXSTRL module _ICONV_UCS2_PREFIX 874
in freestanding applications 628 BIDIATTR 467
usage 624 BIDION 467
EDCXSTRT module locale 473
in freestanding applications 628 naming conventions 476
usage 623 using 475
EDCXSTRX module EOF (end of file)
in freestanding applications 628 resetting terminal I/O 191
usage 624 equality operators
EDCXUNLD routine 657 decimal in C 381
EDCXUSR library function 665 ERRCOUNT run-time option 411
EDCXUSR2 library function 665 errno values 1007
ELPA (Extended Link Pack Area) 370 errors, debugging 418
empty records ESCON channels, striped data sets 93
_EDC_ZERO_RECLEN 16, 501 ESDS (Entry-Sequenced Data Set)
enabled signals 415 alternate index keys 150
enclave use of 147
terminating with CEEAUE_ABND 675 established signals 414
encoded offset 114 examples
ENGLISH run-time messages 657 ccngas1 47
Enhanced ASCII ccngbid1 912
limitations of 787 ccngca1 255
environment ccngca10 251
64-bit 325 ccngca2 253, 255
environment variables ccngca3 255
_BPXK_AUTOCVTS 467 ccngca5 254
_BPXK_CCSIDS 468 ccngca6 261
_BPXK_SIGDANGER 469 ccngca7 264
_CEE_DLLLOAD_XPCOMPAT 478 ccngca9 251
_CEE_DMPTARG 478 ccngcc2 892
_CEE_ENVFILE 479 ccngch1 404
_CEE_ENVFILE_S 481 ccngch2 406
_CEE_HEAP_MANAGER 482 ccngci1 713
_CEE_RUNOPTS 483 ccngci3 726
_EDC_ADD_ERRNO2 486 ccngcl1 842
_EDC_ANSI_OPEN_DEFAULT 101, 486 ccngcl2 844
_EDC_AUTOCVT_BINARY 486 ccngcl3 844
_EDC_BYTE_SEEK 98, 114, 487 ccngcp1 736
_EDC_C99_NAN 489 ccngcp2 737
_EDC_CLEAR_SCREEN 194, 487 ccngcp3 739
_EDC_COMPAT 487 ccngcp4 740
_EDC_CONTEXT_GUARD 488 ccngcp5 743
_EDC_DLL_DIAG 489 ccngcp6 744
_EDC_EOVERFLOW 490 ccngcp7 746
_EDC_ERRNO_DIAG 490 CCNGDB4 755
_EDC_GLOBAL_STREAMS 492 ccngdc1 380
_EDC_IO_ABEND 494 ccngdc2 381
_EDC_IO_TRACE 495 ccngdc3 391
_EDC_POPEN 496 ccngdc4 392
_EDC_PTHREAD_YIELD 496 ccngdi1 224
_EDC_PTHREAD_YIELD_MAX 497 ccngdi2 229
_EDC_PUTENV_COPY 498 ccngdl1 858
_EDC_RRDS_HIDE_KEY 498 ccngdw1 752
_EDC_STOR_INCREMENT 498 ccngdw2 751
_EDC_STOR_INCREMENT_B 499 ccngec1 424
_EDC_STOR_INITIAL 499 ccngev1 501
_EDC_STOR_INITIAL_B 500 ccnggd1 761
_EDC_SUSV3 500 ccnggd2 763
Index 1037
fgetpos() library function (continued) fldata() library function (continued)
optimizing code 586 OS I/O files 119
fgets() library function terminal I/O 196
See also reading z/OS UNIX file system I/O 142
optimizing code 585 floating-point registers 256
fgetwc_unlocked() library function 52 floating-point support
fgetwc() library function 52 binary 539
fgetws_unlocked() library function 53 built-in instructions 528
fgetws() library function 53 decimal 529
FIFO hexadecimal 538
mkfifo() 131, 133 flocate() library function
special files VSAM data sets 150, 162
creating 124 flushing
using 123, 133 binary streams, wide character I/O 57
File I/O trace 232 buffers for terminal files 195
Locating the file I/O trace 233 memory files 208
Sample file I/O trace 232 OS I/O files 109
files terminal files 195
conversion 144 text streams, wide character I/O 56
large support 139 the CELQPIPI MSGRTN file 217
memory VSAM data sets 164, 170
closing 209 z/OS Language Environment message file 216
extending 208 z/OS UNIX file system records 130
flushing 208 fopen() library function
opening 200 See also opening
positioning 208 list of parameters, for
reading 206 memory file I/O 201
repositioning 208 terminal I/O 189
writing 207 VSAM I/O 155
named pipe 133 z/OS OS I/O 95
origin of OS attributes 101 z/OS UNIX file system I/O 127
OS restrictions 32
flushing 109 under MTF 706
opening 81 z/OS UNIX file system files 123
reading from 103 for statement 575
removing 119 fork() library function
renaming 119 data definition considerations 127
repositioning 112, 117 using with memory files 586
writing to 105 form feed escape sequence \f 106
tagging 144 Format-D files restriction 9
VSAM fprintf() library function
closing 172 See writing
deleting a record 161 fputc() library function
flushing 164 See also writing
locating a record 161 optimizing code 585
reading a record 158 fputs() library function
repositioning 161 See also writing
updating a record 160 optimizing code 585
writing a record 159 fputwc_unlocked() library function 54
z/OS, opening 81 fputwc() library function 54
filetag pragma 891 fputws_unlocked() library function 54
fixed-format records fputws() library function 54
overview 10 fread() library function
standard format 10 See also reading
fixed-point data types optimizing code 585, 587
See See decimal data types. FREE=CLOSE parameter, DD statement 84
fixes freestanding applications
++PTF statement 1012, 1013 EDCXISA 625
shipping 1012, 1013 EDCXSTRL 624
fldata() library function EDCXSTRT 623
memory file I/O 209 EDCXSTRX 624
Index 1039
I/O (continued) ILP32 to LP64 migrations (continued)
pipe 131 pointer cast conversions 343
printer output 94 pointer declarations 341
record portability issues 331, 338
introduction 8 portable coding 348
model 9 post-migration activities 329
rules, z/OS UNIX file system 128 pre-migration activities 328
striped data sets 93 precision 343
summary table 27 SAA 351
sysout data set 92 shared structures 344, 349
tapes 92 suffixes 348
terminal 189 type definitions 348
text stream 7 unsuffixed numbers 346
wide characters 51 IMEMLIM variable
z/OS Language Environment message file 215 to override the MEMLIMIT default 332
z/OS UNIX file system 123 IMS (Information Management System)
functions 137 default high-level qualifier 83, 201
using with I/O 123 error handling 768
i/o stream libraries opening files 83, 201
optimizing 587 other considerations 768
I/O Stream Library 61 redirecting standard streams 72
I/O Streams File I/O 21 using with CICS 719
IBM-1047 (APL 293), CICS 711 with z/OS XL C/C++ 767
IBM-1047 character set z/OS UNIX 1005
converting to a specific character set 977 in-stream data sets
IBM-1047 coded character set delimiter for data 91
CCNGHC1 977 input 91
converting code to 889 noseek parameter 91
iconv utility include files
converting code sets 861 with z/OS UNIX sockets 447
preparing source code for exporting 900 INCLUDE statement, MVS 669
iconv() library function 862 INFO compiler option
IEBGENER utility (TSO) ensuring portability to LP64 329
tape files 92 INIT token preinitialization 259
IEEE Binary Floating-Point 397 initialization
IEEE Decimal Floating-Point 397 nested enclave
IEFUSI exit routine CEEBXITA's function code for 673
MEMLIMITvalue 332 using CEEBXITA 670
if statement 575 inlining
ifstream class 22 optimization 594
IGNERRNO compiler option 592 suggestions 595
ILP32 under IPA 597
and LP64 325 installation-wide assembler user exit 669
ILP32 to LP64 migrations 351 instruction scheduling 590
alignment differences 333 integer constants
alignment issues 333 64-bit 343
assignment issues 337 interface
availability of suboptions 332 CICS 711
conditional compiler directives 351 DB2 753
conversions between int and pointer 342 DWS 751
converters 351 GDDM 761
customized locales 351 IMS 767
debugging 350 locale-sensitive 784
ensuring portability 329 preinitialized program 258
explicit types 348 interlanguage calls
function prototypes 350 C or C++ and assembler 243
header files 341, 348 linkage specification 240
localedef utility 351 using linkage specifications 237
locales 351 interleaving
LONG_MAX 347 standard streams 63
padding 349 without sync_with_stdio() 64
Index 1041
locale (continued) m_wtransform_layout() library function 909
compiler option examples 895, 896 machine print-control codes 10
converting existing work 901 macros
customizing 839 EDCDSAD 247
environment variables 473 EDCEPIL 247
generating an object module 896 EDCPRLG 247
hybrid coded character set, using 887 EDCPROL 247
library functions EDCXCALL 247
localdtconv() 784 EDCXEPLG 247
localeconv() 784 EDCXPRLG 247
setlocale() 784 use with locale 892
LOCALE compiler option 895 main task for MTF 685
localeconv() library function 796 mainframe
macros 892 education xxvii
overview of z/OS XL C/C++ support 784 malloc() library function
predefined 894 system programming C environment 632, 637, 653
source-code functions summary 891 MB_CUR_MAX, effect on DBCS 51
summary of support in compiler 896 member, PDS and PDSE 88
tests for SAA or POSIX 859 memcmp library function 577, 578
TZ or _TZ environment variable 847 MEMLIMIT default value
using with CICS 718 64-bit virtual memory 332
LOCALE compiler option 895 overriding 332
display of hexadecimal values 919 setting 332
localeconv() library function 784 memory
localedef utility 351 optimizing 607
example 957 memory files
locales automatic name generation 203
display of hexadecimal values 919 closing 209
under ILP32 and LP64 351 example 29, 211
locales, customized 351 example program 210
logical record length parameter extending 208
See LRECL (logical record length) parameter flushing 208
loop statements, optimizing 575 I/O, description 29
low-level z/OS UNIX I/O 137 in hiperspace 199
LP64 input and output 199
and ILP32 325 opening 200
LP64 environment optimizing 587
advantages and disadvantages 326 positioning within 208
application performance and program size 326 reading from 206
migrating applications to 327 repositioning within 208
pointer assignment 342 return values for fldata() 209
restrictions 327 simulated partitioned data sets
LP64 strategy 327 description 204
LPA (Link Pack Area) 370 example 204, 205
LRECL (logical record length) parameter specifying asterisk as file name 203
defaults 32 support under CICS 717
fopen() library function text mode treated as binary 203
See also opening ungetc() considerations 208
memory file I/O 202 using to optimize code 587
terminal I/O 190 writing to 207
VSAM data sets 155 memset library function 578
z/OS OS I/O 97 method files 822, 943
lrecl=X, OS I/O 97 migrating applications
from ILP32 to LP64 327
migration issues, ILP32to-LP64 331
M mkdir() library function 124
m_create_layout() library function 906 mkfifo() library function
m_destroy_layout() library function 909 with z/OS UNIX file system files 124, 131, 133
m_getvalues_layout() library function 907 mknod() library function 124, 133
m_setvalues_layout() library function 906 MSGCLASS, matching for SYSOUT data sets 92
m_transform_layout() library function 907
Index 1043
optimization (continued) OS I/O (continued)
arithmetic constructions 574 flushing records (continued)
C++ 565 example 110
code motion 590 I/O stream library 81
common expression elimination 590 in-stream data sets 91
compilation time 611 lrecl=X 97
constant propagation 590 multivolume data sets 93
control constructs 575 opening files 81
conversions 574 overview 81
dead code elimination 590 password= parameter 98
dead store elimination 590 PDS and PDSE considerations
declarations 575 BLKSIZE values 97
dynamic memory 607 LRECL values 97
expressions 573 overview 88
fixed standard format records 10 RECFM values 96
function arguments 572 reading from files 103
general notes 565 repositioning within files 112
graph coloring register allocation 590 space= parameter 97
i/o stream libraries 587 striped data sets 93
inlining 594, 595 tapes 92
inlining under IPA 597 type= parameter 98
instruction scheduling 590 ungetc() considerations 111, 113
levels 598 writing to files 105
library extensions 579 OS linkage 237, 244, 256
library functions 577 os parameter, fopen()
library lookasides 609 memory file I/O 202
link pack areas 609 terminal I/O 191
loop statements 575 VSAM I/O 156
memory 607 z/OS OS I/O 99
memory files 587 overlapped I/O 100
MVS data sets 585 overrideable run-time options in the user exit 675
noseek parameter for OS I/O 98
OPTIMIZE 589
pointers 572 P
programming recommendations 10 packaging products 1011
referencing bit fields 575 ++MOD method 1012
storage 607 ++PROGRAM method 1013
straightening 589 DLL compiler option 1012
strength reduction 590 final testing 1013
value numbering 589 for changes during servicing 1012
variables 571 IPA compiler option 1012
virtual lookasides 609 LONGNAME compiler option 1012
XPLINK 597 prelinker output 1012
OPTIMIZE RENT compiler option 1012
optimizing 589 under z/OS UNIX System Services 1012
optimized code packed decimal
troubleshooting with dbx 615 assignments 379
option_override 581 conversions 385
order, network byte 430 declarations 377
OS I/O operators 379
acc= parameter 98 using with CICS 718
asis parameter 98 variables 378
asynchronous reads 98, 100 parallel functions 686
asynchronous writes 98, 100 parameter list, OS 244
buffering 99 partitioned concatenation
byteseek parameter 98 compatibility rules 89
closing files 117 data sets 89
description 28 passing parameters
fgetpos() and ftell() values 114 CSP 735
flushing records OS 244
description 109 passing streams across system calls 73
Index 1045
putc() library function (continued) RECFM (record format) (continued)
optimizing code 585 V (variable format)
putchar() library function overview 13
See writing VSAM data sets 155
puts() library function z/OS OS I/O 96
See writing record
putwc_unlocked() library function 54 empty
putwc() library function 54 _EDC_ZERO_RECLEN 16, 501
putwchar_unlocked() library function 54 files, using fseek() and ftell() 116
putwchar() library function 54 fixed standard format 10
I/O
byte stream behavior 18
Q fixed-format behavior 13
QMF (Query Management Facility) introduction 8
with has SAA callable interface 775 restriction 52
undefined-format behavior 18
variable-format behavior 16
R spanned 14
RACF (Resource Access Control Facility) specifying length 31
no hyphens in names for 82 undefined-length 16
qualifier required in data set name 83 variable-length 13
raise() library function z/OS UNIX file system I/O rules 128
error handling 410 zero-byte
RBA (Random Byte Address) _EDC_ZERO_RECLEN 16, 501
in VSAM 150 redirection
RDW (record descriptor word) 96 standard streams 61
reachable pragma 581 introduction 70
read-write lock 355 to fully qualified data sets 70
read() library function using DD statements 71
with pipes 133 using freopen() 70
z/OS UNIX file system files 129 using PARM 70
reading standard streams in a system programming C
from memory files 206 environment 621
from OS I/O files 103 stderr, with z/OS Language Environment MSGFILE
from terminal files 191 option 68
from the CELQPIPI MSGRTN file 217 stream, using assignment 68
from the z/OS Language Environment message streams under CICS 73
file 215 streams under IMS 72
from VSAM data sets 158 streams under TSO
from z/OS UNIX file system files 128 from the command line 72
multibyte characters 52 introduction 72
using recfm=U 96 streams, using freopen() 68
realloc() library function symbols 67
system programming C environment 637, 653 reentrancy
reason codes and XPLINK 370
in user exits 674 constructed 370
RECFM (record format) in z/OS XL C/C++ 369
F (fixed-format) 10 limitations 370
memory file I/O 202 modified CEEBXITA must be reentrant 672
overview 9 natural 370
RECFM defaults 32 with respect to CICS 725
recfm=* extension 31, 96 register
recfm=A extension 96 allocation 590
restrictions 33 conventions 256
S (fixed standard) 10 variables 572
S (variable spanned) 14 regular z/OS UNIX file system files 123
specifying 31 relational operators
terminal I/O 190 decimal in C 381
U (undefined format) relative byte offset 114
overview 16 remove() library function
reading OS files 96 memory I/O files 209
Index 1047
SIGFPE signal spanned records 14
error condition 415 SPILL compiler option 593
under decimal 383 spool data sets 488
SIGILL signal 415 sprintf() library function
SIGINT signal 415 in freestanding routines 626
SIGIOERR signal 229, 415 system programming C environment 632, 637, 653
signal square brackets ([ and ])
actions, defaults 418 displaying on workstation or 3270 919
delivery displaying square brackets 922
ANSI C rules 411 square brackets 922
asynchronous 413 sscanf() library function
POSIX rules 411 character to integer conversions 578
handling stand-alone modules 622
default 418 standalone CICS translator 730
disabled 415 standard
enabled 415 records 10
established 414 stream
hardware 415 association with ddnames 71
raise 410 buffering 45
software 415 cerr 21
with signal() and raise() 410 cin 21
with z/OS Language Environment 410 clog 21
SIGSEGV signal 415 cout 21
SIGTERM signal 415 default open modes 62
SIGUSR1 signal 415 direct assignment 68
SIGUSR2 signal 415 global behavior 76, 492
sizeof operator 383 interleaving 63
SMP/E interleaving without sync_with_stdio() 64
packaging considerations 1011 passing across a system() call 73
socket redirecting 61
address 430 redirection to fully qualified data sets 70
address families 429 redirection under MVS 70
addressing within 429 restrictions in threaded applications 365
AF_INET domain 431 stderr 61
AF_UNIX domain 432 stdin 61
client perspective 434 stdout 61
compiling 444 support under CICS 717
data sets 447 using 61
datagram 429 standard error, redirecting 61
defined 425, 427 standard in, redirecting 61
domains 429 standard out, redirecting 61
families 428 static variables 571
include files 447 STDERR
Internet 425 redirecting with z/OS Language Environment
linking 444 MSGFILE option 68
local 425 stdin, C standard input stream 61
types stdout, C standard output stream 61
datagram 428 STEPLIB DD statement 704
guidelines for using 429 stepping through optimized code using dbx 615
stream 428 storage
typical TCP session 435 allocating with the system programming C
typical UDP session 436 environment 620
using over TCP/IP 425 freeing with EDCXFREE 656
z/OS TCP/IP 446 getting with EDCXGET 654
z/OS UNIX specific 428 optimizing 607
software signals 415 page-aligned, getting with EDCX4KGT 655
space= parameter under CICS 720
memory file I/O 202 Store Clock Fast
terminal I/O 190 built-in instruction 503
VSAM data sets 155 straightening 589
z/OS OS I/O 97 strcat() library function 578
Index 1049
text files (continued) unary operators, decimal data type (continued)
non-ASA RECFM undefined-format behavior 17 precisionof 384
non-ASA RECFM variable-format behavior 15 sizeof 383
RECFM byte stream behavior 18 unbuffered I/O
using fseek() and ftell() 115 setvbuf() function 100
text I/O 7 undefined format records 16
threads ungetc() library function
cancel 362 _EDC_COMPAT environment variable 488
cleanup 363 memory file I/O, effect on fflush() 208
condition variable 355 OS I/O, effect on fflush() 111
create 353 OS I/O, effect on fgetpos() and ftell() 113
functions 353 SEEK_CUR 114
low-level z/OS UNIX I/O 137 ungetwc() library function
management 353 effect on fflush(), wide character I/O 57
mutex 355 effect on fgetpos(), ftell() and fseek() 58
read-write lock 355 seek_cur 58
signals 360 universal reference time 847
thread-specific data 358 unlink() library function
using in z/OS UNIX applications 353 using with named pipes 134
using with MVS files 365 with z/OS UNIX file system files 131
throw 403 unnamed pipes
time zone creating 124
customizing 847 example 132
specifying 796 using 131
tolower() macro 577 UNROLL compiler option 594
toupper() macro 577 unroll pragma 581
traceback 404 unsuffixed numbers
transaction execution ILP32 to LP64 migrations 346
built-in instructions, hardware 541 updating VSAM records 160
translation tables 861 user exit
transport protocols 426 for initialization 670
TRAP run-time option for termination 669, 670, 671
CEEBXITA assembler user exit and 671 run-time options 675
how CEEAUE_ABND is affected by 675 under CICS 673, 675
IMS considerations 768 user words 665
troubleshooting user-server stub routines 652
stepping through optimized code using dbx 615
try 403
TSO (Time Sharing Option) V
default high-level qualifier 83, 200 V-format records 13
opening files 83, 200 va_arg macro
redirecting standard streams 72 and decimal data types 389
setting the user prefix 83, 201 value numbering 589
TUNE compiler option 591 variable arguments
type= parameter and decimal data types 389
memory file I/O 202 variable pragma 582
terminal I/O 190 variable-format records 13
VSAM data sets 155 variables
z/OS OS I/O 98 decimal 378
types, sockets 429 environment 467
TZ environment variable 847 exported 280
tzset() library function external 572
not thread-safe 367 global 571
local 571
locale 473
U register 572
UDP socket session 436 static 571
ulimit command variant characters 919
MEMLIMIT system parameter 332 default coding 919
unary operators, decimal data type detail 885
digitsof 383 displaying on workstation or 3270 919
Index 1051
xsacc library function 664
xusr() library function 665
xusr2() library function 665
Z
z/OS Basic Skills information center xxvii
z/OS Language Environment
message file I/O, description 30
message file output 215
z/OS TCP/IP
child process creation restrictions 447
configuration file access 447
header file restrictions 446
interprocess communication 446
socket API restrictions 446
z/OS UNIX
application programming environment 1005
I/O, low-level 137
z/OS UNIX file system
character special 124
closing files 131
creating files 123
deleting 131
directory 124
example 137, 140
FIFO 124
file types 123
flushing records 130
I/O functions, example program 137
I/O stream library 123
I/O, description 28
input and output 123
link 124
naming files 124
reading streams and files 128
record I/O rules 128
regular 123
setting positions within files 130
writing to streams and files 129
z/OS UNIX System Services
ulimit command 332
z/OS XL C/C++ integrated CICS translator 726
zero-byte records, _EDC_ZERO_RECLEN 16, 501
zFS file systems 587
Printed in USA
SC09-4765-13