- THE PL/I NEWSLETTER -

- THE PL/I NEWSLETTER -

- THE PL/I NEWSLETTER -

ISSUE No. 11 – NOVEMBER 2009

Copyright © 2009 by Robin Vowels. All rights reserved for the authors.
IN THIS ISSUE:
  1. Editorial
  2. New PL/I book
  3. A Parsing editor for ECLIPSE, by Bill Fenlason
  4. PL/I Division De-mystified, by Peter Flass
  5. A Different View of BOOL, by Peter Flass
  6. PL/I - the secure alternative
  7. Useful Macros, by Rolf Drees
  8. PL/I and thoughts of encapsulation, by John Wood
  9. Some more functions, by Robin Vowels
  10. Usefulle Webbe Lynx ...
  11. IBM PL/I Offerings in the U.S.

  1. Editorial

    We welcome your contributions to this newsletter. It will continue only through your efforts. Thank you in advance.
    Please send any comments and contributions for the next newsletter to r|o|b|i|n|5|1 at dodo dot com dot au

    The tenth issue may be downloaded from: The PL/I Newsletter, No. 10, September 2008.
    The ninth issue may be downloaded from: The PL/I Newsletter, No. 9, April 2006.
    The eighth issue may be downloaded from: The PL/I Newsletter, No. 8, January 2005.
    The seventh issue may be downloaded from: The PL/I Newsletter, No. 7, December 2004.
    The sixth issue may be downloaded from: The PL/I Newsletter, No. 6, December 2003.
    The fifth issue may be downloaded from: The PL/I Newsletter, No. 5, August 2002.
    The fourth issue may be downloaded from: The PL/I Newsletter, No. 4, November 2001.
    The third issue may be downloaded from: The PL/I Newsletter, No. 3, June 2001.
    The second issue may be downloaded from: The PL/I Newsletter, No. 2, September 2000.
    The first issue may be downloaded from: The PL/I Newsletter, No. 1, July 2000.


  2. New PL/I Book

    Eberhard Sturm's new book about PL/I was published this year. This is his first English translation of his best-selling German book that is in its 7th edition. However, it's not a mere translation; it is also an updated version of that book.
    Entitled The New PL/I ... for PC, Workstation and Mainframe, it covers IBM's current compilers, and the title says it all.

    Particulars of the English-language edition are:
    E. Sturm, The New PL/I ... for PC, Workstation and Mainframe, Vieweg-Teubner, Wiesbaden, Germany, 2009. ISBN: 978-3-8348-0726-7.

    Details of the German-language edition are:
    E. Sturm, Das neue PL/I (fur PC, Workstations und Mainframe), 7th Ed., Vieweg-Verlag (2008) ISBN: 3-528-44792-3

  3. A Parsing Editor for ECLIPSE

    by Bill Fenlason

    A couple of years ago I put together a syntax error checking PL/I Editor for the Eclipse framework. The package is named Pliedit, for PL/I Editor. There was some interest, but not enough for me to pursue it at the time. I recently decided to give it one more try rather than abandoning it totally. I made some revisions and fixed some problems that the original version had, including some performance issues with huge PL/I source files.
    I've set up a web site for the PL/I Editor at pliedit.com. The homepage contains basic information, and there are Eclipse Update sites for Eclipse versions 3.2 through 3.5. You can download Pliedit by using the normal Eclipse software installation process (anonymously - no user information is tracked). There is also a bulletin board with discussion forums.
    Because of the complexity of PL/I, both a scanner generator and parser generator were used. The colorization capabilities are very detailed, including the ability to have distinct color and font for individual keywords based on semantics rather than syntax. Currently, error checking is only at the statement level. (I'll have a go at full AST processing next time around.) There is little preprocessor support for now.
    Pliedit is not a finished product but based on the 80/20 (or 90/10) rule, I think Pliedit in its current state can be useful for PL/I programmers who also use Eclipse. If you are interested, visit the pliedit.com web site. The discussion forums are at pliedit.com/bb .

    Bill Fenlason From: "billfen@hvc.rr.com" <billfen@HVC.RR.COM> Sent: Saturday, June 13, 2009 12:25 AM
  4. PL/I Division De-mystified

    by Peter Flass

    PL/I offers a richer variety of basic data types than most languages. Consider just computational data. C has the floating-point types float, double, long double, integer types short [int] and long [int], and possibly char can be considered a computational data type.

    PL/I computational data has base, scale, mode, and precision. Scale can be fixed or float, roughly corresponding to C. Mode can be real or complex; C has no complex data. Base can be binary or decimal; decimal data is unknown in C. Precision is the attribute that provides the most power, but also some degree of confusion. In place of C's short and long, for example, PL/I allows the programmer to specify the precision, the number of bits(binary), or digits(decimal) that are required to store the data, although the hardware can use more if appropriate. For example, a machine with a word size of 32 bits can store a fixed binary value up to FIXED BIN(31) [one bit is reserved for the sign and is not counted].

    An often-unnoticed appendage to precision called the scale factor sometimes causes confusion. For fixed data precision is specified as a pair of numbers ( number-of-digits [, scale-factor ] ), where the scale-factor is assumed to be zero if not specified. Float data has no scale-factor, since by definition floating-point data includes its own scale. So far, so good. A number representing the number of items in inventory might be declared FIXED DECIMAL(8), or alternatively FIXED DECIMAL(8,0), which provides storage to handle quantities up to 10,000,000. The count must obviously be a whole number of items, and so the ",0". A number representing a bank balance might be declared FIXED DECIMAL(12,2), which would reserve storage to handle balances up to $10,000,000.00, dollars and cents. Non-US readers feel free to read this using your own currency conventions, PL/I supports them all.

    The scale factor can cause some confusion when performing division as part of an arithmetic expression. C INT data is, as the name indicates, always integer. The compiler assures that expressions of type INT will always give integer results: in C 5/3=1. In PL/I, the scale factor is always taken into account, even when it is zero. For addition, subtraction, and multiplication, if all the operands have a scale factor of zero, the result will too. For division, however, PL/I always tries to preserve the maximum possible significance of a fractional quotient. Many books on PL/I fail to point out this fact. In practical terms, the compiler converts the dividend (the number being divided) to a temporary value which has just enough digits to hold its declared value, followed by zeroes to pad out the maximum possible length of that data type. The definition from the standard is:
    m = N
    n = N-p+q-s
    Here "m" is the precision of the temporary result, "N" is the maximum number of bits or digits allowed for the data type, "p" is the number of bits or digits in the original value of the dividend, "q", and "s" are the scale factors of the dividend and the divisor.

    This conversion is defined by the language, not the implementation. The only possible differences among machines might be in the maximum sizes of data which can be handled (N). Here are a couple of examples for IBM S/390 architecture:

    FIXED BINARY(15,0) divided by FIXED BINARY(15,0): The temporary result is FIXED BINARY(31,15). That's right, the quotient will have fifteen bits of fractional result.

    FIXED DECIMAL(5,0) divided by FIXED DECIMAL(5,2): The temporary result is FIXED DECIMAL(15,8).

    Most PL/I "Language Reference" or similar manuals will have a table providing formulas for results of expressions involving different types of operands like "Table 16: Results of Arithmetic Operations for Coded Arithmetic Operands" in IBM's SC26-3114.

    Having gotten to this point, a natural question is "so what?" In many cases this may not matter. For example 5/3 evaluates to 1.666.... Assigning this result to a FIXED variable with a scale factor of zero will truncate to an integer (1), exactly as in C. Assigning the result to a FLOAT variable, will result in the expected 1.666... to the limits of precision. Try this in C; the result will be 1.00000..., because the expression 5/3 involves integers and evaluates to an INT before assignment. To achieve the same result, C has to resort to casting, an art so arcane that I had to try three times to get it correct for my test. A C cast in this case is a method of forcing the conversion of data during expression evaluation. C has to use a cast to force the expression 5/3 to be evaluated as FLOAT. Guess which one of these is correct C:
    f = (float)(5/3); f = (float)5/3; or f = (float)(5)/3;

    The other situation in which you have to be aware of what PL/I is doing is when the division is part of a larger expression. Compare the statement i = (5/3) * 3 in PL/I and C. C divides five by three and gets one (integer division), then multiplies one by three and gets the result "three". PL/I divides five by three and gets 1.6666... (scaled integer division), it then multiplies 3.00000 (three scaled to the same number of fractional digits as the result of the division) and gets 4.999.... Assigning this result to i truncates to an integer "four". This may or may not be the desired result, but in any case you'd best be aware of what's happening. Another unobvious point is that PL/I will use decimal operations, since the constants "5" and "3" are decimal constants, the exact equivalent of the C expression would be (101B/11B) * 11B, or (BINARY(5)/BINARY(3))*BINARY(3).

    PL/I provides a way for the programmer to exercise further control over division by way of the DIVIDE built-in function. The syntax is DIVIDE( dividend, divisor, precision [, scale] ). Divisor and dividend are self-explanatory. Here "precision" is the required precision of the result of the division, and "scale" is the required scale factor. As usual with PL/I built-in functions, the base, scale, and mode of the result are determined by the attributes of the dividend and the divisor. If the result is FLOAT the scale must be omitted. If the result is FIXED and the scale is omitted, zero is assumed.

    The result of DIVIDE(5,3,15) [or DIVIDE(5,3,15,0)] will have a no fractional digits; an integer result of "one", or the same as C's (5/3). To obtain the same result as the C expression (5/3) * 3, code: DIVIDE(5,3,15) * 3

  5. A different view of BOOL

    by Peter Flass

    The BOOL builtin function is typically described in language like the following from an IBM PL/I language reference:

    Bool returns a bit string that is the result of a Boolean operation, specified by z, on x and y. ... Z is converted to a bit string of length 4, if necessary. When a bit from x is matched with a bit from y, the corresponding bit of the result is specified by a selected bit of z, as follows:
    xyResult

    00bit 1 of z
    01bit 2 of z
    10bit 3 of z
    11bit 4 of z

    This language is an adaptation of the description of BOOL in the PL/I standard. It manages to provide an exact description of how the function operates, without providing a clue to what it is doing, or why.

    In the course of implementing the BOOL builtin, I did some research that caused me to look at BOOL in a different and perhaps more useful way.

    There are sixteen boolean functions of two variables, conventionally listed as follows:

    (C-language notation used for operators).
    Ref:Wolfram Mathworld
    operationsymbolname
    F00FALSE
    F1X&YAND
    F2X&~YX AND NOT Y
    F3XX
    F4~X&YNOT X AND Y
    F5YY
    F6X^YXOR
    F7X|YOR
    F8~(X|Y)NOR
    F9(X&Y)|(~X&~Y)XNOR
    F10~YNOT Y
    F11X|~YX OR NOT Y
    F12~XNOT X
    F13~X|YNOT X OR Y
    F14~(X&Y)NAND
    F151TRUE

    Interestingly, if the 'z' bit string is thought of as an integer between 0 and 15, the result of BOOL is the result of the corresponding function listed above.

    Here are a few examples:

    XYZ Result
    '0'B'1'B'0001'B'0'B(AND)
    '010'B'111'B'0111'B'111'B(OR)
    '0011'B'0110'B'0110'B'0101'B(XOR)

    The preprocessor can be used to make the operation clearer:

    %DECLARE $FALSE   CHARACTER;
    %DECLARE $AND     CHARACTER;
    %DECLARE $AND_NOT CHARACTER;
    %DECLARE $X       CHARACTER;
    %DECLARE $NOT_AND CHARACTER;
    %DECLARE $Y       CHARACTER;
    %DECLARE $XOR     CHARACTER;
    %DECLARE $OR      CHARACTER;
    %DECLARE $NOR     CHARACTER;
    %DECLARE $XNOR    CHARACTER;
    %DECLARE $NOT_Y   CHARACTER;
    %DECLARE $OR_NOT  CHARACTER;
    %DECLARE $NOT_X   CHARACTER;
    %DECLARE $NOT_OR  CHARACTER;
    %DECLARE $NAND    CHARACTER;
    %DECLARE $TRUE    CHARACTER;
    %$FALSE   = '''0000''B';
    %$AND     = '''0001''B';
    %$AND_NOT = '''0010''B';
    %$X       = '''0011''B';
    %$NOT_AND = '''0100''B';
    %$Y       = '''0101''B';
    %$XOR     = '''0110''B';
    %$OR      = '''0111''B';
    %$NOR     = '''1000''B';
    %$XNOR    = '''1001''B';
    %$NOT_Y   = '''1010''B';
    %$NOT_X   = '''1011''B';
    %$NOT_OR  = '''1100''B';
    %$NAND    = '''1101''B';
    %$TRUE    = '''1110''B';
    %$FALSE   = '''1111''B';
    
    r = BOOL(x,y,$AND);
    r = BOOL(x,y,$OR);
    ... etc ...
    

  6. PL/I - the secure alternative

    (contributed by and commentary by Peter Flass)

    This material is excerpted from an IBM research report:

    "Thirty Years Later: Lessons from the Multics Security Evaluation" by Paul A. Karger and Roger R. Schell. At the time of writing, the complete document is available from The IBM Thomas J. Watson Research Center. The report consists of two papers to be presented at the 18th Annual Computer Security Applications Conference (ACSAC), December 9-13, 2002. Following the conference, the papers should be available from ACSAC.

    [Here's the direct link to the paper. -- Ed]

    One of the most common types of security penetrations today is buffer overflow. However, when you look at the published history of Multics security problems, you find essentially no buffer overflows. Multics generally did not suffer from buffer overflows, both because of the choice of implementation language and because of the use of several hardware features. ...

    Although PL/I had some influence on the development of C, the differences in the handling of varying length data structures between the two languages can be seen as a major cause of buffer overflows. In C, the length of all character strings is varying and can only be determined by searching for a null byte. By contrast, PL/I character strings may be either fixed length or varying length, but a maximum length must always be specified, either at compile time or in an argument descriptor or in another variable using the REFER option. When PL/I strings are used or copied, the maximum length specifications are honored by the compiled code, resulting in automatic string truncation or padding, even when full string length checking is not enabled. The net result is that a PL/I programmer would have to work very hard to program a buffer overflow error, while a C programmer has to work very hard to avoid programming a buffer overflow error. [italics mine]
    ...

    PL/I also provides richer features for arrays and structures. While these differences are not as immediately visible as the character string differences, an algorithm coded in PL/I will have less need for pointers and pointer arithmetic than the same algorithm coded in C. [again my italics]

    It has long been argued that one of the chief causes of software flaws is the use of the C language. Hopefully the current movement toward more secure software will make developers pay more attention to the influence of language choice on software reliability.

  7. Useful Macros

    by Rolf Drees

    The PL/I macro SAY is helpful for programmers.

    The macro SAY offers some service around the PL/I command 'PUT SKIP LIST'. At first it is just easier to write SAY in the source than PUT SKIP LIST, especially in case of IF-cascades or nested DOs. This can be done by a simple pre-processor variable like this:

    %DCL SAY CHAR; %SAY = 'PUT SKIP LIST'; With this pre-processor-DCL the typical PUT SKIP LISTs in the source looks like this: SAY ('CURRENT TIME: ' !! TIME ()); /* CURRENT TIME: 123456789 */ After using this some time I found it would be useful to add some services. At first it would be nice to underline the text with a given character (usually '-' , '=', or '*'). For that it was necessary to change the pre-processor-variable to a statement and add an underline-parameter.
    Another change was to draw a box around the text with a given character. SAY now could be used like this: SAY ('CURRENT TIME: ' !! TIME ()) /* CURRENT TIME: 123456789 */ UNDERLINE ('='); /* ======================= */ SAY ('CURRENT TIME: ' !! TIME ()) /* =========================== */ BOX ('='); /* = CURRENT TIME: 123456789 = */ /* =========================== */ The next one was justify the text or box in the middle or at the right of the line. The standard-linesize of SYSPRINT is 120 but it can be changed at OPEN like this: OPEN FILE (SYSPRINT) LINESIZE (80); So SAY gets a JUSTIFY- and also a WIDTH-parameter. If WIDTH is not specified it is set to the default of 120.
    This one will put the text in the middle of an 80-character-line: SAY ('CURRENT TIME: ' !! TIME ()) JUSTIFY (CENTER) WIDTH (80); Adjustment to the right is also possible: SAY ('CURRENT TIME: ' !! TIME ()) JUSTIFY (RIGHT); When testing this I found that PUT SKIP LIST always adds a blank to the text (as a delimiter), so I used PUT SKIP EDIT instead.
    It is possible to use UNDERLINE/BOX in combination with JUSTIFY. Because there is no file specified, the output always goes to SYSPRINT. But it can be used for other files as well, therefore just declare SYSPRINT as a file-variable:
    Instead of DCL SYSPRINT FILE PRINT; code DCL SYSPRINT FILE VARIABLE INIT (REPORT); DCL REPORT FILE PRINT; With this declaration SAY puts the text to the file REPORT.

    Now the macro looks like a PL/I-command with the following syntax:

    SAY (some text) UNDERLINE/BOX ( 'char') JUSTIFY (LEFT/MIDDLE/RIGHT) WIDTH (number); For any comments, questions or ideas you can contact me at rolf.drees@gad.de.

    Here now is the macro SAY:

    /*===================================================================*/ /* */ /* Macro SAY by Rolf Drees rolf.drees@gad.de */ /* */ /* SAY writes a given text to SYSPRINT (via PUT SKIP EDIT). */ /* It is possible to underline the text or to draw a box around the */ /* text. The text can be justified to left (default), center or */ /* right of the line. The line-width is 120 but it is possible to */ /* specify another line-width. */ /* */ /* Syntax: */ /* */ /* SAY ('text') --+--------------------------------+--->> */ /* I I */ /* +-- UNDERLINE/BOX ('one char') --+ */ /* */ /* */ /* >>--+--------------------------------+--+-------------------+--* */ /* I I I I */ /* +-- JUSTIFY (LEFT/CENTER/RIGHT)--+ +-- WIDTH ( num ) --+ */ /* */ /* */ /* Example: Result: */ /* 1 5 10 15 20 25 */ /* +----+----+----+----+----+ */ /* */ /* SAY (TIME ()); 123456789 */ /* */ /* SAY (TIME ()) UNDERLINE ('-'); 123456789 */ /* --------- */ /* */ /* SAY (TIME ()) BOX ('='); ============= */ /* = 123456789 = */ /* ============= */ /* */ /* SAY (TIME ()) UNDERLINE ('-') 123456789 */ /* JUSTIFY (CENTER) --------- */ /* WIDTH (25); */ /* */ /* SAY (TIME ()) BOX ('=') ============= */ /* JUSTIFY (RIGHT) = 123456789 = */ /* WIDTH (25); ============= */ /* */ /*===================================================================*/ %dcl say entry; %say: proc ($text, underline, box, justify, width) statement; dcl ($text, underline, box, justify, width) char; if ^parmset (width) then width = '120'; if parmset (box) then width !!= ' - 4'; select (justify); /* generate the col/format for put skip edit */ when ('', 'LEFT') justify = '(col (1), a)'; when ('CENTER') justify = '(col ((' !! width !! ' - length (' !! $text !! ')) / 2 + 1), a)'; when ('RIGHT') justify = '(col (' !! width !! ' - length (' !! $text !! ') + 1), a)'; end; select; when (parmset (box)) do; ans ('do;') skip; ans (' put skip edit (copy (' !! box !! ', length (' !! $text !! ') + 4)) ' !! justify !! ';') skip; ans (' put skip edit ('!! box !! ' !! '' '' !! ' !! $text !! '!! '' '' !! ' !! box !! ') ' !! justify !! ';') skip; ans (' put skip edit (copy (' !! box !! ', length (' !! $text !! ') + 4)) ' !! justify !! ';') skip; ans ('end;'); end; when (parmset (underline)) do; ans ('do;') skip; ans (' put skip edit (' !! $text !! ') ' !! justify !! ';') skip; ans (' put skip edit (copy (' !! underline !! ', length (' !! $text !! '))) ' !! justify !! ';') skip; ans ('end;'); end; other ans ('put skip edit ('!! $text !! ') ' !! justify !! ';') skip; end; %end say;

  8. PL/I and thoughts of encapsulation

    by John Wood

    I have been reading about the OO ideas of code/data encapsulation to reduce some tightly coupled monolithic code that I have to something I can understand in detail, and I wondered how sympathetic PL/I would be to the use of those techniques. RTFM I hear your murmur! None such ever existed! I am also disposed to the ideas of Test-Driven development and wondered if the use of Junit and Java might be better than writing my own PL/I test handler. Two ways to do that: ask someone who has done it, and do it oneself. Option two is open to me.

    My chosen sample code on which to experiment was the creation of a single control block (a resource anchor to which many linked lists are chained, named RCOMMON) and a linked list of data control blocks (list has an unknown number of elements, list is not ordered, named DCOMMON). The current code base has create DCOMMON code anywhere it fancies, data elements in the DCOMMON block are read or updated directly without necessarily any validation.

    The first steps on the PL/I side are to bring the data and logic within a single procedure, and to permit data element read/write only through a defined interface. One procedure for the RCOMMON and one procedure for the DCOMMON. The encapsulating procedure would be the only resource allowed to update data directly, access to data items is via published "getters" and "setters". I can see how this enforces validation, but I do have some concerns about the cost. I want to raise that at the end, hoping that someone with more knowledge that I will be able to answer.

    The working code allows for initial creation of block, and get/set for data elements.

    Dcl _initRcommon ENTRY RETURNS(pointer byaddr); Dcl _getRcommonC ENTRY (character(32)) RETURNS(character byaddr); Dcl _setRcommonC ENTRY (character(32),character) RETURNS(fixed bin(31) byaddr); Dcl _getRcommonP ENTRY (character(32)) RETURNS(pointer byaddr); Dcl _setRcommonP ENTRY (character(32),pointer) RETURNS(fixed bin(31) byaddr); The xxxRcommonC allow get/set character fields, xxxRcommonP allow get/set pointer fields, and so on for other data types. I did try to use "generic procedure calls" but could not see how to separate getRcommonC from getRcommonP since the input parameters are the same type. The getters return their field value of the prescribed type, and the setters return a return code.

    I did something similar with DCOMMON

    Dcl _initDcommon ENTRY (character(16)) RETURNS(pointer byaddr); Dcl _fndDcommon ENTRY (pointer) RETURNS(pointer byaddr); Dcl _getDcommonC ENTRY (pointer,char(32)) RETURNS(character(64) byaddr); Dcl _setDcommonC ENTRY (pointer,char(32),char(64)) RETURNS(fixed bin(31) byaddr); Dcl _getDcommonP ENTRY (pointer,char(32)) RETURNS(pointer byaddr); Dcl _setDcommonP ENTRY (pointer,char(32),pointer) RETURNS(fixed bin(31) byaddr); The creation of a DCOMMON block requires the storage to be allocated and chained to the RCOMMON using its Rcommmon.child_first pointer. The "init" function only requires a blockname and returns a handle, which is used in all subsequent calls. A second DCOMMON block requires to be added to the existing chain. The difference between Rcommon and Dcommon is that Rcommon has no need of Dcommon knowledge, but Dcommon has need to update the Rcommon.child_first pointer which is now only accessible though its published getter/setter.

    Look at the code for RCOMMON.
    Look at the code for DCOMMON.

    I created a short test main program to verify the code, then I created some "test orchestration" code so that I could just call "run test 1" "run test2" with predictable results that I might test.
    Look at the PL/I test program which calls the functions which have been bound in by linkedit.
    Look at the PL/I test program which calls the DLL.
    Look at the DLL test orchestration code.
    The PL/I brings the DLL into memory by

    fetch T01Common title('DLLCOMMON/T01COMMON');

    My original code was title('dllCommon/T01common'); I spent a whole evening puzzling why that did not work. I still do not really understand why, but Eberhard Sturm's The New PL/I book told me what to do. It had arrived only recently and I was not going to open it until I had finished rereading "Refactoring" by Martin Fowler. Stupid Boy.

    Moving on now to making the PL/I code available to Junit and Java, on the basis that the ANT/Junit testing suites contain a lot of thought and good work by many developers. The test orchestration code that interfaces to Java needs language conversion routines. I have used two tiers of Java to achieve this, the top level runs the tests, the lower level defines the Java native Interface (JNI) that calls the PL/I DLL directly. In this case there may be no need, but I have trialed cases where the PLI returns binary data or arrays, the lower level Java deals with this, maybe making some result to pass back to the higher level to test with an "assert" condition. In this way you can write a range of tests, and the entire suite of code can be compiled and run and any failures highlighted, the test is run by running a single BAT from a Windows DOS prompt. The tests I have here compiled and ran to completion in less that one second (my environment is Win2000 with VA PLI_2.1.14 on a dual-core AMD machine).
    Look at the Java "wrapper" which calls the DLL.
    View the Java-DLL test orchestration code.

    I need to point out some difficulties with the PROC statement. The external clause needs to define an ID which Java can recognise, in this case

    <Java><DLL name><entry name>.

    If your Java code is within a package then the ID will need to reflect that, this is not documented in the IBM literature that I could see, and you have no idea how long it took me to understand that! Now the ID becomes

    <Java><Java package name><DLL name><entry name> jniCommon01:Proc( JNIEnv , thisObject, first PLI parameter... ) external("_Java_jniCommon_jniCommon01") returns( pointer byvalue ) options( linkage(stdcall) byvalue ); The test suite tests the successful load of the DLL try { System.loadLibrary("testXcommon"); } before running as many automated tests as is coded.
    Look at the Java "wrapper" which calls the DLL.
    View the Java test driver.
    Look at the BAT file I use to drive it.

    In the customisation of the BAT environment I use ...

    set PACKAGE=<Java package name> set basesource=%MHOME%\\source\\%package% where folder structure is <project><source><javaPackage> or just set basesource=%MHOME% ie : project folder where all code, classes and .exe are all in the single project folder

    Summary

    I have attempted to answer my own question about how painful or otherwise is it to create and run an automated test suite of PLI code using Junit. The answer is \'93not too bad at all\'94 once the mechanics of it are laid out. I have not used ANT as yet, but I believe that it allows some parts of a build/test to continue even if one leg fails.

    The question of efficiency remains, run time efficiency that is.

    I always thought that setting a variable with something like

    r_ptr -> Rcommon.reg_first_dcommon = addr(thisDcommon); would be no more than a dozen assembler instructions.

    Updating the same field using a setter interface, as in

    if setRcommon("reg_first_dcommon", addr(thisDcommon))>0 then //...error condition...//; would be nearer a thousand assembler instructions, what with all the savearea, parameter and register stuff. It might be worth it even so, just to tidy up the code as long as the modern CPU chips offset the performance hit. Does anybody have any idea of the resources used by these two techniques? Martin Fowler states explicitly that "modern" languages have more or less done away with the overhead in calling a method. Really??? Hummmmm, how did they do that, then?

    Next
    A colleague who had coerced me into looking seriously at encapsulation and Junit thought that I should have the main code calling a "linked list orchestration interface" which coordinated the manipulation of Rcommon and Dcommon and all the other linked lists I have. Then the Dcommon routine would have no need to issue a _setRcommon call, it would be handled by the higher interface.

    You can see:
    This description in RTF format
    This description in PDF format

  9. Some More Functions

    by Robin Vowels

    Continuing our series about built-in functions, we look at some string functions specifically for WIDECHAR strings.

    • ULENGTH (S). returns the number of UTF characters in a string.
      If S is CHAR, then S must contain valid UTF characters.

    • ULENGTH8 (S). Returns the length of the character string needed if S were converted to a UTF-8 string.
      If S is CHAR, S is not checked for valid characters.
      If S is WIDECHAR and does not contain valid UTF characters, the ERROR condition is raised.

    • ULENGTH16 (S). Returns the length of a WIDECHAR string S if the UTF characters were converted to UTF-16.
      If S is CHAR, S must cotain valid UTF-8 characters. If it does not, the ERROR condition is raised.
      If S is WIDECHAR, S is not checked for valid characters.

    • UPOS (S, N). Returns the position of the N-th UTF character in string S.
      If S is CHAR, S must contain valid UTF characters.
      If S is WIDECHAR, S must contain valid UTF-16 characters.
      Otherwise, the ERROR condition is raised.

    • USUBSTR (S, i, j). Takes the substring of a UTF string, beginning at the i-th character and continuing for j characters.
      If S is CHAR, S must contain valid UTF characters.
      If S is WIDECHAR, S must contain valid UTF-16 characters.
      Otherwise the ERROR condition is raised.
      If i < 1 or j < 0 or i+j-1 is greater than ULENGTH(S), the ERROR condition is raised.

    • USURROGATE (S). Returns the position of the first UTF surrogate pair in string S.

    • UVALID (S). Returns 0 if S contains only valid UTF characters.
      Otherwise returns the position of the first non-UTF character in string S.

    • UWIDTH (S, N). Returns the width of the N-th UTF character in string S.
      If S is CHAR, then S must contain valid UTF characters.
      If S is WIDECHAR, then S must contain valid UTF-16 characters.

    • PLITRAN11 (D, S, N, Table_address).
      This subroutine translates N characters of one-byte data at S to the destination D.
      Table_address is 256 bytes.

    • PLITRAN12 (D, S, N, Table_address).
      This subroutine translates N characters of one-byte data at S to two-byte data at the destination D.
      Table_address is 512 bytes.

    • PLITRAN21 (D, S, N, Table_address).
      This subroutine translates N characters of two-byte data at S to one-byte data at the destination D.
      Table_address is 64Kb bytes.

    • PLITRAN22 (D, S, N, Table_address).
      This subroutine translates N characters of two-byte data at S to two-byte data at the destination D.
      Table_address is 128Kb bytes.

    • UNALLOCATED (P). Returns '1'B if pointer P is not allocated, '0'b otherwise.
      Note that P must be a double-word address. When current addresses are searched, they will be treated as if similarly aligned.

  10. Usefulle Webbe Lynx ...

    • Peter Flass is building a resource at Peter Flass's PL/I home page.

    • Ironspring PL/I runs on OS/2. Free download at http://www.iron-spring.com
      21 May, 2009: PL/I beta version 0.8a released.
      This version adds list-directed input, the DISPLAY statement, and the condition-handling builtins ONCHAR, ONCODE, ONCOUNT, ONFILE, ONKEY, ONLOC and ONSOURCE.
      A cross-reference listing can now be produced, and subscripted label constants are supported.
      ELF object files can now optionally be generated in addition to the standard OMF.
      A full list of enhancements and bugs fixed is available in the "readme" file in the zip.

    • Micro Focus' Open PL/I has a full range of PL/I products, which are available on HP-UX, Windows XP and Vista, Sun Sparc Solaris 2.x, Intel SuSE Linux, and Intel Redhat Linux.
      See also http://microfocus.com:80/Liant/index.asp

    • Kednos' web site has PL/I manuals and compilers, etc.
      For information, contact tom@kednos.com
    • PL/I courses:
      http://www.training-classes.com/course_hierarchy/Computer/Programming_Languages/PL_1/
      http://www.datatrain.net/library.aspx?id=2639

  11. Current IBM PL/I offerings in the U.S.

    IBM's Rational Development for System z V7.6 is available as from October 2009.
    Information about Rational Development for System z V7.6, contains various software including PL/I for Windows.

    Included are PL/I maintenance tools, tools to develop and test web services, CICS, and a configurable editor.
    Enhancements to the editor include syntax checking while typing.

    Read the documentation for Rational Developer for System z.
    Look here and download the PL/I Language Reference, and related manuals.
    This LRM is for Rational Developer for System z PL/I for Windows, version 7.6, PL/I for z/OS, and for PL/I for AIX.
    Both English and Japanese versions of the manuals are available.


Any comments and contributions for the next newsletter to r|o|b|i|n|5|1 at dodo dot com dot au (Team PL/I) please.

PL/I PL/I PL/I