0

While trying to make an ADA binding to a third party C/C++ library (SAPNWRFCSDK) I came to problems of type inference for array types:

First problem:

The Gnat-Binding-Generator from gcc (gcc -fdump-ada-spec) is generating lots of intermediate named array types for different index ranges:

type anon3115_anon3128_array is array (0 .. 8) of aliased SAP_UC;
type anon3115_anon3131_array is array (0 .. 3) of aliased SAP_UC;
type anon3115_anon3134_array is array (0 .. 12) of aliased SAP_UC;

Those types are used in records. If I want to pass those fields to a procedure or function I would like to have a unbounded type signature for example with following type:

type SAP_UC_Array is array (Int range <>) of aliased SAP_UC;

But the generated types are no subtypes of this cannot be passed. One solution would be to change the field declarations in the Records to:

field : SAP_UC_Array(0 .. 8);

But this would mean to "process" the generated binding file and change all definitions. Is it possible to create an named array subtype with a specified index range or what would be the solution?

Second Problem:

Some array type definitions have equivalent Component types.

subtype RFC_CHAR is SAP_UC; 
type RFC_DATE is array (0 .. 7) of aliased RFC_CHAR;

This array definition is not considered as equivalent to an Array of Component type SAP_UC. Is it possible to tell Ada that these types are equivalent?

Florian B.
  • 51
  • 6
  • I've found the binding auto-generation is more of an aid to getting a binding rather being a one-stop solution. It works best when used on a simple, stable set of header files. I'll run it, fix up the generated code, and hopefully never have to run it again on that set of headers. – Marc C Apr 14 '14 at 20:00
  • You are right. There is some more odd stuff in the generated signatures. For example for the C-signature of an array pointer `SAP_UC const * x` the Ada signature `x : access SAP_UC`is generated, what means that I have to pass arrays as `arr(0)'access` – Florian B. Apr 15 '14 at 07:41
  • Which is why I'd go into the binding and add a `type SAP_UC_Ptr is access SAP_UC;` declaration and use that in place of the 'access' signature. – Marc C Apr 15 '14 at 17:35

2 Answers2

1

You can say this in Ada:

type SAP_UC_Array is array (Int range <>) of aliased SAP_UC;

subtype anon3115_anon3128_array is SAP_UC_Array (0 .. 8);
subtype anon3115_anon3131_array is SAP_UC_Array (0 .. 3);
subtype anon3115_anon3134_array is SAP_UC_Array (0 .. 12);

I apologize if you already knew this, but I can't tell whether the question was simply about getting the Gnat-Binding-Generator to generate the subtype declarations. I can't help you with the GNAT question.

As for the second question: Every type declaration creates a new, distinct type; there is no way to treat two distinct types as equivalent. (The language will automatically convert types in some cases, but I think that's only in cases involving anonymous types or certain special types defined by the language such as "universal integer".) In this case, though, there's no particular reason to declare an array type like RFC_DATE. If you already have a type that's an array of SAP_UC, such as SAP_UC_Array, then you could just as well say

subtype RFC_DATE is SAP_UC_Array (0 .. 7);

since the element type, RFC_CHAR, is basically just a "rename" of SAP_UC. (Of course this won't help you if the type declarations are being generated by a tool.)

ajb
  • 29,914
  • 3
  • 49
  • 73
  • Thanks a lot! Range constrained array subtypes are exactly what I was looking for. Anyway I will have to modify the generated ads-header file. But with this suggestions it will be easy to do the edits programatically. – Florian B. Apr 15 '14 at 07:28
0

Now I have the challenge to convert an Ada-String into a SAP_UC_Array. Acutally a funciton

function toUnicode( adaString : String) return SAP_UC_Array;

is needed. For this I would like to use the C-Function:

SAP_UC const * toUnicode( char const * s)
{
    UConverter * converter;
    UErrorCode err = U_ZERO_ERROR;
    SAP_UC  * target;
    target = (SAP_UC *) calloc(   strlen(s)+1, sizeof(SAP_UC)  ); // Creating wonderfull Memory Leaks 
    converter = ucnv_open( "8859-1", &err );
    int len = ucnv_toUChars(converter, target, strlen(s)+1, s, strlen(s), &err); 
    ucnv_close( converter );
    return target;
}

This function could be mapped to yield an access SAP_UC - the correspondence to the C-Pointer SAP_UC const *:

   function toUnicode (arg1 : Interfaces.C.Strings.chars_ptr) return access SAP_UC;  
   pragma Import (C, toUnicode, "toUnicode");

I am calling this with toUnicode(New_String(adaString)) and getting a reference to the first SAP_UC character. But I would rather like to get back an unrestricted SAP_UC_Array . Is this possible?

Well I am having found a work-around - admittedly not elegant - but it works. A C function that allows a character-wise read-out of the Array:

SAP_UC getChar(SAP_UC * u, int i)
{
        return u[i];
}

with corresponding Ada-Signature:

    function getChar(a : access SAP_UC; i: Int) return sapucx_h.SAP_UC;
    pragma Import (C, getChar, "getChar");

In Ada I am having a function, that populates a given SAP_UC_Array elementwise:

    function sU( s : String; b : out SAP_UC_Array ) return SAP_UC_Array is
        a : access SAP_UC;
    begin
        a := toUnicode( New_String(s));
        for i in 0 .. Int'Val(s'length) loop
            b(i) := getChar(a,i);
        end loop;
        return b;
    end;

And for "dynamic" memory allocation I am using:

function  cU( s : String ) return    SAP_UC_Array
is
begin
    declare
        tmp  :  SAP_UC_Array(0 .. s'length);    
    begin
        return sU(s,tmp);
    end;
end;

I am sure that there are better solutions.

Florian B.
  • 51
  • 6