This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

Example: Module in C++

Discussion of Eggdrop's code and module programming in C.
Post Reply
K
Kappa007
Voice
Posts: 38
Joined: Tue Jul 26, 2005 9:53 pm

Example: Module in C++

Post by Kappa007 »

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

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 ;)


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

Code: Select all

/*
 * 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: Select all

/*
 * 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: Select all

/*
 * 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: Select all

/*
 * 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: Select all

# 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: Select all

$ 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.
User avatar
demond
Revered One
Posts: 3073
Joined: Sat Jun 12, 2004 9:58 am
Location: San Francisco, CA
Contact:

Post by demond »

congratulations!

good job indeed
connection, sharing, dcc problems? click <here>
before asking for scripting help, read <this>
use

Code: Select all

 tag when posting logs, code
t
tulpik
Voice
Posts: 4
Joined: Mon May 15, 2006 7:34 am

Compilation problems.

Post by tulpik »

Hellow Kappa007, i am problem with compile example module.

Code: Select all

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
User avatar
De Kus
Revered One
Posts: 1361
Joined: Sun Dec 15, 2002 11:41 am
Location: Germany

Post by De Kus »

the errors occur in

Code: Select all

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...
t
tulpik
Voice
Posts: 4
Joined: Mon May 15, 2006 7:34 am

Post by tulpik »

What header file? hello.h? No, I copy code form web to files.
User avatar
De Kus
Revered One
Posts: 1361
Joined: Sun Dec 15, 2002 11:41 am
Location: Germany

Post by De Kus »

No idea, you can look up yourself, I don't have the time for this:
http://www.google.com/search?q=__stdcal ... +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...
t
tulpik
Voice
Posts: 4
Joined: Mon May 15, 2006 7:34 am

Post by tulpik »

Lol :)

Btw, probaly nothing.
User avatar
Alchera
Revered One
Posts: 3344
Joined: Mon Aug 11, 2003 12:42 pm
Location: Ballarat Victoria, Australia
Contact:

Post by Alchera »

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
t
tulpik
Voice
Posts: 4
Joined: Mon May 15, 2006 7:34 am

Post by tulpik »

Yes I create 5 files with Makefile.
K
Kappa007
Voice
Posts: 38
Joined: Tue Jul 26, 2005 9:53 pm

Post by Kappa007 »

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...
User avatar
De Kus
Revered One
Posts: 1361
Joined: Sun Dec 15, 2002 11:41 am
Location: Germany

Post by De Kus »

then add define to zero string for __stdcall, if its not compiling on win32 :D.
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...
K
Kappa007
Voice
Posts: 38
Joined: Tue Jul 26, 2005 9:53 pm

Post by Kappa007 »

Edited the code (removed the __stdcall). Should work now.
Post Reply