StringTemplate.F90 Source File


This file depends on

sourcefile~~stringtemplate.f90~~EfferentGraph sourcefile~stringtemplate.f90 StringTemplate.F90 sourcefile~mapl_exceptionhandling.f90 MAPL_ExceptionHandling.F90 sourcefile~stringtemplate.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~mapl_keywordenforcer.f90 MAPL_KeywordEnforcer.F90 sourcefile~stringtemplate.f90->sourcefile~mapl_keywordenforcer.f90 sourcefile~mapl_errorhandling.f90 MAPL_ErrorHandling.F90 sourcefile~mapl_exceptionhandling.f90->sourcefile~mapl_errorhandling.f90 sourcefile~mapl_throw.f90 MAPL_Throw.F90 sourcefile~mapl_exceptionhandling.f90->sourcefile~mapl_throw.f90 sourcefile~mapl_errorhandling.f90->sourcefile~mapl_throw.f90

Files dependent on this one

sourcefile~~stringtemplate.f90~~AfferentGraph sourcefile~stringtemplate.f90 StringTemplate.F90 sourcefile~extdataabstractfilehandler.f90 ExtDataAbstractFileHandler.F90 sourcefile~extdataabstractfilehandler.f90->sourcefile~stringtemplate.f90 sourcefile~extdataclimfilehandler.f90 ExtDataClimFileHandler.F90 sourcefile~extdataclimfilehandler.f90->sourcefile~stringtemplate.f90 sourcefile~extdatafilestream.f90 ExtDataFileStream.F90 sourcefile~extdatafilestream.f90->sourcefile~stringtemplate.f90 sourcefile~extdatagridcompmod.f90 ExtDataGridCompMod.F90 sourcefile~extdatagridcompmod.f90->sourcefile~stringtemplate.f90 sourcefile~extdatagridcompng.f90 ExtDataGridCompNG.F90 sourcefile~extdatagridcompng.f90->sourcefile~stringtemplate.f90 sourcefile~extdatasimplefilehandler.f90 ExtDataSimpleFileHandler.F90 sourcefile~extdatasimplefilehandler.f90->sourcefile~stringtemplate.f90 sourcefile~fieldbundleread.f90 FieldBundleRead.F90 sourcefile~fieldbundleread.f90->sourcefile~stringtemplate.f90 sourcefile~mapl_cfio.f90 MAPL_CFIO.F90 sourcefile~mapl_cfio.f90->sourcefile~stringtemplate.f90 sourcefile~mapl_generic.f90 MAPL_Generic.F90 sourcefile~mapl_generic.f90->sourcefile~stringtemplate.f90 sourcefile~mapl_geosatmaskmod.f90 MAPL_GeosatMaskMod.F90 sourcefile~mapl_geosatmaskmod.f90->sourcefile~stringtemplate.f90 sourcefile~mapl_historygridcomp.f90 MAPL_HistoryGridComp.F90 sourcefile~mapl_historygridcomp.f90->sourcefile~stringtemplate.f90 sourcefile~mapl_obsutil.f90 MAPL_ObsUtil.F90 sourcefile~mapl_obsutil.f90->sourcefile~stringtemplate.f90 sourcefile~mapl_trajectorymod_smod.f90 MAPL_TrajectoryMod_smod.F90 sourcefile~mapl_trajectorymod_smod.f90->sourcefile~stringtemplate.f90

Source Code

#include "MAPL_Exceptions.h"
#include "unused_dummy.H"
module MAPL_StringTemplate
use ESMF
use MAPL_ExceptionHandling
use MAPL_KeywordEnforcerMod


implicit none
private

public fill_grads_template
public StrTemplate

character(len=2), parameter :: valid_tokens(15) = ["y4","y2","m1","m2","mc","Mc","MC","d1","d2","h1","h2","h3","n2","S2","D3"]
character(len=3),parameter :: mon_lc(12) = [&
   'jan','feb','mar','apr','may','jun',   &
   'jul','aug','sep','oct','nov','dec']
integer, parameter :: uninit_time = -999999

contains
   subroutine StrTemplate(str, tmpl, class, xid, nymd, nhms, stat, preserve)
      character(len=*), intent(out) :: str
      character(len=*), intent(in ) :: tmpl

      character(len=*), optional, intent(in ) :: class
      character(len=*), optional, intent(in ) :: xid
      integer,          optional, intent(in ) :: nymd
      integer,          optional, intent(in ) :: nhms
      integer,          optional, intent(out) :: stat
      logical,          optional, intent(in ) :: preserve

      _UNUSED_DUMMY(class)

      call fill_grads_template(str, tmpl, &
            experiment_id=xid, nymd=nymd, nhms=nhms,preserve=preserve, rc=stat)
   end subroutine StrTemplate

   subroutine fill_grads_template(output_string,template,unusable,experiment_id,nymd,nhms,time,preserve,rc)
      character(len=*), intent(out) :: output_string
      character(len=*), intent(in)  :: template
      class(keywordEnforcer), optional, intent(in) :: unusable
      character(len=*), intent(in), optional :: experiment_id
      integer, intent(in), optional :: nymd
      integer, intent(in), optional :: nhms
      type(ESMF_Time), intent(in), optional :: time
      logical, intent(in), optional :: preserve
      integer, intent(out), optional :: rc

      integer :: year,month,day,hour,minute,second,tmpl_length,output_length
      integer  :: i, m, istp, k, kstp, i1, i2
      character(len=1) :: c0,c1,c2
      character(len=4) :: sbuf
      logical :: valid_token,preserve_
      integer :: status
     
      _UNUSED_DUMMY(unusable)
      if (present(preserve)) then
         preserve_=preserve
      else
         preserve_=.false.
      end if
      year=uninit_time
      month=uninit_time
      day=uninit_time
      hour=uninit_time
      minute=uninit_time
      second=uninit_time
      if (present(time)) then
         _ASSERT(.not.present(nymd),'can not specify an ESMF_Time and an integer time')
         _ASSERT(.not.present(nhms),'can not specify an ESMF_Time and an integer time')
         call ESMF_TimeGet(time,yy=year,mm=month,dd=day,h=hour,m=minute,s=second,rc=status)
         _VERIFY(status)
      end if
      if (present(nymd)) then
         _ASSERT(.not.present(time),'can not specify an ESMF_Time and an integer time')
         year = nymd/10000
         month = mod(nymd/100,100)
         day = mod(nymd,100)
      end if
      if (present(nhms)) then
         _ASSERT(.not.present(time),'can not specify an ESMF_Time and an integer time')
         hour = nhms/10000
         minute = mod(nhms/100,100)
         second = mod(nhms,100)  
      end if
      output_string = ""

      output_length=len(output_string)
      tmpl_length=len_trim(template)
      i=0
      istp=1
      k=1
      kstp=1
      do while(i+istp <= tmpl_length)
         i=i+istp
         c0 = template(i:i)
         if (c0 == "%") then
            i1=i+1
            c1=""
            if (i1<=tmpl_length) c1=template(i1:i1)
            select case(c1)
            case("s")
               if (present(experiment_id)) then
                  istp=2
                  m=min(k+len_trim(experiment_id)-1,output_length)
                  output_string(k:m)=experiment_id
                  k=m+1
                  cycle
               else if (preserve_) then
                  output_string(k:k+1)="%s"
                  k=k+1
               else
                  _FAIL("Using %s token with no experiment id")
               end if
            case("%")
               istp=2
               output_string(k:k)=c1
               k=k+1
               cycle
            case default
               c2=""
               i2=i1+1
               if(i2 <= tmpl_length) c2=template(i2:i2)
               valid_token = check_token(c1//c2) 
               if (valid_token) then
                  istp=3
                  if (.not.preserve_) then
                     _ASSERT(present(nymd) .or. present(nhms) .or. present(time),'Using token with no time')
                  end if
                  sbuf = evaluate_token(c1//c2,year,month,day,hour,minute,second,preserve_)
                  kstp = len_trim(sbuf)
                  m=k+kstp-1
                  output_string(k:m)=sbuf
                  k=m+1
               else
                  _FAIL("Invalid token in file template: "//c1//c2)
               end if
            end select
         else
            istp=1
            output_string(k:k)=template(i:i)
            k=k+1
         end if
      enddo
      _RETURN(_SUCCESS)

   end subroutine fill_grads_template

   function check_token(token) result(is_valid)
      character(len=2), intent(in) :: token
      logical :: is_valid
      integer :: i 
      is_valid = .false.
      do i=1,size(valid_tokens)
         if (token==valid_tokens(i)) then
            is_valid=.true.
            exit
         end if
      enddo
   end function check_token

   function evaluate_token(token,year,month,day,hour,minute,second,preserve) result(buffer)
      character(len=2), intent(in) :: token
      integer, intent(in) :: year,month,day,hour,minute,second
      logical, intent(in) :: preserve
      character(len=4) :: buffer
      character(len=1) :: c1,c2
      type(ESMF_Time)  :: time
      integer(ESMF_KIND_I4) :: doy
      integer :: status, rc
      type(ESMF_Calendar) :: gregorianCalendar
      c1=token(1:1)
      c2=token(2:2)
      select case(c1)
      case("y")
         if (.not.skip_token(year,preserve)) then
            if (c2 == "2" ) then
               write(buffer,'(i2.2)')mod(year,100)
            else if (c2 == "4" ) then
               write(buffer,'(i4.4)')year
            end if
         else
            buffer="%"//token
         end if
      case("m")
         if (.not.skip_token(month,preserve)) then
            if (c2 == "c") then
               buffer = mon_lc(month)
            else if (c2 == "1") then
               if (day < 10) then
                  write(buffer,'(i1)')month
               else
                  write(buffer,'(i2)')month
               end if
            else if (c2 == "2") then
               write(buffer,'(i2.2)')month 
            end if
         else
            buffer="%"//token
         end if
      case("d")
         if (.not.skip_token(day,preserve)) then
            if (c2 == "2") then
               write(buffer,'(i2.2)')day
            else if (c1 == "1") then
               if (day < 10) then
                  write(buffer,'(i1)')day
               else
                  write(buffer,'(i2)')day
               end if
            end if
         else
            buffer="%"//token
         end if
      case("D")   ! dayOfYear
         if (.not.skip_token(day,preserve)) then
            if (c2 == "3") then
               gregorianCalendar = ESMF_CalendarCreate(ESMF_CALKIND_GREGORIAN, &
                    name='Gregorian_obs' , rc=rc)
               call ESMF_TimeSet(time, yy=year, mm=month, dd=day, &
                    calendar=gregorianCalendar, _RC)
               call ESMF_TimeGet(time, dayOfYear=doy, _RC)
               call ESMF_CalendarDestroy(gregorianCalendar)
               write(buffer,'(i3.3)')doy
            else
               _FAIL('Day of Year must be %D3')
            end if
         else
            buffer="%"//token
         end if
      case("h")
         if (.not.skip_token(hour,preserve)) then
            if (c2 == "3") then
               write(buffer,'(i3.3)')hour
            else if (c2 == "2") then
               write(buffer,'(i2.2)')hour
            else if (c1 == "1") then
               if (day < 10) then
                  write(buffer,'(i1)')hour
               else
                  write(buffer,'(i2)')hour
               end if
            end if
         else
            buffer="%"//token
         end if
      case("n")
         if (.not.skip_token(minute,preserve)) then
            write(buffer,'(i2.2)')minute
         else
            buffer="%"//token
         end if
      case("S")
         if (.not.skip_token(second,preserve)) then
            write(buffer,'(i2.2)')second
         else
            buffer="%"//token
         end if
      end select

   end function evaluate_token

   function skip_token(val,preserve) result(skip)
      integer :: val
      logical :: preserve

      logical :: skip

      skip = .false.
      if (val==uninit_time .and. preserve) skip = .true.

   end function skip_token

end module MAPL_StringTemplate