Skip to content

Commit

Permalink
feat(c+go): implement API for obtaining the total number of rules
Browse files Browse the repository at this point in the history
Implements the new function `yrx_rules_count()` in the C API, and the new method `Rules.Count()` in the Golang API.
  • Loading branch information
plusvic committed Sep 12, 2024
1 parent f5a8b94 commit 441f4ed
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 7 deletions.
5 changes: 5 additions & 0 deletions capi/include/yara_x.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ enum YRX_RESULT yrx_rules_iterate(struct YRX_RULES *rules,
YRX_RULE_CALLBACK callback,
void *user_data);

// Returns the total number of rules.
//
// Returns -1 in case of error.
int yrx_rules_count(struct YRX_RULES *rules);

// Destroys a [`YRX_RULES`] object.
void yrx_rules_destroy(struct YRX_RULES *rules);

Expand Down
18 changes: 15 additions & 3 deletions capi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ cargo cinstall -p yara-x-capi --release
The command above will put the library and header files in the correct path
in your system (usually `/usr/local/lib` and `/usr/local/include` for Linux
and MacOS users), and will generate a `.pc` file so that `pkg-config` knows
and macOS users), and will generate a `.pc` file so that `pkg-config` knows
about the library.
In Linux and MacOS you can check if everything went fine by compiling a simple
In Linux and macOS you can check if everything went fine by compiling a simple
test program, like this:
```text
Expand Down Expand Up @@ -94,7 +94,7 @@ includes:
#![allow(clippy::not_unsafe_ptr_arg_deref)]

use std::cell::RefCell;
use std::ffi::{c_char, c_void, CStr, CString};
use std::ffi::{c_char, c_int, c_void, CStr, CString};
use std::mem::ManuallyDrop;
use std::ptr::slice_from_raw_parts_mut;
use std::slice;
Expand Down Expand Up @@ -432,6 +432,18 @@ pub unsafe extern "C" fn yrx_rules_iterate(
}
}

/// Returns the total number of rules.
///
/// Returns -1 in case of error.
#[no_mangle]
pub unsafe extern "C" fn yrx_rules_count(rules: *mut YRX_RULES) -> c_int {
if let Some(rules) = rules.as_ref() {
rules.0.iter().len() as c_int
} else {
-1
}
}

/// Destroys a [`YRX_RULES`] object.
#[no_mangle]
pub unsafe extern "C" fn yrx_rules_destroy(rules: *mut YRX_RULES) {
Expand Down
10 changes: 6 additions & 4 deletions go/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,13 @@ func TestRulesIter(t *testing.T) {
c.AddSource("rule test_2 { condition: true }")
assert.NoError(t, err)

rules := c.Build().Slice()
rules := c.Build()
assert.Equal(t, 2, rules.Count())

assert.Len(t, rules, 2)
assert.Equal(t, rules[0].Identifier(), "test_1")
assert.Equal(t, rules[1].Identifier(), "test_2")
slice := rules.Slice()
assert.Len(t, slice, 2)
assert.Equal(t, "test_1", slice[0].Identifier())
assert.Equal(t, "test_2", slice[1].Identifier())
}

func TestWarnings(t *testing.T) {
Expand Down
9 changes: 9 additions & 0 deletions go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ func (r *Rules) Slice() []*Rule {
return rules
}

// Count returns the total number of rules.
//
// This is more a more efficient alternative to len(rules.Slice()).
func (r *Rules) Count() int {
count := C.yrx_rules_count(r.cRules)
runtime.KeepAlive(r)
return int(count)
}

// Rule represents a YARA rule.
type Rule struct {
namespace string
Expand Down

0 comments on commit 441f4ed

Please sign in to comment.