MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
BlockParser.f90
Go to the documentation of this file.
1 !> @brief This module contains block parser methods
2 !!
3 !! This module contains the generic block parser type and methods that are
4 !! used to parse MODFLOW 6 block data.
5 !!
6 !<
8 
9  use kindmodule, only: dp, i4b, lgp
10  use devfeaturemodule, only: dev_feature
12  use inputoutputmodule, only: urword, upcase, openfile, &
13  io_getunit => getunit
15  use simvariablesmodule, only: errmsg
17 
18  implicit none
19 
20  private
22 
24  integer(I4B), public :: iuactive !< flag indicating if a file unit is active, variable is not used internally
25  integer(I4B), private :: inunit !< file unit number
26  integer(I4B), private :: iuext !< external file unit number
27  integer(I4B), private :: iout !< listing file unit number
28  integer(I4B), private :: linesread !< number of lines read
29  integer(I4B), private :: lloc !< line location counter
30  character(len=LINELENGTH), private :: blockname !< block name
31  character(len=LINELENGTH), private :: blocknamefound !< block name found
32  character(len=LENHUGELINE), private :: laststring !< last string read
33  character(len=:), allocatable, private :: line !< current line
34  type(longlinereadertype) :: line_reader
35  contains
36  procedure, public :: initialize
37  procedure, public :: clear
38  procedure, public :: getblock
39  procedure, public :: getcellid
40  procedure, public :: getcurrentline
41  procedure, public :: getdouble
42  procedure, public :: trygetdouble
43  procedure, public :: getinteger
44  procedure, public :: getlinesread
45  procedure, public :: getnextline
46  procedure, public :: getremainingline
47  procedure, public :: terminateblock
48  procedure, public :: getstring
49  procedure, public :: getstringcaps
50  procedure, public :: storeerrorunit
51  procedure, public :: getunit
52  procedure, public :: devopt
53  procedure, private :: readscalarerror
54  end type blockparsertype
55 
56 contains
57 
58  !> @ brief Initialize the block parser
59  !!
60  !! Method to initialize the block parser.
61  !!
62  !<
63  subroutine initialize(this, inunit, iout)
64  ! -- dummy variables
65  class(blockparsertype), intent(inout) :: this !< BlockParserType object
66  integer(I4B), intent(in) :: inunit !< input file unit number
67  integer(I4B), intent(in) :: iout !< listing file unit number
68  !
69  ! -- initialize values
70  this%inunit = inunit
71  this%iuext = inunit
72  this%iuactive = inunit
73  this%iout = iout
74  this%blockName = ''
75  this%linesRead = 0
76  !
77  ! -- return
78  return
79  end subroutine initialize
80 
81  !> @ brief Close the block parser
82  !!
83  !! Method to clear the block parser, which closes file(s) and clears member
84  !! variables.
85  !!
86  !<
87  subroutine clear(this)
88  ! -- dummy variables
89  class(blockparsertype), intent(inout) :: this !< BlockParserType object
90  ! -- local variables
91  logical :: lop
92  !
93  ! Close any connected files
94  if (this%inunit > 0) then
95  inquire (unit=this%inunit, opened=lop)
96  if (lop) then
97  close (this%inunit)
98  end if
99  end if
100  !
101  if (this%iuext /= this%inunit .and. this%iuext > 0) then
102  inquire (unit=this%iuext, opened=lop)
103  if (lop) then
104  close (this%iuext)
105  end if
106  end if
107  !
108  ! Clear all member variables
109  this%inunit = 0
110  this%iuext = 0
111  this%iuactive = 0
112  this%iout = 0
113  this%lloc = 0
114  this%linesRead = 0
115  this%blockName = ''
116  this%line = ''
117  deallocate (this%line)
118  !
119  ! -- return
120  return
121  end subroutine clear
122 
123  !> @ brief Get block
124  !!
125  !! Method to get the block from a file. The file is read until the blockname
126  !! is found.
127  !!
128  !<
129  subroutine getblock(this, blockName, isFound, ierr, supportOpenClose, &
130  blockRequired, blockNameFound)
131  ! -- dummy variables
132  class(blockparsertype), intent(inout) :: this !< BlockParserType object
133  character(len=*), intent(in) :: blockName !< block name to search for
134  logical, intent(out) :: isFound !< boolean indicating if the block name was found
135  integer(I4B), intent(out) :: ierr !< return error code, 0 indicates block was found
136  logical, intent(in), optional :: supportOpenClose !< boolean indicating if the block supports open/close, default false
137  logical, intent(in), optional :: blockRequired !< boolean indicating if the block is required, default true
138  character(len=*), intent(inout), optional :: blockNameFound !< optional return value of block name found
139  ! -- local variables
140  logical :: continueRead
141  logical :: supportOpenCloseLocal
142  logical :: blockRequiredLocal
143  !
144  ! -- process optional variables
145  if (present(supportopenclose)) then
146  supportopencloselocal = supportopenclose
147  else
148  supportopencloselocal = .false.
149  end if
150  !
151  if (present(blockrequired)) then
152  blockrequiredlocal = blockrequired
153  else
154  blockrequiredlocal = .true.
155  end if
156  continueread = blockrequiredlocal
157  this%blockName = blockname
158  this%blockNameFound = ''
159  !
160  if (blockname == '*') then
161  call uget_any_block(this%line_reader, this%inunit, this%iout, &
162  isfound, this%lloc, this%line, blocknamefound, &
163  this%iuext)
164  if (isfound) then
165  this%blockNameFound = blocknamefound
166  ierr = 0
167  else
168  ierr = 1
169  end if
170  else
171  call uget_block(this%line_reader, this%inunit, this%iout, &
172  this%blockName, ierr, isfound, &
173  this%lloc, this%line, this%iuext, continueread, &
174  supportopencloselocal)
175  if (isfound) this%blockNameFound = this%blockName
176  end if
177  this%iuactive = this%iuext
178  this%linesRead = 0
179  !
180  ! -- return
181  return
182  end subroutine getblock
183 
184  !> @ brief Get the next line
185  !!
186  !! Method to get the next line from a file.
187  !!
188  !<
189  subroutine getnextline(this, endOfBlock)
190  ! -- dummy variables
191  class(blockparsertype), intent(inout) :: this !< BlockParserType object
192  logical, intent(out) :: endOfBlock !< boolean indicating if the end of the block was read
193  ! -- local variables
194  integer(I4B) :: ierr
195  integer(I4B) :: ival
196  integer(I4B) :: istart
197  integer(I4B) :: istop
198  real(DP) :: rval
199  character(len=10) :: key
200  logical :: lineread
201  !
202  ! -- initialize local variables
203  endofblock = .false.
204  ierr = 0
205  lineread = .false.
206  !
207  ! -- read next line
208  loop1: do
209  if (lineread) exit loop1
210  call this%line_reader%rdcom(this%iuext, this%iout, this%line, ierr)
211  this%lloc = 1
212  call urword(this%line, this%lloc, istart, istop, 0, ival, rval, &
213  this%iout, this%iuext)
214  key = this%line(istart:istop)
215  call upcase(key)
216  if (key == 'END' .or. key == 'BEGIN') then
217  call uterminate_block(this%inunit, this%iout, key, &
218  this%blockNameFound, this%lloc, this%line, &
219  ierr, this%iuext)
220  this%iuactive = this%iuext
221  endofblock = .true.
222  lineread = .true.
223  elseif (key == '') then
224  ! End of file reached.
225  ! If this is an OPEN/CLOSE file, close the file and read the next
226  ! line from this%inunit.
227  if (this%iuext /= this%inunit) then
228  close (this%iuext)
229  this%iuext = this%inunit
230  this%iuactive = this%inunit
231  else
232  errmsg = 'Unexpected end of file reached.'
233  call store_error(errmsg)
234  call this%StoreErrorUnit()
235  end if
236  else
237  this%lloc = 1
238  this%linesRead = this%linesRead + 1
239  lineread = .true.
240  end if
241  end do loop1
242  !
243  ! -- return
244  return
245  end subroutine getnextline
246 
247  !> @ brief Get a integer
248  !!
249  !! Function to get a integer from the current line.
250  !!
251  !<
252  function getinteger(this) result(i)
253  ! -- return variable
254  integer(I4B) :: i !< integer variable
255  ! -- dummy variables
256  class(blockparsertype), intent(inout) :: this !< BlockParserType object
257  ! -- local variables
258  integer(I4B) :: istart
259  integer(I4B) :: istop
260  real(dp) :: rval
261  !
262  ! -- get integer using urword
263  call urword(this%line, this%lloc, istart, istop, 2, i, rval, &
264  this%iout, this%iuext)
265  !
266  ! -- Make sure variable was read before end of line
267  if (istart == istop .and. istop == len(this%line)) then
268  call this%ReadScalarError('INTEGER')
269  end if
270  !
271  ! -- return
272  return
273  end function getinteger
274 
275  !> @ brief Get the number of lines read
276  !!
277  !! Function to get the number of lines read from the current block.
278  !!
279  !<
280  function getlinesread(this) result(nlines)
281  ! -- return variable
282  integer(I4B) :: nlines !< number of lines read
283  ! -- dummy variable
284  class(blockparsertype), intent(inout) :: this !< BlockParserType object
285  !
286  ! -- number of lines read
287  nlines = this%linesRead
288  !
289  ! -- return
290  return
291  end function getlinesread
292 
293  !> @ brief Get a double precision real
294  !!
295  !! Function to get adouble precision floating point number from
296  !! the current line.
297  !!
298  !<
299  function getdouble(this) result(r)
300  ! -- return variable
301  real(dp) :: r !< double precision real variable
302  ! -- dummy variables
303  class(blockparsertype), intent(inout) :: this !< BlockParserType object
304  ! -- local variables
305  integer(I4B) :: istart
306  integer(I4B) :: istop
307  integer(I4B) :: ival
308  !
309  ! -- get double precision real using urword
310  call urword(this%line, this%lloc, istart, istop, 3, ival, r, &
311  this%iout, this%iuext)
312  !
313  ! -- Make sure variable was read before end of line
314  if (istart == istop .and. istop == len(this%line)) then
315  call this%ReadScalarError('DOUBLE PRECISION')
316  end if
317 
318  end function getdouble
319 
320  subroutine trygetdouble(this, r, success)
321  ! -- dummy variables
322  class(blockparsertype), intent(inout) :: this !< BlockParserType object
323  real(DP), intent(inout) :: r !< double precision real variable
324  logical(LGP), intent(inout) :: success !< whether parsing was successful
325  ! -- local variables
326  integer(I4B) :: istart
327  integer(I4B) :: istop
328  integer(I4B) :: ival
329 
330  call urword(this%line, this%lloc, istart, istop, 3, ival, r, &
331  this%iout, this%iuext)
332 
333  success = .true.
334  if (istart == istop .and. istop == len(this%line)) then
335  success = .false.
336  end if
337 
338  end subroutine trygetdouble
339 
340  !> @ brief Issue a read error
341  !!
342  !! Method to issue an unable to read error.
343  !!
344  !<
345  subroutine readscalarerror(this, vartype)
346  ! -- dummy variables
347  class(blockparsertype), intent(inout) :: this !< BlockParserType object
348  character(len=*), intent(in) :: vartype !< string of variable type
349  ! -- local variables
350  character(len=MAXCHARLEN - 100) :: linetemp
351  !
352  ! -- use linetemp as line may be longer than MAXCHARLEN
353  linetemp = this%line
354  !
355  ! -- write the message
356  write (errmsg, '(3a)') 'Error in block ', trim(this%blockName), '.'
357  write (errmsg, '(4a)') &
358  trim(errmsg), ' Could not read variable of type ', trim(vartype), &
359  " from the following line: '"
360  write (errmsg, '(3a)') &
361  trim(errmsg), trim(adjustl(this%line)), "'."
362  call store_error(errmsg)
363  call this%StoreErrorUnit()
364  !
365  ! -- return
366  return
367  end subroutine readscalarerror
368 
369  !> @ brief Get a string
370  !!
371  !! Method to get a string from the current line and optionally convert it
372  !! to upper case.
373  !!
374  !<
375  subroutine getstring(this, string, convertToUpper)
376  ! -- dummy variables
377  class(blockparsertype), intent(inout) :: this !< BlockParserType object
378  character(len=*), intent(out) :: string !< string
379  logical, optional, intent(in) :: convertToUpper !< boolean indicating if the string should be converted to upper case, default false
380  ! -- local variables
381  integer(I4B) :: istart
382  integer(I4B) :: istop
383  integer(I4B) :: ival
384  integer(I4B) :: ncode
385  real(DP) :: rval
386  !
387  ! -- process optional variables
388  if (present(converttoupper)) then
389  if (converttoupper) then
390  ncode = 1
391  else
392  ncode = 0
393  end if
394  else
395  ncode = 0
396  end if
397  !
398  call urword(this%line, this%lloc, istart, istop, ncode, &
399  ival, rval, this%iout, this%iuext)
400  string = this%line(istart:istop)
401  this%laststring = this%line(istart:istop)
402  !
403  ! -- return
404  return
405  end subroutine getstring
406 
407  !> @ brief Get an upper case string
408  !!
409  !! Method to get a string from the current line and convert it
410  !! to upper case.
411  !!
412  !<
413  subroutine getstringcaps(this, string)
414  ! -- dummy variables
415  class(blockparsertype), intent(inout) :: this !< BlockParserType object
416  character(len=*), intent(out) :: string !< upper case string
417  !
418  ! -- call base GetString method with convertToUpper variable
419  call this%GetString(string, converttoupper=.true.)
420  !
421  ! -- return
422  return
423  end subroutine getstringcaps
424 
425  !> @ brief Get the rest of a line
426  !!
427  !! Method to get the rest of the line from the current line.
428  !!
429  !<
430  subroutine getremainingline(this, line)
431  ! -- dummy variables
432  class(blockparsertype), intent(inout) :: this !< BlockParserType object
433  character(len=:), allocatable, intent(out) :: line !< remainder of the line
434  ! -- local variables
435  integer(I4B) :: lastpos
436  integer(I4B) :: newlinelen
437  !
438  ! -- get the rest of the line
439  lastpos = len_trim(this%line)
440  newlinelen = lastpos - this%lloc + 2
441  newlinelen = max(newlinelen, 1)
442  allocate (character(len=newlinelen) :: line)
443  line(:) = this%line(this%lloc:lastpos)
444  line(newlinelen:newlinelen) = ' '
445  !
446  ! -- return
447  return
448  end subroutine getremainingline
449 
450  !> @ brief Ensure that the block is closed
451  !!
452  !! Method to ensure that the block is closed with an "end".
453  !!
454  !<
455  subroutine terminateblock(this)
456  ! -- dummy variables
457  class(blockparsertype), intent(inout) :: this !< BlockParserType object
458  ! -- local variables
459  logical :: endofblock
460  !
461  ! -- look for block termination
462  call this%GetNextLine(endofblock)
463  if (.not. endofblock) then
464  errmsg = "LOOKING FOR 'END "//trim(this%blockname)// &
465  "'. FOUND: "//"'"//trim(this%line)//"'."
466  call store_error(errmsg)
467  call this%StoreErrorUnit()
468  end if
469  !
470  ! -- return
471  return
472  end subroutine terminateblock
473 
474  !> @ brief Get a cellid
475  !!
476  !! Method to get a cellid from a line.
477  !!
478  !<
479  subroutine getcellid(this, ndim, cellid, flag_string)
480  ! -- dummy variables
481  class(blockparsertype), intent(inout) :: this !< BlockParserType object
482  integer(I4B), intent(in) :: ndim !< number of dimensions (1, 2, or 3)
483  character(len=*), intent(out) :: cellid !< cell =id
484  logical, optional, intent(in) :: flag_string !< boolean indicating id cellid is a string
485  ! -- local variables
486  integer(I4B) :: i
487  integer(I4B) :: j
488  integer(I4B) :: lloc
489  integer(I4B) :: istart
490  integer(I4B) :: istop
491  integer(I4B) :: ival
492  integer(I4B) :: istat
493  real(DP) :: rval
494  character(len=10) :: cint
495  character(len=100) :: firsttoken
496  !
497  ! -- process optional variables
498  if (present(flag_string)) then
499  lloc = this%lloc
500  call urword(this%line, lloc, istart, istop, 0, ival, rval, this%iout, &
501  this%iuext)
502  firsttoken = this%line(istart:istop)
503  read (firsttoken, *, iostat=istat) ival
504  if (istat > 0) then
505  call upcase(firsttoken)
506  cellid = firsttoken
507  return
508  end if
509  end if
510  !
511  cellid = ''
512  do i = 1, ndim
513  j = this%GetInteger()
514  write (cint, '(i0)') j
515  if (i == 1) then
516  cellid = cint
517  else
518  cellid = trim(cellid)//' '//cint
519  end if
520  end do
521  !
522  ! -- return
523  return
524  end subroutine getcellid
525 
526  !> @ brief Get the current line
527  !!
528  !! Method to get the current line.
529  !!
530  !<
531  subroutine getcurrentline(this, line)
532  ! -- dummy variables
533  class(blockparsertype), intent(inout) :: this !< BlockParserType object
534  character(len=*), intent(out) :: line !< current line
535  !
536  ! -- get the current line
537  line = this%line
538  !
539  ! -- return
540  return
541  end subroutine getcurrentline
542 
543  !> @ brief Store the unit number
544  !!
545  !! Method to store the unit number for the file that caused a read error.
546  !! Default is to terminate the simulation when this method is called.
547  !!
548  !<
549  subroutine storeerrorunit(this, terminate)
550  ! -- dummy variable
551  class(blockparsertype), intent(inout) :: this !< BlockParserType object
552  logical, intent(in), optional :: terminate !< boolean indicating if the simulation should be terminated
553  ! -- local variables
554  logical :: lterminate
555  !
556  ! -- process optional variables
557  if (present(terminate)) then
558  lterminate = terminate
559  else
560  lterminate = .true.
561  end if
562  !
563  ! -- store error unit
564  call store_error_unit(this%iuext, terminate=lterminate)
565  !
566  ! -- return
567  return
568  end subroutine storeerrorunit
569 
570  !> @ brief Get the unit number
571  !!
572  !! Function to get the unit number for the block parser.
573  !!
574  !<
575  function getunit(this) result(i)
576  ! -- return variable
577  integer(I4B) :: i !< unit number for the block parser
578  ! -- dummy variables
579  class(blockparsertype), intent(inout) :: this !< BlockParserType object
580  !
581  ! -- block parser unit number
582  i = this%iuext
583  !
584  ! -- return
585  return
586  end function getunit
587 
588  !> @ brief Disable development option in release mode
589  !!
590  !! Terminate with an error if in release mode (IDEVELOPMODE = 0). Enables
591  !! options for development and testing while disabling for public release.
592  !!
593  !<
594  subroutine devopt(this)
595  ! -- dummy variables
596  class(blockparsertype), intent(inout) :: this
597  !
598  errmsg = "Invalid keyword '"//trim(this%laststring)// &
599  "' detected in block '"//trim(this%blockname)//"'."
600  call dev_feature(errmsg, this%iuext)
601  !
602  return
603  end subroutine devopt
604 
605  ! -- static methods previously in InputOutput
606  !> @brief Find a block in a file
607  !!
608  !! Subroutine to read from a file until the tag (ctag) for a block is
609  !! is found. Return isfound with true, if found.
610  !!
611  !<
612  subroutine uget_block(line_reader, iin, iout, ctag, ierr, isfound, &
613  lloc, line, iuext, blockRequired, supportopenclose)
614  implicit none
615  ! -- dummy variables
616  type(longlinereadertype), intent(inout) :: line_reader
617  integer(I4B), intent(in) :: iin !< file unit
618  integer(I4B), intent(in) :: iout !< output listing file unit
619  character(len=*), intent(in) :: ctag !< block tag
620  integer(I4B), intent(out) :: ierr !< error
621  logical, intent(inout) :: isfound !< boolean indicating if the block was found
622  integer(I4B), intent(inout) :: lloc !< position in line
623  character(len=:), allocatable, intent(inout) :: line !< line
624  integer(I4B), intent(inout) :: iuext !< external file unit number
625  logical, optional, intent(in) :: blockrequired !< boolean indicating if the block is required
626  logical, optional, intent(in) :: supportopenclose !< boolean indicating if the block supports open/close
627  ! -- local variables
628  integer(I4B) :: istart
629  integer(I4B) :: istop
630  integer(I4B) :: ival
631  integer(I4B) :: lloc2
632  real(dp) :: rval
633  character(len=:), allocatable :: line2
634  character(len=LINELENGTH) :: fname
635  character(len=MAXCHARLEN) :: ermsg
636  logical :: supportoc, blockrequiredlocal
637  !
638  ! -- code
639  if (present(blockrequired)) then
640  blockrequiredlocal = blockrequired
641  else
642  blockrequiredlocal = .true.
643  end if
644  supportoc = .false.
645  if (present(supportopenclose)) then
646  supportoc = supportopenclose
647  end if
648  iuext = iin
649  isfound = .false.
650  mainloop: do
651  lloc = 1
652  call line_reader%rdcom(iin, iout, line, ierr)
653  if (ierr < 0) then
654  if (blockrequiredlocal) then
655  ermsg = 'Required block "'//trim(ctag)// &
656  '" not found. Found end of file instead.'
657  call store_error(ermsg)
658  call store_error_unit(iuext)
659  end if
660  ! block not found so exit
661  exit
662  end if
663  call urword(line, lloc, istart, istop, 1, ival, rval, iin, iout)
664  if (line(istart:istop) == 'BEGIN') then
665  call urword(line, lloc, istart, istop, 1, ival, rval, iin, iout)
666  if (line(istart:istop) == ctag) then
667  isfound = .true.
668  if (supportoc) then
669  ! Look for OPEN/CLOSE on 1st line after line starting with BEGIN
670  call line_reader%rdcom(iin, iout, line2, ierr)
671  if (ierr < 0) exit
672  lloc2 = 1
673  call urword(line2, lloc2, istart, istop, 1, ival, rval, iin, iout)
674  if (line2(istart:istop) == 'OPEN/CLOSE') then
675  ! -- Get filename and preserve case
676  call urword(line2, lloc2, istart, istop, 0, ival, rval, iin, iout)
677  fname = line2(istart:istop)
678  ! If line contains '(BINARY)' or 'SFAC', handle this block elsewhere
679  chk: do
680  call urword(line2, lloc2, istart, istop, 1, ival, rval, iin, iout)
681  if (line2(istart:istop) == '') exit chk
682  if (line2(istart:istop) == '(BINARY)' .or. &
683  line2(istart:istop) == 'SFAC') then
684  call line_reader%bkspc(iin)
685  exit mainloop
686  end if
687  end do chk
688  iuext = io_getunit()
689  call openfile(iuext, iout, fname, 'OPEN/CLOSE')
690  else
691  call line_reader%bkspc(iin)
692  end if
693  end if
694  else
695  if (blockrequiredlocal) then
696  ermsg = 'Error: Required block "'//trim(ctag)// &
697  '" not found. Found block "'//line(istart:istop)// &
698  '" instead.'
699  call store_error(ermsg)
700  call store_error_unit(iuext)
701  else
702  call line_reader%bkspc(iin)
703  end if
704  end if
705  exit mainloop
706  else if (line(istart:istop) == 'END') then
707  call urword(line, lloc, istart, istop, 1, ival, rval, iin, iout)
708  if (line(istart:istop) == ctag) then
709  ermsg = 'Error: Looking for BEGIN '//trim(ctag)// &
710  ' but found END '//line(istart:istop)// &
711  ' instead.'
712  call store_error(ermsg)
713  call store_error_unit(iuext)
714  end if
715  end if
716  end do mainloop
717  !
718  ! -- return
719  return
720  end subroutine uget_block
721 
722  !> @brief Find the next block in a file
723  !!
724  !! Subroutine to read from a file until next block is found.
725  !! Return isfound with true, if found, and return the block name.
726  !!
727  !<
728  subroutine uget_any_block(line_reader, iin, iout, isfound, &
729  lloc, line, ctagfound, iuext)
730  implicit none
731  ! -- dummy variables
732  type(longlinereadertype), intent(inout) :: line_reader
733  integer(I4B), intent(in) :: iin !< file unit number
734  integer(I4B), intent(in) :: iout !< output listing file unit
735  logical, intent(inout) :: isfound !< boolean indicating if a block was found
736  integer(I4B), intent(inout) :: lloc !< position in line
737  character(len=:), allocatable, intent(inout) :: line !< line
738  character(len=*), intent(out) :: ctagfound !< block name
739  integer(I4B), intent(inout) :: iuext !< external file unit number
740  ! -- local variables
741  integer(I4B) :: ierr, istart, istop
742  integer(I4B) :: ival, lloc2
743  real(dp) :: rval
744  character(len=100) :: ermsg
745  character(len=:), allocatable :: line2
746  character(len=LINELENGTH) :: fname
747  !
748  ! -- code
749  isfound = .false.
750  ctagfound = ''
751  iuext = iin
752  do
753  lloc = 1
754  call line_reader%rdcom(iin, iout, line, ierr)
755  if (ierr < 0) exit
756  call urword(line, lloc, istart, istop, 1, ival, rval, iin, iout)
757  if (line(istart:istop) == 'BEGIN') then
758  call urword(line, lloc, istart, istop, 1, ival, rval, iin, iout)
759  if (line(istart:istop) /= '') then
760  isfound = .true.
761  ctagfound = line(istart:istop)
762  call line_reader%rdcom(iin, iout, line2, ierr)
763  if (ierr < 0) exit
764  lloc2 = 1
765  call urword(line2, lloc2, istart, istop, 1, ival, rval, iout, iin)
766  if (line2(istart:istop) == 'OPEN/CLOSE') then
767  iuext = io_getunit()
768  call urword(line2, lloc2, istart, istop, 0, ival, rval, iout, iin)
769  fname = line2(istart:istop)
770  call openfile(iuext, iout, fname, 'OPEN/CLOSE')
771  else
772  call line_reader%bkspc(iin)
773  end if
774  else
775  ermsg = 'Block name missing in file.'
776  call store_error(ermsg)
777  call store_error_unit(iin)
778  end if
779  exit
780  end if
781  end do
782  return
783  end subroutine uget_any_block
784 
785  !> @brief Evaluate if the end of a block has been found
786  !!
787  !! Subroutine to evaluate if the end of a block has been found. Abnormal
788  !! termination if 'begin' is found or if 'end' encountered with
789  !! incorrect tag.
790  !!
791  !<
792  subroutine uterminate_block(iin, iout, key, ctag, lloc, line, ierr, iuext)
793  implicit none
794  ! -- dummy variables
795  integer(I4B), intent(in) :: iin !< file unit number
796  integer(I4B), intent(in) :: iout !< output listing file unit number
797  character(len=*), intent(in) :: key !< keyword in block
798  character(len=*), intent(in) :: ctag !< block name
799  integer(I4B), intent(inout) :: lloc !< position in line
800  character(len=*), intent(inout) :: line !< line
801  integer(I4B), intent(inout) :: ierr !< error
802  integer(I4B), intent(inout) :: iuext !< external file unit number
803  ! -- local variables
804  character(len=LENBIGLINE) :: ermsg
805  integer(I4B) :: istart
806  integer(I4B) :: istop
807  integer(I4B) :: ival
808  real(dp) :: rval
809  ! -- format
810 1 format('ERROR. "', a, '" DETECTED WITHOUT "', a, '". ', '"END', 1x, a, &
811  '" MUST BE USED TO END ', a, '.')
812 2 format('ERROR. "', a, '" DETECTED BEFORE "END', 1x, a, '". ', '"END', 1x, a, &
813  '" MUST BE USED TO END ', a, '.')
814  !
815  ! -- code
816  ierr = 1
817  select case (key)
818  case ('END')
819  call urword(line, lloc, istart, istop, 1, ival, rval, iout, iin)
820  if (line(istart:istop) /= ctag) then
821  write (ermsg, 1) trim(key), trim(ctag), trim(ctag), trim(ctag)
822  call store_error(ermsg)
823  call store_error_unit(iin)
824  else
825  ierr = 0
826  if (iuext /= iin) then
827  ! -- close external file
828  close (iuext)
829  iuext = iin
830  end if
831  end if
832  case ('BEGIN')
833  write (ermsg, 2) trim(key), trim(ctag), trim(ctag), trim(ctag)
834  call store_error(ermsg)
835  call store_error_unit(iin)
836  end select
837  !
838  ! -- return
839  return
840  end subroutine uterminate_block
841 
842 end module blockparsermodule
This module contains block parser methods.
Definition: BlockParser.f90:7
subroutine trygetdouble(this, r, success)
subroutine getstring(this, string, convertToUpper)
@ brief Get a string
integer(i4b) function getlinesread(this)
@ brief Get the number of lines read
subroutine initialize(this, inunit, iout)
@ brief Initialize the block parser
Definition: BlockParser.f90:64
integer(i4b) function getunit(this)
@ brief Get the unit number
subroutine, public uterminate_block(iin, iout, key, ctag, lloc, line, ierr, iuext)
Evaluate if the end of a block has been found.
integer(i4b) function getinteger(this)
@ brief Get a integer
subroutine, public uget_any_block(line_reader, iin, iout, isfound, lloc, line, ctagfound, iuext)
Find the next block in a file.
subroutine, public uget_block(line_reader, iin, iout, ctag, ierr, isfound, lloc, line, iuext, blockRequired, supportopenclose)
Find a block in a file.
subroutine readscalarerror(this, vartype)
@ brief Issue a read error
subroutine getnextline(this, endOfBlock)
@ brief Get the next line
subroutine getstringcaps(this, string)
@ brief Get an upper case string
subroutine clear(this)
@ brief Close the block parser
Definition: BlockParser.f90:88
subroutine getremainingline(this, line)
@ brief Get the rest of a line
subroutine getcurrentline(this, line)
@ brief Get the current line
subroutine terminateblock(this)
@ brief Ensure that the block is closed
subroutine storeerrorunit(this, terminate)
@ brief Store the unit number
real(dp) function getdouble(this)
@ brief Get a double precision real
subroutine devopt(this)
@ brief Disable development option in release mode
subroutine getblock(this, blockName, isFound, ierr, supportOpenClose, blockRequired, blockNameFound)
@ brief Get block
subroutine getcellid(this, ndim, cellid, flag_string)
@ brief Get a cellid
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:44
integer(i4b), parameter lenhugeline
maximum length of a huge line
Definition: Constants.f90:16
integer(i4b), parameter lenbigline
maximum length of a big line
Definition: Constants.f90:15
integer(i4b), parameter maxcharlen
maximum length of char string
Definition: Constants.f90:46
Disable development features in release mode.
Definition: DevFeature.f90:2
subroutine, public dev_feature(errmsg, iunit)
Terminate if in release mode (guard development features)
Definition: DevFeature.f90:21
subroutine, public upcase(word)
Convert to upper case.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
subroutine, public urword(line, icol, istart, istop, ncode, n, r, iout, in)
Extract a word from a string.
This module defines variable data types.
Definition: kind.f90:8
This module contains the LongLineReaderType.
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
subroutine, public store_error_unit(iunit, terminate)
Store the file unit number.
Definition: Sim.f90:168
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string