/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1998 - 2005, All Rights Reserved */ /* */ /* MODULE NAME : mvl_obj.c */ /* PRODUCT(S) : MMSEASE-LITE */ /* */ /* MODULE DESCRIPTION : */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* mvl_vmd_dom_add */ /* mvl_vmd_var_add */ /* mvl_vmd_nvl_add */ /* mvl_vmd_jou_add */ /* mvl_vmd_dom_remove */ /* mvl_vmd_var_remove */ /* mvl_vmd_nvl_remove */ /* mvl_vmd_jou_remove */ /* mvl_nvl_create */ /* mvl_nvl_destroy */ /* mvl_vmd_create */ /* mvl_vmd_destroy */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 02/26/08 JRB 28 mvl_vmd_destroy: do NOT free var->data (do */ /* not know if it was allocated). */ /* Check var or NVL is deletable before delete. */ /* mvl_vmd_dom_remove: remove dom objects first.*/ /* mvl_dom_destroy: do NOT remove dom objects. */ /* Add mvl_var_add_alloc, mvl_var_create_alloc. */ /* Add mvl_var_create_derived. */ /* Remove unused functions. */ /* 02/21/07 JRB 27 Fix funct names in this module header. */ /* 12/04/06 JRB 26 mvl_vmd_destroy: add arg to specify which VMD*/ /* and DO NOT destroy all rpt_ctrl (let user). */ /* 10/30/06 JRB 25 Add vmd_ctrl arg to several functions & chg */ /* prefix from "mvl_" to "mvl_vmd_". */ /* Add vmd_ctrl, net_info args to mvl_nvl_create.*/ /* Check that (net_info!=NULL) before using it. */ /* Move "*_delete" to mvl_objb.c with other */ /* insert/delete functions. */ /* Add mvl_vmd_create. */ /* 08/09/06 JRB 24 Free "last_data" only in mvl_var_destroy. */ /* Save type_ctrl in MVL_VAR_ASSOC. */ /* mvl_vmd_destroy: free mvl61850_rpt_ctrl_list.*/ /* 01/30/06 GLB 23 Integrated porting changes for VMS */ /* 10/25/05 EJV 22 Fix "last_data" memory leaks: alloc only if */ /* last_data==NULL, free only if last_data!=NULL.*/ /* 09/22/05 JRB 21 mvl_vmd_destroy: del VMD-spec vars, NVLs too.*/ /* 06/29/05 CRM 20 Add mvl_vmd_destroy. */ /* 06/27/05 JRB 19 Alloc "va->last_data" in mvl_nvl_create & */ /* free it in mvl_nvl_destroy so special NVL */ /* functs not needed for IEC/UCA reports. */ /* 06/27/05 JRB 18 mvl_var_create: chk type. */ /* 04/27/05 CRM 17 Added code to free dom->jou_tbl in */ /* mvl_dom_destroy */ /* 06/04/04 JRB 16 mvl_var_create: if (data), set use_static_data.*/ /* 10/03/03 JRB 15 mvl_nvl_add: set nvl_scope in MVL_NVLIST_CTRL*/ /* mvl_nvl_add/mvl_var_add: chk for valid dom first*/ /* 02/25/02 MDE 14 Now get max PDU size from mvl_cfg_info */ /* 01/23/02 EJV 13 Added journals to domain: */ /* mvl_init_dom - added max_num_jou param */ /* mvl_dom_resize - added max_num_jou param */ /* mvl_dom_create - added max_num_jou param */ /* mvl_dom_add - added max_num_jou param */ /* mvl_clear_dom_objs -added code for journals*/ /* mvl_jou_delete - added DOM_SPEC case */ /* 10/25/00 JRB 12 Del u_mvl funct ptrs. Call functs directly. */ /* Control with #ifdefs. */ /* 04/14/00 JRB 11 Move sort & compare code to mvl_objb.c */ /* 04/12/00 MDE 10 Moved AA resize code to mvl_acse.c */ /* 01/21/00 MDE 09 Now use MEM_SMEM for dynamic memory */ /* 09/15/99 JRB 08 Mv mvl_obj_nosort to mvl_objb.c for DOS link */ /* 09/13/99 MDE 07 Added SD_CONST modifiers */ /* 09/07/99 MDE 06 Changed MVL_VA_SCOPE to MVL_SCOPE */ /* 07/12/99 MDE 05 Fixed problem 'destroying' dom w/NVL or VAR */ /* 04/07/99 MDE 04 Logging improvements */ /* 03/18/99 MDE 03 Enhanced dynamic object facilities */ /* 01/20/99 JRB 02 Reduce # of functions. Chg names and args. */ /* Call new "mvl_???_insert" functions. */ /* Add ..nvl_remove, ..nvl_create, ..nvl_destroy*/ /* 11/18/98 MDE 01 Created */ /************************************************************************/ #include "glbtypes.h" #include "sysincs.h" #include "mvl_acse.h" #include "mvl_log.h" #if defined(MVL_UCA) #include "mvl_uca.h" /* need "MVLU_RPT_*" */ #endif /************************************************************************/ /* For debug version, use a static pointer to avoid duplication of */ /* __FILE__ strings. */ /************************************************************************/ #ifdef DEBUG_SISCO SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; #endif ST_VOID (*u_mvl_dom_destroy) (MVL_DOM_CTRL *dom); ST_VOID (*u_mvl_var_destroy)(MVL_VAR_ASSOC *va); ST_VOID (*u_mvl_nvl_destroy) (MVL_NVLIST_CTRL *nvl); ST_VOID (*u_mvl_jou_destroy) (MVL_JOURNAL_CTRL *jou); /************************************************************************/ /* SCOPE RESIZING FUNCTIONS */ /************************************************************************/ /************************************************************************/ /* mvl_vmd_resize */ /************************************************************************/ ST_VOID mvl_vmd_resize (ST_INT max_num_dom, ST_INT max_num_var, ST_INT max_num_nvl, ST_INT max_num_jou) { if (max_num_dom < mvl_vmd.num_dom) { MVL_LOG_NERR0 ("Resizing VMD: new max DOM is less than current"); max_num_dom = mvl_vmd.num_dom; } if (max_num_var < mvl_vmd.num_var_assoc) { MVL_LOG_NERR0 ("Resizing VMD: new max VA is less than current"); max_num_var = mvl_vmd.num_var_assoc; } if (max_num_nvl < mvl_vmd.num_nvlist) { MVL_LOG_NERR0 ("Resizing VMD: new max NVL is less than current"); max_num_nvl = mvl_vmd.num_nvlist; } if (max_num_jou < mvl_vmd.num_jou) { MVL_LOG_NERR0 ("Resizing VMD: new max JOU is less than current"); max_num_jou = mvl_vmd.num_jou; } _mvl_resize_ptr_tbl (&(mvl_vmd.max_num_dom), (ST_VOID ***)&(mvl_vmd.dom_tbl), max_num_dom); _mvl_resize_ptr_tbl (&(mvl_vmd.max_num_var_assoc), (ST_VOID ***)&(mvl_vmd.var_assoc_tbl), max_num_var); _mvl_resize_ptr_tbl (&(mvl_vmd.max_num_nvlist), (ST_VOID ***)&(mvl_vmd.nvlist_tbl), max_num_nvl); _mvl_resize_ptr_tbl (&(mvl_vmd.max_num_jou), (ST_VOID ***)&(mvl_vmd.jou_tbl), max_num_jou); } /************************************************************************/ /* mvl_dom_resize */ /************************************************************************/ ST_VOID mvl_dom_resize (MVL_DOM_CTRL *dom, ST_INT max_num_var, ST_INT max_num_nvl, ST_INT max_num_jou) { if (max_num_var < dom->num_var_assoc) { MVL_LOG_NERR0 ("Resizing Domain: new max VA is less than current"); max_num_var = dom->num_var_assoc; } if (max_num_nvl < dom->num_nvlist) { MVL_LOG_NERR0 ("Resizing Domain: new max NVL is less than current"); max_num_nvl = dom->num_nvlist; } if (max_num_jou < dom->num_jou) { MVL_LOG_NERR0 ("Resizing Domain: new max JOU is less than current"); max_num_jou = dom->num_jou; } _mvl_resize_ptr_tbl (&(dom->max_num_var_assoc), (ST_VOID ***)&(dom->var_assoc_tbl), max_num_var); _mvl_resize_ptr_tbl (&(dom->max_num_nvlist), (ST_VOID ***)&(dom->nvlist_tbl), max_num_nvl); _mvl_resize_ptr_tbl (&(dom->max_num_jou), (ST_VOID ***)&(dom->jou_tbl), max_num_jou); } /************************************************************************/ /* _mvl_resize_ptr_tbl */ /************************************************************************/ ST_VOID _mvl_resize_ptr_tbl (ST_INT *p_max_num, ST_VOID ***p_ptr_tbl, ST_INT new_size) { /* See if something needs to be done at all */ if (*p_max_num == new_size) return; /* See if the table is going away altogether */ if (new_size != 0) { if (*p_max_num != 0) *p_ptr_tbl = (ST_VOID **) M_REALLOC (MSMEM_GEN, *p_ptr_tbl, (new_size * sizeof (ST_VOID *))); else /* We did not have a table, but need one now */ *p_ptr_tbl = (ST_VOID **) M_CALLOC (MSMEM_GEN, new_size, sizeof (ST_VOID *)); } else { /* If we had a table, we need to free it */ if (*p_max_num != 0) M_FREE (MSMEM_GEN, *p_ptr_tbl); } *p_max_num = new_size; } /************************************************************************/ /* mvl_nvl_remove_all */ /* Remove all VMD-Specific NVLs & Domain-Specific NVLs in this VMD. */ /* CRITICAL: Use "mvl_vmd_nvl_remove". It makes sure it is safe to */ /* remove each NVL. */ /* RETURNS: SD_SUCCESS or SD_FAILURE */ /************************************************************************/ ST_RET mvl_nvl_remove_all (MVL_VMD_CTRL *vmd_ctrl) { ST_INT didx; MVL_DOM_CTRL *dom; /* Destroy VMD-Specific NVLs. */ while (vmd_ctrl->num_nvlist) { MVL_NVLIST_CTRL *nvl; OBJECT_NAME obj; nvl = vmd_ctrl->nvlist_tbl[vmd_ctrl->num_nvlist-1]; /* point to last nvl*/ obj.obj_name.vmd_spec = nvl->name; obj.object_tag = VMD_SPEC; if (mvl_vmd_nvl_remove (vmd_ctrl, &obj, NULL) != SD_SUCCESS) { MVL_LOG_ERR1 ("Error removing VMD-specific NVL='%s'", nvl->name); return (SD_FAILURE); } } /* Destroy Domain-Specific NVLs in all domains. */ for (didx = 0; didx < vmd_ctrl->num_dom; didx++) { dom = vmd_ctrl->dom_tbl [didx]; while (dom->num_nvlist) { MVL_NVLIST_CTRL *nvl; OBJECT_NAME obj; nvl = dom->nvlist_tbl[dom->num_nvlist-1]; /* point to last nvl*/ obj.obj_name.item_id = nvl->name; obj.domain_id = dom->name; obj.object_tag = DOM_SPEC; if (mvl_vmd_nvl_remove (vmd_ctrl, &obj, NULL) != SD_SUCCESS) { MVL_LOG_ERR2 ("Error removing NVL='%s' in domain '%s'", nvl->name, dom->name); return (SD_FAILURE); } } } return (SD_SUCCESS); } /************************************************************************/ /* mvl_var_in_nvl */ /* Is this var used in this NVL? */ /************************************************************************/ ST_BOOLEAN mvl_var_in_nvl (MVL_NVLIST_CTRL *nvl, MVL_VAR_ASSOC *var) { ST_INT vidx; MVL_VAR_ASSOC *nvl_var; /* variable used in a NVL */ for (vidx = 0; vidx < nvl->num_of_entries; vidx++) { nvl_var = nvl->entries[vidx]; if (nvl_var == var || nvl_var->base_va == var) { /* This variable (or a variable derived from it) is used in the NVL. */ return(SD_TRUE); } } return (SD_FALSE); /* This variable is NOT used in the NVL. */ } /************************************************************************/ /* mvl_var_deletable */ /* Is this var deletable (i.e. NOT referenced by other objects)? */ /************************************************************************/ ST_BOOLEAN mvl_var_deletable (MVL_VMD_CTRL *vmd_ctrl, MVL_VAR_ASSOC *var) { ST_INT didx, nvlidx; MVL_DOM_CTRL *dom; MVL_NVLIST_CTRL *nvl; assert (var->base_va == NULL); /* DEBUG: these are always base variables.*/ /* Make sure var is not used in any VMD-specific NVL. */ for (nvlidx = 0; nvlidx < vmd_ctrl->num_nvlist; ++nvlidx) { nvl = vmd_ctrl->nvlist_tbl[nvlidx]; if (mvl_var_in_nvl (nvl, var)) { MVL_LOG_ERR2 ("Variable=%s cannot be deleted because it is used in VMD-specific NVL=%s", var->name, nvl->name); return(SD_FALSE); } } /* Make sure var is not used in any Domain-specific NVL in any Domain. */ for (didx = 0; didx < vmd_ctrl->num_dom; didx++) { dom = vmd_ctrl->dom_tbl [didx]; for (nvlidx = 0; nvlidx < dom->num_nvlist; nvlidx++) { nvl = dom->nvlist_tbl[nvlidx]; if (mvl_var_in_nvl (nvl, var)) { MVL_LOG_ERR2 ("Variable=%s cannot be deleted because it is used in Domain-specific NVL=%s", var->name, nvl->name); return(SD_FALSE); } } } return (SD_TRUE); /* ok to delete it */ } /************************************************************************/ /* mvl_nvl_deletable */ /* Is this NVL deletable (i.e. NOT referenced by other objects)? */ /************************************************************************/ ST_BOOLEAN mvl_nvl_deletable (MVL_VMD_CTRL *vmd_ctrl, MVL_NVLIST_CTRL *nvl) { #if defined(MVL_UCA) /* check for IEC 61850 or UCA RCBs using this NVL*/ MVLU_RPT_CTRL *rptCtrl; /* NOTE: the flag "nvl->mms_deletable" is only used by the MMS service*/ /* DeleteNamedVariableList, not to prevent MVL from deleting this NVL.*/ /* See if NVL is used in any IEC 61850 Report Control Block. */ //lnk编译修改:原前置程序未使用 /*for (rptCtrl = mvl61850_rpt_ctrl_list; rptCtrl != NULL; rptCtrl = (MVLU_RPT_CTRL *) list_get_next (mvl61850_rpt_ctrl_list, rptCtrl)) { if (rptCtrl->dsNvl == nvl) { MVL_LOG_ERR1 ("NVL='%s' cannot be deleted because it is used in a IEC 61850 Report Control Block", nvl->name); return (SD_FALSE); } }*/ /* See if NVL is used in any UCA Report Control Block. */ //lnk编译修改:原前置程序未使用 /*for (rptCtrl = mvlu_rpt_ctrl_list; rptCtrl != NULL; rptCtrl = (MVLU_RPT_CTRL *) list_get_next (mvlu_rpt_ctrl_list, rptCtrl)) { if (rptCtrl->dsNvl == nvl) { MVL_LOG_ERR1 ("NVL='%s' cannot be deleted because it is used in a UCA Report Control Block", nvl->name); return (SD_FALSE); } }*/ #endif /* defined(MVL_UCA) */ /* NOTE: if not MVL_UCA, nothing to check. */ return (SD_TRUE); /* ok to delete it */ } /************************************************************************/ /************************************************************************/ /* DOMAIN */ /************************************************************************/ /************************************************************************/ /* mvl_vmd_dom_add */ /* Add a domain. Allocate, fill in, and insert into table. */ /************************************************************************/ MVL_DOM_CTRL *mvl_vmd_dom_add (MVL_VMD_CTRL *vmd_ctrl, ST_CHAR *name, ST_INT max_num_var, ST_INT max_num_nvl, ST_INT max_num_jou, ST_BOOLEAN copy_name) { MVL_DOM_CTRL *dom; dom = mvl_dom_create (name, max_num_var, max_num_nvl, max_num_jou, copy_name); /* Insert it in table. */ if (mvl_vmd_dom_insert (vmd_ctrl, dom)) { /* Failed. */ M_FREE (MSMEM_GEN, dom); return (NULL); } return (dom); } /************************************************************************/ /* mvl_dom_create */ /************************************************************************/ MVL_DOM_CTRL *mvl_dom_create (ST_CHAR *name, ST_INT max_num_var, ST_INT max_num_nvl, ST_INT max_num_jou, ST_BOOLEAN copy_name) { MVL_DOM_CTRL *dom; /* Allocate object and fill in "name". */ if (copy_name) { dom = (MVL_DOM_CTRL *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_DOM_CTRL) + strlen (name) + 1); dom->name = (ST_CHAR *) (dom+1); strcpy (dom->name, name); /* copy name */ } else { dom = (MVL_DOM_CTRL *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_DOM_CTRL)); dom->name = name; /* point to user buffer */ } /* Allocate the pointer tables */ mvl_dom_resize (dom, max_num_var, max_num_nvl, max_num_jou); return (dom); } /************************************************************************/ /* mvl_dom_cleanup */ /* Remove all objects (NVLs, variables, journals) from this domain. */ /* CRITICAL: Use "*_remove" functions. They make sure it is safe to */ /* remove each object. */ /************************************************************************/ ST_RET mvl_dom_cleanup (MVL_VMD_CTRL *vmd_ctrl, MVL_DOM_CTRL *dom) { ST_INT i; if (dom->foundry_objects) { MVL_LOG_NERR1 ("Cannot remove objects from domain '%s' because Foundry objects present", dom->name); return (SD_FAILURE); } /* Remove all NVL from this domain. Stop on first error. */ while (dom->num_nvlist) { MVL_NVLIST_CTRL *nvl; OBJECT_NAME obj; nvl = dom->nvlist_tbl[dom->num_nvlist-1]; /* point to last nvl*/ obj.obj_name.item_id = nvl->name; obj.domain_id = dom->name; obj.object_tag = DOM_SPEC; if (mvl_vmd_nvl_remove (vmd_ctrl, &obj, NULL) != SD_SUCCESS) { MVL_LOG_ERR2 ("Error removing NVL='%s' from domain='%s'", nvl->name, dom->name); return (SD_FAILURE); } } /* Remove all variables from this domain. Stop on first error. */ while (dom->num_var_assoc > 0) { MVL_VAR_ASSOC *var; OBJECT_NAME obj; var = dom->var_assoc_tbl[dom->num_var_assoc-1]; /* point to last var*/ obj.obj_name.item_id = var->name; obj.domain_id = dom->name; obj.object_tag = DOM_SPEC; if (mvl_vmd_var_remove (vmd_ctrl, &obj, NULL) != SD_SUCCESS) { MVL_LOG_ERR2 ("Error removing variable='%s' from domain='%s'", var->name, dom->name); return (SD_FAILURE); } } /* Delete the Journal control table. */ /* DEBUG: Should use mvl_vmd_jou_remove here but it can't fail, so */ /* using mvl_jou_destroy is just as good for now. */ if (dom->max_num_jou) { for (i = 0; i < dom->num_jou; ++i) mvl_jou_destroy (dom->jou_tbl[i]); } dom->num_jou = 0; return (SD_SUCCESS); } /************************************************************************/ /* mvl_vmd_dom_remove */ /************************************************************************/ ST_RET mvl_vmd_dom_remove (MVL_VMD_CTRL *vmd_ctrl, ST_CHAR *dom_name) { MVL_DOM_CTRL *dom; ST_RET retcode = SD_FAILURE; dom = mvl_vmd_find_dom (vmd_ctrl, dom_name); if (dom != NULL) { /* Remove all objects in domain before delete/destroy.*/ retcode = mvl_dom_cleanup (vmd_ctrl, dom); if (retcode) MVL_LOG_ERR1 ("Error removing objects from domain, so cannot remove domain '%s'", dom->name); else { /* cleanup successful */ /* NOTE: this delete should never fail because we already found it.*/ dom = mvl_vmd_dom_delete (vmd_ctrl, dom_name); if (dom != NULL) mvl_dom_destroy (dom); /* cannot fail. retcode already = SD_SUCCESS*/ else retcode = SD_FAILURE; /* delete failed. Should never happen */ } } return (retcode); } /************************************************************************/ /* mvl_dom_destroy */ /* NOTE: this assumes all objects already removed from domain. */ /************************************************************************/ ST_VOID mvl_dom_destroy (MVL_DOM_CTRL *dom) { if (u_mvl_dom_destroy != NULL) (*u_mvl_dom_destroy)(dom); if (dom->max_num_var_assoc != 0) M_FREE (MSMEM_GEN, dom->var_assoc_tbl); if (dom->max_num_nvlist != 0) M_FREE (MSMEM_GEN, dom->nvlist_tbl); if (dom->max_num_jou != 0) M_FREE (MSMEM_GEN, dom->jou_tbl); M_FREE (MSMEM_GEN, dom); } /************************************************************************/ /**** VARIABLE ASSOCIATIONS */ /************************************************************************/ /* mvl_vmd_var_add */ /* Add a variable association. Allocate, fill in, and insert into table.*/ /* NOT RECOMMENDED: use mvl_var_add_alloc. */ /************************************************************************/ MVL_VAR_ASSOC *mvl_vmd_var_add (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info, ST_INT type_id, ST_VOID *data, MVL_VAR_PROC *proc, ST_BOOLEAN copy_name) { MVL_VAR_ASSOC *va; MVL_DOM_CTRL *dom = NULL; /* Find domain, if necessary, before allocating anything. */ if (obj->object_tag==DOM_SPEC && (dom = mvl_vmd_find_dom (vmd_ctrl, obj->domain_id)) == NULL) { MVL_LOG_ERR2 ("Error creating VAR '%s': domain '%s' not found", obj->obj_name.vmd_spec, obj->domain_id); return (NULL); } va = mvl_var_create (obj, type_id, data, proc, copy_name); /* Insert it in table. */ if (va) { if (mvl_vmd_var_insert (vmd_ctrl, va, obj, net_info)) { /* Failed. */ mvl_var_destroy (va); /* destroy var just created */ return (NULL); } } return (va); } /************************************************************************/ /* mvl_var_create */ /* NOT RECOMMENDED: use mvl_var_create_alloc. */ /************************************************************************/ MVL_VAR_ASSOC *mvl_var_create (OBJECT_NAME *obj, ST_INT type_id, ST_VOID *data, MVL_VAR_PROC *proc, ST_BOOLEAN copy_name) { MVL_VAR_ASSOC *va; MVL_TYPE_CTRL *type_ctrl; type_ctrl = mvl_type_ctrl_find (type_id); if (type_ctrl == NULL) { MVL_LOG_ERR0 ("Cannot create variable (type_id invalid)."); return (NULL); } /* Allocate object and fill in "name". */ if (copy_name) { va = (MVL_VAR_ASSOC *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_VAR_ASSOC) + strlen (obj->obj_name.vmd_spec) + 1); va->name = (ST_CHAR *) (va+1); strcpy (va->name, obj->obj_name.vmd_spec); /* copy name */ } else { va = (MVL_VAR_ASSOC *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_VAR_ASSOC)); va->name = obj->obj_name.vmd_spec; /* point to user buffer */ } /* Fill in rest of object. */ va->type_id = type_id; va->type_ctrl = type_ctrl; /* don't need to call mvl_get_runtime */ /* to get type details. */ va->data = data; #if defined(MVL_UCA) /* If caller set the data ptr (!=NULL), assume they want to use static data.*/ if (data!=NULL) va->use_static_data = SD_TRUE; #endif va->proc = proc; return (va); } /************************************************************************/ /* mvl_var_add_alloc */ /* Add a variable association. Allocate, fill in, and insert into table.*/ /************************************************************************/ MVL_VAR_ASSOC *mvl_var_add_alloc (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info, ST_INT type_id, MVL_VAR_PROC *proc) { MVL_VAR_ASSOC *va; MVL_DOM_CTRL *dom = NULL; /* Find domain, if necessary, before allocating anything. */ if (obj->object_tag==DOM_SPEC && (dom = mvl_vmd_find_dom (vmd_ctrl, obj->domain_id)) == NULL) { MVL_LOG_ERR2 ("Error creating VAR '%s': domain '%s' not found", obj->obj_name.vmd_spec, obj->domain_id); return (NULL); } va = mvl_var_create_alloc (obj->obj_name.vmd_spec, type_id, proc); /* Insert it in table. */ if (va) { if (mvl_vmd_var_insert (vmd_ctrl, va, obj, net_info)) { /* Failed. */ mvl_var_destroy (va); /* destroy var just created */ return (NULL); } } return (va); } /************************************************************************/ /* mvl_var_create_alloc */ /* Create a new variable. ALWAYS allocate a buffer for */ /* the data (buffer is automatically freed when variable is destroyed). */ /* CRITICAL: DO NOT use for "derived" variables. Instead use */ /* mvl_var_create_derived. */ /************************************************************************/ MVL_VAR_ASSOC *mvl_var_create_alloc (ST_CHAR *name, ST_INT type_id, MVL_VAR_PROC *proc) { MVL_VAR_ASSOC *va; MVL_TYPE_CTRL *type_ctrl; type_ctrl = mvl_type_ctrl_find (type_id); if (type_ctrl == NULL) { MVL_LOG_ERR0 ("Cannot create variable (type_id invalid)."); return (NULL); } /* Allocate one buffer for MVL_VAR_ASSOC plus "data" plus "name". */ va = (MVL_VAR_ASSOC *) chk_calloc (1, sizeof (MVL_VAR_ASSOC) /* space for struct*/ + type_ctrl->data_size /* space for "data"*/ + strlen (name) + 1); /* space for "name"*/ /* Set data ptr right after MVL_VAR_ASSOC struct. */ /* NOTE: data is before name so alignment should be good for any data.*/ va->data = (va+1); /* Set name ptr right after data. */ va->name = ((ST_CHAR *) (va->data)) + type_ctrl->data_size; strcpy (va->name, name); /* copy name */ /* Fill in rest of object. */ va->type_id = type_id; va->type_ctrl = type_ctrl; /* save for easy access later. */ va->use_static_data = SD_TRUE; /* always SD_TRUE */ va->proc = proc; return (va); } /************************************************************************/ /* mvl_var_create_derived */ /* Create a "derived" variable. */ /* NOTE: Structure member "proc" always set to NULL. */ /* Structure member "data" points inside base variable. */ /************************************************************************/ MVL_VAR_ASSOC *mvl_var_create_derived (ST_CHAR *name, ST_INT type_id, MVL_VAR_ASSOC *baseVa, /* base variable from which to derive */ ST_INT offset_from_base, ST_RTINT prim_num) { MVL_VAR_ASSOC *va; MVL_TYPE_CTRL *type_ctrl; type_ctrl = mvl_type_ctrl_find (type_id); if (type_ctrl == NULL) { MVL_LOG_ERR0 ("Cannot create variable (type_id invalid)."); return (NULL); } /* Allocate object and fill in "name". */ va = (MVL_VAR_ASSOC *) chk_calloc (1, sizeof (MVL_VAR_ASSOC) + strlen (name) + 1); va->name = (ST_CHAR *) (va+1); strcpy (va->name, name); /* copy name */ /* Fill in rest of object. */ va->type_id = type_id; va->type_ctrl = type_ctrl; /* save for easy access later. */ /* va->proc = NULL (due to calloc above) */ /* Set special "va" elements only for derived variables. */ va->base_va = baseVa; va->user_info = baseVa->user_info; /* Save offset_from_base & prim_num passed as arguments. */ va->offset_from_base = offset_from_base; va->prim_num = prim_num; if (va->base_va->use_static_data) va->data = (((ST_CHAR *) va->base_va->data) + va->offset_from_base); /* else caller must set va->data. */ return (va); } /************************************************************************/ /* mvl_vmd_var_remove */ /************************************************************************/ ST_RET mvl_vmd_var_remove (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info) { MVL_VAR_ASSOC *va; /* First find it & make sure it is deletable. */ va = mvl_vmd_find_var (vmd_ctrl, obj, net_info); if (va == NULL || mvl_var_deletable (vmd_ctrl, va) == SD_FALSE) { MVL_LOG_ERR1 ("Error deleting variable='%s': not found or not deletable.", obj->obj_name.vmd_spec); return (SD_FAILURE); } va = mvl_vmd_var_delete (vmd_ctrl, obj, net_info); if (va == NULL) return (SD_FAILURE); mvl_var_destroy (va); return (SD_SUCCESS); } /************************************************************************/ /* mvl_var_destroy */ /************************************************************************/ ST_VOID mvl_var_destroy (MVL_VAR_ASSOC *va) { if (u_mvl_var_destroy != NULL) (*u_mvl_var_destroy)(va); /* "last_data" may have been allocated if this var used in NVL. */ if (va->last_data) chk_free (va->last_data); /* renxiaobao 日志 if (va->last_log_data) chk_free (va->last_log_data);*/ M_FREE (MSMEM_GEN, va); } /************************************************************************/ /**** NAMED VARIABLE LISTS */ /************************************************************************/ /* mvl_vmd_nvl_add */ /* Add a Named Variable List. Allocate, fill in, and insert into table. */ /************************************************************************/ MVL_NVLIST_CTRL *mvl_vmd_nvl_add (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *nvl_obj, MVL_NET_INFO *net_info, ST_INT num_var, OBJECT_NAME *var_obj, /* array of var names */ ST_BOOLEAN copy_name) { MVL_NVLIST_CTRL *nvl; MVL_DOM_CTRL *dom = NULL; /* Find domain, if necessary, before allocating anything. */ if (nvl_obj->object_tag==DOM_SPEC && (dom = mvl_vmd_find_dom (vmd_ctrl, nvl_obj->domain_id)) == NULL) { MVL_LOG_ERR2 ("Error creating NVL '%s': domain '%s' not found", nvl_obj->obj_name.vmd_spec, nvl_obj->domain_id); return (NULL); } /* Allocate it AND fill it in. */ nvl = mvl_nvl_create (vmd_ctrl, nvl_obj->obj_name.vmd_spec, num_var, var_obj, net_info, copy_name); if (nvl == NULL) return (NULL); /* Add scope info to "nvl". */ nvl->nvl_scope.scope = nvl_obj->object_tag; nvl->nvl_scope.dom = dom; /* NOTE: NULL if not DOM_SPEC (see above) */ /* Insert it in table. */ if (mvl_vmd_nvl_insert (vmd_ctrl, nvl, nvl_obj, net_info)) { /* Failed. */ mvl_nvl_destroy (nvl); return (NULL); } return (nvl); } /************************************************************************/ /* mvl_nvl_create */ /************************************************************************/ /* Given a list of MMS object names, create a MVL Named Variable List. */ /* This can include both configured and MVLU manufactured variables */ /* Use 'mvl_nvl_destroy' to free this NVL. */ MVL_NVLIST_CTRL *mvl_nvl_create (MVL_VMD_CTRL *vmd_ctrl, ST_CHAR *nvlName, ST_INT numNames, OBJECT_NAME *var_obj, /* array of var obj names*/ MVL_NET_INFO *net_info, /* where to find var_obj*/ /* if it is AA_SPEC */ ST_BOOLEAN copy_name) { MVL_NVLIST_CTRL *nvl; ST_INT j; /* Allocate object and fill in "name". */ if (copy_name) { nvl = (MVL_NVLIST_CTRL *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_NVLIST_CTRL) + strlen (nvlName) + 1); nvl->name = (ST_CHAR *) (nvl+1); strcpy (nvl->name, nvlName); /* copy name */ } else { nvl = (MVL_NVLIST_CTRL *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_NVLIST_CTRL)); nvl->name = nvlName; /* point to user buffer */ } /* Fill in rest of object. */ nvl->entries = (MVL_VAR_ASSOC **) M_CALLOC (MSMEM_GEN, numNames, sizeof (MVL_VAR_ASSOC *)); nvl->va_scope = (MVL_SCOPE *) M_CALLOC (MSMEM_GEN, numNames, sizeof (MVL_SCOPE)); nvl->num_of_entries = numNames; for (j = 0; j < nvl->num_of_entries; ++j, ++var_obj) { MVL_VAR_ASSOC *var; if ((nvl->entries[j] = var = _mvl_objname_to_va (vmd_ctrl, net_info, MMSOP_INFO_RPT, var_obj, &nvl->va_scope[j], SD_FALSE, NULL, NULL)) == NULL) { MVL_LOG_ERR2 ("Error creating NVL '%s': member variable '%s' not found", nvlName, var_obj->obj_name.vmd_spec); mvl_nvl_destroy (nvl); return (NULL); } else { #if defined(MVL_UCA) /* Alloc buffer for last data (used for IEC/UCA reports). */ if (!var->last_data) var->last_data = chk_calloc (1, mvl_type_ctrl[var->type_id].data_size); /*renxiaobao 日志 if (!var->last_log_data) var->last_log_data = chk_calloc (1, mvl_type_ctrl[var->type_id].data_size);*/ #endif } } return (nvl); } /************************************************************************/ /* mvl_vmd_nvl_remove */ /* Remove a Named Variable List. Delete it from table and "destroy" it. */ /************************************************************************/ ST_RET mvl_vmd_nvl_remove (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info) { MVL_NVLIST_CTRL *nvl; /* First find it & make sure it is deletable. */ nvl = mvl_vmd_find_nvl (vmd_ctrl, obj, net_info); if (nvl == NULL || mvl_nvl_deletable (vmd_ctrl, nvl) == SD_FALSE) { MVL_LOG_ERR1 ("Error deleting NVL='%s': not found or not deletable.", obj->obj_name.vmd_spec); return (SD_FAILURE); } /* Delete it from table. */ if ((nvl = mvl_vmd_nvl_delete (vmd_ctrl, obj, net_info)) == NULL) return (SD_FAILURE); /* nvl not found */ /* Destroy it. */ mvl_nvl_destroy (nvl); return (SD_SUCCESS); } /************************************************************************/ /* mvl_nvl_destroy */ /************************************************************************/ /* Free a MVL Named Variable List created by 'mvl_nvl_create' */ ST_VOID mvl_nvl_destroy (MVL_NVLIST_CTRL *nvl) { MVL_VAR_ASSOC *va; ST_INT i; if (u_mvl_nvl_destroy != NULL) (*u_mvl_nvl_destroy)(nvl); /* Free up any manufactured variables */ for (i = 0; i < nvl->num_of_entries; ++i) { va = nvl->entries[i]; #if defined(MVL_UCA) || defined(USE_MANUFACTURED_OBJS) /* NOTE: "va" may be NULL if mvl_nvl_create failed while adding entries.*/ if (va && va->va_to_free == va) { //u_mvl_free_va (MMSOP_INFO_RPT, va, NULL);//lnk编译删除,原前置程序未使用 } #endif } M_FREE (MSMEM_GEN, nvl->entries); M_FREE (MSMEM_GEN, nvl->va_scope); M_FREE (MSMEM_GEN, nvl); } /************************************************************************/ /**** JOURNALS */ /************************************************************************/ /* mvl_vmd_jou_add */ /* Add a Journal. Allocate, fill in, and insert into table. */ /************************************************************************/ MVL_JOURNAL_CTRL *mvl_vmd_jou_add (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info, ST_BOOLEAN copy_name) { MVL_JOURNAL_CTRL *jou; jou = mvl_jou_create (obj, net_info, copy_name); if (mvl_vmd_jou_insert (vmd_ctrl, jou, obj, net_info)) { /* Failed. */ M_FREE (MSMEM_GEN, jou); return (NULL); } return (jou); } /************************************************************************/ /* mvl_jou_create */ /************************************************************************/ MVL_JOURNAL_CTRL *mvl_jou_create (OBJECT_NAME *obj, MVL_NET_INFO *net_info, ST_BOOLEAN copy_name) { MVL_JOURNAL_CTRL *jou; /* Allocate object and fill in "name". */ if (copy_name) { jou = (MVL_JOURNAL_CTRL *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_JOURNAL_CTRL) + strlen (obj->obj_name.vmd_spec) + 1); jou->name = (ST_CHAR *) (jou+1); strcpy (jou->name, obj->obj_name.vmd_spec); /* copy name */ } else { jou = (MVL_JOURNAL_CTRL *) M_CALLOC (MSMEM_GEN, 1, sizeof (MVL_JOURNAL_CTRL)); jou->name = obj->obj_name.vmd_spec; /* point to user buffer */ } return (jou); } /************************************************************************/ /* mvl_vmd_jou_remove */ /************************************************************************/ ST_RET mvl_vmd_jou_remove (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info) { MVL_JOURNAL_CTRL *jou; jou = mvl_vmd_jou_delete (vmd_ctrl, obj, net_info); if (jou == NULL) return (SD_FAILURE); mvl_jou_destroy (jou); return (SD_SUCCESS); } /************************************************************************/ /* mvl_jou_destroy */ /************************************************************************/ ST_VOID mvl_jou_destroy (MVL_JOURNAL_CTRL *jou) { if (u_mvl_jou_destroy != NULL) (*u_mvl_jou_destroy)(jou); M_FREE (MSMEM_GEN, jou); } /************************************************************************/ /* mvl_vmd_create */ /* Create a new VMD with empty object arrays. */ /* Use "mvl_vmd_destroy" to destroy the VMD. */ /************************************************************************/ MVL_VMD_CTRL *mvl_vmd_create (ST_INT max_num_dom, ST_INT max_num_var, ST_INT max_num_nvl, ST_INT max_num_journal) { MVL_VMD_CTRL *vmd_ctrl = chk_calloc (1, sizeof (MVL_VMD_CTRL)); vmd_ctrl->max_num_var_assoc = max_num_var; if (vmd_ctrl->max_num_var_assoc) vmd_ctrl->var_assoc_tbl = (MVL_VAR_ASSOC **) chk_calloc ( vmd_ctrl->max_num_var_assoc, sizeof (MVL_VAR_ASSOC *)); vmd_ctrl->max_num_nvlist = max_num_nvl; if (vmd_ctrl->max_num_nvlist) vmd_ctrl->nvlist_tbl = (MVL_NVLIST_CTRL **) chk_calloc ( vmd_ctrl->max_num_nvlist, sizeof (MVL_NVLIST_CTRL *)); vmd_ctrl->max_num_dom = max_num_dom; if (vmd_ctrl->max_num_dom) vmd_ctrl->dom_tbl = (MVL_DOM_CTRL **) chk_calloc ( vmd_ctrl->max_num_dom, sizeof (MVL_DOM_CTRL *)); vmd_ctrl->max_num_jou = max_num_journal; if (vmd_ctrl->max_num_jou) vmd_ctrl->jou_tbl = (MVL_JOURNAL_CTRL **) chk_calloc ( vmd_ctrl->max_num_jou, sizeof (MVL_JOURNAL_CTRL *)); return (vmd_ctrl); }; /************************************************************************/ /* mvl_vmd_destroy */ /* Destroy all objects in this VMD. */ /* RETURNS: SD_SUCCESS or error code */ /************************************************************************/ ST_RET mvl_vmd_destroy (MVL_VMD_CTRL *vmd_ctrl) { ST_RET ret; ST_INT j; MVL_DOM_CTRL *dom; ret = SD_SUCCESS; /* default ret val: returned if LD linked list empty.*/ /* Remove all NVL from this VMD and from all Domains before deleting */ /* Domains. NVLs might reference vars in other domains. */ /* CRITICAL: Must be done first, or vars can't be destroyed later. */ ret = mvl_nvl_remove_all (vmd_ctrl); if (ret) { MVL_LOG_ERR0 ("Error destroying VMD: failed removing all NVL."); return (ret); } /* Delete VMD-Specific Variables. */ for (j = 0; j < vmd_ctrl->num_var_assoc; ++j) mvl_var_destroy (vmd_ctrl->var_assoc_tbl[j]); vmd_ctrl->num_var_assoc = 0; /* Delete Domains (always VMD-Specific). */ while ((dom = mvl_vmd_dom_find_last (vmd_ctrl)) != NULL) { ret = mvl_vmd_dom_remove (vmd_ctrl, dom->name); if (ret != SD_SUCCESS) break; } /* Destroy all types for this VMD. */ if (ret == SD_SUCCESS) ret = mvl_vmd_type_id_destroy_all (vmd_ctrl); /* Finally, free the tables and the VMD itself (allocated by mvl_vmd_create).*/ /* NOTE: can't do this for "mvl_vmd" because it was created by Foundry.*/ if (vmd_ctrl != &mvl_vmd) { if (vmd_ctrl->var_assoc_tbl) chk_free (vmd_ctrl->var_assoc_tbl); if (vmd_ctrl->nvlist_tbl) chk_free (vmd_ctrl->nvlist_tbl); if (vmd_ctrl->dom_tbl) chk_free (vmd_ctrl->dom_tbl); if (vmd_ctrl->jou_tbl) chk_free (vmd_ctrl->jou_tbl); chk_free (vmd_ctrl); } return (ret); }