egghelp.org community Forum Index
[ egghelp.org home | forum home ]
egghelp.org community
Discussion of eggdrop bots, shell accounts and tcl scripts.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Example: Module in C++

 
Post new topic   Reply to topic    egghelp.org community Forum Index -> Modules & Programming
View previous topic :: View next topic  
Author Message
Kappa007
Voice


Joined: 26 Jul 2005
Posts: 38

PostPosted: Fri Jan 20, 2006 10:14 pm    Post subject: Example: Module in C++ Reply with quote

Oke, since some people (including myself Wink) thought it might be useful to be able to write modules C++ rather than in plain C here we go Very Happy

The problem when trying to use C++ code with eggdrop is that eggdrop uses some global function table for imports which does not mix very with C++.
A simple "extern C" is not enough to be able to include the "module.h".


So my approach is to use a wrapper.
We start building normal module which wraps all stuff we need and compile that one with C.
Then we take the header file of that and just include it in our C++ files.
At the end we link all together.
Only thing we need are some structs from eggdrop to be able to bind/unbind commands from C++.

The whole thing ofcourse only works well when we don't need A LOT of eggdrop core functions cause then it might be a lot work to wrap them all Wink


My example module is called "cpphello.mod" and it just outputs a message to channel when triggered via "!hello".

Code:

/*
 * hello.h -- part of cpphello.mod
 *   
 * Example how to write an eggdrop module in C++
 *
 * Originally written by Kappa007         2006-01-21
 *
 *
 * Copyright (c) by Kappa007. All rights reserved.
 */

#ifndef __HELLO_H__
#define __HELLO_H__

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus


    /*** Common typedefs and structs from eggdrop ***/

    typedef void (*Function) ();

    struct flag_record {
      int match;
      int global;
      int udef_global;
      int bot;
      int chan;
      int udef_chan;
    };

    typedef unsigned short int u_16bit_t;
    typedef unsigned char u_8bit_t;

    typedef struct tcl_cmd_b {
      struct tcl_cmd_b *next;

      struct flag_record flags;
      char *func_name;              /* Proc name. */
      int hits;                     /* Number of times this proc was triggered. */
      u_8bit_t attributes;          /* Flags for this entry. TC_* */
    } tcl_cmd_t;


    typedef struct tcl_bind_mask_b {
      struct tcl_bind_mask_b *next;

      tcl_cmd_t *first;             /* List of commands registered for this bind. */
      char *mask;
      u_8bit_t flags;               /* Flags for this entry. TBM_*  */
    } tcl_bind_mask_t;

    typedef struct tcl_bind_list_b {
      struct tcl_bind_list_b *next;

      tcl_bind_mask_t *first;       /* Pointer to registered binds
                                     * for this list.               */
      char name[5];                 /* Name of the bind.            */
      u_8bit_t flags;               /* Flags for this element. HT_* */
      ::Function func;                /* Function used as the Tcl calling interface
                                     * for procs actually representing C functions. */
    } tcl_bind_list_t, *p_tcl_bind_list;

    typedef struct {
      char *name;
      char *flags;
      ::Function func;
      char *funcname;
    } cmd_t;



    /*** Prototypes ***/
    int  BindCommand(unsigned char table, cmd_t* cc, unsigned char bind);
    void PutServer(const char* text);
    void PutDCC(const int idx, const char* text);


#ifdef __cplusplus
}
#endif // __cplusplus

#endif // __HELLO_H__

Code:

/*
 * hello.c -- part of cpphello.mod
 *   
 * Example how to write an eggdrop module in C++
 *
 * Originally written by Kappa007         2006-01-21
 *
 *
 * Copyright (c) by Kappa007. All rights reserved.
 */

#define MODULE_NAME "CppHello"

#include "src/mod/module.h"
#include <stdlib.h>

#undef global

/*** Include your C++ exports here ***/
#include "hello.hpp"

static Function *global = NULL;

static int CppHello_expmem()
{
    return 0;
}

static void CppHello_report(int idx, int details)
{
    dprintf(idx, "%s running.", MODULE_NAME);
}

static char* CppHello_close()
{   
    ShutdownCppModule();

    module_undepend(MODULE_NAME);
    return NULL;
}

EXPORT_SCOPE char* CppHello_start();

static Function CppHello_table[] = {
  (Function) CppHello_start,
  (Function) CppHello_close,
  (Function) CppHello_expmem,
  (Function) CppHello_report,
};

char* CppHello_start(Function *global_funcs)
{
    global = global_funcs;
    module_register(MODULE_NAME, CppHello_table, 1, 0);

    //TODO: check module dependencies here

    // Call the "init" of your C++ code   
    InitCppModule();

    return NULL;
}


/*** wrapper functions ***/

int BindCommand(unsigned char table, cmd_t* cc, unsigned char bind)
{
    if (cc == NULL)
    {
        return -1;
    }
   
    // get the bind table
    p_tcl_bind_list H_temp;
    switch (table)
    {
        case 0:
            H_temp = find_bind_table("dcc");
            break;
        case 1:       
            H_temp = find_bind_table("msg");
            break;
        case 2:
            H_temp = find_bind_table("pub");
            break;
        default:
            return -1;
    }
    if (!H_temp) return -1;

    // add or remove commands
    if (bind != 0)
    {
        add_builtins(H_temp, cc);
    }
    else
    {
        rem_builtins(H_temp, cc);
    }
    return 0;
}


void PutServer(const char* text)
{
    dprintf(DP_SERVER, text);
}

void PutDCC(const int idx, const char* text)
{
    dprintf(idx, text);
}


Code:

/*
 * hello.hpp -- part of cpphello.mod
 *   
 * Example how to write an eggdrop module in C++
 *
 * Originally written by Kappa007         2006-01-21
 *
 *
 * Copyright (c) by Kappa007. All rights reserved.
 */

#ifndef __HELLO_HPP__
#define __HELLO_HPP__

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

void InitCppModule();
void ShutdownCppModule();


#ifdef __cplusplus
}
#endif // __cplusplus

#endif // __HELLO_HPP__

Code:

/*
 * hello.cpp -- part of cpphello.mod
 *   
 * Example how to write an eggdrop module in C++
 *
 * Originally written by Kappa007         2006-01-21
 *
 *
 * Copyright (c) by Kappa007. All rights reserved.
 */

#include "hello.h"
#include "hello.hpp"
#include <string>

using namespace std;

class  MyHelloClass;
static MyHelloClass*   myHelloClass = NULL;

int ChanHello(char *nick, char *host, char *hand, char *channel, char *text);

class MyHelloClass
{
    private:
        cmd_t*      myCommandTable;
        string      myReply;
    public:
        MyHelloClass(string aReply) :
          myCommandTable( NULL ),
          myReply( aReply )
        {
            myCommandTable = new cmd_t[2];
            myCommandTable[0].name       = "!hello";
            myCommandTable[0].flags      = "";
            myCommandTable[0].func       = reinterpret_cast<Function>(&ChanHello);
            myCommandTable[0].funcname   = NULL;
            memset(static_cast<void*>(&myCommandTable[1]), 0, sizeof(cmd_t));

            ::BindCommand(2, myCommandTable, true);
        }
        ~MyHelloClass()
        {
            ::BindCommand(2, myCommandTable, false);
            if (myCommandTable != NULL) delete[] myCommandTable;
        }
        string   Reply()
        {
            return myReply;
        }
};

void InitCppModule()
{
    myHelloClass = new MyHelloClass("Hello from C++!");
}

void ShutdownCppModule()
{
    if (myHelloClass != NULL)
    {
        delete myHelloClass;
    }
}

int ChanHello(char *nick, char *host, char *hand, char *channel, char *text)
{
    string aMsg = "";
    aMsg += "PRIVMSG ";
    aMsg += channel;
    aMsg += " :";
    aMsg += myHelloClass->Reply();
    PutServer( aMsg.c_str() );
    return 0;
}

Code:

# Makefile for src/mod/cpphello.mod/

srcdir = .

doofus:
   @echo ""
   @echo "Let's try this from the right directory..."
   @echo ""
   @cd ../../../ && make

static: ../cpphello.o

modules: ../../../cpphello.$(MOD_EXT)

../hello.o:
   $(CC) $(CFLAGS) $(CPPFLAGS) -DMAKING_MODS -c $(srcdir)/hello.c
   @rm -f ../hello.o
   mv hello.o ../

../hello_cpp.o:
   $(CC) $(CFLAGS) $(CPPFLAGS) -DMAKING_MODS -c $(srcdir)/hello.cpp -o $(srcdir)/hello_cpp.o
   @rm -f ../hello_cpp.o
   mv hello_cpp.o ../


../../../cpphello.$(MOD_EXT): \
   ../hello.o \
   ../hello_cpp.o
   $(LD) -o ../../../cpphello.$(MOD_EXT) ../hello.o ../hello_cpp.o -lstdc++ $(XLIBS) $(MODULE_XLIBS)
   $(STRIP) ../../../cpphello.$(MOD_EXT)

depend:
   $(CC) $(CFLAGS) $(CPPFLAGS) -MM $(srcdir)/cpphello.c > .depend

clean:
   @rm -f .depend *.o *.$(MOD_EXT) *~

distclean: clean

#safety hash
../cpphello.o: .././cpphello.mod/cpphello.c ../../../src/mod/module.h \
 ../../../src/main.h ../../../src/lang.h ../../../src/eggdrop.h \
 ../../../src/flags.h ../../../src/proto.h ../../../lush.h \
 ../../../src/misc_file.h ../../../src/cmdt.h ../../../src/tclegg.h \
 ../../../src/tclhash.h ../../../src/chan.h ../../../src/users.h \
 ../../../src/compat/compat.h ../../../src/compat/inet_aton.h \
 ../../../src/compat/snprintf.h \
 ../../../src/compat/memset.h ../../../src/compat/memcpy.h \
 ../../../src/compat/strcasecmp.h ../../../src/mod/modvals.h \
 ../../../src/tandem.h


Tested with eggdrop v1.6.17 and
Code:

$ uname -a
CYGWIN_NT-5.2 BETA 1.5.18(0.132/4/2) 2005-07-02 20:30 x86_64 unknown unknown Cygwin

$ gcc -v
Reading specs from /usr/lib/gcc/i686-pc-cygwin/3.4.4/specs
Configured with: /gcc/gcc-3.4.4/gcc-3.4.4-1/configure --verbose --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc --libdir=/usr/l
ib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-languages=c,ada,c++,d,f77,java,objc --enable-n
ls --without-included-gettext --enable-version-specific-runtime-libs --without-x --enable-libgcj --disable-java-awt --with-system-
zlib --enable-interpreter --disable-libgcj-debug --enable-threads=posix --enable-java-gc=boehm --disable-win32-registry --enable-s
jlj-exceptions --enable-hash-synchronization --enable-libstdcxx-debug : (reconfigured)
Thread model: posix
gcc version 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)



Have fun!


Regards,
Kappa007


Last edited by Kappa007 on Sun May 21, 2006 9:56 am; edited 3 times in total
Back to top
View user's profile Send private message
demond
Revered One


Joined: 12 Jun 2004
Posts: 3073
Location: San Francisco, CA

PostPosted: Fri Jan 20, 2006 11:50 pm    Post subject: Reply with quote

congratulations!

good job indeed
_________________
connection, sharing, dcc problems? click <here>
before asking for scripting help, read <this>
use [code] tag when posting logs, code
Back to top
View user's profile Send private message Visit poster's website
tulpik
Voice


Joined: 15 May 2006
Posts: 4

PostPosted: Mon May 15, 2006 7:38 am    Post subject: Compilation problems. Reply with quote

Hellow Kappa007, i am problem with compile example module.

Code:

gcc -pipe -fPIC -g -O2 -Wall -I. -I../../.. -I../../.. -I../../../src/mod -DHAVE_CONFIG_H   -DMAKING_MODS -c .././cpphello.mod/hello.c
In file included from ../cpphello.mod/hello.c:20:
../cpphello.mod/hello.hpp:20: error: syntax error before "InitCppModule"
../cpphello.mod/hello.hpp:20: warning: type defaults to `int' in declaration of `InitCppModule'
../cpphello.mod/hello.hpp:20: warning: data definition has no type or storage class
../cpphello.mod/hello.hpp:21: error: syntax error before "ShutdownCppModule"
../cpphello.mod/hello.hpp:21: warning: type defaults to `int' in declaration of `ShutdownCppModule'
../cpphello.mod/hello.hpp:21: warning: data definition has no type or storage class
make[2]: *** [../hello.o] Error 1
make[2]: Leaving directory `/home/gimper/downloads/eggdrop/src/mod/cpphello.mod'
make[1]: *** [cpphello.mod_so] Error 2
make[1]: Leaving directory `/home/gimper/downloads/eggdrop/src/mod'
make: *** [modules] Error 2


Please pack your code to zip archive and share it. Thanx!


tulpik
Back to top
View user's profile Send private message
De Kus
Revered One


Joined: 15 Dec 2002
Posts: 1361
Location: Germany

PostPosted: Mon May 15, 2006 7:57 am    Post subject: Reply with quote

the errors occur in
Code:
void __stdcall InitCppModule();
void __stdcall ShutdownCppModule();

seems they don't like the __stdcall, maybe its not defined. missing a header file?
_________________
De Kus
StarZ|De_Kus, De_Kus or DeKus on IRC
Copyright 2005-2009 by De Kus - published under The MIT License
Love hurts, love strengthens...
Back to top
View user's profile Send private message MSN Messenger
tulpik
Voice


Joined: 15 May 2006
Posts: 4

PostPosted: Mon May 15, 2006 8:05 am    Post subject: Reply with quote

What header file? hello.h? No, I copy code form web to files.
Back to top
View user's profile Send private message
De Kus
Revered One


Joined: 15 Dec 2002
Posts: 1361
Location: Germany

PostPosted: Mon May 15, 2006 8:10 am    Post subject: Reply with quote

No idea, you can look up yourself, I don't have the time for this:
http://www.google.com/search?q=__stdcall+%22syntax+error+before%22
_________________
De Kus
StarZ|De_Kus, De_Kus or DeKus on IRC
Copyright 2005-2009 by De Kus - published under The MIT License
Love hurts, love strengthens...
Back to top
View user's profile Send private message MSN Messenger
tulpik
Voice


Joined: 15 May 2006
Posts: 4

PostPosted: Mon May 15, 2006 8:19 am    Post subject: Reply with quote

Lol Smile

Btw, probaly nothing.
Back to top
View user's profile Send private message
Alchera
Revered One


Joined: 11 Aug 2003
Posts: 3344
Location: Ballarat Victoria, Australia

PostPosted: Mon May 15, 2006 7:29 pm    Post subject: Reply with quote

tulpik wrote:
What header file? hello.h? No, I copy code form web to files.

Did you correctly name the sections (posted above)? There's 5 files in total, not one.

i.e. hello.h hello.c hello.hpp hello.cpp and finally the makefile

Do you know what a header file is?
_________________
Add [SOLVED] to the thread title if your issue has been.
Search | FAQ | RTM
Back to top
View user's profile Send private message Visit poster's website
tulpik
Voice


Joined: 15 May 2006
Posts: 4

PostPosted: Tue May 16, 2006 4:06 am    Post subject: Reply with quote

Yes I create 5 files with Makefile.
Back to top
View user's profile Send private message
Kappa007
Voice


Joined: 26 Jul 2005
Posts: 38

PostPosted: Thu May 18, 2006 5:57 pm    Post subject: Reply with quote

Yes cut the __stdcall, it's not needed.
__stdcall is the calling-convention of the Win32 API it's usually not used on *nix/g++

Only appeared there cause I used cygwin...
Back to top
View user's profile Send private message
De Kus
Revered One


Joined: 15 Dec 2002
Posts: 1361
Location: Germany

PostPosted: Fri May 19, 2006 8:02 pm    Post subject: Reply with quote

then add define to zero string for __stdcall, if its not compiling on win32 Very Happy.
_________________
De Kus
StarZ|De_Kus, De_Kus or DeKus on IRC
Copyright 2005-2009 by De Kus - published under The MIT License
Love hurts, love strengthens...
Back to top
View user's profile Send private message MSN Messenger
Kappa007
Voice


Joined: 26 Jul 2005
Posts: 38

PostPosted: Sun May 21, 2006 9:58 am    Post subject: Reply with quote

Edited the code (removed the __stdcall). Should work now.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    egghelp.org community Forum Index -> Modules & Programming All times are GMT - 4 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Forum hosting provided by Reverse.net

Powered by phpBB © 2001, 2005 phpBB Group
subGreen style by ktauber