Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
March 21, 2018 #import mapi.h | ||||
---|---|---|---|---|
| ||||
Is there an step by step introduction how to convert a C header of an external lib into the right extern(C){} block? A blog post or tutorial, or chapter in a D book? (I have those from Packt Publishing) (Especially I am trying to get this used with D: Montetdb C-API https://www.monetdb.org/Documentation/Manuals/SQLreference/Programming/MAPI With: https://github.com/snaga/monetdb/blob/master/clients/mapilib/mapi.h) The page: https://dlang.org/spec/interfaceToC.html is known, but not detailed enough for me. |
March 21, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to Martin Tschierschke | Martin Tschierschke wrote:
> or tutorial
ok, tutorial:
1. learn C.
2. learn D.
3. DO IT!
;-)
|
March 21, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to Martin Tschierschke | On Wednesday, 21 March 2018 at 16:22:45 UTC, Martin Tschierschke wrote: > Is there an step by step introduction how to convert a C header of an external lib into the right extern(C){} block? > > A blog post or tutorial, or chapter in a D book? (I have those from Packt Publishing) While googling I found this: https://dlang.org/blog/2017/12/05/interfacing-d-with-c-getting-started/ Haven't read it yet, but might give you some more insight. For automatic conversion I stumbled across Dstep which I so far like a lot: https://github.com/jacob-carlborg/dstep |
March 21, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to Martin Tschierschke | On Wednesday, 21 March 2018 at 16:22:45 UTC, Martin Tschierschke wrote:
> Is there an step by step introduction how to convert a C header of an external lib into the right extern(C){} block?
>
> A blog post or tutorial, or chapter in a D book? (I have those from Packt Publishing)
>
> (Especially I am trying to get this used with D:
> Montetdb C-API https://www.monetdb.org/Documentation/Manuals/SQLreference/Programming/MAPI
> With: https://github.com/snaga/monetdb/blob/master/clients/mapilib/mapi.h)
>
> The page: https://dlang.org/spec/interfaceToC.html is known, but not detailed enough for me.
The easiest thing to do is to write a wrapper in C. The wrapper will include all necessary headers and provide some easy to use functions that you can call from D. Of course, you'll need to use a C compiler to compile it.
Anyway, this header looks very straightforwar, no particular tricks with the preprocessor. It should be something like this (untested, obviously):
import core.stdc.stdio : FILE;
enum
{
MAPI_AUTO = 0, /* automatic type detection */
MAPI_TINY = 1,
MAPI_UTINY = 2,
MAPI_SHORT = 3,
MAPI_USHORT = 4,
MAPI_INT = 5,
MAPI_UINT = 6,
MAPI_LONG = 7,
MAPI_ULONG = 8,
MAPI_LONGLONG = 9,
MAPI_ULONGLONG = 10,
MAPI_CHAR = 11,
MAPI_VARCHAR = 12,
MAPI_FLOAT = 13,
MAPI_DOUBLE = 14,
MAPI_DATE = 15,
MAPI_TIME = 16,
MAPI_DATETIME = 17,
MAPI_NUMERIC = 18,
}
enum int PLACEHOLDER = '?';
enum
{
MAPI_SEEK_SET = 0,
MAPI_SEEK_CUR = 1,
MAPI_SEEK_END = 2,
}
enum
{
MAPI_TRACE = 1,
MAPI_TRACE_LANG = 2,
}
alias MapiMsg = int;
enum
{
MOK = 0,
MERROR = -1,
MTIMEOUT = -2,
MMORE = -3,
MSERVER = -4,
}
enum
{
LANG_MAL = 0,
LANG_SQL = 2,
LANG_JAQL = 3,
}
/* prompts for MAPI protocol */
enum int PROMPTBEG = '\001'; /* start prompt bracket */
/* prompt: ready for new query */
const(char)* PROMPT1 = "\001\001\n".ptr;
/* prompt: more data needed */
const(char)* PROMTP2 = "\001\002\n".ptr;
/*
* The table field information is extracted from the table headers
* obtained from the server. This list may be extended in the future.
* The type of both the 'param' and 'binding'
* variables refer to their underlying C-type. They are used for
* automatic type coercion between back-end and application.
*/
struct MapiStruct;
alias Mapi = MapiStruct*;
/* this definition is a straight copy from sql/include/sql_query.h */
enum
{
Q_PARSE = 0,
Q_TABLE = 1,
Q_UPDATE = 2,
Q_SCHEMA = 3,
Q_TRANS = 4,
Q_PREPARE = 5,
Q_BLOCK = 6,
}
struct MapiStatement;
alias MapiHdl = MapiStatement*;
alias mapi_uint64 = ulong;
alias mapi_int64 = long;
/* three structures used for communicating date/time information */
/* these structs are deliberately compatible with the ODBC versions
SQL_DATE_STRUCT, SQL_TIME_STRUCT, and SQL_TIMESTAMP_STRUCT */
/* used by MAPI_DATE */
struct MapiDate
{
short year;
ushort month;
ushort day;
}
/* used by MAPI_TIME */
struct MapiTime
{
ushort hour;
ushort minute;
ushort second;
}
/* used by MAPI_DATETIME */
struct MapiDateTime
{
short year;
ushort month;
ushort day;
ushort hour;
ushort minute;
ushort second;
uint fraction; /* in 1000 millionths of a second (10e-9) */
}
/* connection-oriented functions */
extern (C)
{
Mapi mapi_mapi(const char *host,
int port,
const char *username,
const char *password,
const char *lang,
const char *dbname);
// and so on...
}
|
March 22, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to nkm1 | On Wednesday, 21 March 2018 at 18:42:43 UTC, nkm1 wrote: > On Wednesday, 21 March 2018 at 16:22:45 UTC, Martin Tschierschke wrote: >> [...] > > The easiest thing to do is to write a wrapper in C. The wrapper will include all necessary headers and provide some easy to use functions that you can call from D. Of course, you'll need to use a C compiler to compile it. > Anyway, this header looks very straightforwar, no particular tricks with the preprocessor. It should be something like this (untested, obviously): > > [...] Thank you! Especially this was a missing link: >struct MapiStruct; >alias Mapi = MapiStruct*; |
March 22, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | On Wednesday, 21 March 2018 at 17:12:07 UTC, Timoses wrote:
> On Wednesday, 21 March 2018 at 16:22:45 UTC, Martin Tschierschke wrote:
>> Is there an step by step introduction how to convert a C header of an external lib into the right extern(C){} block?
>>
>> A blog post or tutorial, or chapter in a D book? (I have those from Packt Publishing)
>
> While googling I found this:
> https://dlang.org/blog/2017/12/05/interfacing-d-with-c-getting-started/
>
> Haven't read it yet, but might give you some more insight.
>
> For automatic conversion I stumbled across Dstep which I so far like a lot:
> https://github.com/jacob-carlborg/dstep
Thank you! I will have a look at both, an Mike Parker is pointing to his book, too,
so now together with the post from "nkm1" I should be able to make it!
@ketmar, I learned C but the counter of years from that time was stored in a nibble and so I got an overflow...error :-)
|
March 22, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to Martin Tschierschke | On Thursday, 22 March 2018 at 12:53:23 UTC, Martin Tschierschke wrote: > On Wednesday, 21 March 2018 at 17:12:07 UTC, Timoses wrote: [...] I got it, my first mini test with C bindings! Important missing at first: (stderr) import core.stdc.stdio : stderr, FILE; and use of toStringz inside: mapi_query(dbh, toStringz(q) ) After installing monetdb and starting the server with: https://www.monetdb.org/Documentation/UserGuide/Tutorial My minimal version of the example compiled with dmd app.d -I /usr/local/lib/libmapi.so (My dub.json is still incomplete so the linking failed.) Here is the code: (only the minimum of mapi.h is icluded!) ``` std.stdio; import std.string; /* interfacing winth monetdb #include mapi.h */ /* minimum to run code of example at: https://www.monetdb.org/Documentation/Manuals/SQLreference/Programming/MAPI */ import core.stdc.stdio : stderr,FILE; import core.stdc.stdlib; struct MapiStruct; alias Mapi = MapiStruct*; struct MapiStatement; alias MapiHdl = MapiStatement*; enum MOK = 0 ; alias MapiMsg = int; extern(System){ Mapi mapi_connect(const char* host, int port, const char* username, const char* password, const char* lang, const char* dbname); MapiHdl mapi_query(Mapi mid, const char *cmd); int mapi_fetch_row(MapiHdl hdl); char *mapi_fetch_field(MapiHdl hdl, int fnr); MapiMsg mapi_error(Mapi mid); MapiMsg mapi_explain(Mapi mid, FILE* fd); MapiMsg mapi_destroy(Mapi mid); MapiMsg mapi_close_handle(MapiHdl hdl); MapiMsg mapi_explain_result(MapiHdl hdl, FILE* fd); MapiMsg mapi_next_result(MapiHdl hdl); MapiMsg mapi_explain_query(MapiHdl hdl, FILE* fd); char *mapi_result_error(MapiHdl hdl); } void die(Mapi dbh, MapiHdl hdl) { if (hdl != null) { mapi_explain_query(hdl, stderr); do { if (mapi_result_error(hdl) != null) mapi_explain_result(hdl, stderr); } while (mapi_next_result(hdl) == 1); mapi_close_handle(hdl); mapi_destroy(dbh); } else if (dbh != null) { mapi_explain(dbh, stderr); mapi_destroy(dbh); } else { fprintf(stderr, "command failed\n"); } exit(-1); } MapiHdl query(Mapi dbh, string q) { MapiHdl ret = null; if ((ret = mapi_query(dbh, toStringz(q) )) == null || mapi_error(dbh) != MOK) die(dbh, ret); return(ret); } void update(Mapi dbh, string q) { MapiHdl ret = query(dbh, q); if (mapi_close_handle(ret) != MOK) die(dbh, ret); } void main() { auto dbh = mapi_connect("localhost", 50000, "monetdb", "monetdb", "sql", "voc"); writeln("DB-connect"); update(dbh, "CREATE TABLE emp (name VARCHAR(20), age INT)"); writeln("create"); update(dbh, "INSERT INTO emp VALUES ('John', 23)"); update(dbh, "INSERT INTO emp VALUES ('Mary', 22)"); auto hdl = query(dbh, "SELECT * FROM emp"); while (mapi_fetch_row(hdl)) { auto name = mapi_fetch_field(hdl, 0); auto age = mapi_fetch_field(hdl, 1); printf("%s is %s\n", name, age); } } ``` Will try to make a complete binding available later... |
March 22, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to Martin Tschierschke | On Wednesday, 21 March 2018 at 16:22:45 UTC, Martin Tschierschke wrote:
> Is there an step by step introduction how to convert a C header of an external lib into the right extern(C){} block?
In short, they should be binary compatible: where is a pointer on C side, should be a pointer on D side, same for integer sizes, data layout an calling conventions.
|
March 22, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to Martin Tschierschke | On Wednesday, 21 March 2018 at 16:22:45 UTC, Martin Tschierschke wrote: > Is there an step by step introduction how to convert a C header of an external lib into the right extern(C){} block? In addition to what others have said, I found the following article on the D Wiki useful: https://wiki.dlang.org/D_binding_for_C |
March 22, 2018 Re: #import mapi.h | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Thursday, 22 March 2018 at 17:42:46 UTC, Paul Backus wrote:
> On Wednesday, 21 March 2018 at 16:22:45 UTC, Martin Tschierschke wrote:
>> Is there an step by step introduction how to convert a C header of an external lib into the right extern(C){} block?
>
> In addition to what others have said, I found the following article on the D Wiki useful:
>
> https://wiki.dlang.org/D_binding_for_C
Thank you, this one is very good!
|
Copyright © 1999-2021 by the D Language Foundation