Hey,

        I got fed up with having to define each hook in two different places
in four different ways, so I wrote a little tool to generate them all for
me, based on their names. I thought I'd share the result with you all. It's
probably more lines of code than if I had just manually defined each hook,
but the more hooks I add to my app, the more of a gain this will be. :)

        Cheers,
                Tyler

#ifndef LIBBTPEER_HOOK_H
#define LIBBTPEER_HOOK_H

#include <apr.h>
#include <apr_hooks.h>

#define BTP_DECLARE(type)            type
#define BTP_DECLARE_NONSTD(type)     type
#define BTP_DECLARE_DATA

#define BTP_DECLARE_HOOK(ret,name,args) \
	APR_DECLARE_EXTERNAL_HOOK(btp,BTP,ret,name,args)

#define BTP_IMPLEMENT_HOOK_RUN_ALL(ret,name,args_decl,args_use,ok,decline) \
	APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(btp,BTP,ret,name,args_decl, \
                                            args_use,ok,decline)


#endif /* LIBBTPEER_HOOK_H */
DYN=hook.c hook.h const.h peer_command.c peer_command.h

noinst_PROGRAMS = mkpeerhooks

AM_CPPFLAGS=-I$(top_srcdir)/src

noinst_LTLIBRARIES = libhooks.la
libhooks_la_SOURCES = hook.c peer_command.c

hook.c: hook.h const.h

peer_command.c: peer_command.h

$(DYN): mkpeerhooks
        ./mkpeerhooks $@ > $@

clean-local:
        rm -f $(DYN)
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <ctype.h>

/* command_s must come first because they are part of the bittorrent protocol,
 * and we map protocol input directly to them.
 */
#define BTP_PEER_COMMANDS   9

#define HOOK_RET "apr_status_t"
#define HOOK_DECL "(btp_torrent* t, btp_peer* p, void* app_data)"
 
const char *hook_names[] = {
    "peer_command_choke",            /*0*/
    "peer_command_unchoke",          /*1*/
    "peer_command_interested",       /*2*/
    "peer_command_uninterested",     /*3*/
    "peer_command_have",             /*4*/
    "peer_command_bitfield",         /*5*/
    "peer_command_request",          /*6*/
    "peer_command_piece",            /*7*/
    "peer_command_cancel",           /*8*/
    "metainfo_sha1",
    "torrent_announce",
    NULL
};

static inline char* toup(const char* down) {
    int i = strlen(down);
    int j = 0;
    char* s = malloc(i+1);
    
    for(;j<i;j++) {
        s[j]=toupper(down[j]);
        if(s[j] == '.')
            s[j] = '_';
    }
    
    s[j]=0;
    
    return s;
}

static inline void header(const char* f) {
    printf(
        "/* This file was auto-generated by mkpeerhooks.c "VERSION" */\n\n"
        "#ifndef LIBBTPEER_HOOKS_%s\n#define LIBBTPEER_HOOKS_%s\n\n",
        f, f
    );
    return;
}

static inline void footer(const char* f) {
    printf("\n#endif /* LIBBTPEER_HOOKS_%s */\n\n", f);
}

static inline void includes() {
    puts(
        "#include <apr.h>\n"
        "#include <apr_errno.h>\n\n"
        "#include <stdint.h>\n\n"
        "#include <libbtpeer/hook.h>\n"
        "#include <libbtpeer/types/btp_torrent.h>\n"
        "#include <libbtpeer/types/btp_peer.h>\n\n"
    );
    
    return;
}



static inline void const_h() {
    int i;
    
    includes();
    
    printf("#define BTP_PEER_COMMANDS %i\n", BTP_PEER_COMMANDS);
    printf("typedef %s (*btp_hook) %s;\n", HOOK_RET, HOOK_DECL);

    for(i=0;hook_names[i];i++)
        printf("#define BTP_%s %i\n", toup(hook_names[i]), i);
    
    
    return;
}


static inline void hook_h() {
    int i;
    
    includes();
    
    for(i=0;hook_names[i];i++) 
        printf(
            "BTP_DECLARE_HOOK(\n"
            "    "HOOK_RET",\n"
            "    %s,\n"
            "    "HOOK_DECL"\n"
            ")\n"
            "\n",
            hook_names[i]
        );
    
    return;
}

static inline void hook_c() {   
    int i;
    
    includes();
    
    puts(
        "#include <libbtpeer/hooks/hook.h>\n"
        "APR_HOOK_STRUCT(\n"
    );
    
    for(i=0;hook_names[i];i++)
        printf("    APR_HOOK_LINK(%s)\n", hook_names[i]);
    
    puts(")\n\n");
    
    for(i=0;hook_names[i];i++)
        printf(
            "BTP_IMPLEMENT_HOOK_RUN_ALL(\n"
            "    "HOOK_RET", %s,\n"
            "    "HOOK_DECL",\n"
            "    (t, p, app_data),\n"
            "    APR_SUCCESS, APR_EAGAIN\n"
            ")\n\n",
            hook_names[i]
        );
    
    return;
}

static inline void peer_command_h() {
    puts(
        "#include <libbtpeer/hooks/const.h>\n"
        "#include <libbtpeer/hooks/hook.h>\n"
        "extern "
        HOOK_RET
        " btp_run_command(uint8_t cmd, btp_torrent* t, "
        "btp_peer* p, void* app_data);\n\n"
    );
    
    
}

static inline void peer_command_c() {
    int i;
    
    includes();
    
    puts(
        "#include <libbtpeer/hooks/const.h>\n"
        "#include <libbtpeer/hooks/hook.h>\n"
        "#include <libbtpeer/hooks/peer_command.h>\n\n"
        "static const btp_hook commands[] = {\n"
    );
    
    for(i=0;i<BTP_PEER_COMMANDS;i++) {
        printf("    btp_run_%s", hook_names[i]);
        if(i != BTP_PEER_COMMANDS - 1)
            putchar(',');
        putchar('\n');
    }
    
    puts(
        "};\n\n"
        HOOK_RET
        " btp_run_command(uint8_t cmd, btp_torrent* t, btp_peer* p, "
        "void* app_data) {\n"
        "    if(cmd > BTP_PEER_COMMANDS)\n"
        "        return APR_EINVAL;\n"
        "    else\n"
        "        return commands[cmd](t, p, app_data);\n"
        "}\n\n"
    );
    
    return;
}

int main(int argc, char** argv) {
    if(argc > 1) {
        const char* file = argv[1];
        const char* ufile = toup(file);
    
        header(ufile);
    
        if(!strcmp(file, "const.h"))
            const_h();
        else if(!strcmp(file, "peer_command.c"))
            peer_command_c();
        else if(!strcmp(file, "peer_command.h"))
            peer_command_h();
        else if(!strcmp(file, "hook.h"))
            hook_h();
        else if(!strcmp(file, "hook.c"))
            hook_c();
        else
            exit(1);

        footer(ufile);
        exit(0);
    } else {
        exit(1);
    }
}

Reply via email to