LCOV - code coverage report
Current view: top level - utils/public - namelist.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 57.1 % 35 20
Test Date: 2026-08-20 21:51:39 Functions: 66.7 % 3 2

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2026  The MESA Team
       4              : !
       5              : !   This program is free software: you can redistribute it and/or modify
       6              : !   it under the terms of the GNU Lesser General Public License
       7              : !   as published by the Free Software Foundation,
       8              : !   either version 3 of the License, or (at your option) any later version.
       9              : !
      10              : !   This program is distributed in the hope that it will be useful,
      11              : !   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              : !   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      13              : !   See the GNU Lesser General Public License for more details.
      14              : !
      15              : !   You should have received a copy of the GNU Lesser General Public License
      16              : !   along with this program. If not, see <https://www.gnu.org/licenses/>.
      17              : !
      18              : ! ***********************************************************************
      19              : 
      20              : !> Reading nested namelists
      21              : module utils_namelist
      22              :    implicit none
      23              :    private
      24              : 
      25              :    integer, parameter :: max_nested_inlists = 10
      26              :    integer, parameter :: max_extra_inlists = 5
      27              : 
      28              :    abstract interface
      29              :       !> Read a single inlist
      30              :       !>
      31              :       !> Implementations of this interface should only read one namelist (with the unit, iostat, and iomsg passed to read) and
      32              :       !> optionally set the extra_inlists and extra_inlists_mask arguments. Each element of extra_inlists for which
      33              :       !> extra_inlists_mask is set to true will also be read in by read_namelist. If there is no need to read in extra inlists,
      34              :       !> just set all elements of extra_inlists_mask to false.
      35              :       subroutine reader(unit, iostat, iomsg, extra_inlists, extra_inlists_mask)
      36              :          use const_def, only: strlen
      37              :          import max_extra_inlists
      38              :          implicit none
      39              :          integer, intent(in) :: unit
      40              :          integer, intent(out) :: iostat
      41              :          character(len=strlen), intent(out) :: iomsg
      42              :          character(len=strlen), dimension(max_extra_inlists), intent(out) :: extra_inlists
      43              :          logical, dimension(max_extra_inlists), intent(out) :: extra_inlists_mask
      44              :       end subroutine reader
      45              :    end interface
      46              : 
      47              :    type missing_namelist
      48              :       integer, private :: action
      49              :    end type missing_namelist
      50              : 
      51              :    type(missing_namelist), public, parameter :: missing_namelist_error = missing_namelist(0)
      52              :    type(missing_namelist), public, parameter :: missing_namelist_warning = missing_namelist(1)
      53              :    type(missing_namelist), public, parameter :: missing_namelist_silent = missing_namelist(2)
      54              : 
      55              :    public :: read_namelist, missing_namelist, reader, max_extra_inlists
      56              : 
      57              :    contains
      58              :       !> Read a nested set of namelists starting from a single file.
      59              :       !>
      60              :       !> This also handles error reporting to the user. Missing namelist
      61              :       !> entries are handled based on the value of the `missing` argument.
      62           13 :       subroutine read_namelist(file, r, namelist_name, ierr, missing)
      63              :          character(len=*), intent(in) :: file
      64              :          procedure(reader) :: r
      65              :          character(len=*), intent(in) :: namelist_name
      66              :          integer, intent(out) :: ierr
      67              :          type(missing_namelist), intent(in) :: missing
      68              : 
      69           13 :          if (len_trim(file) == 0) then
      70            1 :             ierr = 0
      71            1 :             return
      72              :          end if
      73              : 
      74           12 :          call read_one_namelist(file, r, namelist_name, 1, ierr, missing)
      75              :       end subroutine read_namelist
      76              : 
      77           24 :       recursive subroutine read_one_namelist(file, r, namelist_name, level, ierr, missing)
      78              :          use const_def, only: strlen
      79              : 
      80              :          character(len=*), intent(in) :: file
      81              :          procedure(reader) :: r
      82              :          character(len=*), intent(in) :: namelist_name
      83              :          integer, intent(in) :: level
      84              :          integer, intent(out) :: ierr
      85              :          type(missing_namelist), intent(in) :: missing
      86              : 
      87              :          integer :: iostat, unit, i
      88              :          character(len=strlen) :: iomsg
      89              :          character(len=strlen), dimension(max_extra_inlists) :: extra_inlists
      90              :          logical, dimension(max_extra_inlists) :: extra_inlists_mask
      91              : 
      92           12 :          if (level >= max_nested_inlists) then
      93            0 :             write(*, *) '[ERROR]: too many levels of nested ', namelist_name, ' inlist files'
      94            0 :             ierr = -1
      95            1 :             return
      96              :          end if
      97              : 
      98              :          open(newunit = unit, file = trim(file), action = 'read', &
      99           12 :             delim = 'quote', status = 'old', iostat = iostat, iomsg = iomsg)
     100              : 
     101           12 :          if (iostat /= 0) then
     102            0 :             write(*, *) '[ERROR]: Failed to open ', namelist_name, &
     103            0 :                ' namelist file "', trim(file), '". Error message: "', trim(iomsg), '"'
     104            0 :             ierr = -1
     105            0 :             return
     106              :          end if
     107              : 
     108           12 :          call r(unit, iostat, iomsg, extra_inlists, extra_inlists_mask)
     109              : 
     110           12 :          close(unit)
     111              : 
     112           12 :          if (iostat /= 0) then
     113            1 :             if (is_iostat_end(iostat)) then
     114            1 :                select case(missing%action)
     115              :                case(missing_namelist_error%action)
     116            0 :                   write(*, *) '[ERROR]: Failed to read ', namelist_name, &
     117            0 :                      ' namelist from "', trim(file), '". Namelist ', namelist_name, ' is not found'
     118            0 :                   ierr = -1
     119              :                case(missing_namelist_warning%action)
     120            1 :                   write(*, *) '[WARNING]: Failed to read ', namelist_name, &
     121            2 :                      ' namelist from "', trim(file), '". Namelist ', namelist_name, ' is not found'
     122              :                case(missing_namelist_silent%action)
     123              :                   ! Do nothing
     124              :                end select
     125              :                extra_inlists_mask(:) = .false.
     126              :             else
     127            0 :                write(*, *) '[ERROR]: Failed to read ', namelist_name, &
     128            0 :                   ' namelist from "', trim(file), '". Error message: "', trim(iomsg), '"'
     129            0 :                ierr = -1
     130              :             end if
     131            1 :             return
     132              :          end if
     133              : 
     134           66 :          do i=1, max_extra_inlists
     135           66 :             if (extra_inlists_mask(i) .and. len_trim(extra_inlists(i)) /= 0) then
     136            0 :                call read_one_namelist(extra_inlists(i), r, namelist_name, level + 1, ierr, missing)
     137              : 
     138            0 :                if (ierr /= 0) then
     139              :                   return
     140              :                end if
     141              :             end if
     142              :          end do
     143              : 
     144              :       end subroutine read_one_namelist
     145            0 : end module utils_namelist
        

Generated by: LCOV version 2.0-1