/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/*	(c) Copyright Systems Integration Specialists Company, Inc.,	*/
/*	2004-2006 All Rights Reserved					*/
/*									*/
/* MODULE NAME : sclstore.c						*/
/* PRODUCT(S)  : MMS-EASE-LITE						*/
/*									*/
/* MODULE DESCRIPTION :							*/
/*	Functions to store information parsed from SCL file.		*/
/*									*/
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE :				*/
/*			scl_lntype_create				*/
/*			scl_lntype_add_do				*/
/*			scl_dotype_create				*/
/*			scl_dotype_add_da				*/
/*			scl_dotype_add_sdo				*/
/*			scl_datype_create				*/
/*			scl_datype_add_bda				*/
/*			scl_enumtype_create				*/
/*			scl_enumtype_add_enumval			*/
/*			scl_fcda_add					*/
/*			scl_dai_add					*/
/*			scl_dataset_add					*/
/*			scl_rcb_add					*/
/*			scl_lcb_add					*/
/*			scl_gcb_add					*/
/*			scl_ln_add					*/
/*			scl_ld_create					*/
/*			scl_info_destroy				*/
/*									*/
/* MODIFICATION LOG :							*/
/*  Date     Who   Rev     Comments					*/
/* --------  ---  ------   -------------------------------------------  */
/* 04/23/08  JRB    11     Add scl_sgcb_add.				*/
/* 07/26/06  JRB    10     Add scl_subnet_add, scl_cap_add, scl_gse_add,*/
/*			   scl_smv_add.					*/
/* 04/04/06  JRB    09	   Add scl_svcb_add: alloc SCL_SVCB & add to list.*/
/* 03/15/06  JRB    08     Simplify functions: Do not copy data.	*/
/*			    Most functions take only (SCL_INFO *) arg &	*/
/*			    just alloc struct and add to linked list.	*/
/*			   Del scl_dotype_add_da_val,			*/
/*			    scl_datype_add_bda_val, scl_header_save.	*/
/* 01/30/06  GLB    07     Integrated porting changes for VMS           */
/* 07/25/05  JRB    06     If nameStructure!=IEDName, ignore it and	*/
/*			   assume nameStructure=IEDName anyway.		*/
/* 06/29/05  CRM    05     Add scl_info_destroy.			*/
/* 06/24/05  JRB    04     Chg "ord" from unsigned to signed value.	*/
/* 02/15/05  JRB    03     Chg scl_ld_create to generate scl_ld->domName.*/
/*			   Chg scl_fcda_add to generate scl_fcda->domName.*/
/*			   Chg scl_ln_add to generate scl_ln->varName.	*/
/*			   Add scl_header_save.				*/
/* 07/19/04  JRB    02     Add scl_lcb_add, scl_gcb_add.		*/
/* 06/10/04  JRB    01     Initial Revision.				*/
/************************************************************************/
#include "glbtypes.h"
#include "sysincs.h"
#include "scl.h"
#include "sx_log.h"
#include "str_util.h"

#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif


/* NOTE:
 * Functions with "scl_" prefix used while parsing SCL file to
 * store data in linked lists.
 * Functions with "scl2_" prefix (see sclproc.c) used to read info from
 * linked lists and create MMS objects (Domains, variables, NVLs, etc.).
 */

/************************************************************************/
/*			scl_lntype_create				*/
/* Begin creation of a Logical Node Type (LNodeType).			*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_LNTYPE *scl_lntype_create (
		SCL_INFO *scl_info)	/* struct to store all SCL info	*/
  {
SCL_LNTYPE *scl_lntype;

  scl_lntype = (SCL_LNTYPE *) chk_calloc (1, sizeof (SCL_LNTYPE));
  /* Add LNType to front of LNType List.	*/
  list_add_first (&scl_info->lnTypeHead, scl_lntype);
  return (scl_lntype);
  }

/************************************************************************/
/*			scl_lntype_add_do				*/
/* Add a Data Object (DO) to a Logical Node Type (LNodeType).		*/
/* Adds to lntype created by most recent call to "scl_lntype_create".	*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_DO *scl_lntype_add_do (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_DO *scl_do = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->lnTypeHead)
    {
    scl_do = (SCL_DO *) chk_calloc (1, sizeof (SCL_DO));
    /* Add DO to front of DO List in first entry of LNType list	*/
    list_add_first (&scl_info->lnTypeHead->doHead, scl_do);
    }
  else
    SXLOG_ERR0 ("Cannot add DO to NULL LNTYPE");
  return (scl_do);
  }

/************************************************************************/
/*			scl_dotype_create				*/
/* Begin creation of a Data Object Type (DOType).			*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_DOTYPE *scl_dotype_create (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_DOTYPE *scl_dotype;

  scl_dotype = (SCL_DOTYPE *) chk_calloc (1, sizeof (SCL_DOTYPE));
  /* Add DOType to front of DOType List.	*/
  list_add_first (&scl_info->doTypeHead, scl_dotype);
  return (scl_dotype);
  }

/************************************************************************/
/*			scl_dotype_add_da				*/
/* Add a Data Attribute (DA) to a Data Object Type (DOType).		*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_DA *scl_dotype_add_da (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_DA *scl_da = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->doTypeHead)
    {
    scl_da = (SCL_DA *) chk_calloc (1, sizeof (SCL_DA));
    /* CRITICAL: DA and SDO use same struct, "objtype" tells which one it is.*/
    scl_da->objtype = SCL_OBJTYPE_DA;
    /* Add DA to front of DA List in first entry of DOType list	*/
    list_add_first (&scl_info->doTypeHead->daHead, scl_da);
    }
  else
    SXLOG_ERR0 ("Cannot add DA to NULL DO");
  return (scl_da);
  }

/************************************************************************/
/*			scl_dotype_add_sdo				*/
/* Add a (SDO) to a Data Object Type (DOType).				*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_DA *scl_dotype_add_sdo (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_DA *scl_da = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->doTypeHead)
    {
    scl_da = (SCL_DA *) chk_calloc (1, sizeof (SCL_DA));
    /* CRITICAL: DA and SDO use same struct, "objtype" tells which one it is.
     * NOTE: Because this is SDO, the sAddr, bType, and valKind members of
     * the scl_da structure are NOT used.
     */
    scl_da->objtype = SCL_OBJTYPE_SDO;
    /* Add DA to front of DA List in first entry of DOType list	*/
    list_add_first (&scl_info->doTypeHead->daHead, scl_da);
    }
  else
    SXLOG_ERR0 ("Cannot add SDO to NULL DO");
  return (scl_da);
  }

/************************************************************************/
/*			scl_datype_create				*/
/* Begin creation of a Data Attribute Type (DAType).			*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_DATYPE *scl_datype_create (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_DATYPE *scl_datype;

  scl_datype = (SCL_DATYPE *) chk_calloc (1, sizeof (SCL_DATYPE));
  /* Add DAType to front of DAType List.	*/
  list_add_first (&scl_info->daTypeHead, scl_datype);
  return (scl_datype);
  }
/************************************************************************/
/*			scl_datype_add_bda				*/
/* Add a Basic Data Attribute (BDA) to a Data Attribute Type (DAType).	*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_BDA *scl_datype_add_bda (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_BDA *scl_bda = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->daTypeHead)
    {
    scl_bda = (SCL_BDA *) chk_calloc (1, sizeof (SCL_BDA));
    /* Add BDA to front of BDA List in first entry of DAType list	*/
    list_add_first (&scl_info->daTypeHead->bdaHead, scl_bda);
    }
  else
    SXLOG_ERR0 ("Cannot add BDA to NULL DATYPE");
  return (scl_bda);
  }

/************************************************************************/
/*			scl_enumtype_create				*/
/* Begin creation of an EnumType.					*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_ENUMTYPE *scl_enumtype_create (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_ENUMTYPE *scl_enumtype;

  scl_enumtype = (SCL_ENUMTYPE *) chk_calloc (1, sizeof (SCL_ENUMTYPE));
  /* Add EnumType to front of EnumType List.	*/
  list_add_first (&scl_info->enumTypeHead, scl_enumtype);
  return (scl_enumtype);
  }


/************************************************************************/
/*			scl_enumtype_add_enumval			*/
/* Add an EnumVal to an EnumType.					*/
/* Add to EnumType created by most recent call to scl_enumtype_create.	*/
/* RETURNS:	SD_SUCCESS or error code				*/
/************************************************************************/
SCL_ENUMVAL *scl_enumtype_add_enumval (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_ENUMVAL *scl_enumval = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->enumTypeHead)
    {
    scl_enumval = (SCL_ENUMVAL *) chk_calloc (1, sizeof (SCL_ENUMVAL));
    /* Add EnumVal to front of EnumVal List in first entry of EnumType list	*/
    list_add_first (&scl_info->enumTypeHead->enumvalHead, scl_enumval);
    }
  else
    SXLOG_ERR0 ("Cannot add ENUMVAL to NULL ENUMTYPE");
  return (scl_enumval);
  }


/************************************************************************/
/*			scl_fcda_add				*/
/* Allocates a SCL_FCDA struct						*/
/* and adds it to the linked list "fcdaHead" in SCL_DATASET.		*/
/************************************************************************/
SCL_FCDA *scl_fcda_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_FCDA *scl_fcda = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead
      && scl_info->ldHead->lnHead
      && scl_info->ldHead->lnHead->datasetHead)
    {
    scl_fcda = (SCL_FCDA *) chk_calloc (1, sizeof (SCL_FCDA));
    /* Add FCDA to front of FCDA List.	*/
    list_add_first (&scl_info->ldHead->lnHead->datasetHead->fcdaHead, scl_fcda);
    }
  else
    SXLOG_ERR0 ("Cannot add FCDA to NULL DATASET");

  return (scl_fcda);
  }

/************************************************************************/
/*			scl_dai_add					*/
/* Allocates a SCL_DAI struct						*/
/* and adds it to the linked list "daiHead" in SCL_LN.			*/
/************************************************************************/
SCL_DAI *scl_dai_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_DAI *scl_dai = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead
      && scl_info->ldHead->lnHead)
    {
    scl_dai = (SCL_DAI *) chk_calloc (1, sizeof (SCL_DAI));
    /* Add DAI to front of DAI List.	*/
    list_add_first (&scl_info->ldHead->lnHead->daiHead, scl_dai);
    }
  else
    SXLOG_ERR0 ("Cannot add DAI to NULL LN");
  return (scl_dai);
  }

/************************************************************************/
/*			scl_dataset_add				*/
/* Allocates a SCL_DATASET struct					*/
/* and adds it to the linked list "datasetHead" in SCL_LN.		*/
/************************************************************************/
SCL_DATASET *scl_dataset_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
				/* TRUNCATED if longer than buffer	*/
  {
SCL_DATASET *scl_dataset = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead
      && scl_info->ldHead->lnHead)
    {
    scl_dataset = (SCL_DATASET *) chk_calloc (1, sizeof (SCL_DATASET));
    /* Add DATASET to front of DATASET List.	*/
    list_add_first (&scl_info->ldHead->lnHead->datasetHead, scl_dataset);
    }
  else
    SXLOG_ERR0 ("Cannot add DATASET to NULL LN");
  return (scl_dataset);
  }

/************************************************************************/
/*			scl_rcb_add					*/
/* Alloc & add SCL_RCB struct to the linked list "rcbHead" in SCL_LN.	*/
/* NOTE: struct is not filled in yet.					*/
/* NOTE: the RptEnabled element of the SCL file is ignored. SISCO software*/
/*	does not need to know which clients may access the RCB.		*/
/************************************************************************/
SCL_RCB *scl_rcb_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_RCB *scl_rcb = NULL;

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead
      && scl_info->ldHead->lnHead)
    {
    scl_rcb = (SCL_RCB *) chk_calloc (1, sizeof (SCL_RCB));
    /* Add RCB to front of RCB List.	*/
    list_add_first (&scl_info->ldHead->lnHead->rcbHead, scl_rcb);
    }
  else
    SXLOG_ERR0 ("Cannot add RCB to NULL LN");
  return (scl_rcb);
  }

/************************************************************************/
/*			scl_lcb_add					*/
/* Alloc & add a SCL_LCB struct to the linked list "lcbHead" in SCL_LN.	*/
/* NOTE: struct is not filled in yet.					*/
/************************************************************************/
SCL_LCB *scl_lcb_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_LCB *scl_lcb = NULL;

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead
      && scl_info->ldHead->lnHead)
    {
    scl_lcb = (SCL_LCB *) chk_calloc (1, sizeof (SCL_LCB));
    /* Add LCB to front of LCB List.	*/
    list_add_first (&scl_info->ldHead->lnHead->lcbHead, scl_lcb);
    }
  else
    SXLOG_ERR0 ("Cannot add LCB to NULL LN");
  return (scl_lcb);
  }

/************************************************************************/
/*			scl_gcb_add					*/
/* Add a GOOSE Control Block (GCB).					*/
/* Allocates a SCL_GCB struct						*/
/* and adds it to the linked list "gcbHead" in SCL_LN.			*/
/* NOTE: The SCL file may also contain one or more "IEDName" elements to*/
/*       indicate IEDs that should subscribe for GOOSE data. We have no	*/
/*       way to use this information, so it is ignored.			*/
/************************************************************************/
SCL_GCB *scl_gcb_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_GCB *scl_gcb = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead
      && scl_info->ldHead->lnHead)
    {
    scl_gcb = (SCL_GCB *) chk_calloc (1, sizeof (SCL_GCB));
    /* Add GCB to front of GCB List.	*/
    list_add_first (&scl_info->ldHead->lnHead->gcbHead, scl_gcb);
    }
  else
    SXLOG_ERR0 ("Cannot add GCB (GOOSE Control Block) to NULL LN");
  return (scl_gcb);
  }

/************************************************************************/
/*			scl_sgcb_add					*/
/* Add a Setting Group Control Block (SGCB).				*/
/* Allocates a SCL_SGCB struct, stores ptr in "sgcb" in SCL_LN.		*/
/************************************************************************/
SCL_SGCB *scl_sgcb_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_SGCB *scl_sgcb = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead
      && scl_info->ldHead->lnHead)
    {
    /* Only one SGCB allowed. Make sure not already set.	*/
    if (scl_info->ldHead->lnHead->sgcb != NULL)
      {
      SXLOG_ERR0 ("Duplicate SGCB (Setting Group Control Block) not allowed");
      return (NULL);
      }
    else  
      scl_info->ldHead->lnHead->sgcb = scl_sgcb = (SCL_SGCB *) chk_calloc (1, sizeof (SCL_SGCB));
    }
  else
    SXLOG_ERR0 ("Cannot add SGCB (Setting Group Control Block) to NULL LN");
  return (scl_sgcb);
  }

/************************************************************************/
/*			scl_svcb_add					*/
/* Alloc & add SCL_SVCB struct to the linked list "svcbHead" in SCL_LN.	*/
/* NOTE: struct is not filled in yet.					*/
/************************************************************************/
SCL_SVCB *scl_svcb_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_SVCB *scl_svcb = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead
      && scl_info->ldHead->lnHead)
    {
    scl_svcb = (SCL_SVCB *) chk_calloc (1, sizeof(SCL_SVCB));
    /* Add to front of list.	*/
    list_add_first (&scl_info->ldHead->lnHead->svcbHead, scl_svcb);
    }
  else
    SXLOG_ERR0 ("Cannot add SVCB to NULL LN");
  return (scl_svcb);
  }

/************************************************************************/
/*			scl_ln_add					*/
/* Allocates a SCL_LN struct						*/
/* and adds it to the linked list "lnHead" in SCL_LD.			*/
/************************************************************************/
SCL_LN *scl_ln_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_LN *scl_ln = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->ldHead)
    {
    scl_ln = (SCL_LN *) chk_calloc (1, sizeof (SCL_LN));
    /* Add LN to front of LN List.	*/
    list_add_first (&scl_info->ldHead->lnHead, scl_ln);
    }
  else
    SXLOG_ERR0 ("Cannot add LN to NULL LD");
  return (scl_ln);
  }

/************************************************************************/
/*			scl_ld_create					*/
/* Allocates SCL_LD struct						*/
/* and adds it to the linked list "ldHead" in SCL_INFO.			*/
/************************************************************************/
SCL_LD *scl_ld_create (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_LD *scl_ld = NULL;	/* assume failure	*/

  scl_ld = (SCL_LD *) chk_calloc (1, sizeof (SCL_LD));
  /* Add LD to front of LD List.	*/
  list_add_first (&scl_info->ldHead, scl_ld);

  return (scl_ld);
  }

/************************************************************************/
/*			scl_subnet_add					*/
/* Allocates SCL_SUBNET struct						*/
/* and adds it to the linked list "subnetHead" in SCL_INFO.		*/
/************************************************************************/
SCL_SUBNET *scl_subnet_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_SUBNET *scl_subnet = NULL;	/* assume failure	*/

  scl_subnet = (SCL_SUBNET *) chk_calloc (1, sizeof (SCL_SUBNET));
  /* Add to front of list.	*/
  list_add_first (&scl_info->subnetHead, scl_subnet);

  return (scl_subnet);
  }

/************************************************************************/
/*			scl_cap_add					*/
/* Allocates a SCL_CAP struct						*/
/* and adds it to the linked list "capHead" in SCL_SUBNET.		*/
/************************************************************************/
SCL_CAP *scl_cap_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_CAP *scl_cap = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->subnetHead)
    {
    scl_cap = (SCL_CAP *) chk_calloc (1, sizeof (SCL_CAP));
    /* Add to front of list.	*/
    list_add_first (&scl_info->subnetHead->capHead, scl_cap);
    }
  else
    SXLOG_ERR0 ("Cannot add CAP to NULL SUBNET");
  return (scl_cap);
  }

/************************************************************************/
/*			scl_gse_add					*/
/* Allocates a SCL_GSE struct						*/
/* and adds it to the linked list "gseHead" in SCL_CAP.			*/
/************************************************************************/
SCL_GSE *scl_gse_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_GSE *scl_gse = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->subnetHead->capHead)
    {
    scl_gse = (SCL_GSE *) chk_calloc (1, sizeof (SCL_GSE));
    /* Add to front of list.	*/
    list_add_first (&scl_info->subnetHead->capHead->gseHead, scl_gse);
    }
  else
    SXLOG_ERR0 ("Cannot add GSE to NULL CAP");
  return (scl_gse);
  }

/************************************************************************/
/*			scl_smv_add					*/
/* Allocates a SCL_SMV struct						*/
/* and adds it to the linked list "smvHead" in SCL_CAP.			*/
/************************************************************************/
SCL_SMV *scl_smv_add (
	SCL_INFO *scl_info)	/* main struct where all SCL info stored*/
  {
SCL_SMV *scl_smv = NULL;	/* assume failure	*/

  /* All higher level linked lists must be initialized.	*/
  if (scl_info->subnetHead->capHead)
    {
    scl_smv = (SCL_SMV *) chk_calloc (1, sizeof (SCL_SMV));
    /* Add to front of list.	*/
    list_add_first (&scl_info->subnetHead->capHead->smvHead, scl_smv);
    }
  else
    SXLOG_ERR0 ("Cannot add SMV to NULL CAP");
  return (scl_smv);
  }

/************************************************************************/
/*			scl_info_destroy				*/
/* Destroy all info stored in the SCL_INFO structure by "scl_parse".	*/
/* NOTE: most buffers were allocated by functions in this module. The	*/
/*   elements "Val" and "desc" in several structures were allocated	*/
/*   by functions in "sclparse.c".					*/
/************************************************************************/
ST_VOID scl_info_destroy (SCL_INFO *scl_info)
  {
SCL_LNTYPE *lnType;	
SCL_DO *scl_do;
SCL_LD *scl_ld;
SCL_LN *scl_ln;
SCL_RCB *scl_rcb;
SCL_LCB *scl_lcb;
SCL_GCB *scl_gcb;
SCL_SVCB *scl_svcb;
SCL_DAI *scl_dai;
SCL_DATASET *scl_dataset;
SCL_FCDA *scl_fcda;
SCL_DATYPE * scl_daType;
SCL_BDA *scl_bda;
SCL_ENUMTYPE *scl_enum;
SCL_ENUMVAL *scl_enumval;
SCL_DOTYPE *scl_doType;	
SCL_DA *scl_da;	
SCL_SUBNET *scl_subnet;
SCL_CAP *scl_cap;
SCL_GSE *scl_gse;
SCL_SMV *scl_smv;

  while ((scl_subnet = (SCL_SUBNET *) list_get_first(&scl_info->subnetHead)) != NULL)
    {
    while ((scl_cap = (SCL_CAP *) list_get_first(&scl_subnet->capHead)) != NULL)
      {
      while ((scl_gse = (SCL_GSE *) list_get_first(&scl_cap->gseHead)) != NULL)
        {
        chk_free(scl_gse);
        }
      while ((scl_smv = (SCL_SMV *) list_get_first(&scl_cap->smvHead)) != NULL)
        {
        chk_free(scl_smv);
        }
      if (scl_cap->desc)
        chk_free (scl_cap->desc);
      chk_free (scl_cap);
      }
    if (scl_subnet->desc)
      chk_free (scl_subnet->desc);
    chk_free (scl_subnet);
    }

  while ((scl_daType = (SCL_DATYPE *) list_get_first (&scl_info->daTypeHead)) != NULL)
    {	
    while ((scl_bda = (SCL_BDA *) list_get_first (&scl_daType->bdaHead)) != NULL)
      {	
      if (scl_bda->desc)
        chk_free (scl_bda->desc);
      if (scl_bda->Val)
        chk_free (scl_bda->Val);
      chk_free (scl_bda);
      }
    chk_free (scl_daType);
    }

  while ((lnType = (SCL_LNTYPE *) list_get_first (&scl_info->lnTypeHead)) != NULL)
    {	
    while ((scl_do = (SCL_DO *) list_get_first (&lnType->doHead)) != NULL)
      {	
      chk_free (scl_do);
      }
    chk_free (lnType);
    }
  while ((scl_doType = (SCL_DOTYPE *) list_get_first (&scl_info->doTypeHead)) != NULL)
    {	
    while ((scl_da = (SCL_DA *) list_get_first (&scl_doType->daHead)) != NULL)
      {	
      if (scl_da->desc)
        chk_free (scl_da->desc);
      if (scl_da->Val)
        chk_free (scl_da->Val);
      chk_free (scl_da);
      }
    chk_free (scl_doType);
    }
  while ((scl_enum = (SCL_ENUMTYPE *) list_get_first (&scl_info->enumTypeHead)) != NULL)
    {	
    while ((scl_enumval = (SCL_ENUMVAL *) list_get_first (&scl_enum->enumvalHead)) != NULL)
      {	
      chk_free (scl_enumval);
      }
    chk_free (scl_enum);
    }
  while ((scl_ld = (SCL_LD *) list_get_first (&scl_info->ldHead)) != NULL)
    {	
    while ((scl_ln = (SCL_LN *) list_get_first (&scl_ld->lnHead)) != NULL)
      {	
      while ((scl_dai = (SCL_DAI *) list_get_first (&scl_ln->daiHead)) != NULL)
	{	
        if (scl_dai->Val)
          chk_free (scl_dai->Val);
	chk_free (scl_dai);
	}

      while ((scl_dataset = (SCL_DATASET *) list_get_first (&scl_ln->datasetHead)) != NULL)
	{	
	while ((scl_fcda = (SCL_FCDA *) list_get_first (&scl_dataset->fcdaHead)) != NULL)
	  {	
	  chk_free (scl_fcda);
	  }
        if (scl_dataset->desc)
          chk_free (scl_dataset->desc);
	chk_free (scl_dataset);
	}

      while ((scl_rcb = (SCL_RCB *) list_get_first (&scl_ln->rcbHead)) != NULL)
	{	
        if (scl_rcb->desc)
          chk_free (scl_rcb->desc);
	chk_free (scl_rcb);
	}

      while ((scl_lcb = (SCL_LCB *) list_get_first (&scl_ln->lcbHead)) != NULL)
	{	
        if (scl_lcb->desc)
          chk_free (scl_lcb->desc);
	chk_free (scl_lcb);
	}

      while ((scl_gcb = (SCL_GCB *) list_get_first (&scl_ln->gcbHead)) != NULL)
	{	
        if (scl_gcb->desc)
          chk_free (scl_gcb->desc);
	chk_free (scl_gcb);
	}
      while ((scl_svcb = (SCL_SVCB *) list_get_first (&scl_ln->svcbHead)) != NULL)
	{	
        if (scl_svcb->desc)
          chk_free (scl_svcb->desc);
	chk_free (scl_svcb);
	}
      /* Only one SGCB allowed (no linked list)	*/
      if (scl_ln->sgcb)
        {	
        if (scl_ln->sgcb->desc)
          chk_free (scl_ln->sgcb->desc);
        chk_free (scl_ln->sgcb);
        }
      if (scl_ln->desc)
        chk_free (scl_ln->desc);
      chk_free (scl_ln);
      }
    if (scl_ld->desc)
      chk_free (scl_ld->desc);
    chk_free (scl_ld);
    }
  }


