/************************************************************************/ /* 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 Êý×é*/ /*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; jmvluTypeInfo.sortedNum = i+1; } M_FREE (MSMEM_GEN, sortedNames); }