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