www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Convert string[] to char**

reply Bruce Smith <b.e.smith computer.org> writes:
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hello

/[I'll prefix this question by stating that I am not a strong C 
programmer; my long experience is in a wide range of languages other 
than C//]/

I wish to call some functions in a complex C library from D. Since this 
a large & complex library, I've wrapped a bunch of the functions using 
SWIG (swig -d -d2 ...). One of the C functions has a signature like:

void foo(const char * const *keys);

SWIG has given me a D function signature like:

     void foo(char** keys);

In my D program it is natural to represent some keys as an array of 
strings, for example:

     string[] mykeys;

How should I convert mykeys from string[] to char** so that I can call 
foo with mykeys as the actual parameter?

Regards
Jun 04 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-06-04 09:18, Bruce Smith wrote:
 Hello

 /[I'll prefix this question by stating that I am not a strong C
 programmer; my long experience is in a wide range of languages other
 than C//]/

 I wish to call some functions in a complex C library from D. Since this
 a large & complex library, I've wrapped a bunch of the functions using
 SWIG (swig -d -d2 ...). One of the C functions has a signature like:

 void foo(const char * const *keys);

 SWIG has given me a D function signature like:

      void foo(char** keys);

 In my D program it is natural to represent some keys as an array of
 strings, for example:

      string[] mykeys;

 How should I convert mykeys from string[] to char** so that I can call
 foo with mykeys as the actual parameter?

I think you need to do something like: import std.conv; string[] mykeys; char*[] ckeys; ckeys.reserve(mykeys.length); foreach (key ; mykeys) ckeys ~= to!(char*)(key); foo(ckeys.ptr); -- /Jacob Carlborg
Jun 04 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-06-04 12:41, bearophile wrote:

 An alternative is something like (untested):

 auto ckeys = mykeys.map!toStringz.array;

Right, that should work. -- /Jacob Carlborg
Jun 04 2013
parent David <d dav1d.de> writes:
Am 04.06.2013 13:49, schrieb Bruce Smith:
 Thank you Jacob and bearophile ... just had to add a cast to get rid of
 immutable from your suggestion. For completeness, this compiles under
 2.063:
 
     void foo(char** k)
     {
         // body
     }
 
     string[] mykeys;
     auto ckeys = cast(char**)mykeys.map!toStringz.array;
 
     foo(ckeys);
 
 Bruce
 
 On 04/06/13 20:59, Jacob Carlborg wrote:
 On 2013-06-04 12:41, bearophile wrote:

 An alternative is something like (untested):

 auto ckeys = mykeys.map!toStringz.array;

Right, that should work.


Casting it isn't the best way here, you shouldn't cast immutability away, make sure your function does not mutate it (it must not!) then you could change the function signature to const(void*)*, otherwise use char[] instead of string, this should do it: mykeys.map!(x => x.dup.toStringz).array
Jun 04 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Jacob Carlborg:

 I think you need to do something like:

 import std.conv;

 string[] mykeys;
 char*[] ckeys;
 ckeys.reserve(mykeys.length);

 foreach (key ; mykeys)
     ckeys ~= to!(char*)(key);

 foo(ckeys.ptr);

An alternative is something like (untested): auto ckeys = mykeys.map!toStringz.array; Bye, bearophile
Jun 04 2013
prev sibling next sibling parent Bruce Smith <b.e.smith computer.org> writes:
Thank you Jacob and bearophile ... just had to add a cast to get rid of 
immutable from your suggestion. For completeness, this compiles under 2.063:

     void foo(char** k)
     {
         // body
     }

     string[] mykeys;
     auto ckeys = cast(char**)mykeys.map!toStringz.array;

     foo(ckeys);

Bruce

On 04/06/13 20:59, Jacob Carlborg wrote:
 On 2013-06-04 12:41, bearophile wrote:

 An alternative is something like (untested):

 auto ckeys = mykeys.map!toStringz.array;

Right, that should work.

Jun 04 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
David:

 mykeys.map!(x => x.dup.toStringz).array

Is toStringz already dup-ping the buffer? Bye, bearophile
Jun 04 2013
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Tuesday, 4 June 2013 at 12:20:24 UTC, bearophile wrote:
 David:

 mykeys.map!(x => x.dup.toStringz).array

Is toStringz already dup-ping the buffer?

Not necessarily. IIRC, if the string already has a null terminator then it just returns the string ptr. Only dups if it needs to.
Jun 04 2013
prev sibling parent Bruce Smith <b.e.smith computer.org> writes:
The C function's signature is determined by the library from which it 
originates; the D signature created by SWIG is tied to the C original; 
therefore I can't alter the fact that the parameter is of type char** 
(i.e. it is mutable).

OTOH, toStringz produces an immutable string.

Bruce

On 04/06/13 22:07, David wrote:
 Am 04.06.2013 13:49, schrieb Bruce Smith:
 Thank you Jacob and bearophile ... just had to add a cast to get rid of
 immutable from your suggestion. For completeness, this compiles under
 2.063:

      void foo(char** k)
      {
          // body
      }

      string[] mykeys;
      auto ckeys = cast(char**)mykeys.map!toStringz.array;

      foo(ckeys);

 Bruce

 On 04/06/13 20:59, Jacob Carlborg wrote:
 On 2013-06-04 12:41, bearophile wrote:

 An alternative is something like (untested):

 auto ckeys = mykeys.map!toStringz.array;



away, make sure your function does not mutate it (it must not!) then you could change the function signature to const(void*)*, otherwise use char[] instead of string, this should do it: mykeys.map!(x => x.dup.toStringz).array

Jun 04 2013