/*
Copyright (c) 2019 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;
/*--------------------------------------------------------------------*\
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 = ProRelationEval (relset, line, &result);
PT_TEST_LOG_SUCC ("ProRelationEval()");
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);
}