diff --git a/.gitignore b/.gitignore index e05a551..721dcf9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ Session.vim cscope.out build/ .sconsign.dblite +*.os +*.pyc diff --git a/.travis.yml b/.travis.yml index 1458ecd..8c5af52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,27 @@ language: c compiler: - gcc - clang +env: + - BINDINGS=none +matrix: + include: + - compiler: gcc + language: python + python: 2.7 + env: BINDINGS=python + - compiler: clang + language: python + python: 2.7 + env: BINDINGS=python +before_install: + - sudo apt-get update -qq + - if [ "$BINDINGS" == "python" ]; then sudo apt-get install -qq swig python-dev; fi script: - - scons + - scons bindings=$BINDINGS test notifications: - irc: "irc.upstandinghackers.com#hammer" + irc: + channels: + - "irc.upstandinghackers.com#hammer" + use_notice: true + skip_join: true + diff --git a/SConstruct b/SConstruct index 623bc5d..e30f6df 100644 --- a/SConstruct +++ b/SConstruct @@ -7,8 +7,12 @@ import sys vars = Variables(None, ARGUMENTS) vars.Add(PathVariable('DESTDIR', "Root directory to install in (useful for packaging scripts)", None, PathVariable.PathIsDirCreate)) vars.Add(PathVariable('prefix', "Where to install in the FHS", "/usr/local", PathVariable.PathAccept)) +vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['python'])) -env = Environment(ENV = {'PATH' : os.environ['PATH']}, variables = vars) +env = Environment(ENV = {'PATH' : os.environ['PATH']}, variables = vars, tools=['default', 'scanreplace'], toolpath=['tools']) + +if not 'bindings' in env: + env['bindings'] = [] def calcInstallPath(*elements): path = os.path.abspath(os.path.join(*map(env.subst, elements))) @@ -28,11 +32,16 @@ if 'DESTDIR' in env: env['libpath'] = calcInstallPath("$prefix", "lib") env['incpath'] = calcInstallPath("$prefix", "include", "hammer") -# TODO: Add pkgconfig +env['parsersincpath'] = calcInstallPath("$prefix", "include", "hammer", "parsers") +env['backendsincpath'] = calcInstallPath("$prefix", "include", "hammer", "backends") +env['pkgconfigpath'] = calcInstallPath("$prefix", "lib", "pkgconfig") +env.ScanReplace('libhammer.pc.in') env.MergeFlags("-std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-attributes") -if not env['PLATFORM'] == 'darwin': +if env['PLATFORM'] == 'darwin': + env.Append(SHLINKFLAGS = ['-install_name', '$TARGET']) +else: env.MergeFlags("-lrt") AddOption("--variant", @@ -49,7 +58,12 @@ AddOption("--coverage", action="store_true", help="Build with coverage instrumentation") -env['BUILDDIR'] = 'build/$VARIANT' +AddOption("--in-place", + dest="in_place", + default=False, + action="store_true", + help="Build in-place, rather than in the build/ tree") + dbg = env.Clone(VARIANT='debug') dbg.Append(CCFLAGS=['-g']) @@ -68,19 +82,38 @@ if GetOption("coverage"): LDFLAGS=["-fprofile-arcs", "-ftest-coverage"], LIBS=['gcov']) +env["CC"] = os.getenv("CC") or env["CC"] +env["CXX"] = os.getenv("CXX") or env["CXX"] + if os.getenv("CC") == "clang" or env['PLATFORM'] == 'darwin': env.Replace(CC="clang", CXX="clang++") +env["ENV"].update(x for x in os.environ.items() if x[0].startswith("CCC_")) + #rootpath = env['ROOTPATH'] = os.path.abspath('.') #env.Append(CPPPATH=os.path.join('#', "hammer")) +testruns = [] + Export('env') +Export('testruns') -env.SConscript(["src/SConscript"], variant_dir='build/$VARIANT/src') -env.SConscript(["examples/SConscript"], variant_dir='build/$VARIANT/examples') +if not GetOption("in_place"): + env['BUILD_BASE'] = 'build/$VARIANT' + lib = env.SConscript(["src/SConscript"], variant_dir='$BUILD_BASE/src') + env.Alias("examples", env.SConscript(["examples/SConscript"], variant_dir='$BUILD_BASE/examples')) +else: + env['BUILD_BASE'] = '.' + lib = env.SConscript(["src/SConscript"]) + env.Alias(env.SConscript(["examples/SConscript"])) -env.Command('test', 'build/$VARIANT/src/test_suite', 'env LD_LIBRARY_PATH=build/$VARIANT/src $SOURCE') +#env.Command('test', '$BUILD_BASE/src/test_suite', 'env LD_LIBRARY_PATH=$BUILD_BASE/src $SOURCE') + +env.Alias("test", testruns) env.Alias("install", "$libpath") env.Alias("install", "$incpath") +env.Alias("install", "$parsersincpath") +env.Alias("install", "$backendsincpath") +env.Alias("install", "$pkgconfigpath") diff --git a/examples/base64_sem1.c b/examples/base64_sem1.c index 46e58da..4da171f 100644 --- a/examples/base64_sem1.c +++ b/examples/base64_sem1.c @@ -23,7 +23,7 @@ // They must be named act_. /// -HParsedToken *act_bsfdig(const HParseResult *p) +HParsedToken *act_bsfdig(const HParseResult *p, void* user_data) { HParsedToken *res = H_MAKE_UINT(0); @@ -54,7 +54,7 @@ H_ACT_APPLY(act_index0, h_act_index, 0); #define act_document act_index0 // General-form action to turn a block of base64 digits into bytes. -HParsedToken *act_base64_n(int n, const HParseResult *p) +HParsedToken *act_base64_n(int n, const HParseResult *p, void* user_data) { HParsedToken *res = H_MAKE_SEQN(n); @@ -83,7 +83,7 @@ H_ACT_APPLY(act_base64_3, act_base64_n, 3); H_ACT_APPLY(act_base64_2, act_base64_n, 2); H_ACT_APPLY(act_base64_1, act_base64_n, 1); -HParsedToken *act_base64(const HParseResult *p) +HParsedToken *act_base64(const HParseResult *p, void* user_data) { assert(p->ast->token_type == TT_SEQUENCE); assert(p->ast->seq->used == 2); diff --git a/examples/base64_sem2.c b/examples/base64_sem2.c index 84155da..b7a2263 100644 --- a/examples/base64_sem2.c +++ b/examples/base64_sem2.c @@ -49,7 +49,7 @@ uint8_t bsfdig_value(const HParsedToken *p) // helper: append a byte value to a sequence #define seq_append_byte(res, b) h_seq_snoc(res, H_MAKE_UINT(b)) -HParsedToken *act_base64(const HParseResult *p) +HParsedToken *act_base64(const HParseResult *p, void* user_data) { assert(p->ast->token_type == TT_SEQUENCE); assert(p->ast->seq->used == 2); diff --git a/examples/dns.c b/examples/dns.c index 3f730b9..63df3a4 100644 --- a/examples/dns.c +++ b/examples/dns.c @@ -15,7 +15,7 @@ // Validations /// -bool validate_hdzero(HParseResult *p) { +bool validate_hdzero(HParseResult *p, void* user_data) { if (TT_UINT != p->ast->token_type) return false; return (0 == p->ast->uint); @@ -25,7 +25,7 @@ bool validate_hdzero(HParseResult *p) { * Every DNS message should have QDCOUNT entries in the question * section, and ANCOUNT+NSCOUNT+ARCOUNT resource records. */ -bool validate_message(HParseResult *p) { +bool validate_message(HParseResult *p, void* user_data) { if (TT_SEQUENCE != p->ast->token_type) return false; @@ -86,7 +86,7 @@ void set_rdata(struct dns_rr *rr, HCountedArray *rdata) { } } -HParsedToken* act_header(const HParseResult *p) { +HParsedToken* act_header(const HParseResult *p, void* user_data) { HParsedToken **fields = h_seq_elements(p->ast); dns_header_t header_ = { .id = H_CAST_UINT(fields[0]), @@ -109,7 +109,7 @@ HParsedToken* act_header(const HParseResult *p) { return H_MAKE(dns_header_t, header); } -HParsedToken* act_label(const HParseResult *p) { +HParsedToken* act_label(const HParseResult *p, void* user_data) { dns_label_t *r = H_ALLOC(dns_label_t); r->len = h_seq_len(p->ast); @@ -121,7 +121,7 @@ HParsedToken* act_label(const HParseResult *p) { return H_MAKE(dns_label_t, r); } -HParsedToken* act_rr(const HParseResult *p) { +HParsedToken* act_rr(const HParseResult *p, void* user_data) { dns_rr_t *rr = H_ALLOC(dns_rr_t); rr->name = *H_FIELD(dns_domain_t, 0); @@ -136,7 +136,7 @@ HParsedToken* act_rr(const HParseResult *p) { return H_MAKE(dns_rr_t, rr); } -HParsedToken* act_question(const HParseResult *p) { +HParsedToken* act_question(const HParseResult *p, void* user_data) { dns_question_t *q = H_ALLOC(dns_question_t); HParsedToken **fields = h_seq_elements(p->ast); @@ -153,7 +153,7 @@ HParsedToken* act_question(const HParseResult *p) { return H_MAKE(dns_question_t, q); } -HParsedToken* act_message(const HParseResult *p) { +HParsedToken* act_message(const HParseResult *p, void* user_data) { h_pprint(stdout, p->ast, 0, 2); dns_message_t *msg = H_ALLOC(dns_message_t); diff --git a/examples/dns_common.c b/examples/dns_common.c index 01dd8f0..bf934d6 100644 --- a/examples/dns_common.c +++ b/examples/dns_common.c @@ -10,7 +10,7 @@ H_ACT_APPLY(act_index0, h_act_index, 0) /** * A label can't be more than 63 characters. */ -bool validate_label(HParseResult *p) { +bool validate_label(HParseResult *p, void* user_data) { if (TT_SEQUENCE != p->ast->token_type) return false; return (64 > p->ast->seq->used); @@ -18,7 +18,7 @@ bool validate_label(HParseResult *p) { #define act_label h_act_flatten -HParsedToken* act_domain(const HParseResult *p) { +HParsedToken* act_domain(const HParseResult *p, void* user_data) { HParsedToken *ret = NULL; char *arr = NULL; diff --git a/examples/dns_common.h b/examples/dns_common.h index 8af014b..3e30770 100644 --- a/examples/dns_common.h +++ b/examples/dns_common.h @@ -7,6 +7,6 @@ HParser* init_domain(); HParser* init_character_string(); -HParsedToken* act_index0(const HParseResult *p); +HParsedToken* act_index0(const HParseResult *p, void* user_data); #endif diff --git a/examples/rr.c b/examples/rr.c index dd25063..c179922 100644 --- a/examples/rr.c +++ b/examples/rr.c @@ -11,13 +11,13 @@ // Validations and Semantic Actions /// -bool validate_null(HParseResult *p) { +bool validate_null(HParseResult *p, void* user_data) { if (TT_SEQUENCE != p->ast->token_type) return false; return (65536 > p->ast->seq->used); } -HParsedToken *act_null(const HParseResult *p) { +HParsedToken *act_null(const HParseResult *p, void* user_data) { dns_rr_null_t *null = H_ALLOC(dns_rr_null_t); size_t len = h_seq_len(p->ast); @@ -28,7 +28,7 @@ HParsedToken *act_null(const HParseResult *p) { return H_MAKE(dns_rr_null_t, null); } -HParsedToken *act_txt(const HParseResult *p) { +HParsedToken *act_txt(const HParseResult *p, void* user_data) { dns_rr_txt_t *txt = H_ALLOC(dns_rr_txt_t); const HCountedArray *arr = H_CAST_SEQ(p->ast); @@ -47,7 +47,7 @@ HParsedToken *act_txt(const HParseResult *p) { return H_MAKE(dns_rr_txt_t, txt); } -HParsedToken* act_cstr(const HParseResult *p) { +HParsedToken* act_cstr(const HParseResult *p, void* user_data) { dns_cstr_t *cs = H_ALLOC(dns_cstr_t); const HCountedArray *arr = H_CAST_SEQ(p->ast); @@ -60,7 +60,7 @@ HParsedToken* act_cstr(const HParseResult *p) { return H_MAKE(dns_cstr_t, cs); } -HParsedToken* act_soa(const HParseResult *p) { +HParsedToken* act_soa(const HParseResult *p, void* user_data) { dns_rr_soa_t *soa = H_ALLOC(dns_rr_soa_t); soa->mname = *H_FIELD(dns_domain_t, 0); @@ -74,7 +74,7 @@ HParsedToken* act_soa(const HParseResult *p) { return H_MAKE(dns_rr_soa_t, soa); } -HParsedToken* act_wks(const HParseResult *p) { +HParsedToken* act_wks(const HParseResult *p, void* user_data) { dns_rr_wks_t *wks = H_ALLOC(dns_rr_wks_t); wks->address = H_FIELD_UINT(0); @@ -87,7 +87,7 @@ HParsedToken* act_wks(const HParseResult *p) { return H_MAKE(dns_rr_wks_t, wks); } -HParsedToken* act_hinfo(const HParseResult *p) { +HParsedToken* act_hinfo(const HParseResult *p, void* user_data) { dns_rr_hinfo_t *hinfo = H_ALLOC(dns_rr_hinfo_t); hinfo->cpu = *H_FIELD(dns_cstr_t, 0); @@ -96,7 +96,7 @@ HParsedToken* act_hinfo(const HParseResult *p) { return H_MAKE(dns_rr_hinfo_t, hinfo); } -HParsedToken* act_minfo(const HParseResult *p) { +HParsedToken* act_minfo(const HParseResult *p, void* user_data) { dns_rr_minfo_t *minfo = H_ALLOC(dns_rr_minfo_t); minfo->rmailbx = *H_FIELD(dns_domain_t, 0); @@ -105,7 +105,7 @@ HParsedToken* act_minfo(const HParseResult *p) { return H_MAKE(dns_rr_minfo_t, minfo); } -HParsedToken* act_mx(const HParseResult *p) { +HParsedToken* act_mx(const HParseResult *p, void* user_data) { dns_rr_mx_t *mx = H_ALLOC(dns_rr_mx_t); mx->preference = H_FIELD_UINT(0); @@ -184,7 +184,7 @@ HParser* init_rdata(uint16_t type) { for(uint16_t i = 0; i