diff --git a/src/Type.cc b/src/Type.cc index 810a08b443..85e057137f 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -900,6 +900,45 @@ void RecordType::Describe(ODesc* d) const } } +const char* RecordType::AddFields(type_decl_list* others, attr_list* attr) + { + assert(types); + + bool log = false; + + if ( attr ) + { + loop_over_list(*attr, j) + { + if ( (*attr)[j]->Tag() == ATTR_LOG ) + log = true; + } + } + + loop_over_list(*others, i) + { + TypeDecl* td = (*others)[i]; + + if ( ! td->FindAttr(ATTR_DEFAULT) && ! td->FindAttr(ATTR_OPTIONAL) ) + return "extension field must be &optional or have &default"; + + if ( log ) + { + if ( ! td->attrs ) + td->attrs = new Attributes(new attr_list, td->type); + + td->attrs->AddAttr(new Attr(ATTR_LOG)); + } + + types->append(td); + } + + delete others; + + num_fields = types->length(); + return 0; + } + void RecordType::DescribeFields(ODesc* d) const { if ( d->IsReadable() ) diff --git a/src/Type.h b/src/Type.h index b93fcaa6d7..eccfecb89e 100644 --- a/src/Type.h +++ b/src/Type.h @@ -437,6 +437,10 @@ public: int NumFields() const { return num_fields; } + // Returns 0 if all is ok, otherwise a pointer to an error message. Takes + // ownership of list. + const char* AddFields(type_decl_list* types, attr_list* attr); + void Describe(ODesc* d) const; void DescribeFields(ODesc* d) const; diff --git a/src/parse.y b/src/parse.y index 18ccfff202..15d75341a1 100644 --- a/src/parse.y +++ b/src/parse.y @@ -862,7 +862,25 @@ decl: '{' { parser_redef_enum($3); } enum_body '}' ';' { /* no action */ } - | TOK_TYPE def_global_id ':' refined_type opt_attr ';' + | TOK_REDEF TOK_RECORD global_id TOK_ADD_TO + '{' type_decl_list '}' opt_attr ';' + { + if ( ! $3->Type() ) + $3->Error("unknown identifier"); + else + { + RecordType* add_to = $3->Type()->AsRecordType(); + if ( ! add_to ) + $3->Error("not a record type"); + else { + const char* error = add_to->AddFields($6, $8); + if ( error ) + $3->Error(error); + } + } + } + + | TOK_TYPE global_id ':' refined_type opt_attr ';' { add_type($2, $4, $5, 0); } diff --git a/testing/btest/Baseline/logging.attr-extend/ssh.log b/testing/btest/Baseline/logging.attr-extend/ssh.log new file mode 100644 index 0000000000..d543af3a43 --- /dev/null +++ b/testing/btest/Baseline/logging.attr-extend/ssh.log @@ -0,0 +1,2 @@ +# status country a1 b1 b2 +success unknown 1 3 4 diff --git a/testing/btest/logging/attr-extend.bro b/testing/btest/logging/attr-extend.bro index f6964a749e..4d7e96b98e 100644 --- a/testing/btest/logging/attr-extend.bro +++ b/testing/btest/logging/attr-extend.bro @@ -15,14 +15,14 @@ export { }; } -redef Log += record { - a1: count &log; - a2: count; +redef record Log += { + a1: count &log &optional; + a2: count &optional; }; -redef Log += record { - b1: count; - b2: count; +redef record Log += { + b1: count &optional; + b2: count &optional; } &log; @@ -32,6 +32,6 @@ event bro_init() local cid = [$orig_h=1.2.3.4, $orig_p=1234/tcp, $resp_h=2.3.4.5, $resp_p=80/tcp]; - Log::write(SSH, [$t=network_time(), $id=cid, $status="success", a1=1, a2=2, a3=3, a4=4]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="success", $a1=1, $a2=2, $b1=3, $b2=4]); } diff --git a/testing/rec.bro b/testing/rec.bro new file mode 100644 index 0000000000..904edd4e8c --- /dev/null +++ b/testing/rec.bro @@ -0,0 +1,17 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count &default=42; + d: count &optional; +}; + +global f: Foo = [$a=21]; + +print f; + diff --git a/testing/rec2.bro b/testing/rec2.bro new file mode 100644 index 0000000000..c8324ae577 --- /dev/null +++ b/testing/rec2.bro @@ -0,0 +1,17 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count &default=42; + d: string &optional; +}; + +global f: Foo = [$a=21, $d="XXX"]; + +print f; + diff --git a/testing/wrong-rec.bro b/testing/wrong-rec.bro new file mode 100644 index 0000000000..e5f553bf45 --- /dev/null +++ b/testing/wrong-rec.bro @@ -0,0 +1,13 @@ +# @TEST-EXEC-FAIL: bro %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count; + d: string &optional; +}; +