From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,fb17569fccf2604b X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII Path: g2news2.google.com!postnews.google.com!j39g2000yqh.googlegroups.com!not-for-mail From: Ludovic Brenta Newsgroups: comp.lang.ada Subject: Re: Trouble writing Ada callback from C Date: Fri, 11 Sep 2009 01:24:42 -0700 (PDT) Organization: http://groups.google.com Message-ID: References: NNTP-Posting-Host: 153.98.68.197 Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Trace: posting.google.com 1252657482 1397 127.0.0.1 (11 Sep 2009 08:24:42 GMT) X-Complaints-To: groups-abuse@google.com NNTP-Posting-Date: Fri, 11 Sep 2009 08:24:42 +0000 (UTC) Complaints-To: groups-abuse@google.com Injection-Info: j39g2000yqh.googlegroups.com; posting-host=153.98.68.197; posting-account=pcLQNgkAAAD9TrXkhkIgiY6-MDtJjIlC User-Agent: G2/1.0 X-HTTP-UserAgent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2,gzip(gfe),gzip(gfe) Xref: g2news2.google.com comp.lang.ada:8284 Date: 2009-09-11T01:24:42-07:00 List-Id: On Sep 11, 9:57=A0am, Jerry 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 > =A0 =A0(label =A0 =A0: out char_array; > =A0 =A0 a_length : size_t); > pragma Convention(C, geolocation_labeler); > > -- Highly shortened version. > procedure geolocation_labeler > =A0 =A0(label =A0 =A0: out char_array; > =A0 =A0 a_length : size_t) > is > =A0 =A0 direction_label : Unbounded_String; > begin > =A0 =A0 Put_Line("a_length =3D " & a_length'img); -- for testing > =A0 =A0 direction_label :=3D To_Unbounded_String(" N"); -- not always len= gth > 2 > =A0 =A0 label :=3D 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) { > =A0 =A0 const char *direction_label; > > =A0 =A0 direction_label =3D " N"; > =A0 =A0 snprintf(label, length, "%s", direction_label); > =A0 =A0 printf(label); /* for testing */ > > } > > The printf(label) returns exactly 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 :=3D (0 .. whatever =3D> ' '); > label_as_char_array_ptr : char_array_access; > > then building the string in label_as_char_array, then doing > > label_as_char_array_ptr :=3D 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 :=3D " N"; -- or whatever begin Update (Item =3D> label, Offset =3D> 0, Str =3D> To_C (Result), Check = =3D> False); -- See AARM B.3.1(43, 50.a/2) exception when others =3D> -- 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.