Hi, Bernd.
Many thanks for the tips here; I appreciate it.
Since C is not my native language (PL/I and Rexx are, btw), let me see if I
understand what you are saying. The pure C code after being through the
preprocessor, is this:
typedef struct real_pcre {
pcre_uint32 magic_number;
pcre_uint32 size;
pcre_uint32 options;
pcre_uint16 flags;
pcre_uint16 max_lookbehind;
pcre_uint16 top_bracket;
pcre_uint16 top_backref;
pcre_uint16 first_char;
pcre_uint16 req_char;
pcre_uint16 name_table_offset;
pcre_uint16 name_entry_size;
pcre_uint16 name_count;
pcre_uint16 ref_count;
const pcre_uint8 *tables;
const pcre_uint8 *nullpad;
} real_pcre;
struct real_pcre;
typedef struct real_pcre pcre;
extern pcre *COMPILE8(const char *, int, const char **, int *,
const unsigned char *);
In PL/I it would look like this:
DCL COMPILE8 EXT ENTRY (
char(*) varyingz BYADDR,
FIXED BIN(31) BYVAUE,
char(*) varyingz BYADDR,
FIXED BIN(31) BYADDR,
char(*) varyingz BYADDR)
RETURNS(byvalue pcre):
and the call would be:
pcre = compile8( string1 /* a varyingz string */
some_int, /* fixed bin(31) */
addr(string2), /* need addr because of indirection */
int2, /* fixed bin(31) by addr here */
some_string /* another varyingz string */ );
How close did I get? Did I get the double "* *" correct?
Another question: would this be possible using the older PL/I for MVS and VM
that is still in use at some sites?
Thanks again.
DJ
On 02/24/2014 03:16 AM, Bernd Oppolzer wrote:
> Further "book reading" (programming guide) shows:
>
> dcl fopen ext('fopen')
> entry( char(*) varyingz byaddr,
> char(*) varyingz byaddr )
> returns( byvalue type file_handle )
> options ( nodescriptor );
>
> there are indeed PL/1 language features to deal
> with C function results, including pointers;
>
> see the example above; the returns clause
> specifies that the fopen function (well known to C coders)
> returns a pointer of type file_handle.
>
> So you may take this as an example and define your function
> COMPILE8 in the same way.
>
> Kind regards
>
> Bernd
>
>
>
> Am 24.02.2014 10:00, schrieb Bernd Oppolzer:
>> I did some "book reading" (language reference for the EP PL/1 compiler V4.4).
>>
>> If you define your external entry with option ASSEMBLER or COBOL
>> (C doesn't exist), you will get the effect that
>>
>> "the PLIRETV() value is taken as the RETURN value of the procedure"
>>
>> in both cases.
>>
>> PLIRETV () is BIN FIXED (31), not BIN FIXED (15) in the meantime,
>>
>> so you could in fact define the C function as ASSEMBLER function (in PL/1),
>> giving a BIN FIXED (31) result, and then convert the BIN FIXED (31) result
>> to a pointer (which it really is).
>>
>> This is not very nice, but it should work, IMHO.
>>
>> No need for a wrapper function, in this case.
>>
>> Kind regards
>>
>> Bernd
>>
>>
>>
>> Am 24.02.2014 09:30, schrieb Bernd Oppolzer:
>>> I would like to add:
>>>
>>> the RETURN facility in PL/1 is somehow different from C and maybe
>>> other languages.
>>>
>>> In C, the return values are limited to values that fit into a register, AFAIK.
>>> So the pointer, that is returned in your case, is technically returned (at the mainframe)
>>> in the same way as the return code, that is, Register 15.
>>>
>>> In PL/1, if you use RETURN, it is implemented as an additional parameter,
>>> following the other parameters. If you RETURN a value in PL/1, you can
>>> still use PLIRETC / PLIRETV, because these are different techniques.
>>>
>>> X = FUNC (A,B C);
>>>
>>> in the PL/1 mainframe implementation is the same as
>>>
>>> CALL FUNC (A,B,C,X)
>>>
>>> leaving room for using PLIRETC / PLIRETV in both cases.
>>>
>>> This is not compatible with C function results.
>>>
>>> Your COBOL coding, which obviously works, shows that things must be
>>> different in COBOL.
>>>
>>> (maybe there are options in PL/1 to change this behaviour, but I
>>> didn't want to use them so far)
>>>
>>> Kind regards
>>>
>>> Bernd
>>>
>>>
>>>
>>>
>>> Am 24.02.2014 09:17, schrieb Bernd Oppolzer:
>>>> First:
>>>>
>>>> You don't have to "change" your open source library, you only code
>>>> a small wrapper function on top of it to make it easier to call it
>>>> from PL/1.
>>>>
>>>> Then:
>>>>
>>>> There are two issues with this function. The first one are the call by value
>>>> parms, which can be easily resolved using the BYVALUE keyword of
>>>> newer PL/1 compilers. The second one is the handling of the C function
>>>> result.
>>>>
>>>> Historically, the function results of C correspond with the PLIRETV ()
>>>> return codes of PL/1, and they are limited to BIN FIXED (15) values.
>>>> So we have an issue here. I don't know if we have newer compiler
>>>> features to cope with that. I simply don't care, because at our site
>>>> we always build wrapper functions to build a PL/1 friendly interface
>>>> to such functions. This is no big deal and can be done within hours.
>>>> We did this since the early 1990s.
>>>>
>>>> This way, I don't even have inform the PL/1 compiler that the external
>>>> function is written in C. The C wrapper function presents a PL/1 compatible
>>>> interface to PL/1, and everything is fine.
>>>>
>>>> We did this in the past even to get rid of the by value parms. All our PL/1 friendly
>>>> interfaces only had (from a C perspective) int function results (that is, return codes,
>>>> suitable for PLIRETV ()), and pointers as parameters, suitable for
>>>> BYADDR parms.
>>>>
>>>> If we could not convince our external partners providing C functions to
>>>> provide such interfaces to their software, we built wrapper
>>>> functions ...
>>>>
>>>> For example: I have a powerful XML parser (and generator) written in ANSI C,
>>>> and to make it callable from PL/1, I have a wrapper function around it that allows
>>>> us to call its different functions (xmlp_open, xml_parser, xmlp_close, ...) using
>>>> one function callable from PL/1 - with different function codes.
>>>>
>>>> If you want to know more about the details, contact me offline.
>>>>
>>>> Kind regards
>>>>
>>>> Bernd
>>>>
>>>>
>>>>
>>>>
>>>> Am 24.02.2014 03:36, schrieb Z.A.:
>>>>> Bernd Oppolzer wrote:
>>>>>
>>>>>
>>>>> >of course, if you want for example all parameters to be
>>>>> >passed by value - just to have the same look and feel for
>>>>> >all of them - this is perfectly simple.
>>>>>
>>>>> >To have all of them passed by reference, you can do this, too,
>>>>> >if the wrapper function takes care of that.
>>>>>
>>>>> The PCRE is an open source library (compile8 is only one of the API
>>>>> calls) and we are bound by its definitions and call conventions.
>>>>> Calls from COBOL do not have any issue and the call below works:
>>>>>
>>>>> call 'COMPILE8' using by value pcrews-pattern-ptr
>>>>> BY VALUE 0
>>>>> BY reference pcrews-error-ptr
>>>>> BY reference pcrews-erroffset
>>>>> BY VALUE pcrews-null-ptr
>>>>> RETURNING RE
>>>>> end-call
>>>>>
>>>>> where all -ptr are defined as USAGE POINTER and RE is defined as:
>>>>> 01 RE USAGE POINTER VALUE NULL.
>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>
>
--
D.J.
|