Line data Source code
1 : !
2 : ! Copyright (C) 2020-2021 Quantum ESPRESSO group
3 : ! This file is distributed under the terms of the
4 : ! GNU General Public License. See the file `License'
5 : ! in the root directory of the present distribution,
6 : ! or http://www.gnu.org/copyleft/gpl.txt .
7 : !
8 : !--------------------------------------------------------
9 :
10 : #if defined HAVE_CONFIG_H
11 : #include "config.h"
12 : #endif
13 :
14 : #include "abi_common.h"
15 :
16 : MODULE xmltools
17 : !--------------------------------------------------------
18 : !
19 : ! Poor-man set of tools for reading and writing xml files
20 : ! Similar to iotk but much simpler - Paolo Giannozzi, June 2020
21 : ! Limitations: too many to be listed in detail. Main ones:
22 : ! * works on a single opened file at the time. Exception:
23 : ! while a file is opened, one can open, R/W, close another file,
24 : ! but it is not possible to operate on both files at the same time
25 : ! * lines no more than 1024 characters long (see maxline parameter)
26 : ! * no more than 9 levels of tags (see maxlevel parameter)
27 : ! * length of tags no more than 80 characters (see maxlength parameter)
28 : ! * can read tags only in the correct order. If a tag is not found, the
29 : ! file is rewound. If "ierr" is present, a second attempt to find the
30 : ! tag is done starting from the top of the file - may work if the searched
31 : ! tag is found only above the current position, and nowhere else
32 : ! * only single values (e.g. no vectors) in attributes
33 : ! * attributes should not contain commas or strange characters
34 : ! * xml comments (<!-- ... -->) or <![CDATA[ ... ]]> cannot be mixed
35 : ! with numerical fields
36 : !
37 : !USE upf_kinds, ONLY : dp
38 : use defs_basis
39 : IMPLICIT NONE
40 : !
41 : #undef __debug
42 : !! define __debug to print information on opened and closed tags
43 : LOGICAL, PARAMETER :: one_line_tags=.true.
44 : !! if true, write tags with one value in a single line:
45 : !! <tag attr1="val1" ... >value</tag>
46 : !! otherwise, as in iotk:
47 : !! <tag attr1="val1" ... >
48 : !! value
49 : !! </tag>
50 : !! Only for single values; arrays are always written as in iotk
51 : !
52 : ! internal variables for reading and writing
53 : !
54 : INTEGER :: xmlunit
55 : INTEGER, PARAMETER :: maxline=1024
56 : CHARACTER(LEN=maxline) :: line
57 : INTEGER :: xmlsave = -1, nopen = 0
58 : INTEGER :: eot
59 : ! eot points to the end of tag in line just scanned
60 : INTEGER :: nattr
61 : CHARACTER(LEN=:), ALLOCATABLE :: attrlist
62 : !
63 : ! variables used to keep track of open tags
64 : !
65 : INTEGER :: nlevel = -1
66 : INTEGER, PARAMETER :: maxlength=80, maxlevel=9
67 : CHARACTER(LEN=maxlength), DIMENSION(0:maxlevel) :: open_tags
68 : !
69 : PRIVATE
70 : ! general subroutines
71 : PUBLIC :: xml_open_file, xml_closefile
72 : ! subroutines for writing
73 : PUBLIC :: add_attr
74 : PUBLIC :: xmlw_writetag, xmlw_opentag, xmlw_closetag
75 : ! subroutines for reading
76 : PUBLIC :: xmlr_readtag, xmlr_opentag, xmlr_closetag
77 : PUBLIC :: get_attr
78 : ! utility functions
79 : PUBLIC :: xml_protect, i2c, l2c, r2c
80 : !
81 : ! Error codes returned by xmlr_opentag / xml_readtag:
82 : ! -1 tag with no value (e.g. <tag attr="val"/>) found (no error)
83 : ! 0 tag found and read (no error)
84 : ! 1 tag not found
85 : ! 2 error parsing file
86 : ! 3 line too long
87 : ! 4 too many levels of tags
88 : !
89 : ! Error codes returned by xmlw_opentag / xml_writetag:
90 : ! 0 tag open and/or written (no error)
91 : ! 1 cannot write to unit "xmlunit"
92 : ! 2 tag name too long
93 : ! 3 wrong number of values for attributes
94 : ! 4 too many levels of tag
95 : !
96 : INTERFACE xmlr_readtag
97 : MODULE PROCEDURE readtag_c, readtag_r, readtag_l, readtag_i, &
98 : readtag_iv, readtag_rv, readtag_rm, readtag_rt, &
99 : readtag_zv, readtag_zm, readtag_zt
100 : END INTERFACE xmlr_readtag
101 : !
102 : ! IMPORTANT NOTICE: complex numbers, z=a+ib, are written as two reals:
103 : ! "a b", not in fortran free format as "(a,b)". Reason:
104 : ! make the file readable by non-fortran tools, e.g. python
105 : !
106 : INTERFACE xmlw_writetag
107 : MODULE PROCEDURE writetag_c, writetag_r, writetag_l, writetag_i, &
108 : writetag_iv, writetag_rv, writetag_rm, writetag_rt, &
109 : writetag_zv, writetag_zm, writetag_zt
110 : END INTERFACE xmlw_writetag
111 : !
112 : INTERFACE get_attr
113 : MODULE PROCEDURE get_i_attr, get_l_attr, get_r_attr, get_c_attr
114 : END INTERFACE get_attr
115 :
116 : INTERFACE add_attr
117 : MODULE PROCEDURE add_i_attr, add_l_attr, add_r_attr, add_c_attr
118 : END INTERFACE add_attr
119 :
120 : CONTAINS
121 :
122 805 : SUBROUTINE get_i_attr ( attrname, attrval_i )
123 : !
124 : ! returns attrval_i=0 if not found or not readable
125 : !
126 : !IMPLICIT NONE
127 : CHARACTER(LEN=*), INTENT(IN) :: attrname
128 : INTEGER, INTENT(OUT) :: attrval_i
129 : !
130 : CHARACTER(LEN=80) :: attrval_c
131 : !
132 805 : CALL get_c_attr ( attrname, attrval_c )
133 805 : if ( len_trim(attrval_c) > 0 ) then
134 719 : READ (attrval_c,*, err=1) attrval_i
135 719 : return
136 : 1 print '("Error reading attribute ",a,": expected integer, found ",a)', &
137 0 : trim(attrname), trim(attrval_c)
138 : end if
139 86 : attrval_i = 0
140 : !
141 : END SUBROUTINE get_i_attr
142 : !
143 144 : SUBROUTINE get_l_attr ( attrname, attrval_l )
144 : !
145 : ! returns attrval_l=.false. if not found or not readable
146 : !
147 : !IMPLICIT NONE
148 : CHARACTER(LEN=*), INTENT(IN) :: attrname
149 : LOGICAL, INTENT(OUT) :: attrval_l
150 : !
151 : CHARACTER(LEN=80) :: attrval_c
152 : !
153 144 : CALL get_c_attr ( attrname, attrval_c )
154 144 : if ( len_trim(attrval_c) > 0 ) then
155 114 : READ (attrval_c,*, err=1) attrval_l
156 114 : return
157 : 1 print '("Error reading attribute ",a,": expected logical, found ",a)', &
158 0 : trim(attrname), trim(attrval_c)
159 : end if
160 30 : attrval_l = .false.
161 : !
162 : END SUBROUTINE get_l_attr
163 : !
164 668 : SUBROUTINE get_r_attr ( attrname, attrval_r )
165 : !
166 : ! returns attrval_r=0 if not found or not readable
167 : !
168 : !IMPLICIT NONE
169 : CHARACTER(LEN=*), INTENT(IN) :: attrname
170 : REAL(dp), INTENT(OUT) :: attrval_r
171 : !
172 : CHARACTER(LEN=80) :: attrval_c
173 : !
174 668 : CALL get_c_attr ( attrname, attrval_c )
175 668 : if ( len_trim(attrval_c) > 0 ) then
176 363 : READ (attrval_c,*, err=1) attrval_r
177 363 : return
178 : 1 print '("Error reading attribute ",a,": expected real, found ",a)', &
179 0 : trim(attrname), trim(attrval_c)
180 : end if
181 305 : attrval_r = 0.0_dp
182 : !
183 : END SUBROUTINE get_r_attr
184 : !
185 1932 : SUBROUTINE get_c_attr ( attrname, attrval_c )
186 : !
187 : ! returns attrval_c='' if not found
188 : !
189 : !IMPLICIT NONE
190 : CHARACTER(LEN=*), INTENT(IN) :: attrname
191 : CHARACTER(LEN=*), INTENT(OUT) :: attrval_c
192 : !
193 : CHARACTER(LEN=1) :: quote
194 : INTEGER :: j0, j1
195 : LOGICAL :: found
196 : !
197 : ! search for attribute name in attrlist: attr1="val1" attr2="val2" ...
198 : !
199 1932 : attrval_c = ''
200 3326 : if ( .not. allocated(attrlist) ) return
201 1852 : if ( len_trim(attrlist) < 1 ) return
202 : !
203 : j0 = 1
204 14098 : do while ( j0 < len_trim(attrlist) )
205 : ! locate = and first quote
206 13640 : j1 = index ( attrlist(j0:), '=' )
207 13640 : quote = attrlist(j0+j1:j0+j1)
208 : ! next line: something is not right
209 13640 : if ( quote /= '"' .and. quote /= "'" ) return
210 : ! check if attribute found: need exact match
211 13640 : found = ( trim(attrname) == adjustl(trim(attrlist(j0:j0+j1-2))) )
212 : ! locate next quote
213 13640 : j0 = j0+j1+1
214 13640 : j1 = index ( attrlist(j0:), quote )
215 13640 : if ( found) then
216 1394 : if ( j1 == 1 ) then
217 : ! two quotes, one after the other ("")
218 16 : attrval_c = ' '
219 : else
220 : ! get value between two quotes
221 1378 : attrval_c = adjustl(trim(attrlist(j0:j0+j1-2)))
222 : end if
223 1394 : return
224 : end if
225 12246 : j0 = j0+j1
226 : end do
227 : !
228 1932 : END SUBROUTINE get_c_attr
229 : !
230 0 : SUBROUTINE add_i_attr ( attrname, attrval_i )
231 : !
232 : !IMPLICIT NONE
233 : CHARACTER(LEN=*), INTENT(IN) :: attrname
234 : INTEGER, INTENT(IN) :: attrval_i
235 : !
236 0 : CALL add_c_attr ( attrname, i2c(attrval_i) )
237 : !
238 0 : END SUBROUTINE add_i_attr
239 : !
240 0 : SUBROUTINE add_l_attr ( attrname, attrval_l )
241 : !
242 : !IMPLICIT NONE
243 : CHARACTER(LEN=*), INTENT(IN) :: attrname
244 : LOGICAL, INTENT(IN) :: attrval_l
245 : !
246 0 : CALL add_c_attr ( attrname, l2c(attrval_l) )
247 : !
248 0 : END SUBROUTINE add_l_attr
249 : !
250 0 : SUBROUTINE add_r_attr ( attrname, attrval_r )
251 : !
252 : !IMPLICIT NONE
253 : CHARACTER(LEN=*), INTENT(IN) :: attrname
254 : REAL(dp), INTENT(IN) :: attrval_r
255 : !
256 0 : CALL add_c_attr ( attrname, r2c(attrval_r) )
257 : !
258 0 : END SUBROUTINE add_r_attr
259 : !
260 0 : SUBROUTINE add_c_attr ( attrname, attrval_c )
261 : !
262 : !IMPLICIT NONE
263 : CHARACTER(LEN=*), INTENT(IN) :: attrname, attrval_c
264 : !
265 0 : IF ( .NOT. ALLOCATED(attrlist) ) THEN
266 0 : attrlist = ' '//TRIM(attrname)//'="'//TRIM(attrval_c)//'"'
267 : ELSE
268 0 : attrlist = attrlist // ' ' // TRIM(attrname)//'="'//TRIM(attrval_c)//'"'
269 : END IF
270 : !
271 0 : END SUBROUTINE add_c_attr
272 : !
273 16 : FUNCTION xml_open_file ( filexml ) RESULT (iun)
274 : !
275 : ! returns on output the opened unit number if opened successfully
276 : ! returns -1 otherwise
277 : !
278 : CHARACTER(LEN=*), INTENT(in) :: filexml
279 : INTEGER :: iun, ios
280 : !
281 16 : IF ( nopen > 1 ) THEN
282 : print "('cannot open file ',a,': two xml files already opened')",&
283 0 : trim(filexml)
284 : iun = -1
285 0 : RETURN
286 : END IF
287 : OPEN ( NEWUNIT=iun, FILE=filexml, FORM='formatted', STATUS='unknown', &
288 16 : IOSTAT=ios)
289 16 : IF ( ios /= 0 ) iun = -1
290 16 : nopen = nopen + 1
291 16 : IF ( nopen > 1 ) xmlsave = xmlunit
292 16 : xmlunit = iun
293 16 : nlevel = 0
294 16 : open_tags(nlevel) = 'root'
295 16 : if ( allocated(attrlist) ) DEALLOCATE ( attrlist)
296 : #if defined ( __debug )
297 : print "('file ',a,' opened with unit ',i5)",trim(filexml),iun
298 : #endif
299 : !
300 16 : END FUNCTION xml_open_file
301 : !
302 16 : SUBROUTINE xml_closefile ( )
303 : !
304 16 : CLOSE ( UNIT=xmlunit, STATUS='keep' )
305 : #if defined ( __debug )
306 : print "('unit ',i5,': file closed')", xmlunit
307 : #endif
308 16 : xmlunit = xmlsave
309 16 : nopen = nopen - 1
310 16 : xmlsave = -1
311 16 : IF (nlevel > 0) print '("warning: file closed at level ",i1,&
312 0 : & " with tag ",A," open")', nlevel, trim(open_tags(nlevel))
313 16 : nlevel = 0
314 : !
315 16 : END SUBROUTINE xml_closefile
316 : !
317 0 : SUBROUTINE xmlw_opentag (name, ierr )
318 : ! On input:
319 : ! name required, character: tag name
320 : ! On output: the tag is left open, ready for addition of data -
321 : ! the tag must be subsequently closed with close_xml_tag
322 : ! If ierr is present, the error code set in write_tag_and_attr is returned
323 : ! If ierr is absent, the above error code is reprinted on output
324 : !
325 : CHARACTER(LEN=*), INTENT(IN) :: name
326 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
327 : !
328 : INTEGER :: ier_
329 : CHARACTER(LEN=1) :: tag_end='>'
330 : !
331 0 : ier_ = write_tag_and_attr (name)
332 : IF ( ier_ < 0 ) ier_ = 0
333 : ! complete tag, leaving it open for further data
334 0 : WRITE (xmlunit, "(A1)", ERR=100) tag_end
335 : ! exit here
336 0 : 100 IF ( present(ierr) ) THEN
337 0 : ierr = ier_
338 0 : ELSE IF ( ier_ > 0 ) THEN
339 0 : print '("Fatal error ",i2," in xmlw_opentag!")', ier_
340 : END IF
341 : !
342 0 : END SUBROUTINE xmlw_opentag
343 :
344 0 : SUBROUTINE writetag_c (name, cval, ierr )
345 : ! On input, same as xmlw_opentag, plus:
346 : ! cval character, value of the tag.
347 : ! If cval=' ' write <name attr1="val1" attr2="val2" ... />
348 : ! If cval='?' write <?name attr1="val1" attr2="val2" ...?>
349 : ! otherwise, write <name attr1="val1" attr2="val2" ...>cval</name>
350 : ! (on a same line if one_line_tags=.true.)
351 : ! On output, same as xmlw_opentag
352 : !
353 : CHARACTER(LEN=*), INTENT(IN) :: name
354 : CHARACTER(LEN=*), INTENT(IN) :: cval
355 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
356 : !
357 : INTEGER :: ier_
358 : LOGICAL :: is_proc
359 : !
360 0 : is_proc = (LEN_TRIM(cval) == 1)
361 0 : IF ( is_proc ) is_proc = is_proc .AND. ( cval(1:1) == '?')
362 : IF (is_proc) THEN
363 0 : ier_ = write_tag_and_attr ( '?'//name )
364 : ELSE
365 0 : ier_ = write_tag_and_attr ( name )
366 : END IF
367 0 : IF ( ier_ > 0 ) GO TO 10
368 : !
369 : ! all is well: write tag value if any, close otherwise
370 : !
371 0 : IF ( LEN_TRIM(cval) == 0 ) THEN
372 : ! empty tag value: close here the tag
373 0 : CALL xmlw_closetag ( '' )
374 0 : ELSE IF ( is_proc ) THEN
375 : ! close "process" tag (e.g. <?xml ... ?>
376 0 : CALL xmlw_closetag ( '?' )
377 : ELSE
378 : ! write value (character)
379 : IF (one_line_tags) THEN
380 0 : WRITE (xmlunit, "('>',A)", ADVANCE='no') trim(cval)
381 : ELSE
382 : WRITE (xmlunit, "('>',/,A)") trim(cval)
383 : ENDIF
384 : ! close here the tag
385 0 : CALL xmlw_closetag ( name )
386 : END IF
387 : ! in case of exit error close the tag anyway
388 0 : 10 IF ( ier_ /= 0 ) WRITE (xmlunit, "('>')", ERR=100)
389 0 : 100 IF ( present(ierr) ) THEN
390 0 : ierr = ier_
391 0 : ELSE IF ( ier_ > 0 ) THEN
392 0 : print '("Fatal error ",i2," in xmlw_writetag!")', ier_
393 : END IF
394 : !
395 0 : END SUBROUTINE writetag_c
396 : !
397 0 : SUBROUTINE writetag_i (name, ival, ierr )
398 : !
399 : ! As writetag_c, for integer value
400 : !
401 : CHARACTER(LEN=*), INTENT(IN) :: name
402 : INTEGER, INTENT(IN) :: ival
403 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
404 : !
405 0 : CALL writetag_c (name, i2c(ival), ierr )
406 : !
407 0 : END SUBROUTINE writetag_i
408 : !
409 0 : SUBROUTINE writetag_iv (name, ivec, ierr )
410 : !
411 : ! As writetag_c, for integer value
412 : !
413 : CHARACTER(LEN=*), INTENT(IN) :: name
414 : INTEGER, INTENT(IN) :: ivec(:)
415 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
416 : !
417 0 : CALL xmlw_opentag (name, ierr )
418 0 : WRITE( xmlunit, '(4I18)') ivec
419 0 : CALL xmlw_closetag ( )
420 : !
421 0 : END SUBROUTINE writetag_iv
422 : !
423 0 : SUBROUTINE writetag_l (name, lval, ierr )
424 : !
425 : ! As writetag_c, for logical value
426 : !
427 : CHARACTER(LEN=*), INTENT(IN) :: name
428 : LOGICAL, INTENT(IN) :: lval
429 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
430 : !
431 0 : CALL writetag_c (name, l2c(lval), ierr )
432 : !
433 0 : END SUBROUTINE writetag_l
434 : !
435 0 : SUBROUTINE writetag_r (name, rval, ierr )
436 : !
437 : ! As writetag_c, for real value
438 : !
439 : CHARACTER(LEN=*), INTENT(IN) :: name
440 : REAL(dp), INTENT(IN) :: rval
441 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
442 : !
443 0 : CALL writetag_c (name, r2c(rval), ierr )
444 : !
445 0 : END SUBROUTINE writetag_r
446 : !
447 0 : SUBROUTINE writetag_rv (name, rvec, ierr )
448 : !
449 : ! As writetag_c, for a vector of real values
450 : !
451 : CHARACTER(LEN=*), INTENT(IN) :: name
452 : REAL(dp), INTENT(IN) :: rvec(:)
453 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
454 : !
455 0 : CALL xmlw_opentag (name, ierr )
456 0 : WRITE( xmlunit, '(3es24.15)') rvec
457 0 : CALL xmlw_closetag ( )
458 : !
459 0 : END SUBROUTINE writetag_rv
460 : !
461 0 : SUBROUTINE writetag_rm (name, rmat, ierr )
462 : !
463 : ! As writetag_c, for a matrix of real values
464 : !
465 : CHARACTER(LEN=*), INTENT(IN) :: name
466 : REAL(dp), INTENT(IN) :: rmat(:,:)
467 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
468 : !
469 0 : CALL xmlw_opentag (name, ierr )
470 0 : WRITE( xmlunit, '(3es24.15)') rmat
471 0 : CALL xmlw_closetag ( )
472 : !
473 0 : END SUBROUTINE writetag_rm
474 : !
475 0 : SUBROUTINE writetag_rt (name, rtens, ierr )
476 : !
477 : ! As writetag_c, for a 3-dim tensor of real values
478 : !
479 : CHARACTER(LEN=*), INTENT(IN) :: name
480 : REAL(dp), INTENT(IN) :: rtens(:,:,:)
481 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
482 : !
483 0 : CALL xmlw_opentag (name, ierr )
484 0 : WRITE( xmlunit, '(3es24.15)') rtens
485 0 : CALL xmlw_closetag ( )
486 : !
487 0 : END SUBROUTINE writetag_rt
488 : !
489 0 : SUBROUTINE writetag_zv (name, zvec, ierr )
490 : !
491 : ! As writetag_c, for a vector of complex values
492 : !
493 : use, intrinsic :: iso_c_binding
494 : CHARACTER(LEN=*), INTENT(IN) :: name
495 : COMPLEX(dp), INTENT(IN), TARGET:: zvec(:)
496 : INTEGER, INTENT(OUT), OPTIONAL :: ierr
497 : !
498 : ! Casts a real pointer (rvec) to a complex array (zvec) via C pointer (!)
499 : ! in order to write complexes as two reals. Some compilers require that
500 : ! the argument of c_loc (zvec) is a pointer or has the "target" attribute
501 : !
502 : TYPE (c_ptr) :: cp
503 0 : REAL(dp), POINTER :: rvec(:)
504 : INTEGER :: n, ndim
505 : !
506 0 : NULLIFY (rvec)
507 0 : cp = c_loc(zvec)
508 0 : CALL c_f_pointer (cp, rvec, shape(zvec)*[2])
509 0 : CALL xmlw_opentag (name, ierr )
510 0 : ndim = SIZE (zvec)
511 0 : DO n=1,2*ndim,2
512 0 : WRITE( xmlunit, *) rvec(n), rvec(n+1)
513 : END DO
514 0 : CALL xmlw_closetag ( )
515 : !
516 0 : END SUBROUTINE writetag_zv
517 : !
518 0 : SUBROUTINE writetag_zm (name, zmat, ierr )
519 : !
520 : ! As writetag_c for a matrix of complex values - see comments in writetag_zv
521 : !
522 : use, intrinsic :: iso_c_binding
523 : CHARACTER(LEN=*), INTENT(IN) :: name
524 : COMPLEX(dp), INTENT(IN), TARGET:: zmat(:,:)
525 : INTEGER, INTENT(OUT), OPTIONAL :: ierr
526 : !
527 : TYPE (c_ptr) :: cp
528 0 : REAL(dp), POINTER :: rmat(:,:)
529 : !
530 0 : NULLIFY (rmat)
531 0 : cp = c_loc(zmat)
532 0 : CALL c_f_pointer (cp, rmat, shape(zmat)*[2,1])
533 : !
534 0 : CALL xmlw_opentag (name, ierr )
535 0 : WRITE( xmlunit, '(2es24.15)') rmat
536 0 : CALL xmlw_closetag ( )
537 : !
538 0 : END SUBROUTINE writetag_zm
539 : !
540 0 : SUBROUTINE writetag_zt (name, ztens, ierr )
541 : !
542 : ! As writetag_c for a matrix of complex values - see comments in writetag_zv
543 : !
544 : use, intrinsic :: iso_c_binding
545 : CHARACTER(LEN=*), INTENT(IN) :: name
546 : COMPLEX(dp), INTENT(IN), TARGET:: ztens(:,:,:)
547 : INTEGER, INTENT(OUT), OPTIONAL :: ierr
548 : !
549 : TYPE (c_ptr) :: cp
550 0 : REAL(dp), POINTER :: rtens(:,:,:)
551 : !
552 0 : NULLIFY (rtens)
553 0 : cp = c_loc(ztens)
554 0 : CALL c_f_pointer (cp, rtens, shape(ztens)*[2,1,1])
555 : !
556 0 : CALL xmlw_opentag (name, ierr )
557 0 : WRITE( xmlunit, '(2es24.15)') rtens
558 0 : CALL xmlw_closetag ( )
559 : !
560 0 : END SUBROUTINE writetag_zt
561 : !
562 0 : FUNCTION write_tag_and_attr (name) RESULT (ierr)
563 : !
564 : CHARACTER(LEN=*), INTENT(IN) :: name
565 : INTEGER :: ierr
566 : ! See list of error codes in the header of this file
567 : !
568 : !LOGICAL :: have_list, have_vals
569 : INTEGER :: i !, la, lv, n1a,n2a, n1v, n2v
570 : !
571 0 : IF ( LEN_TRIM(name) > maxlength ) THEN
572 0 : ierr = 2
573 : RETURN
574 : END IF
575 : !
576 0 : IF ( nlevel+1 > maxlevel ) THEN
577 0 : ierr = 4
578 : RETURN
579 : END IF
580 0 : nlevel = nlevel+1
581 0 : open_tags(nlevel) = TRIM(name)
582 : !
583 : ! pretty (?) printing
584 : !
585 0 : ierr = 1
586 0 : DO i=2,nlevel
587 0 : WRITE (xmlunit, "(' ')", ADVANCE="no", ERR=10)
588 : END DO
589 0 : WRITE (xmlunit, "('<',A)", ADVANCE="no", ERR=10) trim(name)
590 : #if defined ( __debug )
591 : print '("opened (write) level-",i1," tag ",A)', nlevel, trim(open_tags(nlevel))
592 : #endif
593 : !
594 : ! attributes (if present)
595 : !
596 0 : ierr = 3
597 0 : if ( allocated (attrlist) ) then
598 0 : WRITE (xmlunit, "(A)", ADVANCE='no', ERR=10) attrlist
599 0 : deallocate (attrlist)
600 : end if
601 : ! normal exit here
602 : ierr = 0
603 : 10 RETURN
604 : !
605 0 : END FUNCTION write_tag_and_attr
606 : !
607 0 : SUBROUTINE xmlw_closetag ( tag )
608 : ! tag not present: close current open tag with </tag>
609 : ! empty tag present: close current open tag with />
610 : ! tag='?' present: close current open tag with ?>
611 : ! otherwise,close specified tag with </tag>
612 : CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: tag
613 : INTEGER :: i
614 : !
615 0 : IF ( nlevel < 0 ) THEN
616 0 : print "('xmlw_closetag: severe error, closing tag that was never opened')"
617 0 : RETURN
618 : END IF
619 0 : IF ( .NOT.PRESENT(tag) ) THEN
620 0 : DO i=2,nlevel
621 0 : WRITE (xmlunit, '(" ")', ADVANCE='NO')
622 : END DO
623 0 : WRITE (xmlunit, '("</",A,">")') trim(open_tags(nlevel))
624 : #if defined ( __debug )
625 : print '("closed (write) level-",i1," tag ",A)', nlevel, trim(open_tags(nlevel))
626 : #endif
627 : ELSE
628 0 : i = len_trim(tag)
629 0 : IF ( i == 0 ) THEN
630 0 : WRITE (xmlunit, '("/>")')
631 : #if defined ( __debug )
632 : print '("closed (write) level-",i1," tag ",A)', &
633 : nlevel, trim(open_tags(nlevel))
634 : #endif
635 0 : ELSE IF ( i == 1 .AND. tag(1:1) == '?' ) THEN
636 0 : WRITE (xmlunit, '("?>")')
637 : #if defined ( __debug )
638 : print '("closed (write) level-",i1," tag ",A)', nlevel, tag
639 : #endif
640 : ELSE
641 0 : WRITE (xmlunit, '("</",A,">")') trim(tag)
642 : #if defined ( __debug )
643 : print '("closed (write) level-",i1," tag ",A)', nlevel, tag
644 : #endif
645 : END IF
646 : END IF
647 0 : nlevel = nlevel-1
648 : !
649 : END SUBROUTINE xmlw_closetag
650 : !
651 : !--------------------------------------------------------
652 0 : function xml_protect ( data_in ) result (data_out)
653 : !--------------------------------------------------------
654 : !
655 : ! poor-man escaping of a string so that it conforms to xml standard:
656 : ! replace & with @, < and > with *.
657 : ! To prevent problems with attributes, double quotes " are replaced
658 : ! with single quotes '. data_out is left-justified
659 : !
660 : character(len=*), intent(in) :: data_in
661 : character(len=:), allocatable :: data_out
662 : !character(len=1) :: c
663 : integer:: n, i
664 : !
665 0 : n = len_trim(adjustl(data_in))
666 : ! Alternative version with CDATA:
667 : ! allocate(character(len=n+12):: data_out)
668 : ! data_out = '<![CDATA['//trim(adjustl(data_in))//']]>'
669 0 : data_out = trim(adjustl(data_in))
670 0 : do i=1,n
671 0 : if ( data_out(i:i) == '&' ) data_out(i:i) = '@'
672 0 : if ( data_out(i:i) == '<' .or. data_out(i:i) == '>') data_out(i:i) = '*'
673 0 : if ( data_out(i:i) == '"' ) data_out(i:i) = "'"
674 : end do
675 : ! a more complete version should escape & as &, < as <
676 : ! (escaping > as > , " as "es; , ' as &apo; is not strictly needed)
677 : ! BUT taking care not to escape & into &amp;
678 :
679 0 : end function xml_protect
680 :
681 : ! Poor-man conversion utilities from integer, logical, real to character
682 : ! To be used in conjunction with routines in module xmlw to write xml
683 : !
684 261 : function i2c (i) result (c)
685 : integer, intent(in) :: i
686 : character(len=:), allocatable :: c
687 : character(len=11) :: caux
688 : !
689 261 : write(caux,'(i11)') i
690 261 : c = trim(adjustl(caux))
691 : !
692 261 : end function i2c
693 :
694 0 : function l2c (l) result (c)
695 : logical, intent(in) :: l
696 : character(len=:), allocatable :: c
697 : !
698 0 : if (l) then
699 0 : c='true'
700 : else
701 0 : c='false'
702 : endif
703 : !
704 0 : end function l2c
705 :
706 0 : function r2c (f) result (c)
707 : real(dp), intent(in) :: f
708 : character(len=:), allocatable :: c
709 : character(len=30) :: caux
710 : !
711 : !integer :: n, m, i
712 : ! The format of real numbers can be vastly improved
713 : ! this is just the simplest solution
714 0 : write(caux,*) f
715 0 : c = trim(adjustl(caux))
716 : !
717 0 : end function r2c
718 : !
719 0 : SUBROUTINE readtag_i (name, ival, ierr )
720 : !
721 : ! As readtag_c, for integer value
722 : !
723 : CHARACTER(LEN=*), INTENT(IN) :: name
724 : INTEGER, INTENT(OUT) :: ival
725 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
726 : CHARACTER(LEN=80) :: cval
727 : !
728 0 : CALL readtag_c (name, cval, ierr )
729 0 : if ( len_trim(cval) > 0 ) then
730 0 : READ (cval,*) ival
731 : else
732 0 : ival = 0
733 : end if
734 : !
735 0 : END SUBROUTINE readtag_i
736 : !
737 0 : SUBROUTINE readtag_iv (name, ivec, ierr)
738 : !
739 : ! As readtag_c, for a vector of integer values
740 : !
741 : CHARACTER(LEN=*), INTENT(IN) :: name
742 : INTEGER, INTENT(OUT) :: ivec(:)
743 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
744 : INTEGER :: ier_
745 : !
746 0 : CALL xmlr_opentag (name, ier_)
747 0 : if ( ier_ == 0 ) then
748 0 : READ(xmlunit, *) ivec
749 0 : CALL xmlr_closetag ( )
750 : else
751 0 : ivec = 0.0_dp
752 : end if
753 0 : IF ( present (ierr) ) ierr = ier_
754 : !
755 0 : END SUBROUTINE readtag_iv
756 : !
757 0 : SUBROUTINE readtag_l (name, lval, ierr )
758 : !
759 : ! As readtag_c, for logical value
760 : !
761 : CHARACTER(LEN=*), INTENT(IN) :: name
762 : LOGICAL, INTENT(OUT) :: lval
763 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
764 : CHARACTER(LEN=80) :: cval
765 : !
766 0 : CALL readtag_c (name, cval, ierr )
767 0 : if ( len_trim(cval) > 0 ) then
768 0 : READ (cval,*) lval
769 : else
770 0 : lval = .false.
771 : end if
772 : !
773 0 : END SUBROUTINE readtag_l
774 : !
775 0 : SUBROUTINE readtag_r (name, rval, ierr )
776 : !
777 : ! As readtag_c, for real value
778 : !
779 : CHARACTER(LEN=*), INTENT(IN) :: name
780 : REAL(dp), INTENT(OUT) :: rval
781 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
782 : CHARACTER(LEN=80) :: cval
783 : !
784 0 : CALL readtag_c (name, cval, ierr )
785 0 : if ( len_trim(cval) > 0 ) then
786 0 : READ (cval,*) rval
787 : else
788 0 : rval = 0.0_dp
789 : end if
790 : !
791 0 : END SUBROUTINE readtag_r
792 : !
793 283 : SUBROUTINE readtag_rv (name, rvec, ierr)
794 : !
795 : ! As readtag_c, for a vector of real values
796 : !
797 : CHARACTER(LEN=*), INTENT(IN) :: name
798 : REAL(dp), INTENT(OUT) :: rvec(:)
799 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
800 : INTEGER :: ier_
801 : !
802 283 : CALL xmlr_opentag (name, ier_)
803 283 : if ( ier_ == 0 ) then
804 259 : READ(xmlunit, *) rvec
805 259 : CALL xmlr_closetag ( )
806 : else
807 34404 : rvec = 0.0_dp
808 : end if
809 283 : IF ( present (ierr) ) ierr = ier_
810 : !
811 283 : END SUBROUTINE readtag_rv
812 : !
813 16 : SUBROUTINE readtag_rm (name, rmat, ierr)
814 : !
815 : ! As readtag_c, for a matrix of real values
816 : !
817 : CHARACTER(LEN=*), INTENT(IN) :: name
818 : REAL(dp), INTENT(OUT) :: rmat(:,:)
819 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
820 : INTEGER :: ier_
821 : !
822 16 : CALL xmlr_opentag (name, ier_)
823 16 : if ( ier_ == 0 ) then
824 16 : READ(xmlunit, *) rmat
825 16 : CALL xmlr_closetag ( )
826 : else
827 0 : rmat = 0.0_dp
828 : end if
829 16 : IF ( present (ierr) ) ierr = ier_
830 : !
831 16 : END SUBROUTINE readtag_rm
832 : !
833 0 : SUBROUTINE readtag_rt (name, rtens, ierr)
834 : !
835 : ! As readtag_c, for a 3-dim tensor of real values
836 : !
837 : CHARACTER(LEN=*), INTENT(IN) :: name
838 : REAL(dp), INTENT(OUT) :: rtens(:,:,:)
839 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
840 : INTEGER :: ier_
841 : !
842 0 : CALL xmlr_opentag (name, ier_)
843 0 : if ( ier_ == 0 ) then
844 0 : READ(xmlunit, *) rtens
845 0 : CALL xmlr_closetag ( )
846 : else
847 0 : rtens = 0.0_dp
848 : end if
849 0 : IF ( present (ierr) ) ierr = ier_
850 : !
851 0 : END SUBROUTINE readtag_rt
852 : !
853 0 : SUBROUTINE readtag_zv (name, zvec, ierr)
854 : !
855 : ! As readtag_c, for a vector of complex values - see comments in writetag_zv
856 : !
857 : use, intrinsic :: iso_c_binding
858 : CHARACTER(LEN=*), INTENT(IN) :: name
859 : COMPLEX(dp), INTENT(OUT), target :: zvec(:)
860 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
861 : !
862 : TYPE (c_ptr) :: cp
863 0 : REAL(dp), POINTER :: rvec(:)
864 : INTEGER :: ier_
865 : !
866 0 : CALL xmlr_opentag (name, ier_)
867 0 : if ( ier_ == 0 ) then
868 0 : NULLIFY (rvec)
869 0 : cp = c_loc(zvec)
870 0 : CALL c_f_pointer ( cp, rvec, shape(zvec)*[2])
871 0 : READ( xmlunit, *) rvec
872 0 : CALL xmlr_closetag ( )
873 : else
874 0 : zvec = 0.0_dp
875 : end if
876 0 : IF ( present (ierr) ) ierr = ier_
877 : !
878 0 : END SUBROUTINE readtag_zv
879 : !
880 0 : SUBROUTINE readtag_zm (name, zmat, ierr)
881 : !
882 : ! As readtag_c, for a matrix of complex values - see comments in writetag_zv
883 : !
884 : use, intrinsic :: iso_c_binding
885 : CHARACTER(LEN=*), INTENT(IN) :: name
886 : COMPLEX(dp), INTENT(OUT), target :: zmat(:,:)
887 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
888 : TYPE (c_ptr) :: cp
889 0 : REAL(dp), POINTER :: rmat(:,:)
890 : INTEGER :: ier_
891 : !
892 0 : CALL xmlr_opentag (name, ier_)
893 0 : if ( ier_ == 0 ) then
894 0 : NULLIFY (rmat)
895 0 : cp = c_loc(zmat)
896 0 : CALL c_f_pointer (cp, rmat, shape(zmat)*[2,1])
897 0 : READ(xmlunit, *) rmat
898 0 : CALL xmlr_closetag ( )
899 : else
900 0 : zmat = 0.0_dp
901 : end if
902 0 : IF ( present (ierr) ) ierr = ier_
903 : !
904 0 : END SUBROUTINE readtag_zm
905 : !
906 0 : SUBROUTINE readtag_zt (name, ztens, ierr)
907 : !
908 : ! As readtag_c, for a matrix of complex values - see comments in writetag_zv
909 : !
910 : use, intrinsic :: iso_c_binding
911 : CHARACTER(LEN=*), INTENT(IN) :: name
912 : COMPLEX(dp), INTENT(OUT), target :: ztens(:,:,:)
913 : INTEGER, INTENT(OUT),OPTIONAL :: ierr
914 : TYPE (c_ptr) :: cp
915 0 : REAL(dp), POINTER :: rtens(:,:,:)
916 : INTEGER :: ier_
917 : !
918 0 : CALL xmlr_opentag (name, ier_)
919 0 : if ( ier_ == 0 ) then
920 0 : NULLIFY (rtens)
921 0 : cp = c_loc(ztens)
922 0 : CALL c_f_pointer (cp, rtens, shape(ztens)*[2,1,1])
923 0 : READ(xmlunit, *) rtens
924 0 : CALL xmlr_closetag ( )
925 : else
926 0 : ztens = 0.0_dp
927 : end if
928 0 : IF ( present (ierr) ) ierr = ier_
929 : !
930 0 : END SUBROUTINE readtag_zt
931 : !
932 106 : subroutine readtag_c ( tag, cval, ierr)
933 : !
934 : !implicit none
935 : !
936 : character(len=*), intent(in) :: tag
937 : character(len=*), intent(out):: cval
938 : integer, intent(out), optional :: ierr
939 : !
940 : integer :: i, j, lt !, ll
941 : character(len=1) :: endtag
942 : !
943 106 : call xmlr_opentag ( tag, ierr )
944 : !
945 106 : cval = ''
946 106 : if ( eot < 0 ) then
947 0 : if ( .not. present(ierr) ) then
948 0 : write(std_out,*) 'end of file reached, tag not found'
949 : else
950 0 : ierr = 1
951 : end if
952 106 : return
953 106 : else if ( eot == 0 ) then
954 : ! print *, 'tag found, no value to read on line'
955 : return
956 : else
957 : ! scan current line if there is something after the end of tag
958 : ! (variable "eot"); read a new line otherwise
959 0 : do while(.true.)
960 0 : if ( eot > len_trim(line) ) then
961 0 : read(xmlunit,'(a)', end=10) line
962 0 : j = 1
963 : else
964 : j = eot
965 : end if
966 : ! beginning of val at line(j:j): search for end tag
967 0 : i = index ( line(j:), '</'//trim(tag) )
968 0 : if ( i < 1 ) then
969 : ! </tag> not found on this line: read value and continue
970 0 : cval = trim(cval) // adjustl(trim(line(j:)))
971 : else
972 : ! possible end tag found
973 0 : lt = len_trim(tag)
974 0 : endtag = adjustl( line(j+i+1+lt:) )
975 0 : if ( endtag /= '>' ) then
976 0 : if ( .not.present(ierr)) then
977 0 : write(std_out,*) 'tag ',trim(tag),' not correctly closed'
978 : else
979 0 : ierr = 2
980 : endif
981 : else
982 : ! end of tag found, read value (if any) and exit
983 0 : if ( i > 1 ) cval = trim(cval) // adjustl(trim(line(j:j+i-2)))
984 : ! print *, 'value=',cval
985 : end if
986 : #if defined ( __debug )
987 : print '("closed (read) level-",i1," tag ",A)', &
988 : nlevel, trim(open_tags(nlevel))
989 : #endif
990 0 : nlevel = nlevel -1
991 : !
992 0 : return
993 : !
994 : endif
995 : !
996 : end do
997 : !
998 : end if
999 : ! print *, 'tag </',trim(tag),'> not found'
1000 0 : 10 if ( present(ierr) ) then
1001 0 : ierr = 1
1002 : else
1003 0 : write(std_out,*) 'end of file reached, tag </'//trim(tag)//'> not found'
1004 : end if
1005 : !
1006 106 : end subroutine readtag_c
1007 : !
1008 491 : subroutine xmlr_opentag ( tag, ierr)
1009 : !
1010 : !implicit none
1011 : !
1012 : character(len=*), intent(in) :: tag
1013 : integer, intent(out), optional :: ierr
1014 : ! See list of error codes in the header of this file
1015 : integer :: stat, ntry, ll, lt, i, j, j0
1016 : ! stat=-1: in comment (not actually used)
1017 : ! stat= 0: begin
1018 : ! stat= 1: tag found
1019 : !
1020 : character(len=1) :: quote
1021 : !
1022 491 : nattr=0
1023 491 : ntry =0
1024 387 : if ( allocated(attrlist) ) deallocate (attrlist)
1025 491 : lt = len_trim(tag)
1026 : !
1027 557 : 1 ntry = ntry+1
1028 557 : stat=0
1029 557 : eot =-1
1030 : do while (.true.)
1031 619182 : read(xmlunit,'(a)', end=10) line
1032 619076 : ll = len_trim(line)
1033 619076 : if ( ll == maxline ) then
1034 0 : write(std_out,*)'xmlr_opentag: severe error, line too long'
1035 0 : if (present(ierr)) ierr = 3
1036 451 : return
1037 : end if
1038 : ! j is the current scan position
1039 : j = 1
1040 : ! j0 is the start of attributes and values
1041 : j0 = 1
1042 644225 : parse: do while ( j <= ll )
1043 : !
1044 : ! following case is never set and unnecessary:
1045 : !if ( stat ==-1 ) then
1046 : ! ! scanning a comment
1047 : ! i = index(line(j:),'-->')
1048 : ! if ( i == 0 ) then
1049 : ! ! no end of comment found on this line
1050 : ! exit parse
1051 : ! else
1052 : ! ! end of comment found
1053 : ! stat = 0
1054 : ! j = j+i+3
1055 : ! end if
1056 : !else if ( stat == 0 ) then
1057 1260757 : if ( stat == 0 ) then
1058 : !
1059 : ! searching for tag
1060 : !
1061 616983 : i = index( line(j:),'<'//trim(tag) )
1062 616983 : if ( i == 0 ) then
1063 : ! no tag found on this line
1064 : exit parse
1065 : else
1066 : ! tag found? check what follows our would-be tag
1067 451 : j = j+i+lt
1068 451 : if ( j > ll ) then
1069 : stat = 1
1070 : ! <tag continues in next line
1071 : exit parse
1072 : else if ( line(j:j) == ' ' .or. line(j:j) == '>' &
1073 264 : .or. line(j:j+1)=='/>') then
1074 : ! <tag or <tag> or <tag/> found
1075 264 : stat = 1
1076 : end if
1077 : end if
1078 : !
1079 : else if ( stat == 1 ) then
1080 : ! tag found, search for attributes if any or end of tag
1081 25336 : if (line(j:j) == ' ' ) then
1082 : ! skip blanks: there is at least one if attributes are present
1083 3577 : j = j+1
1084 : ! save value of j into j0: beginning of an attribute
1085 3577 : j0= j
1086 21759 : else if ( line(j:j+1) == '/>' ) then
1087 : ! <tag ... /> found : return
1088 106 : if (present(ierr)) ierr =-1
1089 : ! eot = 0: tag with no value found
1090 106 : eot = 0
1091 : !
1092 106 : return
1093 : !
1094 21653 : else if ( line(j:j) == '>' ) then
1095 : ! <tag ... > found
1096 : ! eot points to the rest of the line
1097 345 : eot = j+1
1098 345 : if (present(ierr)) ierr = 0
1099 345 : nlevel = nlevel+1
1100 345 : IF ( nlevel > maxlevel ) THEN
1101 0 : write(std_out,*) 'xmlr_opentag: severe error, too many levels'
1102 0 : if (present(ierr)) ierr = 4
1103 : else
1104 345 : open_tags(nlevel) = trim(tag)
1105 : #if defined ( __debug )
1106 : print '("opened (read) level-",i1," tag ",A)',&
1107 : nlevel, trim(open_tags(nlevel))
1108 : #endif
1109 : end if
1110 : !
1111 345 : return
1112 : !
1113 21308 : else if ( line(j:j) == '=' ) then
1114 : ! end of attribute located: save attribute (with final =)
1115 2249 : nattr=nattr+1
1116 : ! print *, 'attr=',line(j0:j-1)
1117 2249 : if ( nattr == 1 ) then
1118 397 : attrlist = line(j0:j)
1119 : else
1120 1852 : attrlist = attrlist//' '//line(j0:j)
1121 : end if
1122 : ! continue searching for attribute value
1123 : j = j+1
1124 19059 : else if ( line(j:j) == '"' .or. line(j:j) =="'" ) then
1125 : ! first occurrence of ' or " found, look for next
1126 2249 : quote = line(j:j)
1127 2249 : i = index(line(j+1:),quote)
1128 2249 : if ( i < 1 ) then
1129 : ! print *, 'Error: matching quote not found'
1130 : go to 10
1131 : else
1132 : ! save attribute value (with quotes) and continue scanning
1133 : ! print *, 'attrval=',line(j:j+i-2)
1134 2249 : attrlist = attrlist//line(j:j+i)
1135 2249 : j = j+i+1
1136 : end if
1137 : else
1138 : ! continue scanning until end of attribute
1139 : j = j+1
1140 : endif
1141 : !
1142 : end if
1143 : end do parse
1144 : !
1145 : end do
1146 : !
1147 106 : 10 if ( stat == 0 ) then
1148 106 : if ( present(ierr) ) then
1149 106 : ierr = 1
1150 : ! quick-and-dirty pseudo-fix to deal with tags not found:
1151 : ! rewind and try again - will work if the desired tag is
1152 : ! found above the current position (and nowhere else)
1153 106 : rewind(xmlunit)
1154 106 : if ( ntry == 1 ) go to 1
1155 : else
1156 0 : write(std_out,*) 'end of file reached, tag '//trim(tag)//' not found'
1157 : end if
1158 : else
1159 0 : write(std_out,*) 'xmlr_opentag: severe parsing error'
1160 0 : if ( present(ierr) ) ierr = 2
1161 : end if
1162 : !
1163 491 : end subroutine xmlr_opentag
1164 : !
1165 345 : subroutine xmlr_closetag ( tag, ierr)
1166 : !
1167 : !implicit none
1168 : !
1169 : character(len=*), intent(in), optional :: tag
1170 : integer, intent(out), optional :: ierr
1171 : ! 0: </tag> found
1172 : ! 1: </tag> not found
1173 : ! 2: error parsing file
1174 : !
1175 : integer :: stat, ll, lt, i, j
1176 : ! stat=-1: in comment (not actually used)
1177 : ! stat= 0: begin
1178 : ! stat= 1: end
1179 : !
1180 345 : if ( nlevel < 0 ) &
1181 0 : print '("xmlr_closetag: severe error, closing tag that was never opened")'
1182 : stat=0
1183 : #if defined ( __debug )
1184 : if ( .not. present(tag) ) then
1185 : print '("closed (read) level-",i1," tag ",A)', &
1186 : nlevel, trim(open_tags(nlevel))
1187 : else
1188 : print '("closed (read) level-",i1," tag ",A)', nlevel, tag
1189 : end if
1190 : #endif
1191 : do while (.true.)
1192 24336 : read(xmlunit,'(a)', end=10) line
1193 24336 : ll = len_trim(line)
1194 24336 : if ( ll == maxline ) then
1195 0 : write(std_out,*) 'Fatal error: line too long'
1196 0 : if (present(ierr)) ierr = 2
1197 0 : return
1198 : end if
1199 : ! j is the current scan position
1200 : j = 1
1201 24681 : parse: do while ( j <= ll )
1202 : !
1203 : ! following case is never set and unnecessary:
1204 : !if ( stat ==-1 ) then
1205 : ! scanning a comment
1206 : ! i = index(line(j:),'-->')
1207 : ! if ( i == 0 ) then
1208 : ! no end of comment found on this line
1209 : ! exit parse
1210 : ! else
1211 : ! end of comment found
1212 : ! stat = 0
1213 : ! j = j+i+3
1214 : ! end if
1215 : !else if ( stat == 0 ) then
1216 48648 : if ( stat == 0 ) then
1217 : !
1218 : ! searching for closing tag
1219 : !
1220 24312 : IF ( .NOT.PRESENT(tag) ) THEN
1221 24312 : i = index( line(j:),'</'//trim(open_tags(nlevel)) )
1222 24312 : lt= len_trim(open_tags(nlevel))
1223 : ELSE
1224 0 : i = index( line(j:),'</'//trim(tag) )
1225 0 : lt= len_trim(tag)
1226 : END IF
1227 24312 : if ( i == 0 ) then
1228 : ! no tag found on this line
1229 : exit parse
1230 : else
1231 : ! tag found? check what follows our would-be tag
1232 345 : j = j+i+1+lt
1233 345 : if ( j > ll ) then
1234 : stat = 1
1235 : ! </tag continues in next line
1236 : exit parse
1237 345 : else if ( line(j:j) == ' ' .or. line(j:j) == '>') then
1238 : ! </tag or </tag> found
1239 345 : stat = 1
1240 : end if
1241 : end if
1242 : !
1243 : else if ( stat == 1 ) then
1244 : !
1245 : ! </tag found, search for end of tag
1246 : !
1247 345 : if (line(j:j) == ' ' ) then
1248 : ! skip blanks
1249 0 : j = j+1
1250 345 : else if ( line(j:j) == '>' ) then
1251 : ! </tag ... > found
1252 : ! print *, '</tag> found'
1253 345 : if ( present(ierr) ) ierr = 0
1254 : !print '("closed")'
1255 345 : nlevel = nlevel - 1
1256 : !
1257 345 : return
1258 : !
1259 : endif
1260 : !
1261 : end if
1262 : end do parse
1263 : !
1264 : end do
1265 : !
1266 0 : 10 write(std_out,*) 'end of file reached, closing tag not found'
1267 0 : if ( present(ierr) ) ierr = 1
1268 : !
1269 : end subroutine xmlr_closetag
1270 :
1271 4101 : END MODULE xmltools
|