comp.lang.ada
 help / color / mirror / Atom feed
From: Ludovic Brenta <ludovic@ludovic-brenta.org>
Subject: Re: Trouble writing Ada callback from C
Date: Fri, 11 Sep 2009 01:24:42 -0700 (PDT)
Date: 2009-09-11T01:24:42-07:00	[thread overview]
Message-ID: <f637f1e2-f78b-4d3d-8afb-03376fbd27cd@j39g2000yqh.googlegroups.com> (raw)
In-Reply-To: e54f9d08-3083-4c98-974f-9695005679b3@x6g2000prc.googlegroups.com

On Sep 11, 9:57 am, Jerry <lancebo...@qwest.net> wrote:
> I have a problem with writing an Ada procedure, used as a callback
> from C, in which one of the arguments is an output char * (in the C
> version). The actual length of the returned "string" isn't known at
> calling time, even though the caller apparently allocates 40
> characters (see below). However, the actual number of characters
> returned by the C version is less than 40.
>
> My problem is how to pass probably a char_array back out which is the
> correct length, but which length is not known at the time the Ada
> callback is called from C.
>
> Here is a highly shortened version of one of many things that I have
> tried. I have not compiled or run this shortened version, but I
> believe that it contains the essence of the longer version:
>
> procedure geolocation_labeler
>    (label    : out char_array;
>     a_length : size_t);
> pragma Convention(C, geolocation_labeler);
>
> -- Highly shortened version.
> procedure geolocation_labeler
>    (label    : out char_array;
>     a_length : size_t)
> is
>     direction_label : Unbounded_String;
> begin
>     Put_Line("a_length = " & a_length'img); -- for testing
>     direction_label := To_Unbounded_String(" N"); -- not always length
> 2
>     label := To_C(To_String(direction_label), False);
> end geolocation_labeler;
>
> Of course, this fails with:
> raised CONSTRAINT_ERROR : blabla.adb:xxx length check failed
>
> Note that the Put_Line always prints 40, passed by the C caller.
>
> Here is a highly shortened version of the C callback. Note that PLINT
> is just an integer.
>
> /* Highly shortened version.*/
> void
> geolocation_labeler(char *label, PLINT length) {
>     const char *direction_label;
>
>     direction_label = " N";
>     snprintf(label, length, "%s", direction_label);
>     printf(label); /* for testing */
>
> }
>
> The printf(label) returns exactly <space>N (in this case) without \n.
> In particular, it is only 2 characters, not 40. (Presumably, length
> has a value of 40 here as well, although I have not tested that
> assumption.)
>
> I have tried things such as changing the type of label in the argument
> list then declaring e.g.
>
> label_as_char_array : aliased char_array := (0 .. whatever => ' ');
> label_as_char_array_ptr : char_array_access;
>
> then building the string in label_as_char_array, then doing
>
> label_as_char_array_ptr := label_as_char_array'Unchecked_Access;
>
> and then returning label_as_char_array_ptr. That also didn't work.
>
> So how do I mimic the char * behavior of C when the length of the
> output array is not known at call time?

I take it you mean "not known at compile time" because it is indeed
"known at call time".

C doesn't have proper strings; it has pointers to null-terminated
arrays of characters, which do not carry bounds information. So, the
specification of your callback is not "return a string in an array"
but "write N characters starting where label points, where N+1 <
a_length, followed by a null character (ASCII.NUL)".  Here is a
possible implementation (not compiled or tested either):

with Interfaces.C.Strings; use Interfaces.C.Strings;
procedure geolocation_labeler (label : in chars_ptr; length : in
size_t) is
   Result : constant String := " N"; -- or whatever
begin
   Update (Item => label, Offset => 0, Str => To_C (Result), Check =>
False);
   -- See AARM B.3.1(43, 50.a/2)
exception
   when others =>
      -- Important: callbacks must handle all exceptions because the C
layer
      -- calling us cannot propagate or handle them.
      null; -- or report it.
end geolocation_labeler;

HTH

--
Ludovic Brenta.



  reply	other threads:[~2009-09-11  8:24 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-09-11  7:57 Trouble writing Ada callback from C Jerry
2009-09-11  8:24 ` Ludovic Brenta [this message]
2009-09-11 20:38   ` sjw
2009-09-12  5:28   ` Jerry
2009-09-12  5:46     ` sjw
2009-09-16 23:06       ` Jerry
2009-09-12  8:44     ` Georg Bauhaus
2009-09-12 18:40 ` Vadim Godunko
2009-09-16 23:19   ` Jerry
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox