Oppolzer - Informatik / Blog


Blog-Hauptseite      Neuester Artikel      Älterer Artikel      Neuerer Artikel      Älterer gleiche Kategorie      Neuerer gleiche Kategorie

PL1-L - Diskussion über PL/1-Interface für PCRE (Perl compatible Reg. Ex)

Subject:

Re: calling C from PL/I....

From:

Bernd Oppolzer <bernd.oppolzer@T-ONLINE.DE>

Reply-To:

PL1 (language) discussions <PL1-L@LISTSERV.DARTMOUTH.EDU>

Date:

2014.02.24 12:50:44


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.

Blog-Hauptseite      Neuester Artikel      Älterer Artikel      Neuerer Artikel      Älterer gleiche Kategorie      Neuerer gleiche Kategorie