"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "libpromises/eval_context.c" between
cfengine-3.15.3.tar.gz and cfengine-3.15.4.tar.gz

About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.

eval_context.c  (cfengine-3.15.3):eval_context.c  (cfengine-3.15.4)
skipping to change at line 55 skipping to change at line 55
#include <fncall.h> #include <fncall.h>
#include <ring_buffer.h> #include <ring_buffer.h>
#include <logging_priv.h> #include <logging_priv.h>
#include <known_dirs.h> #include <known_dirs.h>
#include <printsize.h> #include <printsize.h>
#include <regex.h> #include <regex.h>
#include <map.h> #include <map.h>
#include <conversion.h> /* DataTypeIsIterable */ #include <conversion.h> /* DataTypeIsIterable */
#include <cleanup.h> #include <cleanup.h>
/* If we need to put a scoped variable into a special scope, use the string
* below to replace the original scope separator.
* (e.g. "config.var" -> "this.config___var" ) */
#define NESTED_SCOPE_SEP "___"
static const char *STACK_FRAME_TYPE_STR[STACK_FRAME_TYPE_MAX] = { static const char *STACK_FRAME_TYPE_STR[STACK_FRAME_TYPE_MAX] = {
"BUNDLE", "BUNDLE",
"BODY", "BODY",
"PROMISE_TYPE", "PROMISE_TYPE",
"PROMISE", "PROMISE",
"PROMISE_ITERATION" "PROMISE_ITERATION"
}; };
/** /**
Define FuncCacheMap. Define FuncCacheMap.
skipping to change at line 220 skipping to change at line 225
} }
static static
int PackageManagerSeqCompare(const void *a, const void *b, ARG_UNUSED void *data ) int PackageManagerSeqCompare(const void *a, const void *b, ARG_UNUSED void *data )
{ {
return StringSafeCompare((char*)a, ((PackageModuleBody*)b)->name); return StringSafeCompare((char*)a, ((PackageModuleBody*)b)->name);
} }
void AddPackageModuleToContext(const EvalContext *ctx, PackageModuleBody *pm) void AddPackageModuleToContext(const EvalContext *ctx, PackageModuleBody *pm)
{ {
assert(ctx != NULL);
assert(pm != NULL);
/* First check if the body is there added from previous pre-evaluation /* First check if the body is there added from previous pre-evaluation
* iteration. If it is there update it as we can have new expanded variables . */ * iteration. If it is there update it as we can have new expanded variables . */
ssize_t pm_seq_index; Seq *const bodies = ctx->package_promise_context->package_modules_bodies;
if ((pm_seq_index = SeqIndexOf(ctx->package_promise_context->package_modules ssize_t index = SeqIndexOf(bodies, pm->name, PackageManagerSeqCompare);
_bodies, if (index != -1)
pm->name, PackageManagerSeqCompare)) != -1)
{ {
SeqRemove(ctx->package_promise_context->package_modules_bodies, pm_seq_i ndex); SeqRemove(bodies, index);
} }
SeqAppend(ctx->package_promise_context->package_modules_bodies, pm); SeqAppend(bodies, pm);
} }
PackageModuleBody *GetPackageModuleFromContext(const EvalContext *ctx, PackageModuleBody *GetPackageModuleFromContext(const EvalContext *ctx,
const char *name) const char *name)
{ {
if (name == NULL) if (name == NULL)
{ {
return NULL; return NULL;
} }
skipping to change at line 546 skipping to change at line 554
} }
if (context_expression_whitespace_rx == NULL) if (context_expression_whitespace_rx == NULL)
{ {
Log(LOG_LEVEL_ERR, "The context expression whitespace regular expression could not be compiled, aborting."); Log(LOG_LEVEL_ERR, "The context expression whitespace regular expression could not be compiled, aborting.");
return EXPRESSION_VALUE_ERROR; return EXPRESSION_VALUE_ERROR;
} }
if (StringMatchFullWithPrecompiledRegex(context_expression_whitespace_rx, co ntext)) if (StringMatchFullWithPrecompiledRegex(context_expression_whitespace_rx, co ntext))
{ {
Log(LOG_LEVEL_INFO, "class names can't be separated by whitespace withou t an intervening operator in expression '%s'", context); Log(LOG_LEVEL_ERR, "class expressions can't be separated by whitespace w ithout an intervening operator in expression '%s'", context);
return EXPRESSION_VALUE_ERROR; return EXPRESSION_VALUE_ERROR;
} }
Buffer *condensed = BufferNewFrom(context, strlen(context)); Buffer *condensed = BufferNewFrom(context, strlen(context));
BufferRewrite(condensed, &ClassCharIsWhitespace, true); BufferRewrite(condensed, &ClassCharIsWhitespace, true);
res = ParseExpression(BufferData(condensed), 0, BufferSize(condensed)); res = ParseExpression(BufferData(condensed), 0, BufferSize(condensed));
BufferDestroy(condensed); BufferDestroy(condensed);
if (!res.result) if (!res.result)
{ {
skipping to change at line 940 skipping to change at line 948
} }
free(frame->path); free(frame->path);
free(frame); free(frame);
} }
} }
static static
void FreePackageManager(PackageModuleBody *manager) void FreePackageManager(PackageModuleBody *manager)
{ {
assert(manager != NULL);
free(manager->name); free(manager->name);
free(manager->interpreter);
free(manager->module_path);
RlistDestroy(manager->options); RlistDestroy(manager->options);
free(manager); free(manager);
} }
static static
PackagePromiseContext *PackagePromiseConfigNew() PackagePromiseContext *PackagePromiseConfigNew()
{ {
PackagePromiseContext *package_promise_defaults = PackagePromiseContext *package_promise_defaults =
xmalloc(sizeof(PackagePromiseContext)); xmalloc(sizeof(PackagePromiseContext));
package_promise_defaults->control_package_module = NULL; package_promise_defaults->control_package_module = NULL;
skipping to change at line 1933 skipping to change at line 1945
break; break;
default: default:
assert(false && "Canary: promisee not scalar or list"); assert(false && "Canary: promisee not scalar or list");
} }
} }
return promisees; return promisees;
} }
/**
* We cannot have double-scoped variables (e.g. "this.config.var1"), so if we
* want to put a scoped variable into a special scope, we need to mangle the
* name like this:
* "config.var1" -> "config___var1"
*/
static inline char *MangleScopedVarNameIntoSpecialScopeName(const char *scope, c
onst char *var_name)
{
const size_t var_name_len = strlen(var_name);
/* Replace '.' with NESTED_SCOPE_SEP */
char *new_var_name = xmalloc(var_name_len + sizeof(NESTED_SCOPE_SEP));
memcpy(new_var_name, var_name, var_name_len + 1 /* including '\0' */);
/* Make sure we only replace the "scope." string, not all dots. */
char *scope_with_dot = StringConcatenate(2, scope, ".");
char *scope_with_underscores = StringConcatenate(2, scope, NESTED_SCOPE_SEP)
;
ssize_t ret = StringReplace(new_var_name, var_name_len + sizeof(NESTED_SCOPE
_SEP),
scope_with_dot, scope_with_undersc
ores);
assert(ret == (var_name_len + sizeof(NESTED_SCOPE_SEP) - 2));
free(scope_with_dot);
free(scope_with_underscores);
return new_var_name;
}
/* /*
* Copies value, so you need to free your own copy afterwards. * Copies value, so you need to free your own copy afterwards.
*/ */
bool EvalContextVariablePutSpecial(EvalContext *ctx, SpecialScope scope, const c har *lval, const void *value, DataType type, const char *tags) bool EvalContextVariablePutSpecial(EvalContext *ctx, SpecialScope scope, const c har *lval, const void *value, DataType type, const char *tags)
{ {
char *new_lval = NULL;
if (strchr(lval, '.') != NULL)
{
VarRef *ref = VarRefParse(lval);
if (ref->scope != NULL)
{
new_lval = MangleScopedVarNameIntoSpecialScopeName(ref->scope, lval)
;
}
VarRefDestroy(ref);
}
if (strchr(lval, '[')) if (strchr(lval, '['))
{ {
// dealing with (legacy) array reference in lval, must parse // dealing with (legacy) array reference in lval, must parse
VarRef *ref = VarRefParseFromScope(lval, SpecialScopeToString(scope)); VarRef *ref = VarRefParseFromScope(new_lval ? new_lval : lval, SpecialSc opeToString(scope));
bool ret = EvalContextVariablePut(ctx, ref, value, type, tags); bool ret = EvalContextVariablePut(ctx, ref, value, type, tags);
free(new_lval);
VarRefDestroy(ref); VarRefDestroy(ref);
return ret; return ret;
} }
else else
{ {
// plain lval, skip parsing // plain lval, skip parsing
const VarRef ref = VarRefConst(NULL, SpecialScopeToString(scope), lval); const VarRef ref = VarRefConst(NULL, SpecialScopeToString(scope), new_lv
return EvalContextVariablePut(ctx, &ref, value, type, tags); al ? new_lval : lval);
bool ret = EvalContextVariablePut(ctx, &ref, value, type, tags);
free(new_lval);
return ret;
} }
} }
const void *EvalContextVariableGetSpecial( const void *EvalContextVariableGetSpecial(
const EvalContext *const ctx, const EvalContext *const ctx,
const SpecialScope scope, const SpecialScope scope,
const char *const varname, const char *const varname,
DataType *const type_out) DataType *const type_out)
{ {
VarRef *const ref = VarRefParseFromScope( VarRef *const ref = VarRefParseFromScope(
skipping to change at line 2018 skipping to change at line 2071
} }
} }
static VariableTable *GetVariableTableForScope(const EvalContext *ctx, static VariableTable *GetVariableTableForScope(const EvalContext *ctx,
#ifdef NDEBUG #ifdef NDEBUG
ARG_UNUSED ARG_UNUSED
#endif /* ns is only used in assertions ... */ #endif /* ns is only used in assertions ... */
const char *ns, const char *ns,
const char *scope) const char *scope)
{ {
assert(ctx != NULL);
switch (SpecialScopeFromString(scope)) switch (SpecialScopeFromString(scope))
{ {
case SPECIAL_SCOPE_SYS:
case SPECIAL_SCOPE_DEF: case SPECIAL_SCOPE_DEF:
/* 'def.' is not as special as the other scopes below. (CFE-3668) */
return ctx->global_variables;
case SPECIAL_SCOPE_SYS:
case SPECIAL_SCOPE_MON: case SPECIAL_SCOPE_MON:
case SPECIAL_SCOPE_CONST: case SPECIAL_SCOPE_CONST:
assert(!ns || strcmp("default", ns) == 0); assert(!ns || strcmp("default", ns) == 0);
return ctx->global_variables; return ctx->global_variables;
case SPECIAL_SCOPE_MATCH: case SPECIAL_SCOPE_MATCH:
assert(!ns || strcmp("default", ns) == 0); assert(!ns || strcmp("default", ns) == 0);
return ctx->match_variables; return ctx->match_variables;
case SPECIAL_SCOPE_EDIT: case SPECIAL_SCOPE_EDIT:
skipping to change at line 2187 skipping to change at line 2245
return false; return false;
} }
Rval rval = (Rval) { (void *)value, DataTypeToRvalType(type) }; Rval rval = (Rval) { (void *)value, DataTypeToRvalType(type) };
VariableTable *table = GetVariableTableForScope(ctx, ref->ns, ref->scope); VariableTable *table = GetVariableTableForScope(ctx, ref->ns, ref->scope);
const Promise *pp = EvalContextStackCurrentPromise(ctx); const Promise *pp = EvalContextStackCurrentPromise(ctx);
VariableTablePut(table, ref, &rval, type, tags, pp ? pp->org_pp : pp); VariableTablePut(table, ref, &rval, type, tags, pp ? pp->org_pp : pp);
return true; return true;
} }
/**
* Change ref for e.g. 'config.var1' to 'this.config___var1'
*
* @see MangleScopedVarNameIntoSpecialScopeName()
*/
static inline VarRef *MangledThisScopedRef(const VarRef *ref)
{
VarRef *mangled_this_ref = VarRefCopy(ref);
char *scope_underscores_lval = StringConcatenate(3, mangled_this_ref->scope,
NESTED_SCOPE_SEP,
mangled_this_ref->lval);
free(mangled_this_ref->lval);
mangled_this_ref->lval = scope_underscores_lval;
free(mangled_this_ref->scope);
mangled_this_ref->scope = xstrdup("this");
return mangled_this_ref;
}
static Variable *VariableResolve2(const EvalContext *ctx, const VarRef *ref) static Variable *VariableResolve2(const EvalContext *ctx, const VarRef *ref)
{ {
assert(ref != NULL);
// Get the variable table associated to the scope // Get the variable table associated to the scope
VariableTable *table = GetVariableTableForScope(ctx, ref->ns, ref->scope); VariableTable *table = GetVariableTableForScope(ctx, ref->ns, ref->scope);
Variable *var; Variable *var;
if (table) if (table)
{ {
var = VariableTableGet(table, ref); var = VariableTableGet(table, ref);
if (var) if (var)
{ {
return var; return var;
} }
else if (ref->num_indices > 0) /* why? TODO comment */ else if (ref->num_indices > 0)
{ {
/* Iteration over slists creates special variables in the 'this.'
* scope with the slist variable replaced by the individual
* values. However, if a scoped variable is part of the variable
* reference, e.g. 'config.data[$(list)]', the special iteration
* variables use mangled names to avoid having two scopes
* (e.g. 'this.config___data[list_item1]' instead of
* 'this.config.data[list_item1]').
*
* If the ref we are looking for has indices and it has a scope, it
* might be the case described above. Let's give it a try before
* falling back to the indexless container lookup described below
* (which will not have the list-iteration variables expanded). */
if (ref->scope != NULL)
{
VariableTable *this_table = GetVariableTableForScope(ctx, ref->n
s,
SpecialScop
eToString(SPECIAL_SCOPE_THIS));
if (this_table != NULL)
{
VarRef *mangled_this_ref = MangledThisScopedRef(ref);
var = VariableTableGet(this_table, mangled_this_ref);
VarRefDestroy(mangled_this_ref);
if (var != NULL)
{
return var;
}
}
}
/* If the lookup with indices (the [idx1][idx2]... part of the
* variable reference) fails, there might still be a container
* variable where the indices actually refer to child objects inside
* the container structure. */
VarRef *base_ref = VarRefCopyIndexless(ref); VarRef *base_ref = VarRefCopyIndexless(ref);
var = VariableTableGet(table, base_ref); var = VariableTableGet(table, base_ref);
VarRefDestroy(base_ref); VarRefDestroy(base_ref);
if (var && var->type == CF_DATA_TYPE_CONTAINER) if (var && var->type == CF_DATA_TYPE_CONTAINER)
{ {
return var; return var;
} }
} }
} }
skipping to change at line 2232 skipping to change at line 2343
* will qualify a reference to 'this' scope and when evaluating a body, it * will qualify a reference to 'this' scope and when evaluating a body, it
* will qualify a reference to 'body' scope. * will qualify a reference to 'body' scope.
*/ */
static Variable *VariableResolve(const EvalContext *ctx, const VarRef *ref) static Variable *VariableResolve(const EvalContext *ctx, const VarRef *ref)
{ {
assert(ref->lval); assert(ref->lval);
/* We will make a first lookup that works in almost all cases: will look /* We will make a first lookup that works in almost all cases: will look
* for local or global variables, depending of the current scope. */ * for local or global variables, depending of the current scope. */
Variable *var1 = VariableResolve2(ctx, ref); Variable *ret_var = VariableResolve2(ctx, ref);
if (var1) if (ret_var != NULL)
{ {
return var1; return ret_var;
} }
/* Try to qualify non-scoped vars to the scope: /* Try to qualify non-scoped vars to the scope:
"this" for promises, "body" for bodies, current bundle for bundles. */ "this" for promises, "body" for bodies, current bundle for bundles. */
VarRef *scoped_ref = NULL; VarRef *scoped_ref = NULL;
if (!VarRefIsQualified(ref)) if (!VarRefIsQualified(ref))
{ {
scoped_ref = VarRefCopy(ref); scoped_ref = VarRefCopy(ref);
VarRefStackQualify(ctx, scoped_ref); VarRefStackQualify(ctx, scoped_ref);
Variable *var2 = VariableResolve2(ctx, scoped_ref); ret_var = VariableResolve2(ctx, scoped_ref);
if (var2) if (ret_var != NULL)
{ {
VarRefDestroy(scoped_ref); VarRefDestroy(scoped_ref);
return var2; return ret_var;
} }
ref = scoped_ref; /* continue with the scoped variable */ ref = scoped_ref; /* continue with the scoped variable */
} }
const Bundle *last_bundle = EvalContextStackCurrentBundle(ctx); const Bundle *last_bundle = EvalContextStackCurrentBundle(ctx);
/* If we are in a promise or a body, the variable might be coming from the /* If we are in a promise or a body, the variable might be coming from the
* last bundle. So try a last lookup with "this" or "body" special scopes * last bundle. So try a last lookup with "this" or "body" special scopes
* replaced with the last bundle. */ * replaced with the last bundle. */
if ((SpecialScopeFromString(ref->scope) == SPECIAL_SCOPE_THIS || if ((SpecialScopeFromString(ref->scope) == SPECIAL_SCOPE_THIS ||
SpecialScopeFromString(ref->scope) == SPECIAL_SCOPE_BODY) SpecialScopeFromString(ref->scope) == SPECIAL_SCOPE_BODY)
&& last_bundle != NULL) && last_bundle != NULL)
{ {
VarRef *ref2 = VarRefCopy(ref); VarRef *ref2 = VarRefCopy(ref);
VarRefQualify(ref2, last_bundle->ns, last_bundle->name); VarRefQualify(ref2, last_bundle->ns, last_bundle->name);
Variable *var3 = VariableResolve2(ctx, ref2); ret_var = VariableResolve2(ctx, ref2);
VarRefDestroy(scoped_ref); VarRefDestroy(scoped_ref);
VarRefDestroy(ref2); VarRefDestroy(ref2);
return var3; return ret_var;
} }
VarRefDestroy(scoped_ref); VarRefDestroy(scoped_ref);
return NULL; return NULL;
} }
/** /**
* *
* @NOTE NULL is a valid return value if #type_out is of list type and the * @NOTE NULL is a valid return value if #type_out is of list type and the
* list is empty. To check if the variable didn't resolve, check if * list is empty. To check if the variable didn't resolve, check if
* #type_out was set to CF_DATA_TYPE_NONE. * #type_out was set to CF_DATA_TYPE_NONE.
*/ */
const void *EvalContextVariableGet(const EvalContext *ctx, const VarRef *ref, Da taType *type_out) const void *EvalContextVariableGet(const EvalContext *ctx, const VarRef *ref, Da taType *type_out)
 End of changes. 28 change blocks. 
21 lines changed or deleted 139 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)