Files
microser/mmslib/mvlu/mvlu_rt.c
2026-06-15 15:48:16 +08:00

423 lines
15 KiB
C
Raw Blame History

/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/* (c) Copyright Systems Integration Specialists Company, Inc., */
/* 1997-2001, All Rights Reserved */
/* */
/* MODULE NAME : mvlu_rt.c */
/* PRODUCT(S) : */
/* */
/* MODULE DESCRIPTION : */
/* */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
/* main */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 01/18/08 JRB 11 We allow up to 15 char LNName (sclparse.c), */
/* so max flatname must be MAX_IDENT_LEN-15. */
/* 07/20/07 JRB 10 Flatnames must be shorter to add LNName later*/
/* 11/22/06 JRB 09 Free bufs if _mvlu_build_uca_name_tbl fails. */
/* 01/30/06 GLB 09 Integrated porting changes for VMS */
/* 03/11/04 GLB 08 Added "#ifdef DEBUG_SISCO" for "thisFileName" */
/* 09/18/03 JRB 07 Allow array of structures. */
/* DON'T allow array of arrays (return error). */
/* 05/02/03 JRB 06 switch(rt->el_tag): Use default for most cases*/
/* 04/29/03 JRB 05 Chg several functions to return ST_RET. */
/* 04/24/03 JRB 04 Use MAX_IDENT_LEN define. */
/* 03/13/03 JRB 03 mvlu_proc_rt_type: Chg to use RUNTIME_CTRL. */
/* MVLU_UCA_NAME_CTRL: Chg ucaName member from */
/* ptr to array (saves allocs). */
/* 12/11/02 JRB 02 Use new mvl_uca.h */
/* 11/14/02 MDE 01 New module, extracted fo_uca.c */
/************************************************************************/
#include "glbtypes.h"
#include "sysincs.h"
#include "gen_list.h"
#include "mmsdefs.h"
#include "mms_pvar.h"
#include "mms_vvar.h"
#include "mem_chk.h"
#include "mvl_uca.h"
/************************************************************************/
/************************************************************************/
#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif
/************************************************************************/
/************************************************************************/
/* STATIC VARIABLES */
#define MAX_PREFIX_LEN 200
#define MAX_NEST_LEVEL 50
static ST_CHAR *namePrefix[MAX_NEST_LEVEL];
static ST_INT nestLevel;
/************************************************************************/
/* STATIC FUNCTIONS */
static ST_RET _mvlu_set_rt_sort_num (ST_CHAR *typeName,
RUNTIME_TYPE *rt, ST_INT numRt,
MVLU_UCA_NAME_CTRL **ucaNamesOut);
static ST_VOID _mvlu_set_rt_size (RUNTIME_TYPE *rt) ;
static ST_VOID _mvlu_set_rt_offset (RUNTIME_TYPE *rt, ST_INT numRt);
static ST_RET _mvlu_build_uca_name_tbl (RUNTIME_TYPE *rt, ST_INT rt_num,
MVLU_UCA_NAME_CTRL *mvluFoundryInfo);
static ST_RET _mvlu_save_rt_uca_name (ST_INT nestLevel, RUNTIME_TYPE *rt,
MVLU_UCA_NAME_CTRL *mvluFoundryInfo);
static ST_VOID _mvlu_sort_uca_names (MVLU_UCA_NAME_CTRL *ucaNames,
RUNTIME_TYPE *rt, ST_INT numRt);
/************************************************************************/
/************************************************************************/
/* mvlu_proc_rt_type */
/************************************************************************/
ST_RET mvlu_proc_rt_type (ST_CHAR *typeName, RUNTIME_CTRL *rt_ctrl,
MVLU_UCA_NAME_CTRL **ucaNamesOut)
{
RUNTIME_TYPE *rt;
ST_INT i;
ST_RET ret;
/* Set the sortedNum for each RT element */
ret = _mvlu_set_rt_sort_num (typeName, rt_ctrl->rt_first, rt_ctrl->rt_num, ucaNamesOut);
if (ret)
return(ret); /* don't bother continuing */
/* Find the offset of the data for each RT within the type */
_mvlu_set_rt_offset (rt_ctrl->rt_first, rt_ctrl->rt_num);
/* Find the size of each RT within the type */
rt = rt_ctrl->rt_first;
for (i = 0; i < rt_ctrl->rt_num; ++i, ++rt)
_mvlu_set_rt_size (rt);
return (ret);
}
/************************************************************************/
/************************************************************************/
/* _mvlu_set_rt_size */
/************************************************************************/
/* This function would not be needed except that the UCA structure */
/* handling needs to know the size of each subelement too ... */
static ST_VOID _mvlu_set_rt_size (RUNTIME_TYPE *rt)
{
ST_INT numUcaRt;
ST_INT blockedLen;
if (rt->el_tag == RT_ARR_END || rt->el_tag == RT_STR_END)
{
return;
}
if (rt->el_tag == RT_STR_START)
numUcaRt = rt->u.str.num_rt_blks+2;
else if (rt->el_tag == RT_ARR_START)
numUcaRt = rt->u.arr.num_rt_blks+2;
else
numUcaRt = 1;
/* Now we can find the size of this element and it's associates */
blockedLen = ms_get_blocked_length (rt, numUcaRt);
rt->offset_to_last = blockedLen;
}
/************************************************************************/
/************************************************************************/
/* _mvlu_set_rt_offset */
/************************************************************************/
static ST_VOID _mvlu_set_rt_offset (RUNTIME_TYPE *rt, ST_INT numRt)
{
ST_INT data_offset;
SD_CONST RUNTIME_TYPE *rt_end;
ST_INT arr_loops[ASN1_MAX_LEVEL];
ST_BOOLEAN arr_el_set[ASN1_MAX_LEVEL];
ST_INT arr_loop_level;
arr_loop_level = 0;
rt_end = rt + numRt; /* end block */
data_offset = 0;
/* Traverse the RT type as though we were doing a ASN.1 to LOCAL */
while (rt < rt_end)
{
if (rt->el_tag == RT_ARR_END) /* treat case of array ending */
{
if (--arr_loops[arr_loop_level] > 0)/* if need to do next ar elmnt*/
{
rt -= rt->u.arr.num_rt_blks; /* mv rt to start of arr */
continue;
}
else
--arr_loop_level;
}
if (arr_loop_level == 0 || arr_el_set[arr_loop_level] == SD_FALSE)
{
rt->mvluTypeInfo.offSet = data_offset; /* Set the offset */
/* renxiaobao <20><><EFBFBD><EFBFBD>*/
/*arr_el_set[arr_loop_level] = SD_TRUE;*/
}
data_offset += rt->el_size; /* Offset for next */
if (rt->el_tag == RT_ARR_START) /* Set up array looping */
{
++arr_loop_level;
arr_loops[arr_loop_level] = rt->u.arr.num_elmnts;
arr_el_set[arr_loop_level] = SD_FALSE;
}
rt++; /* point to next runtime element */
}
}
/************************************************************************/
/************************************************************************/
/* _mvlu_set_rt_sort_num */
/************************************************************************/
static ST_RET _mvlu_set_rt_sort_num (ST_CHAR *typeName,
RUNTIME_TYPE *rt, ST_INT numRt,
MVLU_UCA_NAME_CTRL **ucaNamesOut)
{
MVLU_UCA_NAME_CTRL *ucaNames;
ST_INT i;
ucaNames = (MVLU_UCA_NAME_CTRL *) chk_calloc (numRt, sizeof (MVLU_UCA_NAME_CTRL));
nestLevel = 0;
/* Derive the UCA names within this type */
namePrefix[0] = (ST_CHAR *) chk_calloc (1, MAX_PREFIX_LEN);
if (typeName != NULL)
strcpy (namePrefix[0], typeName);
if (_mvlu_build_uca_name_tbl (rt, numRt, ucaNames))
{
chk_free(ucaNames);
chk_free(namePrefix[0]);
return (SD_FAILURE); /* don't bother continuing */
}
/* Now sort the UCA names within the type */
_mvlu_sort_uca_names (ucaNames, rt, numRt);
for (i = 0; i < MAX_NEST_LEVEL; ++i)
{
if (namePrefix[i] != NULL)
{
chk_free (namePrefix[i]);
namePrefix[i] = NULL;
}
}
if (ucaNamesOut == NULL)
chk_free (ucaNames);
else
*ucaNamesOut = ucaNames;
return (SD_SUCCESS);
}
/************************************************************************/
/* _mvlu_build_uca_name_tbl */
/* Start with retCode=SD_SUCCESS. If any call to _mvlu_save_rt_uca_name */
/* fails, set retCode=SD_FAILURE. Do not return immediately because we */
/* want to log as many problems as possible first. */
/************************************************************************/
static ST_RET _mvlu_build_uca_name_tbl (RUNTIME_TYPE *rt, ST_INT rt_num,
MVLU_UCA_NAME_CTRL *ucaNames)
{
ST_INT i;
ST_RET retCode=SD_SUCCESS;
nestLevel = 0;
for (i = 0; i < rt_num; ++i, ++rt)
{
ucaNames[i].rtIndex = i;
ucaNames[i].rt = rt;
switch (rt->el_tag)
{
case RT_STR_START :
if (ms_comp_name_pres(rt))
{
if (_mvlu_save_rt_uca_name (nestLevel, rt, &ucaNames[i]))
retCode = SD_FAILURE; /*continue but eventually return this*/
++nestLevel;
if (namePrefix[nestLevel] == NULL)
namePrefix[nestLevel] = (ST_CHAR *) chk_calloc (1, MAX_PREFIX_LEN);
strcpy (namePrefix[nestLevel], namePrefix[nestLevel-1]);
strcat (namePrefix[nestLevel], "$");
strcat (namePrefix[nestLevel], ms_comp_name_find(rt));
}
break;
case RT_STR_END :
--nestLevel;
break;
case RT_ARR_START :
if (_mvlu_save_rt_uca_name (nestLevel, rt, &ucaNames[i]))
retCode = SD_FAILURE; /*continue but eventually return this*/
/* We let the array element inherit our name so we will generate */
/* rd/wr ind handler functions and references for the contained */
/* primitive elements */
/* This causes duplicate names (name of array same as name of */
/* object IN array). That's OK because names of anything inside */
/* array are dropped when sorted (see _mvlu_sort_uca_names). */
/* The "sorted" array of names is used in GetNameList response. */
if (ms_is_rt_prim (rt+1) || (rt+1)->el_tag==RT_STR_START)
{
#if defined(USE_RT_TYPE_2)
(rt+1)->comp_name_ptr = rt->comp_name_ptr;
#elif defined(USE_RT_TYPE_3)
(rt+1)->name_index = rt->name_index;
#else
strcpy ((rt+1)->name, rt->name);
#endif
}
else
{
SLOGALWAYS1 ("Warning: Arrays of arrays not supported for UCA (%s)",
ucaNames[i].ucaName);
retCode = SD_FAILURE; /*continue but eventually return this*/
}
break;
case RT_ARR_END :
break;
default :
if (_mvlu_save_rt_uca_name (nestLevel, rt, &ucaNames[i]))
retCode = SD_FAILURE; /*continue but eventually return this*/
break;
}
}
return (retCode);
}
/************************************************************************/
/* _mvlu_save_rt_uca_name */
/* Start with retCode=SD_SUCCESS. If anything fails, set retCode=SD_FAILURE.*/
/************************************************************************/
static ST_RET _mvlu_save_rt_uca_name (ST_INT nestLevel,
RUNTIME_TYPE *rt,
MVLU_UCA_NAME_CTRL *nameDest)
{
ST_CHAR nameBuf[256];
ST_RET retCode = SD_SUCCESS;
nameDest->ucaName [0] = '\0'; /* start with empty string */
nameDest->rt = rt;
if (ms_comp_name_pres(rt))
{
sprintf (nameBuf, "%s$%s", namePrefix[nestLevel], ms_comp_name_find(rt));
/* Make sure there is room left for longest allowed Logical Node Name*/
/* (11 characters according to IEC 61850-7-2 but we allow 15). */
/* NOTE: this allows 5 or 6 more char than 61850-7-2 specifies, so */
/* it is more forgiving, but it prevents illegal MMS names. */
if (strlen (nameBuf) > (MAX_IDENT_LEN-15))
{
SLOGALWAYS2 ("Error: Flattened IEC 61850 variable name '%s' > %d characters. Illegal.",
nameBuf, (MAX_IDENT_LEN-15));
SLOGCALWAYS0 ("Must allow space for LNName up to 15 characters");
retCode = SD_FAILURE;
}
else
strcpy (nameDest->ucaName, nameBuf);
}
return (retCode);
}
/************************************************************************/
/************************************************************************/
/* SORTING UCA NAMES WITHIN A TYPE */
/************************************************************************/
/* elementCompare */
/************************************************************************/
/* This function is sorting the namelist table */
static ST_INT elementCompare (const MVLU_UCA_NAME_CTRL *a,
const MVLU_UCA_NAME_CTRL *b)
{
return (strcmp (a->ucaName, b->ucaName));
}
/************************************************************************/
/* _mvlu_sort_uca_names */
/************************************************************************/
static ST_VOID _mvlu_sort_uca_names (MVLU_UCA_NAME_CTRL *ucaNames,
RUNTIME_TYPE *rt, ST_INT numRt)
{
ST_INT i;
ST_INT numNames;
MVLU_UCA_NAME_CTRL *sortedNames; /* compressed/sorted array of names*/
sortedNames = (MVLU_UCA_NAME_CTRL *) M_MALLOC (MSMEM_GEN, numRt*sizeof(MVLU_UCA_NAME_CTRL));
/* Compress the name table */
numNames = 0;
for (i = 0; i < numRt; ++i, ++rt)
{
if (ucaNames[i].ucaName[0] != '\0')
{
sortedNames[numNames] = ucaNames[i];
++numNames;
/* CRITICAL:
* The "ucaNames" array contains names for objects inside arrays.
* They must be kept in the original array, because they are needed
* for generating leaf function names.
* However, they are NOT legal variable names, so they are NOT
* copied to the SORTED array (used for GetNameList response).
* This is done by skipping over the runtime type for the array.
*/
if (rt->el_tag==RT_ARR_START)
{
rt += (rt->u.arr.num_rt_blks + 1);
i += (rt->u.arr.num_rt_blks + 1);
}
}
}
/* OK, we now have a raw table of names, go ahead and sort them */
qsort (sortedNames, numNames, sizeof (MVLU_UCA_NAME_CTRL),
(int (*)(const void *,const void *)) elementCompare);
#if 0 /* DEBUG: enable this code to debug sorting algorithm */
if (numNames)
{
ST_INT j;
SLOGALWAYS0 ("Array of UCA variable names (Uncompressed/Unsorted)");
for (j = 0; j<numRt; j++)
SLOGCALWAYS1 ("%s", ucaNames[j].ucaName);
SLOGALWAYS0 ("Array of UCA variable names (Compressed/Sorted)");
for (j = 0; j<numNames; j++)
SLOGCALWAYS1 ("%s", sortedNames[j].ucaName);
}
#endif
/* Now assign sort numbers to the RT elements */
for (i = 0; i < numNames; ++i)
{
sortedNames[i].rt->mvluTypeInfo.sortedNum = i+1;
}
M_FREE (MSMEM_GEN, sortedNames);
}