Rval ExpandPrivateRval(EvalContext *ctx, const char *ns, const char *scope, const void *rval_item, RvalType rval_type) { Rval returnval; returnval.item = NULL; returnval.type = RVAL_TYPE_NOPROMISEE; switch (rval_type) { case RVAL_TYPE_SCALAR: returnval.item = ExpandScalar(ctx, ns, scope, rval_item, NULL); returnval.type = RVAL_TYPE_SCALAR; break; case RVAL_TYPE_LIST: returnval.item = ExpandList(ctx, ns, scope, rval_item, true); returnval.type = RVAL_TYPE_LIST; break; case RVAL_TYPE_FNCALL: returnval.item = ExpandFnCall(ctx, ns, scope, rval_item); returnval.type = RVAL_TYPE_FNCALL; break; case RVAL_TYPE_CONTAINER: returnval = RvalNew(rval_item, RVAL_TYPE_CONTAINER); break; case RVAL_TYPE_NOPROMISEE: break; } return returnval; }
static void test_expand_list_nested(void **state) { EvalContext *ctx = *state; { VarRef *lval = VarRefParse("default:bundle.i"); EvalContextVariablePut(ctx, lval, "one", CF_DATA_TYPE_STRING, NULL); VarRefDestroy(lval); } { VarRef *lval = VarRefParse("default:bundle.inner[one]"); Rlist *list = NULL; RlistAppendScalar(&list, "foo"); EvalContextVariablePut(ctx, lval, list, CF_DATA_TYPE_STRING_LIST, NULL); RlistDestroy(list); VarRefDestroy(lval); } Rlist *outer = NULL; RlistAppendScalar(&outer, "@{inner[$(i)]}"); Rlist *expanded = ExpandList(ctx, "default", "bundle", outer, true); assert_int_equal(1, RlistLen(expanded)); assert_string_equal("foo", RlistScalarValue(expanded)); RlistDestroy(outer); RlistDestroy(expanded); }
LPCSTR FTP::InsertCurrentToQueue(void) { PanelInfo pi, api; FP_SizeItemList backup,il; FTPCopyInfo ci; if(!FP_Info->Control(this, FCTL_GETPANELINFO, &pi) || !FP_Info->Control(INVALID_HANDLE_VALUE, FCTL_GETANOTHERPANELSHORTINFO, &api)) return FMSG(MErrGetPanelInfo); if(pi.SelectedItemsNumber <= 0 || pi.SelectedItemsNumber == 1 && !IS_FLAG(pi.SelectedItems[0].Flags,PPIF_SELECTED)) return FMSG(MErrNoSelection); backup.Add(pi.SelectedItems, pi.SelectedItemsNumber); BOOL rc = ExpandList(backup.Items(), backup.Count(), &il, TRUE); FP_Screen::FullRestore(); if(!rc) return GetLastError() == ERROR_CANCELLED ? NULL : FMSG(MErrExpandList); ci.Download = TRUE; if(api.PanelType != PTYPE_FILEPANEL || api.Plugin) ci.DestPath = ""; else ci.DestPath = api.CurDir; ListToQueque(&il, &ci); return NULL; }
LPCSTR FTP::InsertAnotherToQueue(void) { FP_SizeItemList backup,il; PanelInfo pi; FTPCopyInfo ci; if(!hConnect || ShowHosts) return FMSG(MQErrUploadHosts); if(!FP_Info->Control(INVALID_HANDLE_VALUE, FCTL_GETANOTHERPANELINFO, &pi)) return FMSG(MErrGetPanelInfo); if(pi.SelectedItemsNumber <= 0 || pi.SelectedItemsNumber == 1 && !IS_FLAG(pi.SelectedItems[0].Flags,PPIF_SELECTED)) return FMSG(MErrNoSelection); if(pi.PanelType != PTYPE_FILEPANEL || pi.Plugin) return FMSG(MErrNotFiles); backup.Add(pi.SelectedItems, pi.SelectedItemsNumber); BOOL rc = ExpandList(backup.Items(), backup.Count(), &il, FALSE); FP_Screen::FullRestore(); if(!rc) return GetLastError() == ERROR_CANCELLED ? NULL : FMSG(MErrExpandList); ci.Download = FALSE; GetCurPath(ci.DestPath); ListToQueque(&il, &ci); return NULL; }
FnCall *ExpandFnCall(EvalContext *ctx, const char *ns, const char *scope, const FnCall *f) { FnCall *result = NULL; if (IsCf3VarString(f->name)) { // e.g. usebundle => $(m)(arg0, arg1); Buffer *buf = BufferNewWithCapacity(CF_MAXVARSIZE); ExpandScalar(ctx, ns, scope, f->name, buf); result = FnCallNew(BufferData(buf), ExpandList(ctx, ns, scope, f->args, false)); BufferDestroy(buf); } else { result = FnCallNew(f->name, ExpandList(ctx, ns, scope, f->args, false)); } return result; }
Rval ExpandPrivateRval(EvalContext *ctx, const char *ns, const char *scope, const void *rval_item, RvalType rval_type) { Rval returnval; returnval.item = NULL; returnval.type = RVAL_TYPE_NOPROMISEE; switch (rval_type) { case RVAL_TYPE_SCALAR: { Buffer *buffer = BufferNew(); ExpandScalar(ctx, ns, scope, rval_item, buffer); returnval = (Rval) { BufferClose(buffer), RVAL_TYPE_SCALAR }; } break; case RVAL_TYPE_LIST: returnval.item = ExpandList(ctx, ns, scope, rval_item, true); returnval.type = RVAL_TYPE_LIST; break; case RVAL_TYPE_FNCALL: returnval.item = ExpandFnCall(ctx, ns, scope, rval_item); returnval.type = RVAL_TYPE_FNCALL; break; case RVAL_TYPE_CONTAINER: returnval = RvalNew(JsonCopy(rval_item), RVAL_TYPE_CONTAINER); break; case RVAL_TYPE_NOPROMISEE: break; } return returnval; }
FnCall *ExpandFnCall(char *contextid, FnCall *f, int expandnaked) { CfDebug("ExpandFnCall()\n"); //return NewFnCall(f->name,ExpandList(contextid,f->args,expandnaked)); return NewFnCall(f->name, ExpandList(contextid, f->args, false)); }
Rval EvaluateFinalRval(EvalContext *ctx, const Policy *policy, const char *ns, const char *scope, Rval rval, bool forcelist, const Promise *pp) { assert(ctx); assert(policy); Rval returnval, newret; if ((rval.type == RVAL_TYPE_SCALAR) && IsNakedVar(rval.item, '@')) /* Treat lists specially here */ { char naked[CF_MAXVARSIZE]; GetNaked(naked, rval.item); if (!IsExpandable(naked)) { VarRef *ref = VarRefParseFromScope(naked, scope); DataType value_type = DATA_TYPE_NONE; const void *value = EvalContextVariableGet(ctx, ref, &value_type); if (!value || DataTypeToRvalType(value_type) != RVAL_TYPE_LIST) { returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type); } else { returnval.item = ExpandList(ctx, ns, scope, value, true); returnval.type = RVAL_TYPE_LIST; } VarRefDestroy(ref); } else { returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type); } } else { if (forcelist) /* We are replacing scalar @(name) with list */ { returnval = ExpandPrivateRval(ctx, ns, scope, rval.item, rval.type); } else { if (FnCallIsBuiltIn(rval)) { returnval = RvalCopy(rval); } else { returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type); } } } switch (returnval.type) { case RVAL_TYPE_SCALAR: case RVAL_TYPE_CONTAINER: break; case RVAL_TYPE_LIST: for (Rlist *rp = RvalRlistValue(returnval); rp; rp = rp->next) { if (rp->val.type == RVAL_TYPE_FNCALL) { FnCall *fp = RlistFnCallValue(rp); FnCallResult res = FnCallEvaluate(ctx, policy, fp, pp); FnCallDestroy(fp); rp->val = res.rval; } else { if (EvalContextStackCurrentPromise(ctx)) { if (IsCf3VarString(RlistScalarValue(rp))) { newret = ExpandPrivateRval(ctx, NULL, "this", rp->val.item, rp->val.type); free(rp->val.item); rp->val.item = newret.item; } } } /* returnval unchanged */ } break; case RVAL_TYPE_FNCALL: if (FnCallIsBuiltIn(returnval)) { FnCall *fp = RvalFnCallValue(returnval); returnval = FnCallEvaluate(ctx, policy, fp, pp).rval; FnCallDestroy(fp); } break; default: returnval.item = NULL; returnval.type = RVAL_TYPE_NOPROMISEE; break; } return returnval; }
Rval EvaluateFinalRval(EvalContext *ctx, const Policy *policy, const char *ns, const char *scope, Rval rval, bool forcelist, const Promise *pp) { assert(ctx); assert(policy); Rval returnval; /* Treat lists specially. */ if (rval.type == RVAL_TYPE_SCALAR && IsNakedVar(rval.item, '@')) { char naked[CF_MAXVARSIZE]; GetNaked(naked, rval.item); if (IsExpandable(naked)) /* example: @(blah_$(blue)) */ { returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type); } else { VarRef *ref = VarRefParseFromScope(naked, scope); DataType value_type; const void *value = EvalContextVariableGet(ctx, ref, &value_type); VarRefDestroy(ref); if (DataTypeToRvalType(value_type) == RVAL_TYPE_LIST) { returnval.item = ExpandList(ctx, ns, scope, value, true); returnval.type = RVAL_TYPE_LIST; } else { returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type); } } } else if (forcelist) /* We are replacing scalar @(name) with list */ { returnval = ExpandPrivateRval(ctx, ns, scope, rval.item, rval.type); } else if (FnCallIsBuiltIn(rval)) { returnval = RvalCopy(rval); } else { returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type); } switch (returnval.type) { case RVAL_TYPE_SCALAR: case RVAL_TYPE_CONTAINER: break; case RVAL_TYPE_LIST: for (Rlist *rp = RvalRlistValue(returnval); rp; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_FNCALL: { FnCall *fp = RlistFnCallValue(rp); rp->val = FnCallEvaluate(ctx, policy, fp, pp).rval; FnCallDestroy(fp); break; } case RVAL_TYPE_SCALAR: if (EvalContextStackCurrentPromise(ctx) && IsCf3VarString(RlistScalarValue(rp))) { void *prior = rp->val.item; rp->val = ExpandPrivateRval(ctx, NULL, "this", prior, RVAL_TYPE_SCALAR); free(prior); } /* else: returnval unchanged. */ break; default: assert(!"Bad type for entry in Rlist"); } } break; case RVAL_TYPE_FNCALL: if (FnCallIsBuiltIn(returnval)) { FnCall *fp = RvalFnCallValue(returnval); returnval = FnCallEvaluate(ctx, policy, fp, pp).rval; FnCallDestroy(fp); } break; default: assert(returnval.item == NULL); /* else we're leaking it */ returnval.item = NULL; returnval.type = RVAL_TYPE_NOPROMISEE; break; } return returnval; }
FnCall *ExpandFnCall(EvalContext *ctx, const char *contextid, FnCall *f) { CfDebug("ExpandFnCall()\n"); return FnCallNew(f->name, ExpandList(ctx, contextid, f->args, false)); }
FnCall *ExpandFnCall(EvalContext *ctx, const char *ns, const char *scope, FnCall *f) { return FnCallNew(f->name, ExpandList(ctx, ns, scope, f->args, false)); }