/*
===========================================
   responsible:    DanielD
   description:    Interface to DB Manager
   target:         Perl
   last changed:   24.06.2005

    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
===========================================*/


#include <stddef.h>

#ifdef __cplusplus
#include <math.h>
#include <stdlib.h>
extern "C" {
#else
#define bool char
#define HAS_BOOL 1
#endif

#define PERL_GLUE 1
#define Glue_BEGIN_ALLOW_THREADS
#define Glue_END_ALLOW_THREADS

#include "patchlevel.h"/* no check */

#if defined (ACTIVE_PERL)
    #if PATCHLEVEL < 6
        #define PERL_OBJECT
    #endif
#endif

#include "EXTERN.h"/* no check */
#include "perl.h"/* no check */
#if defined (PERL_OBJECT)
#include "perlCAPI.h"/* no check */
#endif
#include "XSUB.h"/* no check */
#undef free
#undef malloc
#undef realloc
#include <string.h>
#if defined (bool)
#undef bool
#endif
#if defined (PERL_OBJECT)
    #if !defined (PL_sv_undef)
        #define PL_sv_undef sv_undef
    #endif
    #if !defined (PL_sv_yes)
        #define PL_sv_yes sv_yes
    #endif
    #if !defined (PL_errgv)
        #define PL_errgv errgv
    #endif
#endif
#ifdef __cplusplus
}
#endif

#if defined (_WIN32)
#define GLUEEXPORT __declspec(dllexport)
#else
#define GLUEEXPORT
#endif

#define LIT(c) CONST_CAST(char *, c)
#define CROAKBUF_SIZE 200

#define MF__
#if defined (__cplusplus)
#define externC extern "C"
#else
#define externC
#endif

#define SL_None &PL_sv_undef
#define SL_isNone(val) (!SvOK (val))
#define SL_isTrue(val) SvTRUE (val)

static const char * invalidArgCount_C = "Invalid number of arguments";

static void *
getGluePointer (SV * sv, const char * className, char * croakBuf)
{
    IV   tmp;

    if (SvGMAGICAL(sv)) {
        mg_get(sv);
    }

    /* Check to see if this is an object */
    if (sv_isobject(sv)) {
        SV *tsv = (SV*) SvRV(sv);
        if ((SvTYPE(tsv) == SVt_PVHV)) {
            MAGIC *mg;
            if (SvMAGICAL(tsv)) {
                mg = mg_find(tsv,'P');
                if (mg) {
                    SV *rsv = mg->mg_obj;
                    if (sv_isobject(rsv)) {
                        tmp = SvIV((SV*)SvRV(rsv));
                    }
                }
            }
            else {
                strcpy (croakBuf, "Not a valid pointer value");
                return NULL;
            }
        }
        else {
            tmp = SvIV((SV*)SvRV(sv));
        }
    }
    else if (SL_isNone (sv)) {            /* Check for undef */
        strcpy (croakBuf, "Undef object not allowed");
        return NULL;
    }
    else if (SvTYPE(sv) == SVt_RV) {       /* Check for NULL pointer */
        if (!SvROK(sv)) {
            strcpy (croakBuf, "NULL object not allowed");
        }
        else {
            strcpy (croakBuf, "NULL object not allowed");
        }
        return NULL;
    }
    else {                                 /* Dont know what it is */
        strcpy (croakBuf, "Not a valid pointer value");
        return NULL;
    }
    /* Now see if the types match */

    if (!sv_isa (sv, (char *) className)) {
        sprintf (croakBuf, "Object is of class %s (should be %s)",
                HvNAME(SvSTASH(SvRV(sv))), className);
        return NULL;
    }
    return (void*) tmp;
}


/*
 * Exceptions
 */

static const char * CommunicationError_dbm = "CommunicationError";
static const char * DBMServError_dbm = "DBMServError";

/* snippet Perl_precode */
#define CN72 1
#undef na
#include "hsp100.h" /*&variant +a,c */
#include "hcn14.h"  /*&variant +a,c */
#include "patchlevel.h"/* no check */
#if PATCHLEVEL >= 5
    #define na PL_na
#else
    #define na Perl_na
#endif

#if defined (__cplusplus)
#define REFPARM(name)   name
#define INLINE          inline
#else
#define REFPARM(name)   &name
#define INLINE

#undef ROUTINE_DBG_MSP00
#define ROUTINE_DBG_MSP00(lit) static const char * funcname_glue_ = lit

#define REINTERPRET_CAST(type, expr) ((type) expr)
#define STATIC_CAST(type, expr) ((type) expr)
#define CONST_CAST(type, expr) ((type) expr)
#define REFCAST_MEO00(type)
#endif

static void trimPayload (
    const void * dataArg,
    tsp00_Int4 * len);

/*----------------------------------------*/

static int
errorOccured (
    int rc,
    tsp00_ErrTextc VAR_ARRAY_REF msg,
    char * croakBuf)
{
    ROUTINE_DBG_MSP00 ("errorOccured");
    if (rc != 0) {
        sprintf (croakBuf, "%s (%d): %s", CommunicationError_dbm, rc, (char *) msg);
        return 1;
    }
    else {
        return 0;
    }
}

/*----------------------------------------*/

static int
commErrOccured (int rc, char * msg, char * croakBuf)
{
    ROUTINE_DBG_MSP00 ("commErrOccured");
    if (rc != 0) {
        sprintf (croakBuf, "%s (%d): %s", CommunicationError_dbm, rc, msg);
        return 1;
    }
    else {
        return 0;
    }
}

/*----------------------------------------*/

static int
dbmServErrOccured (
    void * nself,
    int rc,
    tsp00_ErrTextc VAR_ARRAY_REF msg,
    const char * cmd,
    char * croakBuf)
{
    ROUTINE_DBG_MSP00 ("dbmServErrOccured");
    const char  * rawData;
    int           errOccurred = 0;
    tsp00_Int4      serverError;
    const void  * payLoad;
    tsp00_Int4      payLoadLen;
    tsp00_Int4      specificError;
    tsp00_ErrTextc errtext;


    if (rc == DBMAPI_COMMERR_CN14) {
        sprintf (croakBuf, "Communication Error: %s", msg);
        return 1;
    }
    serverError = cn14analyzeDbmAnswer (nself, &payLoad, &payLoadLen,
            &specificError, errtext);
    trimPayload (payLoad, &payLoadLen);
    if (serverError != DBMAPI_OK_CN14) {
        errOccurred = 1;
        payLoadLen = MIN_EO00 (150, payLoadLen);
        sprintf (croakBuf, "Error DBM Server: %d %s %*s",
                 specificError, (char*) errtext, payLoadLen, payLoad);
    }
    return errOccurred;
}

/*----------------------------------------*/

static int
allocFailed (void * ptr, char * croakBuf)
{
    ROUTINE_DBG_MSP00 ("allocFailed");

    if (ptr == NULL) {
        strcpy (croakBuf, "Out of memory");
        return 1;
    }
    else {
        return 0;
    }
}

/* endsnippet Perl_precode */
static const char * DBMClassID = "DBM";

typedef struct DBMObjectT {
    const char * classID;
    void *nself;
/* no code for key DBM Perl_/Generic_ in ['Generic_precode']*/
} DBMObjectT;

#define isDBMObject(op) ((op)->classID == DBMClassID)

static const char * notClassDBM_C = "Object not of class DBM";

static DBMObjectT *
newDBM ()
{
    DBMObjectT * result;

    Newz (0, result, 1, DBMObjectT);
    return result;
}

static void
freeDBM (
    DBMObjectT * value)
{
    Safefree (value);
}
/* snippet DBM Generic_precode */

static char * buildInfo ()
{
    static tsp00_Versionc versionString;
    static bool isInitialized;
#if defined (PYTHON_GLUE)
    tsp100_CompName compName = "dbmpy    ";
#elif defined (PERL_GLUE)
    tsp100_CompName compName = "dbmperl  ";
#else
    #error must be either Python or Perl
#endif

    if (!isInitialized) {
        sp100_GetVersionString (compName, s100buildnumber, versionString);
    }
    return versionString;
}

static void
trimPayload (
    const void * data,
    tsp00_Int4 * len)
{
    if (data != NULL) {
        const void * nullPos = memchr (data, '\0', *len);
        if (nullPos != NULL) {
            *len = (tsp00_Int4) (((const char *) nullPos) - ((const char *) data));
        }
    }
    else {
        *len = 0;
    }

}

static void
localRelease (
    void* nself)
{
    if (nself != NULL) {
        cn14release (&nself);
    }
}


#if defined (PYTHON_GLUE)
static void
destructor_DBM (
    PyObject * pyself)
{
    DBMObjectT* self = REINTERPRET_CAST (DBMObjectT*, pyself);

    localRelease (self->nself);
    PyObject_Del (pyself);
}
#endif

typedef struct ReadResultT {
    const char * data;
    int len;
} ReadResultT;

/*----------------------------------------*/

static tsp00_Int4 cmdAndRead (
   void * nself,
   const char * cmd,
   ReadResultT * output,
   tsp00_ErrTextc VAR_ARRAY_REF errtext)
{
    tsp00_Int4 rc;
    tsp00_Int4 serverError;

    Glue_BEGIN_ALLOW_THREADS
    rc = cn14cmdExecute (nself, cmd, strlen (cmd), NULL, NULL, errtext);
    Glue_END_ALLOW_THREADS
    if (rc == DBMAPI_OK_CN14) {
        rc = cn14analyzeDbmAnswer (nself, (const void**) &output->data, &output->len,
                &serverError, errtext);
        if (output->data != NULL) {
            trimPayload (output->data, &output->len);
        }
    }
    return rc;
}

/*----------------------------------------*/

static tsp00_Int4 rawCommand (
   void * nself,
   const char * cmd,
   ReadResultT * output,
   tsp00_ErrTextc VAR_ARRAY_REF errtext)
{
    tsp00_Int4 rc;

    Glue_BEGIN_ALLOW_THREADS
    rc = cn14cmdExecute (nself, cmd, strlen (cmd), NULL, NULL, errtext);
    Glue_END_ALLOW_THREADS
    if (rc == DBMAPI_OK_CN14) {
        output->len = cn14bytesAvailable (nself);
        output->data = cn14rawReadData (nself, &rc);
        if (output->data != NULL) {
            trimPayload (output->data, &output->len);
        }
    }
    return rc;
}

/*----------------------------------------*/

static int cancelCmd (
   void * nself)
{
    Glue_BEGIN_ALLOW_THREADS
    cn14cmdCancel (nself);
    Glue_END_ALLOW_THREADS
    return 0;
}

/*----------------------------------------*/

#if defined (PYTHON_GLUE)
static int readResult2Python (
   void * nself,
   ReadResultT readResult,
   PyObject ** pyResult)
{
    *pyResult = PyString_FromStringAndSize (readResult.data, readResult.len);
    return *pyResult != NULL;
}
#endif

static int doConnect (
   const char * servernode,
   const char * dbname,
   const char * dbroot,
   const char * userpwd,
   void      ** sessionOut,
   tsp00_ErrTextc VAR_ARRAY_REF errtext)
{
    int rc;

    Glue_BEGIN_ALLOW_THREADS
    if (userpwd != NULL) {
        rc = cn14connectDBMUsr (
                REFCAST_MEO00 (tsp00_NodeIdc) servernode,
                REFCAST_MEO00 (tsp00_DbNamec) dbname,
                REFCAST_MEO00 (tsp00_VFilenamec) dbroot,
                REFCAST_MEO00 (tsp00_C64c) userpwd,
                sessionOut, errtext);
    }
    else {
        rc = cn14connectDBM (
                REFCAST_MEO00 (tsp00_NodeIdc) servernode,
                REFCAST_MEO00 (tsp00_DbNamec) dbname,
                REFCAST_MEO00 (tsp00_VFilenamec) dbroot,
                sessionOut, errtext);
    }
    Glue_END_ALLOW_THREADS
    return rc;
}

static INLINE void doSaveUser (
   const char * dbname,
   const char * servernode,
   const char * userpwd)
{
    Glue_BEGIN_ALLOW_THREADS
    cn14saveUser (
                REFCAST_MEO00 (tsp00_NodeIdc) servernode,
                REFCAST_MEO00 (tsp00_DbNamec) dbname,
                REFCAST_MEO00 (tsp00_C64c) userpwd);
    Glue_END_ALLOW_THREADS
}

static INLINE tsp00_Int4 doCheckUser (
   const char * dbname,
   const char * servernode,
   const char * userpwd)
{
    tsp00_Int4 result;

    Glue_BEGIN_ALLOW_THREADS
    result = cn14checkUser (
                REFCAST_MEO00 (tsp00_NodeIdc) servernode,
                REFCAST_MEO00 (tsp00_DbNamec) dbname,
                REFCAST_MEO00 (tsp00_C64c) userpwd);
    Glue_END_ALLOW_THREADS
    return result;
}

static INLINE void doDeleteUser (
   const char * dbname,
   const char * servernode)
{
    Glue_BEGIN_ALLOW_THREADS
    cn14deleteUser (
        REFCAST_MEO00 (tsp00_NodeIdc) servernode,
        REFCAST_MEO00 (tsp00_DbNamec) dbname);
    Glue_END_ALLOW_THREADS
}

/* endsnippet DBM Generic_precode */
/*----------------------------------------*/

externC XS (DBM_cmd)
{
    ROUTINE_DBG_MSP00 ("DBM_cmd");
/* no code for key Perl_/Generic_code */
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    DBMObjectT* self;
    void* nself;
    char * cmd;
    ReadResultT output;
    tsp00_ErrTextc msg;
    tsp00_Int4 result;
    
    cv = cv;
    if (items != 2) {
        croak (invalidArgCount_C);
    }
    self = (DBMObjectT*) getGluePointer (ST(0), DBMClassID, croakBuf);
    if ((self == NULL) || !isDBMObject (self)) {
        croak (croakBuf);
    }
    nself = self->nself;
    switch (items) {
        case 2: cmd = (char *) SvPV (ST(1), na);
    }
    if (!ok) {
        ok = 0;
        goto cleanup_label;
    }
/* no code for key Perl_/Generic_nativeCall */
    result = cmdAndRead (nself, cmd, &output, msg);
    if (dbmServErrOccured (nself, result, msg, cmd, croakBuf)) {
        ok = 0;
        goto cleanup_label;
    }
    /* outargs */
    ST (argvi) = sv_newmortal ();
    sv_setpvn ((SV*) ST (argvi++), (char *) output.data, output.len);
  cleanup_label:
    if (!ok) {
        /* Cleanup */
        croak (croakBuf);
    }
    XSRETURN (argvi);
}

/*----------------------------------------*/

externC XS (DBM_rawCmd)
{
    ROUTINE_DBG_MSP00 ("DBM_rawCmd");
/* no code for key Perl_/Generic_code */
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    DBMObjectT* self;
    void* nself;
    char * cmd;
    ReadResultT output;
    tsp00_ErrTextc msg;
    tsp00_Int4 result;
    
    cv = cv;
    if (items != 2) {
        croak (invalidArgCount_C);
    }
    self = (DBMObjectT*) getGluePointer (ST(0), DBMClassID, croakBuf);
    if ((self == NULL) || !isDBMObject (self)) {
        croak (croakBuf);
    }
    nself = self->nself;
    switch (items) {
        case 2: cmd = (char *) SvPV (ST(1), na);
    }
    if (!ok) {
        ok = 0;
        goto cleanup_label;
    }
/* no code for key Perl_/Generic_nativeCall */
    result = rawCommand (nself, cmd, &output, msg);
    if (commErrOccured (result, msg, croakBuf)) {
        ok = 0;
        goto cleanup_label;
    }
    /* outargs */
    ST (argvi) = sv_newmortal ();
    sv_setpvn ((SV*) ST (argvi++), (char *) output.data, output.len);
  cleanup_label:
    if (!ok) {
        /* Cleanup */
        croak (croakBuf);
    }
    XSRETURN (argvi);
}

/*----------------------------------------*/

externC XS (DBM_cancelCmd)
{
    ROUTINE_DBG_MSP00 ("DBM_cancelCmd");
/* no code for key Perl_/Generic_code */
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    DBMObjectT* self;
    void* nself;
    int result;
    
    cv = cv;
    if (items != 1) {
        croak (invalidArgCount_C);
    }
    self = (DBMObjectT*) getGluePointer (ST(0), DBMClassID, croakBuf);
    if ((self == NULL) || !isDBMObject (self)) {
        croak (croakBuf);
    }
    nself = self->nself;
/* no code for key Perl_/Generic_nativeCall */
    result = cancelCmd (nself);
    /* outargs */
    XSRETURN (argvi);
}

/*----------------------------------------*/

externC XS (DBM_release)
{
    ROUTINE_DBG_MSP00 ("DBM_release");
/* no code for key release Perl_/Generic_ in ['Generic_nativeCall']*/
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    DBMObjectT* self;
    void* nself;
    
    cv = cv;
    if (items != 1) {
        croak (invalidArgCount_C);
    }
    self = (DBMObjectT*) getGluePointer (ST(0), DBMClassID, croakBuf);
    if ((self == NULL) || !isDBMObject (self)) {
        croak (croakBuf);
    }
    nself = self->nself;
/* snippet release Generic_nativeCall */
    localRelease (self->nself);
    self->nself = NULL;
    /* endsnippet release Generic_nativeCall */
    /* outargs */
    XSRETURN (argvi);
}


/*----------------------------------------*/

externC XS (DBM_destructor)
{
    ROUTINE_DBG_MSP00 ("DBM_destructor");
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    DBMObjectT* self;
    void* nself;

    cv = cv;
    if (items != 1) {
        croak (invalidArgCount_C);
    }
    self = (DBMObjectT*) getGluePointer (ST(0), DBMClassID, croakBuf);
    if ((self == NULL) || !isDBMObject (self)) {
        croak (croakBuf);
    }
    nself = self->nself;
    localRelease (nself);
    freeDBM (self);
    XSRETURN (0);
}

/*----------------------------------------*/

externC XS (dbm_DBM)
{
    ROUTINE_DBG_MSP00 ("dbm_DBM");
/* no code for key constructor Perl_/Generic_ in ['Generic_nativeCall']*/
    DBMObjectT * newObj = NULL;
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    char * servernode;
    char * dbname;
    char * dbroot = LIT( "");
    char * userpwd =  NULL;
    void * session;
    tsp00_ErrTextc msg;
    tsp00_Int4 result;
    
    cv = cv;
    if ((items < 2) || (items > 4)) {
        croak (invalidArgCount_C);
    }
    switch (items) {
        case 4: userpwd = (char *) SvPV (ST(3), na);
        case 3: dbroot = (char *) SvPV (ST(2), na);
        case 2: dbname = (char *) SvPV (ST(1), na);
        case 1: servernode = (char *) SvPV (ST(0), na);
    }
    if (!ok) {
        ok = 0;
        goto cleanup_label;
    }
    newObj = newDBM ();
    if (allocFailed (newObj, croakBuf)) {
        ok = 0;
        newObj = NULL;
        goto cleanup_label;
    }
    newObj->classID = DBMClassID;
/* snippet constructor Generic_nativeCall */
    result = doConnect (servernode, dbname, dbroot, userpwd, &session, msg);
    newObj->nself = session;
    ok = ! errorOccured (result, msg, croakBuf);
    /* endsnippet constructor Generic_nativeCall */
    /* outargs */
    ST (argvi) = sv_newmortal ();
    sv_setref_pv (ST (argvi++), (char *)DBMClassID, (void *) newObj);
  cleanup_label:
    if (!ok) {
        /* Cleanup */
        if (newObj != NULL) {
            free (newObj);
        }
        croak (croakBuf);
    }
    XSRETURN (argvi);
}

/*----------------------------------------*/

externC XS (dbm_saveUser)
{
    ROUTINE_DBG_MSP00 ("dbm_saveUser");
/* no code for key Perl_/Generic_code */
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    char * dbname;
    char * servernode;
    char * userpwd;
    
    cv = cv;
    if (items != 3) {
        croak (invalidArgCount_C);
    }
    switch (items) {
        case 3: userpwd = (char *) SvPV (ST(2), na);
        case 2: servernode = (char *) SvPV (ST(1), na);
        case 1: dbname = (char *) SvPV (ST(0), na);
    }
    if (!ok) {
        ok = 0;
        goto cleanup_label;
    }
/* no code for key Perl_/Generic_nativeCall */
    doSaveUser (dbname, servernode, userpwd);
    /* outargs */
  cleanup_label:
    if (!ok) {
        /* Cleanup */
        croak (croakBuf);
    }
    XSRETURN (argvi);
}

/*----------------------------------------*/

externC XS (dbm_checkUser)
{
    ROUTINE_DBG_MSP00 ("dbm_checkUser");
/* no code for key Perl_/Generic_code */
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    char * dbname;
    char * servernode;
    char * userpwd;
    tsp00_Int4 result;
    
    cv = cv;
    if (items != 3) {
        croak (invalidArgCount_C);
    }
    switch (items) {
        case 3: userpwd = (char *) SvPV (ST(2), na);
        case 2: servernode = (char *) SvPV (ST(1), na);
        case 1: dbname = (char *) SvPV (ST(0), na);
    }
    if (!ok) {
        ok = 0;
        goto cleanup_label;
    }
/* no code for key Perl_/Generic_nativeCall */
    result = doCheckUser (dbname, servernode, userpwd);
    /* outargs */
    ST (argvi) = sv_newmortal ();
    sv_setiv (ST (argvi++), (IV) result);
  cleanup_label:
    if (!ok) {
        /* Cleanup */
        croak (croakBuf);
    }
    XSRETURN (argvi);
}

/*----------------------------------------*/

externC XS (dbm__buildInfo)
{
    ROUTINE_DBG_MSP00 ("dbm__buildInfo");
/* no code for key Perl_/Generic_code */
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    char * result;
    
    cv = cv;
    if (items != 0) {
        croak (invalidArgCount_C);
    }
/* no code for key Perl_/Generic_nativeCall */
    result = buildInfo ();
    /* outargs */
    ST (argvi) = sv_newmortal ();
    sv_setpv (ST (argvi++), result);
    XSRETURN (argvi);
}

/*----------------------------------------*/

externC XS (dbm_deleteUser)
{
    ROUTINE_DBG_MSP00 ("dbm_deleteUser");
/* no code for key Perl_/Generic_code */
    int ok = 1;
    int argvi = 0;
    char croakBuf [CROAKBUF_SIZE];
    dXSARGS;
    char * dbname;
    char * servernode;
    
    cv = cv;
    if (items != 2) {
        croak (invalidArgCount_C);
    }
    switch (items) {
        case 2: servernode = (char *) SvPV (ST(1), na);
        case 1: dbname = (char *) SvPV (ST(0), na);
    }
    if (!ok) {
        ok = 0;
        goto cleanup_label;
    }
/* no code for key Perl_/Generic_nativeCall */
    doDeleteUser (dbname, servernode);
    /* outargs */
  cleanup_label:
    if (!ok) {
        /* Cleanup */
        croak (croakBuf);
    }
    XSRETURN (argvi);
}


#if defined (ACTIVE_PERL)
#define boot_SAP__DBTech__dbm boot_SAP__DBTech__dbmaperl
#else
#define boot_SAP__DBTech__dbm boot_SAP__DBTech__dbmcperl
#endif

externC GLUEEXPORT XS(boot_SAP__DBTech__dbm)
{
    dXSARGS;
    char * file = CONST_CAST (char *, __FILE__);
    cv = cv;
    items = items;
    newXS (LIT ("SAP::DBTech::dbmc::dbm_DBM"), dbm_DBM, file);
    newXS (LIT ("SAP::DBTech::dbmc::dbm_saveUser"), dbm_saveUser, file);
    newXS (LIT ("SAP::DBTech::dbmc::dbm_checkUser"), dbm_checkUser, file);
    newXS (LIT ("SAP::DBTech::dbmc::dbm__buildInfo"), dbm__buildInfo, file);
    newXS (LIT ("SAP::DBTech::dbmc::dbm_deleteUser"), dbm_deleteUser, file);
    newXS (LIT ("SAP::DBTech::dbmc::DBM_cmd"), DBM_cmd, file);
    newXS (LIT ("SAP::DBTech::dbmc::DBM_rawCmd"), DBM_rawCmd, file);
    newXS (LIT ("SAP::DBTech::dbmc::DBM_cancelCmd"), DBM_cancelCmd, file);
    newXS (LIT ("SAP::DBTech::dbmc::DBM_release"), DBM_release, file);
    newXS (LIT("SAP::DBTech::dbmc::DBM_destructor"), DBM_destructor, file);
/* no code for key Perl_/Generic_ in ['Python_precode', 'Perl_precode', 'DBM Generic_precode', 'constructor Generic_nativeCall', 'release Generic_nativeCall']*/
    ST(0) = &PL_sv_yes;
    XSRETURN(1);
}

