MAPL_Resource.F90 Source File


This file depends on

sourcefile~~mapl_resource.f90~~EfferentGraph sourcefile~mapl_resource.f90 MAPL_Resource.F90 sourcefile~constants.f90 Constants.F90 sourcefile~mapl_resource.f90->sourcefile~constants.f90 sourcefile~esmfl_mod.f90 ESMFL_Mod.F90 sourcefile~mapl_resource.f90->sourcefile~esmfl_mod.f90 sourcefile~keywordenforcer.f90 KeywordEnforcer.F90 sourcefile~mapl_resource.f90->sourcefile~keywordenforcer.f90 sourcefile~mapl_comms.f90 MAPL_Comms.F90 sourcefile~mapl_resource.f90->sourcefile~mapl_comms.f90 sourcefile~mapl_exceptionhandling.f90 MAPL_ExceptionHandling.F90 sourcefile~mapl_resource.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~internalconstants.f90 InternalConstants.F90 sourcefile~constants.f90->sourcefile~internalconstants.f90 sourcefile~mathconstants.f90 MathConstants.F90 sourcefile~constants.f90->sourcefile~mathconstants.f90 sourcefile~physicalconstants.f90 PhysicalConstants.F90 sourcefile~constants.f90->sourcefile~physicalconstants.f90 sourcefile~esmfl_mod.f90->sourcefile~constants.f90 sourcefile~esmfl_mod.f90->sourcefile~mapl_comms.f90 sourcefile~esmfl_mod.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~base_base.f90 Base_Base.F90 sourcefile~esmfl_mod.f90->sourcefile~base_base.f90 sourcefile~mapl_abstractgridfactory.f90 MAPL_AbstractGridFactory.F90 sourcefile~esmfl_mod.f90->sourcefile~mapl_abstractgridfactory.f90 sourcefile~mapl_gridmanager.f90 MAPL_GridManager.F90 sourcefile~esmfl_mod.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_comms.f90->sourcefile~constants.f90 sourcefile~mapl_comms.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~mapl_comms.f90->sourcefile~base_base.f90 sourcefile~shmem.f90 Shmem.F90 sourcefile~mapl_comms.f90->sourcefile~shmem.f90 sourcefile~errorhandling.f90 ErrorHandling.F90 sourcefile~mapl_exceptionhandling.f90->sourcefile~errorhandling.f90 sourcefile~mapl_throw.f90 MAPL_Throw.F90 sourcefile~mapl_exceptionhandling.f90->sourcefile~mapl_throw.f90 sourcefile~base_base.f90->sourcefile~constants.f90 sourcefile~base_base.f90->sourcefile~keywordenforcer.f90 sourcefile~mapl_range.f90 MAPL_Range.F90 sourcefile~base_base.f90->sourcefile~mapl_range.f90 sourcefile~maplgrid.f90 MaplGrid.F90 sourcefile~base_base.f90->sourcefile~maplgrid.f90 sourcefile~errorhandling.f90->sourcefile~mapl_throw.f90 sourcefile~mapl_abstractgridfactory.f90->sourcefile~constants.f90 sourcefile~mapl_abstractgridfactory.f90->sourcefile~keywordenforcer.f90 sourcefile~mapl_abstractgridfactory.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~mapl_abstractgridfactory.f90->sourcefile~base_base.f90 sourcefile~pfio.f90 pFIO.F90 sourcefile~mapl_abstractgridfactory.f90->sourcefile~pfio.f90 sourcefile~mapl_gridmanager.f90->sourcefile~keywordenforcer.f90 sourcefile~mapl_gridmanager.f90->sourcefile~errorhandling.f90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_abstractgridfactory.f90 sourcefile~mapl_cubedspheregridfactory.f90 MAPL_CubedSphereGridFactory.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_cubedspheregridfactory.f90 sourcefile~mapl_externalgridfactory.f90 MAPL_ExternalGridFactory.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_externalgridfactory.f90 sourcefile~mapl_integer64gridfactorymap.f90 MAPL_Integer64GridFactoryMap.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_integer64gridfactorymap.f90 sourcefile~mapl_latlongridfactory.f90 MAPL_LatLonGridFactory.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_latlongridfactory.f90 sourcefile~mapl_stringgridfactorymap.f90 MAPL_StringGridFactoryMap.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_stringgridfactorymap.f90 sourcefile~mapl_swathgridfactory.f90 MAPL_SwathGridFactory.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_swathgridfactory.f90 sourcefile~mapl_tripolargridfactory.f90 MAPL_TripolarGridFactory.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_tripolargridfactory.f90 sourcefile~mapl_xygridfactory.f90 MAPL_XYGridFactory.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_xygridfactory.f90 sourcefile~mapl_gridmanager.f90->sourcefile~pfio.f90 sourcefile~physicalconstants.f90->sourcefile~mathconstants.f90 sourcefile~shmem.f90->sourcefile~constants.f90

Files dependent on this one

sourcefile~~mapl_resource.f90~~AfferentGraph sourcefile~mapl_resource.f90 MAPL_Resource.F90 sourcefile~mapl_generic.f90 MAPL_Generic.F90 sourcefile~mapl_generic.f90->sourcefile~mapl_resource.f90 sourcefile~test_mapl_resource.pf Test_MAPL_Resource.pf sourcefile~test_mapl_resource.pf->sourcefile~mapl_resource.f90 sourcefile~comp_testing_driver.f90 Comp_Testing_Driver.F90 sourcefile~comp_testing_driver.f90->sourcefile~mapl_generic.f90 sourcefile~mapl.f90 MAPL.F90 sourcefile~comp_testing_driver.f90->sourcefile~mapl.f90 sourcefile~mapl_capgridcomp.f90 MAPL_CapGridComp.F90 sourcefile~comp_testing_driver.f90->sourcefile~mapl_capgridcomp.f90 sourcefile~extdatagridcompmod.f90 ExtDataGridCompMod.F90 sourcefile~extdatagridcompmod.f90->sourcefile~mapl_generic.f90 sourcefile~extdatagridcompng.f90 ExtDataGridCompNG.F90 sourcefile~extdatagridcompng.f90->sourcefile~mapl_generic.f90 sourcefile~mapl.f90->sourcefile~mapl_generic.f90 sourcefile~mapl_capgridcomp.f90->sourcefile~mapl_generic.f90 sourcefile~mapl_capgridcomp.f90->sourcefile~extdatagridcompmod.f90 sourcefile~mapl_capgridcomp.f90->sourcefile~extdatagridcompng.f90 sourcefile~mapl_historygridcomp.f90 MAPL_HistoryGridComp.F90 sourcefile~mapl_capgridcomp.f90->sourcefile~mapl_historygridcomp.f90 sourcefile~mapl_geosatmaskmod.f90 MAPL_GeosatMaskMod.F90 sourcefile~mapl_geosatmaskmod.f90->sourcefile~mapl_generic.f90 sourcefile~mapl_historycollection.f90 MAPL_HistoryCollection.F90 sourcefile~mapl_historycollection.f90->sourcefile~mapl_generic.f90 sourcefile~mapl_historycollection.f90->sourcefile~mapl_geosatmaskmod.f90 sourcefile~mapl_stationsamplermod.f90 MAPL_StationSamplerMod.F90 sourcefile~mapl_historycollection.f90->sourcefile~mapl_stationsamplermod.f90 sourcefile~mapl_trajectorymod.f90 MAPL_TrajectoryMod.F90 sourcefile~mapl_historycollection.f90->sourcefile~mapl_trajectorymod.f90 sourcefile~mapl_historygridcomp.f90->sourcefile~mapl_generic.f90 sourcefile~mapl_historygridcomp.f90->sourcefile~mapl_geosatmaskmod.f90 sourcefile~mapl_historygridcomp.f90->sourcefile~mapl_historycollection.f90 sourcefile~mapl_historygridcomp.f90->sourcefile~mapl_stationsamplermod.f90 sourcefile~mapl_historygridcomp.f90->sourcefile~mapl_trajectorymod.f90 sourcefile~mapl_orbgridcompmod.f90 MAPL_OrbGridCompMod.F90 sourcefile~mapl_orbgridcompmod.f90->sourcefile~mapl_generic.f90 sourcefile~mapl_stationsamplermod.f90->sourcefile~mapl_generic.f90 sourcefile~mapl_trajectorymod.f90->sourcefile~mapl_generic.f90 sourcefile~capdriver.f90 CapDriver.F90 sourcefile~capdriver.f90->sourcefile~mapl.f90 sourcefile~extdataroot_gridcomp.f90 ExtDataRoot_GridComp.F90 sourcefile~capdriver.f90->sourcefile~extdataroot_gridcomp.f90 sourcefile~extdatadriver.f90 ExtDataDriver.F90 sourcefile~extdatadriver.f90->sourcefile~mapl.f90 sourcefile~extdatadrivergridcomp.f90 ExtDataDriverGridComp.F90 sourcefile~extdatadriver.f90->sourcefile~extdatadrivergridcomp.f90 sourcefile~extdatadrivermod.f90 ExtDataDriverMod.F90 sourcefile~extdatadriver.f90->sourcefile~extdatadrivermod.f90 sourcefile~extdatadriver.f90->sourcefile~extdataroot_gridcomp.f90 sourcefile~extdatadrivergridcomp.f90->sourcefile~extdatagridcompmod.f90 sourcefile~extdatadrivergridcomp.f90->sourcefile~extdatagridcompng.f90 sourcefile~extdatadrivergridcomp.f90->sourcefile~mapl.f90 sourcefile~extdatadrivergridcomp.f90->sourcefile~mapl_historygridcomp.f90 sourcefile~extdatadrivermod.f90->sourcefile~mapl.f90 sourcefile~extdatadrivermod.f90->sourcefile~extdatadrivergridcomp.f90 sourcefile~extdatadrivermod.f90->sourcefile~extdataroot_gridcomp.f90 sourcefile~extdataroot_gridcomp.f90->sourcefile~mapl.f90 sourcefile~varspecdescription.f90 VarspecDescription.F90 sourcefile~extdataroot_gridcomp.f90->sourcefile~varspecdescription.f90 sourcefile~mapl_cap.f90 MAPL_Cap.F90 sourcefile~mapl_cap.f90->sourcefile~mapl_capgridcomp.f90 sourcefile~mapl_demo_fargparse.f90 MAPL_demo_fargparse.F90 sourcefile~mapl_demo_fargparse.f90->sourcefile~mapl.f90 sourcefile~mapl_geosatmaskmod_smod.f90 MAPL_GeosatMaskMod_smod.F90 sourcefile~mapl_geosatmaskmod_smod.f90->sourcefile~mapl_geosatmaskmod.f90 sourcefile~mapl_trajectorymod_smod.f90 MAPL_TrajectoryMod_smod.F90 sourcefile~mapl_trajectorymod_smod.f90->sourcefile~mapl_trajectorymod.f90 sourcefile~pfio_mapl_demo.f90 pfio_MAPL_demo.F90 sourcefile~pfio_mapl_demo.f90->sourcefile~mapl.f90 sourcefile~regrid_util.f90 Regrid_Util.F90 sourcefile~regrid_util.f90->sourcefile~mapl.f90 sourcefile~time_ave_util.f90 time_ave_util.F90 sourcefile~time_ave_util.f90->sourcefile~mapl.f90 sourcefile~ut_extdata.f90 ut_ExtData.F90 sourcefile~ut_extdata.f90->sourcefile~extdatagridcompmod.f90 sourcefile~varspecdescription.f90->sourcefile~mapl.f90 sourcefile~mapl_gridcomps.f90 MAPL_GridComps.F90 sourcefile~mapl_gridcomps.f90->sourcefile~mapl_cap.f90 sourcefile~mapl_nuopcwrappermod.f90 MAPL_NUOPCWrapperMod.F90 sourcefile~mapl_nuopcwrappermod.f90->sourcefile~mapl_cap.f90

Source Code

#include "MAPL_Exceptions.h"
#include "MAPL_ErrLog.h"
#include "unused_dummy.H"
!=============================================================================
! FPP macros

#if defined(IO_SUCCESS)
#undef IO_SUCCESS
#endif
#define IO_SUCCESS 0

#if defined(MISMATCH_MESSAGE)
#undef MISMATCH_MESSAGE
#endif
#define MISMATCH_MESSAGE "Type of 'default' does not match type of 'value'."

#if defined(TYPE_CHARACTER)
#undef TYPE_CHARACTER
#endif
#define TYPE_CHARACTER character(len=*)

#if defined(TYPE_INTEGER4)
#undef TYPE_INTEGER4
#endif
#define TYPE_INTEGER4 integer(int32)

#if defined(TYPE_INTEGER8)
#undef TYPE_INTEGER8
#endif
#define TYPE_INTEGER8 integer(int64)

#if defined(TYPE_REAL4)
#undef TYPE_REAL4
#endif
#define TYPE_REAL4 real(real32)

#if defined(TYPE_REAL8)
#undef TYPE_REAL8
#endif
#define TYPE_REAL8 real(real64)

#if defined(TYPE_LOGICAL)
#undef TYPE_LOGICAL
#endif
#define TYPE_LOGICAL logical

#if defined(TYPENUM_CHARACTER)
#undef TYPENUM_CHARACTER
#endif
#define TYPENUM_CHARACTER 0

#if defined(TYPENUM_INTEGER4)
#undef TYPENUM_INTEGER4
#endif
#define TYPENUM_INTEGER4 1

#if defined(TYPENUM_INTEGER8)
#undef TYPENUM_INTEGER8
#endif
#define TYPENUM_INTEGER8 2

#if defined(TYPENUM_REAL4)
#undef TYPENUM_REAL4
#endif
#define TYPENUM_REAL4 3

#if defined(TYPENUM_REAL8)
#undef TYPENUM_REAL8
#endif
#define TYPENUM_REAL8 4

#if defined(TYPENUM_LOGICAL)
#undef TYPENUM_LOGICAL
#endif
#define TYPENUM_LOGICAL 5

!=============================================================================
!END FPP macros
!=============================================================================
!>
!### Module `MAPL_ResourceMod`
!
! Author: GMAO SI-Team
!
! `MAPL_ResourceMod` provides subroutines get scalar and array
! resources from ESMF_Config objects.
!
module MAPL_ResourceMod

   use ESMF
   use ESMFL_Mod
   use gFTL2_StringVector
   use MAPL_CommsMod
   use MAPL_Constants, only: MAPL_CF_COMPONENT_SEPARATOR
   use MAPL_ExceptionHandling
   use MAPL_KeywordEnforcerMod
   use, intrinsic :: iso_fortran_env, only: REAL32, REAL64, int32, int64

   ! !PUBLIC MEMBER FUNCTIONS:
   implicit none
   private

   enum, bind(c)
      enumerator :: MAPL_RESOURCE_VALUE_DEFAULT_MISMATCH = -1
      enumerator :: MAPL_RESOURCE_ARRAY_SIZE_FORMAT_CODE_FAILURE = -2
   end enum

   character(len=*), parameter :: EMPTY_STRING = ''
   integer, parameter :: MAX_LINE_LENGTH = 256

   public MAPL_GetResource_config_scalar
   public MAPL_GetResource_config_array
   public MAX_LINE_LENGTH

   interface array_format
      module procedure :: array_format_simple
      module procedure :: array_format_string
   end interface array_format

   character(len=*), parameter :: TYPE_STRING_CHARACTER = 'Character '
   character(len=*), parameter :: TYPE_STRING_INTEGER4 = 'Integer*4 '
   character(len=*), parameter :: TYPE_STRING_INTEGER8 = 'Integer*8 '
   character(len=*), parameter :: TYPE_STRING_REAL4 = 'Real*4 '
   character(len=*), parameter :: TYPE_STRING_REAL8 = 'Real*8 '
   character(len=*), parameter :: TYPE_STRING_LOGICAL = 'Logical '

   character(len=*), parameter :: CHARACTER_FMT = "(A)"
   character(len=*), parameter :: INTEGER_FMT = "(I0.1)"
   character(len=*), parameter :: REAL_FMT = "(F0.6)"
   character(len=*), parameter :: LOGICAL_FMT = "(L1)"
contains

   !>
   ! Set do_print & print_nondefault_only based on config and if default is present
   ! Print only (do_print) only if printrc is 0 or 1
   ! Print only nondefault values if printrc == 0 and if default is present
   subroutine get_print_settings(config, default_is_present, do_print, print_nondefault_only, rc)
      type(ESMF_Config), intent(inout) :: config
      logical, intent(in) :: default_is_present
      logical, intent(out) :: do_print
      logical, intent(out) :: print_nondefault_only
      integer, optional, intent(out) :: rc

      integer, parameter :: PRINT_ALL = 1
      integer, parameter :: PRINT_DIFFERENT = 0

      integer :: printrc
      integer :: status

      if (MAPL_AM_I_Root()) then
         call ESMF_ConfigGetAttribute(config, printrc, label = 'PRINTRC:', default = 0, _RC)
         do_print = (printrc == PRINT_ALL) .or. (printrc == PRINT_DIFFERENT)
         print_nondefault_only = (printrc == PRINT_DIFFERENT) .and. default_is_present
      else
         do_print = .FALSE.
      end if

   end subroutine get_print_settings

   !>
   ! Check if vector contains string
   logical function vector_contains_str(vector, string)
      type(StringVector), intent(in) :: vector
      character(len=*), intent(in) :: string
      type(StringVectorIterator) :: iter

      iter = vector%begin()

      vector_contains_str = .false.

      do while (iter /= vector%end())
         if (trim(string) == iter%of()) then
            vector_contains_str = .true.
            return
         end if
         call iter%next()
      end do

   end function vector_contains_str

   !>
   ! Check if resource has already been printed (vector contains label) or should be printed
   subroutine set_do_print(label, do_print)
      character(*), intent(in) :: label
      logical, intent(inout) :: do_print

      type(StringVector), pointer, save :: already_printed_labels => null()

      if (do_print) then
         if (.not. associated(already_printed_labels)) then
            allocate(already_printed_labels)
         end if

         ! Do not print label more than once
         if (.not. vector_contains_str(already_printed_labels, trim(label))) then
            call already_printed_labels%push_back(trim(label))
         else
            do_print = .FALSE.
         end if
      end if

   end subroutine set_do_print

   !>
   ! MAPL searches for labels with certain prefixes as well as just the label itself
   pure function get_labels_with_prefix(label, component_name) result(labels_with_prefix)
      character(len=*), intent(in) :: label
      character(len=*), optional, intent(in) :: component_name
      character(len=ESMF_MAXSTR) :: component_type
      character(len=ESMF_MAXSTR) :: labels_with_prefix(4)

      if(present(component_name)) then
         component_type = component_name(index(component_name, ":") + 1:)

         ! The order to search for labels in resource files
         labels_with_prefix(1) = trim(component_name)//"_"//trim(label)
         labels_with_prefix(2) = trim(component_type)//"_"//trim(label)
         labels_with_prefix(3) = trim(label)
         labels_with_prefix(4) = trim(component_name)//MAPL_CF_COMPONENT_SEPARATOR//trim(label)
      else
         labels_with_prefix = EMPTY_STRING
         labels_with_prefix(1) = label
      end if

   end function get_labels_with_prefix

   !>
   ! If possible, find label or label with prefix. Out: label found (logical)  ! version of label found,
   subroutine get_actual_label(config, label, label_is_present, actual_label, unusable, component_name, rc)
      type(ESMF_Config), intent(inout) :: config
      character(len=*), intent(in) :: label
      logical, intent(out) :: label_is_present
      character(len=:), allocatable, intent(out) :: actual_label
      class(KeywordEnforcer), optional, intent(in) :: unusable
      character(len=*), optional, intent(in) :: component_name
      integer, optional, intent(out) :: rc

      character(len=ESMF_MAXSTR), allocatable :: labels_to_try(:)
      integer :: i
      integer :: status

      _UNUSED_DUMMY(unusable)

      label_is_present = .false.

      ! If component_name is present, find label in some form in config. Else search
      ! for exact label

      labels_to_try = get_labels_with_prefix(label, component_name)

      do i = 1, size(labels_to_try)
         actual_label = trim(labels_to_try(i))
         if (len_trim(actual_label) == 0 ) cycle
         call ESMF_ConfigFindLabel(config, label = actual_label, isPresent = label_is_present, _RC)
         if (label_is_present) exit
      end do

      if (.not. label_is_present) actual_label = trim(label)

      _RETURN(_SUCCESS)
   end subroutine get_actual_label

   !>
   ! Find value of scalar variable in config
   subroutine MAPL_GetResource_config_scalar(config, val, label, value_is_set, unusable, default, component_name, iunit, rc)
      type(ESMF_Config), intent(inout) :: config
      class(*), intent(inout) :: val
      character(len=*), intent(in) :: label
      logical, intent(out) :: value_is_set
      class(KeywordEnforcer), optional, intent(in) :: unusable
      class(*), optional, intent(in) :: default
      character(len=*), optional, intent(in) :: component_name
      character(len=*), optional, intent(inout) :: iunit
      integer, optional, intent(out) :: rc

      character(len=:), allocatable :: actual_label
      character(len=:), allocatable :: type_format
      character(len=:), allocatable :: type_string
      character(len=MAX_LINE_LENGTH) :: formatted_value

      logical :: default_is_present
      logical :: label_is_present
      logical :: print_nondefault_only
      logical :: do_print
      logical :: value_is_default

      integer :: io_stat
      integer :: status

      _UNUSED_DUMMY(unusable)

#if defined(IS_ARRAY)
#undef IS_ARRAY
#endif

#if defined(VALUE_)
#undef VALUE_
#endif

#define VALUE_ val

#if defined(TYPE_)
#undef TYPE_
#endif

#if defined(TYPENUM)
#undef TYPENUM
#endif

      default_is_present = present(default)

      ! these need to be initialized explicitly
      value_is_set = .FALSE.
      label_is_present = .FALSE.
      print_nondefault_only = .FALSE.
      do_print = .FALSE.
      value_is_default = .FALSE.

      if (default_is_present) then
         _ASSERT(same_type_as(val, default), "Value and default must have same type")
      end if

      call get_actual_label(config, label, label_is_present, actual_label, component_name = component_name, _RC)

      if(.not. (label_is_present .or. default_is_present)) then
         ! label or default must be present
         value_is_set = .FALSE.
         return
      end if

      call get_print_settings(config, default_is_present, do_print, print_nondefault_only, _RC)

      select type(val)

      type is (TYPE_INTEGER4)

#define TYPE_ TYPE_INTEGER4
#define TYPENUM TYPENUM_INTEGER4
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_INTEGER8)

#define TYPE_ TYPE_INTEGER8
#define TYPENUM TYPENUM_INTEGER8
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_REAL4)

#define TYPE_ TYPE_REAL4
#define TYPENUM TYPENUM_REAL4
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_REAL8)

#define TYPE_ TYPE_REAL8
#define TYPENUM TYPENUM_REAL8
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_LOGICAL)

#define TYPE_ TYPE_LOGICAL
#define TYPENUM TYPENUM_LOGICAL
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_CHARACTER)

#define TYPE_ TYPE_CHARACTER
#define TYPENUM TYPENUM_CHARACTER
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM

      class default
         _FAIL( "Unsupported type")
      end select

      if(do_print) then
         call print_resource(type_string, actual_label, formatted_value, value_is_default, iunit=iunit, _RC)
      end if

      _RETURN(ESMF_SUCCESS)

#undef TYPE_
#undef TYPENUM

   end subroutine MAPL_GetResource_config_scalar

   !>
   ! Find value of array variable in config
   subroutine MAPL_GetResource_config_array(config, val, label, value_is_set, unusable, default, component_name, iunit, rc)
      type(ESMF_Config), intent(inout) :: config
      class(*), intent(inout) :: val(:)
      character(len=*), intent(in) :: label

      logical, intent(out) :: value_is_set
      class(KeywordEnforcer), optional, intent(in) :: unusable
      class(*), optional, intent(in) :: default(:)
      character(len=*), optional, intent(in) :: component_name
      character(len=*), optional, intent(inout) :: iunit
      integer, optional, intent(out) :: rc
      ! We assume we will never have more than 99 values, hence len=2

      character(len=:), allocatable :: actual_label
      character(len=:), allocatable :: type_format
      character(len=:), allocatable :: type_string
      character(len=MAX_LINE_LENGTH) :: formatted_value

      logical :: default_is_present
      logical :: label_is_present
      logical :: print_nondefault_only
      logical :: do_print
      logical :: value_is_default
      integer :: count

      integer :: io_stat
      integer :: status

      _UNUSED_DUMMY(unusable)

#if defined(TYPE_)
#undef TYPE_
#endif

#if defined(TYPENUM)
#undef TYPENUM
#endif

#if defined(IS_ARRAY)
#undef IS_ARRAY
#endif
#define IS_ARRAY

#if defined(VALUE_)
#undef VALUE_
#endif
#define VALUE_ val

#if defined(MAX_CHAR_LEN)
#undef MAX_CHAR_LEN
#endif

      default_is_present = present(default)

      ! these need to be initialized explicitly
      value_is_set = .FALSE.
      label_is_present = .FALSE.
      print_nondefault_only = .FALSE.
      do_print = .FALSE.
      value_is_default = .FALSE.

      if (default_is_present) then
         _ASSERT(same_type_as(val, default), "Value and default must have same type")
      end if

      call get_actual_label(config, label, label_is_present, actual_label, component_name = component_name, _RC)

      ! label or default must be present
      if (.not. label_is_present .and. .not. default_is_present) then
         value_is_set = .FALSE.
         return
      end if

      ! only print if root
      call get_print_settings(config, default_is_present, do_print, print_nondefault_only, _RC)

      count = size(val)

      select type(val)

      type is (TYPE_INTEGER4)

#define TYPE_ TYPE_INTEGER4
#define TYPENUM TYPENUM_INTEGER4
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_INTEGER8)

#define TYPE_ TYPE_INTEGER8
#define TYPENUM TYPENUM_INTEGER8
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_REAL4)

#define TYPE_ TYPE_REAL4
#define TYPENUM TYPENUM_REAL4
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_REAL8)

#define TYPE_ TYPE_REAL8
#define TYPENUM TYPENUM_REAL8
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_LOGICAL)

#define TYPE_ TYPE_LOGICAL
#define TYPENUM TYPENUM_LOGICAL
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      type is (TYPE_CHARACTER)

#define TYPE_ TYPE_CHARACTER
#define TYPENUM TYPENUM_CHARACTER
#include "MAPL_Resource_SetValue.h"
#include "MAPL_Resource_MakeString.h"
#undef TYPE_
#undef TYPENUM


      class default
         _FAIL( "Unsupported type")
      end select

      if(do_print) then
         call print_resource(type_string, actual_label, formatted_value, value_is_default, iunit=iunit, _RC)
      end if

      _RETURN(ESMF_SUCCESS)

   end subroutine MAPL_GetResource_config_array


   !>
   ! Print the resource value
   subroutine print_resource(type_string, label, formatted_value, value_is_default, unusable, iunit, rc)
      character(len=*), intent(in) :: type_string
      character(len=*), intent(in) :: label
      character(len=*), intent(in) :: formatted_value
      logical, intent(in) :: value_is_default
      class(KeywordEnforcer), optional, intent(in) :: unusable
      character(len=*), optional, intent(out) :: iunit
      integer, optional, intent(out) :: rc

      character(len=*), parameter :: DEFAULT_ = ", (default value)"
      character(len=*), parameter :: NONDEFAULT_ = EMPTY_STRING
      character(len=*), parameter :: TRUNCATE = '... [VALUE_TRUNCATED]'
      integer, parameter :: LENGTH_TRUNCATE = len(TRUNCATE)
      character(len=:), allocatable :: output_format
      character(len=:), allocatable :: trailer
      character(len=:), allocatable :: value_out
      character(len=ESMF_MAXSTR) :: output_string
      character(len=MAX_LINE_LENGTH) :: final_output
      integer :: max_length_value_out

      _UNUSED_DUMMY(unusable)

      if(value_is_default) then
         trailer = DEFAULT_
      else
         trailer =  NONDEFAULT_
      end if

      ! maximum line length before adding the label and trailer
      max_length_value_out = MAX_LINE_LENGTH - len_trim(label) - len(trailer)

      value_out = trim(formatted_value)
      if(len(value_out) == 0) then
      ! if something went wrong, the formatted_value will be empty, so provide alternative value_out
         value_out = "[Empty formatted value]"
      else if(len(value_out) > max_length_value_out) then
         ! if value_out is too long (such that the output string will be longer than maxium line length, truncate
         value_out = value_out(1:(max_length_value_out - LENGTH_TRUNCATE)) // TRUNCATE
      end if

      ! Make output_string including label but without the trailer
      output_string = " " // type_string // "Resource Parameter: " // trim(label) // value_out

      ! Add the trailer now
      output_string = trim(output_string) // trailer

      ! Output a string no longer than maximum line length
      final_output = output_string(1:len(final_output))
      output_format = '(a)'

      if(present(iunit)) then
         iunit = EMPTY_STRING
         iunit = final_output(1:min(len(iunit), MAX_LINE_LENGTH))
      else
         write(*, fmt='(a)') trim(final_output)
      end if

      _RETURN(_SUCCESS)

   end subroutine print_resource

   !>
   ! Create array format string from scalar format string
   pure function array_format_string(scalar_format, array_size_string) result(array_format)
      character(len=*), intent(in) :: scalar_format
      character(len=*), intent(in) :: array_size_string
      character(len=:), allocatable :: array_format
      character(len=:), allocatable :: one_group
      integer :: lsf

      lsf = len_trim(scalar_format)
      one_group = scalar_format(2:(lsf-1))
      array_format = '('//trim(adjustl(array_size_string))// '(' // one_group//',1X))'
!      array_format = '('//trim(adjustl(array_size_string))//scalar_format(1:len_trim(scalar_format)-1)//',1X))'

   end function array_format_string

   !wdb fixme This should replace array_format_string, be renamed array_format, and delete interface array_format
   pure function array_format_simple(scalar_format) result(array_format)
      character(len=*), intent(in) :: scalar_format
      character(len=:), allocatable :: array_format
      character(len=:), allocatable :: base_format
      character(len=*), parameter :: UNLIMITED_FORMAT_ITEM = "*"

      base_format = scalar_format(2:(len_trim(scalar_format)-1))
      array_format = '(' // UNLIMITED_FORMAT_ITEM // '(' // base_format //', 1X))'

   end function array_format_simple

   !>
   ! Create format string for array of strings
   pure function string_array_format(array_size_string)
      character(len=*), intent(in) :: array_size_string
      character(len=:), allocatable :: string_array_format
      character(len=:), allocatable :: N

      ! N specifies the number of repeats in the format string.
      N = trim(adjustl(array_size_string))
      string_array_format = '('//N//'(""a"",1X))'

   end function string_array_format

   !>
   ! Compare all the strings in two string arrays
   pure function compare_all(astrings, bstrings)
      character(len=*), dimension(:), intent(in) :: astrings
      character(len=*), dimension(:), intent(in) :: bstrings
      logical :: compare_all

      integer :: i

      compare_all = (size(astrings) == size(bstrings))

      do i=1, size(astrings)
         if(.not. compare_all) exit
         compare_all = (trim(astrings(i)) == trim(bstrings(i)))
      end do

   end function compare_all

   function make_string_character(value_, slen) result(string)
      character(len=*), intent(in) :: value_
      integer, intent(in) :: slen
      character(len=slen) :: string
      integer :: last

      last = min(slen, len(value_))
      string = value_(1:last)

   end function make_string_character

   function make_string_character_array(value_, slen) result(string)
      character(len=*), intent(in) :: value_(:)
      integer, intent(in) :: slen
      character(len=slen) :: string
      character(len=:), allocatable :: raw
      integer :: i, last

      string = ''
      if(size(value_) == 0) return

      raw = EMPTY_STRING
      do i=1, size(value_)
         raw = raw // ' ' // trim(value_(i))
         if(len(raw) > slen) exit
      end do

      last = min(slen, len(raw))
      string = raw(1:last)

   end function make_string_character_array

end module MAPL_ResourceMod