void VerifyClassPromise(EvalContext *ctx, Promise *pp, ARG_UNUSED void *param) { assert(param == NULL); Attributes a; a = GetClassContextAttributes(ctx, pp); if (!FullTextMatch("[a-zA-Z0-9_]+", pp->promiser)) { Log(LOG_LEVEL_VERBOSE, "Class identifier '%s' contains illegal characters - canonifying", pp->promiser); snprintf(pp->promiser, strlen(pp->promiser) + 1, "%s", CanonifyName(pp->promiser)); } if (a.context.nconstraints == 0) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "No constraints for class promise '%s'", pp->promiser); return; } if (a.context.nconstraints > 1) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Irreconcilable constraints in classes for '%s'", pp->promiser); return; } bool global_class; if (a.context.persistent > 0) /* Persistent classes are always global */ { global_class = true; } else if (a.context.scope == CONTEXT_SCOPE_NONE) { /* If there is no explicit scope, common bundles define global classes, other bundles define local classes */ if (strcmp(PromiseGetBundle(pp)->type, "common") == 0) { global_class = true; } else { global_class = false; } } else if (a.context.scope == CONTEXT_SCOPE_NAMESPACE) { global_class = true; } else if (a.context.scope == CONTEXT_SCOPE_BUNDLE) { global_class = false; } if (EvalClassExpression(ctx, a.context.expression, pp)) { if (!ValidClassName(pp->promiser)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Attempted to name a class '%s', which is an illegal class identifier", pp->promiser); } else { if (global_class) { Log(LOG_LEVEL_VERBOSE, "Adding global class '%s'", pp->promiser); EvalContextHeapAddSoft(ctx, pp->promiser, PromiseGetNamespace(pp)); } else { Log(LOG_LEVEL_VERBOSE, "Adding local bundle class '%s'", pp->promiser); EvalContextStackFrameAddSoft(ctx, pp->promiser); } if (a.context.persistent > 0) { Log(LOG_LEVEL_VERBOSE, "Adding persistent class '%s'. (%d minutes)", pp->promiser, a.context.persistent); EvalContextHeapPersistentSave(pp->promiser, PromiseGetNamespace(pp), a.context.persistent, CONTEXT_STATE_POLICY_RESET); } } } }
void KeepClassContextPromise(EvalContext *ctx, Promise *pp, ARG_UNUSED const ReportContext *report_context) { Attributes a; a = GetClassContextAttributes(ctx, pp); if (!FullTextMatch("[a-zA-Z0-9_]+", pp->promiser)) { CfOut(OUTPUT_LEVEL_VERBOSE, "", "Class identifier \"%s\" contains illegal characters - canonifying", pp->promiser); snprintf(pp->promiser, strlen(pp->promiser) + 1, "%s", CanonifyName(pp->promiser)); } if (a.context.nconstraints == 0) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_FAIL, "", pp, a, "No constraints for class promise %s", pp->promiser); return; } if (a.context.nconstraints > 1) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_FAIL, "", pp, a, "Irreconcilable constraints in classes for %s", pp->promiser); return; } // If this is a common bundle ... if (strcmp(PromiseGetBundle(pp)->type, "common") == 0) { if (EvalClassExpression(ctx, a.context.expression, pp)) { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining additional global class %s\n", pp->promiser); if (!ValidClassName(pp->promiser)) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_FAIL, "", pp, a, " !! Attempted to name a class \"%s\", which is an illegal class identifier", pp->promiser); } else { if (a.context.persistent > 0) { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining explicit persistent class %s (%d mins)\n", pp->promiser, a.context.persistent); EvalContextHeapPersistentSave(pp->promiser, PromiseGetNamespace(pp), a.context.persistent, CONTEXT_STATE_POLICY_RESET); EvalContextHeapAddSoft(ctx, pp->promiser, PromiseGetNamespace(pp)); } else { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining explicit global class %s\n", pp->promiser); EvalContextHeapAddSoft(ctx, pp->promiser, PromiseGetNamespace(pp)); } } } /* These are global and loaded once */ /* *(pp->donep) = true; */ return; } // If this is some other kind of bundle (else here??) if (strcmp(PromiseGetBundle(pp)->type, CF_AGENTTYPES[THIS_AGENT_TYPE]) == 0 || FullTextMatch("edit_.*", PromiseGetBundle(pp)->type)) { if (EvalClassExpression(ctx, a.context.expression, pp)) { if (!ValidClassName(pp->promiser)) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_FAIL, "", pp, a, " !! Attempted to name a class \"%s\", which is an illegal class identifier", pp->promiser); } else { if (a.context.persistent > 0) { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining explicit persistent class %s (%d mins)\n", pp->promiser, a.context.persistent); CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> Warning: persistent classes are global in scope even in agent bundles\n"); EvalContextHeapPersistentSave(pp->promiser, PromiseGetNamespace(pp), a.context.persistent, CONTEXT_STATE_POLICY_RESET); EvalContextHeapAddSoft(ctx, pp->promiser, PromiseGetNamespace(pp)); } else { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining explicit local bundle class %s\n", pp->promiser); EvalContextStackFrameAddSoft(ctx, pp->promiser); } } } // Private to bundle, can be reloaded *(pp->donep) = false; return; } }
PromiseResult VerifyClassPromise(EvalContext *ctx, const Promise *pp, ARG_UNUSED void *param) { assert(param == NULL); Attributes a = GetClassContextAttributes(ctx, pp); if (!StringMatchFull("[a-zA-Z0-9_]+", pp->promiser)) { Log(LOG_LEVEL_VERBOSE, "Class identifier '%s' contains illegal characters - canonifying", pp->promiser); xsnprintf(pp->promiser, strlen(pp->promiser) + 1, "%s", CanonifyName(pp->promiser)); } if (a.context.nconstraints == 0) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "No constraints for class promise '%s'", pp->promiser); return PROMISE_RESULT_FAIL; } if (a.context.nconstraints > 1) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Irreconcilable constraints in classes for '%s'", pp->promiser); return PROMISE_RESULT_FAIL; } if (EvalClassExpression(ctx, a.context.expression, pp)) { if (!ValidClassName(pp->promiser)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Attempted to name a class '%s', which is an illegal class identifier", pp->promiser); return PROMISE_RESULT_FAIL; } else { char *tags = NULL; { Buffer *tag_buffer = BufferNew(); BufferAppendString(tag_buffer, "classes promise,attribute_name=label,source=promise"); for (const Rlist *rp = PromiseGetConstraintAsList(ctx, "meta", pp); rp; rp = rp->next) { BufferAppendChar(tag_buffer, ','); BufferAppendString(tag_buffer, RlistScalarValue(rp)); } tags = BufferClose(tag_buffer); } if (/* Persistent classes are always global: */ a.context.persistent > 0 || /* Namespace-scope is global: */ a.context.scope == CONTEXT_SCOPE_NAMESPACE || /* If there is no explicit scope, common bundles define global * classes, other bundles define local classes: */ (a.context.scope == CONTEXT_SCOPE_NONE && 0 == strcmp(PromiseGetBundle(pp)->type, "common"))) { Log(LOG_LEVEL_VERBOSE, "C: + Global class: %s ", pp->promiser); EvalContextClassPutSoft(ctx, pp->promiser, CONTEXT_SCOPE_NAMESPACE, tags); } else { Log(LOG_LEVEL_VERBOSE, "C: + Private class: %s ", pp->promiser); EvalContextClassPutSoft(ctx, pp->promiser, CONTEXT_SCOPE_BUNDLE, tags); } if (a.context.persistent > 0) { Log(LOG_LEVEL_VERBOSE, "C: + Persistent class: '%s'. (%d minutes)", pp->promiser, a.context.persistent); EvalContextHeapPersistentSave(ctx, pp->promiser, a.context.persistent, CONTEXT_STATE_POLICY_RESET, tags); } free(tags); return PROMISE_RESULT_NOOP; } } return PROMISE_RESULT_NOOP; }
/*************************************************************************************** NAME : ParseDefclass DESCRIPTION : (defclass ...) is a construct (as opposed to a function), thus no variables may be used. This means classes may only be STATICALLY defined (like rules). INPUTS : The logical name of the router for the parser input RETURNS : FALSE if successful parse, TRUE otherwise SIDE EFFECTS : Inserts valid class definition into Class Table. NOTES : H/L Syntax : (defclass <name> [<comment>] (is-a <superclass-name>+) <class-descriptor>*) <class-descriptor> :== (slot <name> <slot-descriptor>*) | (role abstract|concrete) | (pattern-match reactive|non-reactive) These are for documentation only: (message-handler <name> [<type>]) <slot-descriptor> :== (default <default-expression>) | (default-dynamic <default-expression>) | (storage shared|local) | (access read-only|read-write|initialize-only) | (propagation no-inherit|inherit) | (source composite|exclusive) (pattern-match reactive|non-reactive) (visibility public|private) (override-message <message-name>) (type ...) | (cardinality ...) | (allowed-symbols ...) | (allowed-strings ...) | (allowed-numbers ...) | (allowed-integers ...) | (allowed-floats ...) | (allowed-values ...) | (allowed-instance-names ...) | (allowed-classes ...) | (range ...) <default-expression> ::= ?NONE | ?VARIABLE | <expression>* ***************************************************************************************/ globle int ParseDefclass( void *theEnv, char *readSource) { SYMBOL_HN *cname; DEFCLASS *cls; PACKED_CLASS_LINKS *sclasses,*preclist; TEMP_SLOT_LINK *slots = NULL; int roleSpecified = FALSE, abstract = FALSE, parseError; #if DEFRULE_CONSTRUCT int patternMatchSpecified = FALSE, reactive = TRUE; #endif SetPPBufferStatus(theEnv,ON); FlushPPBuffer(theEnv); SetIndentDepth(theEnv,3); SavePPBuffer(theEnv,"(defclass "); #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE if ((Bloaded(theEnv)) && (! ConstructData(theEnv)->CheckSyntaxMode)) { CannotLoadWithBloadMessage(theEnv,"defclass"); return(TRUE); } #endif cname = GetConstructNameAndComment(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken,"defclass", EnvFindDefclass,NULL,"#",TRUE, TRUE,TRUE); if (cname == NULL) return(TRUE); if (ValidClassName(theEnv,ValueToString(cname),&cls) == FALSE) return(TRUE); sclasses = ParseSuperclasses(theEnv,readSource,cname); if (sclasses == NULL) return(TRUE); preclist = FindPrecedenceList(theEnv,cls,sclasses); if (preclist == NULL) { DeletePackedClassLinks(theEnv,sclasses,TRUE); return(TRUE); } parseError = FALSE; GetToken(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken); while (GetType(DefclassData(theEnv)->ObjectParseToken) != RPAREN) { if (GetType(DefclassData(theEnv)->ObjectParseToken) != LPAREN) { SyntaxErrorMessage(theEnv,"defclass"); parseError = TRUE; break; } PPBackup(theEnv); PPCRAndIndent(theEnv); SavePPBuffer(theEnv,"("); GetToken(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken); if (GetType(DefclassData(theEnv)->ObjectParseToken) != SYMBOL) { SyntaxErrorMessage(theEnv,"defclass"); parseError = TRUE; break; } if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),ROLE_RLN) == 0) { if (ParseSimpleQualifier(theEnv,readSource,ROLE_RLN,CONCRETE_RLN,ABSTRACT_RLN, &roleSpecified,&abstract) == FALSE) { parseError = TRUE; break; } } #if DEFRULE_CONSTRUCT else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),MATCH_RLN) == 0) { if (ParseSimpleQualifier(theEnv,readSource,MATCH_RLN,NONREACTIVE_RLN,REACTIVE_RLN, &patternMatchSpecified,&reactive) == FALSE) { parseError = TRUE; break; } } #endif else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),SLOT_RLN) == 0) { slots = ParseSlot(theEnv,readSource,slots,preclist,FALSE,FALSE); if (slots == NULL) { parseError = TRUE; break; } } else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),SGL_SLOT_RLN) == 0) { slots = ParseSlot(theEnv,readSource,slots,preclist,FALSE,TRUE); if (slots == NULL) { parseError = TRUE; break; } } else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),MLT_SLOT_RLN) == 0) { slots = ParseSlot(theEnv,readSource,slots,preclist,TRUE,TRUE); if (slots == NULL) { parseError = TRUE; break; } } else if (strcmp(DOToString(DefclassData(theEnv)->ObjectParseToken),HANDLER_DECL) == 0) { if (ReadUntilClosingParen(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken) == FALSE) { parseError = TRUE; break; } } else { SyntaxErrorMessage(theEnv,"defclass"); parseError = TRUE; break; } GetToken(theEnv,readSource,&DefclassData(theEnv)->ObjectParseToken); } if ((GetType(DefclassData(theEnv)->ObjectParseToken) != RPAREN) || (parseError == TRUE)) { DeletePackedClassLinks(theEnv,sclasses,TRUE); DeletePackedClassLinks(theEnv,preclist,TRUE); DeleteSlots(theEnv,slots); return(TRUE); } SavePPBuffer(theEnv,"\n"); /* ========================================================================= The abstract/reactive qualities of a class are inherited if not specified ========================================================================= */ if (roleSpecified == FALSE) { if (preclist->classArray[1]->system && /* Change to cause */ (DefclassData(theEnv)->ClassDefaultsMode == CONVENIENCE_MODE)) /* default role of */ { abstract = FALSE; } /* classes to be concrete. */ else { abstract = preclist->classArray[1]->abstract; } } #if DEFRULE_CONSTRUCT if (patternMatchSpecified == FALSE) { if ((preclist->classArray[1]->system) && /* Change to cause */ (! abstract) && /* default pattern-match */ (DefclassData(theEnv)->ClassDefaultsMode == CONVENIENCE_MODE)) /* of classes to be */ { reactive = TRUE; } /* reactive. */ else { reactive = preclist->classArray[1]->reactive; } } /* ================================================================ An abstract class cannot have direct instances, thus it makes no sense for it to be reactive since it will have no objects to respond to pattern-matching ================================================================ */ if (abstract && reactive) { PrintErrorID(theEnv,"CLASSPSR",1,FALSE); EnvPrintRouter(theEnv,WERROR,"An abstract class cannot be reactive.\n"); DeletePackedClassLinks(theEnv,sclasses,TRUE); DeletePackedClassLinks(theEnv,preclist,TRUE); DeleteSlots(theEnv,slots); return(TRUE); } #endif /* ======================================================= If we're only checking syntax, don't add the successfully parsed defclass to the KB. ======================================================= */ if (ConstructData(theEnv)->CheckSyntaxMode) { DeletePackedClassLinks(theEnv,sclasses,TRUE); DeletePackedClassLinks(theEnv,preclist,TRUE); DeleteSlots(theEnv,slots); return(FALSE); } cls = NewClass(theEnv,cname); cls->abstract = abstract; #if DEFRULE_CONSTRUCT cls->reactive = reactive; #endif cls->directSuperclasses.classCount = sclasses->classCount; cls->directSuperclasses.classArray = sclasses->classArray; /* ======================================================= This is a hack to let functions which need to iterate over a class AND its superclasses to conveniently do so The real precedence list starts in position 1 ======================================================= */ preclist->classArray[0] = cls; cls->allSuperclasses.classCount = preclist->classCount; cls->allSuperclasses.classArray = preclist->classArray; rtn_struct(theEnv,packedClassLinks,sclasses); rtn_struct(theEnv,packedClassLinks,preclist); /* ================================= Shove slots into contiguous array ================================= */ if (slots != NULL) PackSlots(theEnv,cls,slots); AddClass(theEnv,cls); return(FALSE); }
void KeepClassContextPromise(struct Promise *pp) { struct Attributes a; a = GetClassContextAttributes(pp); if (!FullTextMatch("[a-zA-Z0-9_]+",pp->promiser)) { CfOut(cf_verbose,"","Class identifier \"%s\" contains illegal characters - canonifying",pp->promiser); snprintf(pp->promiser, strlen(pp->promiser) + 1, "%s", CanonifyName(pp->promiser)); } if (a.context.broken) { cfPS(cf_error,CF_FAIL,"",pp,a,"Irreconcilable constraints in classes for %s (broken promise)",pp->promiser); return; } if (strcmp(pp->bundletype,"common") == 0) { if (EvalClassExpression(a.context.expression,pp)) { CfOut(cf_verbose,""," ?> defining additional global class %s\n",pp->promiser); if (!ValidClassName(pp->promiser)) { cfPS(cf_error,CF_FAIL,"",pp,a," !! Attempted to name a class \"%s\", which is an illegal class identifier",pp->promiser); } else { NewClass(pp->promiser); } } /* These are global and loaded once */ //*(pp->donep) = true; return; } if (strcmp(pp->bundletype,THIS_AGENT) == 0 || FullTextMatch("edit_.*",pp->bundletype)) { if (EvalClassExpression(a.context.expression,pp)) { Debug(" ?> defining explicit class %s\n",pp->promiser); if (!ValidClassName(pp->promiser)) { cfPS(cf_error,CF_FAIL,"",pp,a," !! Attempted to name a class \"%s\", which is an illegal class identifier",pp->promiser); } else { NewBundleClass(pp->promiser,pp->bundle); } } // Private to bundle, can be reloaded *(pp->donep) = false; return; } }