MODFLOW 6 version 6.9.0.dev0
USGS Modular Hydrologic Model
Loading...
Searching...
No Matches
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
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
57contains
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
7801 format('ERROR. "', a, '" DETECTED WITHOUT "', a, '". ', '"END', 1x, a, &
781 '" MUST BE USED TO END ', a, '.')
7822 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
809end module blockparsermodule
This module contains block parser methods.
subroutine trygetdouble(this, r, success)
subroutine, public uget_block(line_reader, iin, iout, ctag, ierr, isfound, lloc, line, iuext, blockrequired, supportopenclose)
Find a block in a file.
integer(i4b) function getlinesread(this)
@ brief Get the number of lines read
subroutine initialize(this, inunit, iout)
@ brief Initialize the block parser
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 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
subroutine getremainingline(this, line)
@ brief Get the rest of a line
subroutine getcurrentline(this, line)
@ brief Get the current line
subroutine getstring(this, string, converttoupper)
@ brief Get a string
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.
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.
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.
character(len=maxcharlen) errmsg
error message string
integer(i4b) iout
file unit number for simulation output