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