Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions xff/fields/fields.cc
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,15 @@ std::string EnvField(std::string_view key, std::string_view, const RenderContext
return value == nullptr ? "" : value;
}

// Renders {def.NAME}: `key` is NAME; the --define value, or empty when undefined.
std::string DefField(std::string_view key, std::string_view, const RenderContext& ctx) {
if (ctx.defines == nullptr) {
return "";
}
const auto it = ctx.defines->find(std::string(key));
return it == ctx.defines->end() ? "" : it->second;
}

// Resolves a placeholder name to a renderer and its bound key: a numeric
// {0}..{N} -> a regex capture; the {env.NAME} namespace -> the environment;
// otherwise a builtin field from the table (empty key). New namespaces
Expand All @@ -300,6 +309,9 @@ std::pair<detail::FieldFn, std::string> ResolveName(std::string_view name) {
if (name.starts_with("env.")) {
return {&EnvField, std::string(name.substr(4))};
}
if (name.starts_with("def.")) {
return {&DefField, std::string(name.substr(4))};
}
return {LookupField(name), std::string()};
}

Expand Down
5 changes: 4 additions & 1 deletion xff/fields/fields.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#ifndef XFF_FIELDS_FIELDS_H_
#define XFF_FIELDS_FIELDS_H_

#include <map>
#include <string>
#include <string_view>
#include <vector>
Expand All @@ -32,6 +33,7 @@ struct RenderContext {
const vfs::Metadata& metadata; // the entry's metadata
int depth = 0; // 0 for a root operand, +1 per directory level
const std::vector<std::string>* captures = nullptr; // -regex groups for {0..N}: [0] whole match, 1..N groups
const std::map<std::string, std::string>* defines = nullptr; // --define values for {def.NAME}
};

namespace detail {
Expand All @@ -58,7 +60,8 @@ using FieldFn = std::string (*)(std::string_view key, std::string_view qualifier
// \" and \\ are escapes. A numeric placeholder {0}..{N} renders a regex capture
// from RenderContext::captures ({0} the whole match, {1}..{N} the groups; empty
// when unset or out of range) -- used by gated -exec after a -regex match. The
// {env.NAME} namespace renders a process environment variable (empty when unset).
// {env.NAME} namespace renders a process environment variable, and {def.NAME} a
// --define value (each empty when unset).
//
// Compile parses the template once into literal/field segments; the resulting
// Template renders against many entries without re-scanning -- the hot path for
Expand Down
11 changes: 11 additions & 0 deletions xff/fields/fields_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

#include <cstdint>
#include <cstdlib>
#include <map>
#include <string>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
Expand Down Expand Up @@ -155,5 +157,14 @@ TEST_F(FieldsTest, EnvNamespaceReadsEnvironment) {
EXPECT_THAT(Render("{env.XFF_TEST_ENV_VAR}", "p", md, 0), Eq("")); // unset -> empty
}

TEST_F(FieldsTest, DefNamespaceReadsDefines) {
const vfs::Metadata md = Meta(vfs::FileType::kRegular, 0);
const std::map<std::string, std::string> defines = {{"greeting", "hi"}, {"n", "42"}};
const RenderContext ctx{.path = "p", .metadata = md, .defines = &defines};
EXPECT_THAT(Render("{def.greeting}-{def.n}", ctx), Eq("hi-42"));
EXPECT_THAT(Render("{def.missing}", ctx), Eq("")); // undefined -> empty
EXPECT_THAT(Render("[{def.greeting}]", "p", md, 0), Eq("[]")); // no defines map -> empty
}

} // namespace
} // namespace xff::fields
Loading