/* Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved. */ #include <ProToolkit.h> #include <ProParameter.h> #include <ProRelSet.h> #include <PTUDFExamples.h> #include <ProTKRunTime.h> /*====================================================================*\ FUNCTION: PTUDFExParamValidateLimit PURPOSE: Check the parameter value if it meets the given limit restriction. \*====================================================================*/ static ProError PTUDFExParamValidateLimit (ProParamvalue* value, ProParamLimit* limit) { double real_value, real_limit; /*--------------------------------------------------------------------*\ Shouldn't happen, boolean and string params can't be ranged \*--------------------------------------------------------------------*/ if (value->type != PRO_PARAM_INTEGER && value->type != PRO_PARAM_DOUBLE) return PRO_TK_NOT_VALID; if (limit->type == PRO_PARAM_UNLIMITED) return PRO_TK_NO_ERROR; /*--------------------------------------------------------------------*\ Real value and real limit are set to double even if the parameter is integer. \*--------------------------------------------------------------------*/ real_value = (value->type == PRO_PARAM_INTEGER? (double)value->value.i_val : value->value.d_val); real_limit = (limit->value.type == PRO_PARAM_INTEGER ? (double)limit->value.value.i_val : limit->value.value.d_val); switch (limit->type) { case PRO_PARAM_LESS_THAN: return (real_value < real_limit ? PRO_TK_NO_ERROR : PRO_TK_NOT_VALID); case PRO_PARAM_LESS_THAN_OR_EQUAL: return (real_value <= real_limit ? PRO_TK_NO_ERROR : PRO_TK_NOT_VALID); case PRO_PARAM_GREATER_THAN: return (real_value > real_limit ? PRO_TK_NO_ERROR : PRO_TK_NOT_VALID); case PRO_PARAM_GREATER_THAN_OR_EQUAL: return (real_value >= real_limit ? PRO_TK_NO_ERROR : PRO_TK_NOT_VALID); } return (PRO_TK_NO_ERROR); } /*====================================================================*\ FUNCTION: PTUDFExParamValidateConstraint PURPOSE: Check the parameter value in a single constraint to see if it passes. \*====================================================================*/ static ProError PTUDFExParamValidateConstraint (ProRelset* relset, ProName name, ProParamvalue* value, wchar_t* constraint) { ProLine line; char c_line [PRO_LINE_SIZE * 4], c_constraint [PRO_LINE_SIZE * 4]; char c_name [PRO_NAME_SIZE * 4]; char c_param_value [PRO_LINE_SIZE * 4]; char c_buff [2]; int param_name_len, constraint_len; ProParamvalue result; int i; ProUnititem units; /*--------------------------------------------------------------------*\ Convert the new value to a string value expression. \*--------------------------------------------------------------------*/ switch (value->type) { case PRO_PARAM_INTEGER: ProTKSprintf (c_param_value, "%d", value->value.i_val); break; case PRO_PARAM_DOUBLE: ProTKSprintf (c_param_value, "%lf", value->value.d_val); break; case PRO_PARAM_BOOLEAN: ProTKSprintf (c_param_value, "%s", value->value.l_val ? "TRUE" : "FALSE"); break; case PRO_PARAM_STRING: ProWstringToString (c_param_value, value->value.s_val); break; } ProWstringToString (c_name, name); param_name_len = strlen (c_name); ProWstringToString (c_constraint, constraint); constraint_len = strlen (c_constraint); /*--------------------------------------------------------------------*\ Replace each instance of 'name' appearing in the constraint with the value expression. \*--------------------------------------------------------------------*/ strcpy (c_line, ""); for (i = 0; i < constraint_len; i ++) { if (strncmp (&c_constraint[i], c_name, param_name_len) == 0) { strcat (c_line, c_param_value); i = i + param_name_len; } ProTKSprintf (c_buff, "%c", c_constraint [i]); strcat (c_line, c_buff); } ProStringToWstring (line, c_line); /*--------------------------------------------------------------------*\ Pass the modified expression to Pro/E for evaluation. It should output a boolean param value with the result. \*--------------------------------------------------------------------*/ status = ProRelationEvalWithUnitsRefResolve(relset, line, &result, &units, PRO_B_FALSE); PT_TEST_LOG_SUCC ("ProRelationEvalWithUnitsRefResolve()"); if (result.type != PRO_PARAM_BOOLEAN) return (PRO_TK_NOT_VALID); if (result.value.l_val != PRO_B_TRUE) return (PRO_TK_NOT_VALID); return (PRO_TK_NO_ERROR); } /*====================================================================*\ FUNCTION: PTUDFExParamCompareValue PURPOSE: Compare two param values. \*====================================================================*/ static ProError PTUDFExParamCompareValue (ProParamvalue* value, ProParamvalue* permitted_value) { if (value->type != permitted_value->type) return (PRO_TK_NOT_VALID); switch (value->type) { case PRO_PARAM_INTEGER: return (value->value.i_val == permitted_value->value.i_val ? PRO_TK_NO_ERROR : PRO_TK_NOT_VALID); case PRO_PARAM_DOUBLE: return (value->value.d_val == permitted_value->value.d_val ? PRO_TK_NO_ERROR : PRO_TK_NOT_VALID); case PRO_PARAM_BOOLEAN: return (value->value.l_val == permitted_value->value.l_val ? PRO_TK_NO_ERROR : PRO_TK_NOT_VALID); case PRO_PARAM_STRING: { int result; ProWstringCompare (value->value.s_val, permitted_value->value.s_val, PRO_VALUE_UNUSED, &result); return (result == 0 ? PRO_TK_NO_ERROR : PRO_TK_NOT_VALID); } } return (PRO_TK_NOT_VALID); } /*====================================================================*\ FUNCTION: PTUDFExParamRangeFailureStringGet PURPOSE: Create the string showing that the value failed due to a violated range. \*====================================================================*/ static ProError PTUDFExParamRangeFailureStringGet (ProParameter* param, ProParamLimit* minimum, ProParamLimit* maximum, ProLine reason) { ProCharLine c_reason; ProTKSprintf (c_reason, "Parameter violated range assigned."); ProStringToWstring (reason, c_reason); return (PRO_TK_NO_ERROR); } /*====================================================================*\ FUNCTION: PTUDFExParamConstraintFailureStringGet PURPOSE: Create the string showing that the value failed due to a violated constraint. \*====================================================================*/ static ProError PTUDFExParamConstraintFailureStringGet (ProParameter* param, wchar_t* constraint, ProLine reason) { ProCharLine c_reason; ProTKSprintf (c_reason, "Parameter violated constraint assigned."); ProStringToWstring (reason, c_reason); return (PRO_TK_NO_ERROR); } /*====================================================================*\ FUNCTION: PTUDFExParamVerify PURPOSE: Utility for deciding if a given parameter can be set to a given value. \*====================================================================*/ ProError PTUDFExParamVerify (ProParameter* param, ProParamvalue* value, ProLine reason) { ProError ret_status = PRO_TK_NO_ERROR; ProBoolean is_enumerated; ProParamvalue* values; ProBoolean has_range; ProParamLimit minimum; ProParamLimit maximum; ProError min_status, max_status; ProModelitem m_item; ProRelset relset; wchar_t** constraints; int i, array_size; ProCharLine c_reason; /*--------------------------------------------------------------------*\ Check enumerated values for the parameter. \*--------------------------------------------------------------------*/ status = ProParameterIsEnumerated (param, &is_enumerated, &values); PT_TEST_LOG_SUCC ("ProParameterIsEnumerated"); if (is_enumerated) { status = ProArraySizeGet (values, &array_size); PT_TEST_LOG_SUCC ("ProArraySizeGet"); for (i = 0; i < array_size; i++) { /*--------------------------------------------------------------------*\ If this function returns PRO_TK_NO_ERROR, we have a match and can stop checking. \*--------------------------------------------------------------------*/ status = PTUDFExParamCompareValue (value, &values[i]); if (status == PRO_TK_NO_ERROR) break; } if (status != PRO_TK_NO_ERROR) { ProTKSprintf (c_reason, "Parameter value not found in list of available enumerated values."); ProStringToWstring (reason, c_reason); ret_status = PRO_TK_NOT_VALID; } ProArrayFree ((ProArray*)&values); } if (ret_status != PRO_TK_NO_ERROR) return (ret_status); /*--------------------------------------------------------------------*\ Check numerical range for the parameter. \*--------------------------------------------------------------------*/ status = ProParameterRangeGet (param, &has_range, &minimum, &maximum); PT_TEST_LOG ("ProParameterRangeGet", status, status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND); if (has_range && (minimum.type != PRO_PARAM_UNLIMITED && maximum.type != PRO_PARAM_UNLIMITED)) { /*--------------------------------------------------------------------*\ If either function returns PRO_TK_NOT_VALID the value is out of range. \*--------------------------------------------------------------------*/ min_status = PTUDFExParamValidateLimit (value, &minimum); max_status = PTUDFExParamValidateLimit (value, &maximum); if (min_status == PRO_TK_NOT_VALID || max_status == PRO_TK_NOT_VALID) { PTUDFExParamRangeFailureStringGet (param, &minimum, &maximum, reason); ret_status = PRO_TK_NOT_VALID; } } if (ret_status != PRO_TK_NO_ERROR) return (ret_status); /*--------------------------------------------------------------------*\ Check constraints applied to the parameter via parameter tables. \*--------------------------------------------------------------------*/ if (param->owner.type == PRM_MODEL) { status = ProMdlToModelitem (param->owner.who.model, &m_item); } else { m_item = param->owner.who.item; } status = ProModelitemToRelset (&m_item, &relset); status = ProRelsetConstraintsGet (&relset, &constraints); PT_TEST_LOG ("ProRelsetConstraintsGet", status, status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND); if (status == PRO_TK_NO_ERROR) { status = ProArraySizeGet (constraints, &array_size); for (i = 0; i < array_size; i++) { /*--------------------------------------------------------------------*\ If the function returns PRO_TK_NOT_VALID the constraint is violated. \*--------------------------------------------------------------------*/ status = PTUDFExParamValidateConstraint (&relset, param->id, value, constraints[i]); if (status == PRO_TK_NOT_VALID) { PTUDFExParamConstraintFailureStringGet (param, constraints[i], reason); ret_status = PRO_TK_NOT_VALID; break; } } ProArrayFree ((ProArray*)&constraints); } return (ret_status); }